Add logbook catalog index filters

This commit is contained in:
Alexander Sellite 2026-08-29 20:19:47 -04:00
parent 4575830857
commit 81decf2b71
9 changed files with 1540 additions and 10 deletions

View file

@ -1356,6 +1356,24 @@ func _validate_player_menu_nested_controller_back() -> void:
== LogbookPageType.ControllerZone.ENTRIES,
"Global player-menu Back did not return Logbook to creature selection.",
)
logbook_page.call("_set_index_open", true, false)
logbook_page.set(
"_controller_zone",
LogbookPageType.ControllerZone.INDEX,
)
_expect(
bool(menu.call("consume_escape")),
"Global player-menu Back did not consume the Logbook index zone.",
)
_expect(
menu.visible and not bool(logbook_page.get("_index_open")),
"Global player-menu Back did not return from the Logbook index page.",
)
_expect(
int(logbook_page.get("_controller_zone"))
== LogbookPageType.ControllerZone.TABS,
"Global player-menu Back did not return Logbook index focus to tabs.",
)
var net_page := menu.get("_the_net_page") as Control
net_page.set("_active", true)

View file

@ -2,6 +2,7 @@ extends SceneTree
const MainScene = preload("res://main/main.tscn")
const FishCatchType = preload("res://fish/fish_catch.gd")
const MENU_TRANSITION_SETTLE_SECONDS := 3.0
func _initialize() -> void:
@ -36,12 +37,16 @@ func _run() -> void:
var logbook := player_menu.get_node("%CatalogLogbook") as LogbookPage
var backdrop := main.get_node("%PlayerMenuBackdrop") as ColorRect
var hotbar := game_ui.get_node("%Hotbar") as Control
var fishing_spot := main.get("_fishing_spot") as FishingSpot
assert(logbook.get("_fishing_spot") == fishing_spot)
assert(logbook.get("_world_time") == main.get("_world_time"))
assert(logbook.get("_world_weather") == main.get("_world_weather"))
var shortcut := InputEventKey.new()
shortcut.pressed = true
shortcut.physical_keycode = KEY_L
assert(bool(player_menu.call("_handle_direct_page_shortcut", shortcut)))
await create_timer(2.2).timeout
await create_timer(MENU_TRANSITION_SETTLE_SECONDS).timeout
assert(player_menu.visible)
assert(logbook.visible)
assert(backdrop.visible)
@ -51,6 +56,18 @@ func _run() -> void:
var entry_buttons: Dictionary = logbook.get("_entry_buttons")
assert(entry_buttons.size() == 108)
await _capture_if_requested("-unknown")
logbook.call("_set_index_open", true, false)
await process_frame
assert(bool(logbook.get("_index_open")))
assert((logbook.get("_index_body") as Control).visible)
await _capture_if_requested("-index")
logbook.set_compact_presentation(true)
await process_frame
await _capture_if_requested("-index-compact")
logbook.set_compact_presentation(false)
await process_frame
logbook.call("_set_index_open", false, false)
await process_frame
logbook.call(
"_select_category", WaterType.Type.FRESH_WATER
)
@ -68,13 +85,29 @@ func _run() -> void:
logbook.call("_select_entry", &"bluegill", &"bluegill")
await create_timer(0.2).timeout
await _capture_if_requested("-known")
var bluegill := (
main.get("fish_catalog") as FishPool
).get_fish_by_id(&"bluegill")
var bluegill_available_now := fishing_spot.is_species_available_now(bluegill)
var index_options := logbook.get("_index_options") as Dictionary
index_options["availability"] = (
LogbookCatalog.AvailabilityFilter.AVAILABLE_NOW
)
logbook.notify_availability_context_changed()
await process_frame
assert(
(logbook.get("_entry_buttons") as Dictionary).has(&"bluegill")
== bluegill_available_now
)
logbook.call("_reset_index")
await process_frame
assert(bool(player_menu.call("_handle_direct_page_shortcut", shortcut)))
await create_timer(2.2).timeout
await create_timer(MENU_TRANSITION_SETTLE_SECONDS).timeout
assert(not player_menu.visible)
assert(bool(player_menu.call("_handle_direct_page_shortcut", shortcut)))
await create_timer(2.2).timeout
await create_timer(MENU_TRANSITION_SETTLE_SECONDS).timeout
player_menu.call(
"_show_section_immediate", PlayerMenu.Section.PROFILE
)

View file

@ -17,6 +17,8 @@ const CatalogResource: FishPoolType = preload(
"res://fish/pools/fish_catalog.tres"
)
var _query_available_id: StringName
func _initialize() -> void:
call_deferred("_run")
@ -35,6 +37,7 @@ func _run() -> void:
quit()
return
_validate_catalog()
_validate_catalog_query()
await _validate_page()
print("Logbook validation: PASS")
quit()
@ -68,6 +71,348 @@ func _validate_catalog() -> void:
)
func _validate_catalog_query() -> void:
var collection := CollectionLogType.new()
var inventory := FishInventoryType.new()
var fresh_species: Array[FishDataType] = []
for fish: FishDataType in LogbookCatalog.ordered_species(
CatalogResource.candidates
):
if LogbookCatalog.category_for(fish) == LogbookCatalog.Category.FRESH_WATER:
fresh_species.append(fish)
assert(fresh_species.size() == 108)
var first := fresh_species[0]
var second := fresh_species[1]
var unknown := fresh_species[2]
for quality: int in FishQualityType.TIER_COUNT:
collection.record_catch(first.id, quality)
collection.record_catch(second.id, FishQualityType.Tier.BORING)
var held := _make_test_catch(first, true)
assert(inventory.add_catch(held))
var options := _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
var filtered := LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered.size() == 2)
assert(first in filtered and second in filtered)
options["show"] = LogbookCatalog.DiscoveryFilter.MISSING
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered.size() == fresh_species.size() - 2)
options["sort"] = LogbookCatalog.SortMode.CATALOG_NUMBER
options["descending"] = true
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered.front() == fresh_species.back())
assert(filtered.back() == unknown)
options["show"] = LogbookCatalog.DiscoveryFilter.INCOMPLETE
options["descending"] = false
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered == [second])
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
options["sort"] = LogbookCatalog.SortMode.CATCH_COUNT
options["descending"] = true
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered == [first, second])
options = _default_query_options()
options["search"] = unknown.display_name
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered.is_empty())
options["search"] = str(unknown.catalog_number)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered == [unknown])
options = _default_query_options()
options["holding"] = LogbookCatalog.HoldingFilter.FAVORITED
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered == [first])
options["holding"] = LogbookCatalog.HoldingFilter.IN_COOLER
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered == [first])
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
options["group"] = String(first.collection_group)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(first in filtered)
for fish: FishDataType in filtered:
assert(fish.collection_group == first.collection_group)
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
options["rarity"] = (
int(first.rarity) + LogbookCatalog.RarityFilter.COMMON
)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(first in filtered)
for fish: FishDataType in filtered:
assert(fish.rarity == first.rarity)
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
options["method"] = (
int(first.collection_method) + LogbookCatalog.MethodFilter.FISHING
)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(first in filtered)
for fish: FishDataType in filtered:
assert(fish.collection_method == first.collection_method)
var first_season := -1
for season: int in 4:
if first.is_available_in_season(season):
first_season = season
break
assert(first_season >= 0)
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
options["season"] = (
first_season + LogbookCatalog.SeasonFilter.SPRING
)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(first in filtered)
for fish: FishDataType in filtered:
assert(fish.is_available_in_season(first_season))
var first_is_available_by_day := (
first.availability == null or first.availability.allow_day
)
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
options["time"] = (
LogbookCatalog.TimeFilter.DAY
if first_is_available_by_day
else LogbookCatalog.TimeFilter.NIGHT
)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(first in filtered)
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.CAUGHT
options["sort"] = LogbookCatalog.SortMode.QUALITY_PROGRESS
options["descending"] = true
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered == [first, second])
for sort_mode: LogbookCatalog.SortMode in [
LogbookCatalog.SortMode.NAME,
LogbookCatalog.SortMode.RARITY,
LogbookCatalog.SortMode.VALUE,
LogbookCatalog.SortMode.WEIGHT,
]:
options = _default_query_options()
options["sort"] = sort_mode
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(filtered[0] in [first, second])
assert(filtered[1] in [first, second])
assert(filtered[0] != filtered[1])
assert(filtered[2] == unknown)
_query_available_id = second.id
options = _default_query_options()
options["availability"] = (
LogbookCatalog.AvailabilityFilter.AVAILABLE_NOW
)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
Callable(self, "_query_species_available_now"),
)
assert(filtered == [second])
_query_available_id = unknown.id
options["show"] = LogbookCatalog.DiscoveryFilter.MISSING
options["rarity"] = (
int(unknown.rarity) + LogbookCatalog.RarityFilter.COMMON
)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
Callable(self, "_query_species_available_now"),
)
assert(filtered == [unknown])
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.MISSING
options["group"] = String(unknown.collection_group)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(unknown in filtered)
assert(
String(unknown.collection_group)
in LogbookCatalog.available_groups(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
)
)
var unknown_is_available_by_day := (
unknown.availability == null or unknown.availability.allow_day
)
options = _default_query_options()
options["show"] = LogbookCatalog.DiscoveryFilter.MISSING
options["time"] = (
LogbookCatalog.TimeFilter.DAY
if unknown_is_available_by_day
else LogbookCatalog.TimeFilter.NIGHT
)
filtered = LogbookCatalog.filtered_species(
CatalogResource.candidates,
LogbookCatalog.Category.FRESH_WATER,
collection,
inventory,
options,
)
assert(unknown in filtered)
inventory.free()
collection.free()
func _default_query_options() -> Dictionary:
return {
"search": "",
"show": LogbookCatalog.DiscoveryFilter.ALL,
"sort": LogbookCatalog.SortMode.CATALOG_NUMBER,
"descending": false,
"availability": LogbookCatalog.AvailabilityFilter.ANY,
"season": LogbookCatalog.SeasonFilter.ANY,
"time": LogbookCatalog.TimeFilter.ANY,
"rarity": LogbookCatalog.RarityFilter.ANY,
"method": LogbookCatalog.MethodFilter.ANY,
"holding": LogbookCatalog.HoldingFilter.ANY,
"group": "",
}
func _make_test_catch(fish: FishDataType, favorited: bool) -> FishCatchType:
var fish_catch := FishCatchType.new()
fish_catch.fish = fish
fish_catch.fish_id = fish.id
fish_catch.weight_lb = fish.get_minimum_weight()
fish_catch.display_scale = fish.get_display_scale_for_weight(
fish_catch.weight_lb
)
fish_catch.quality = FishQualityType.Tier.BORING
fish_catch.sale_value = fish.get_sale_value_for_weight(fish_catch.weight_lb)
fish_catch.is_favorited = favorited
fish_catch.ensure_identity()
return fish_catch
func _query_species_available_now(fish: FishDataType) -> bool:
return fish != null and fish.id == _query_available_id
func _validate_page() -> void:
var collection := CollectionLogType.new()
var inventory := FishInventoryType.new()
@ -91,6 +436,10 @@ func _validate_page() -> void:
assert(outer_margin.get_theme_constant("margin_right") == 160)
assert(outer_margin.get_theme_constant("margin_bottom") == 106)
assert(is_equal_approx(book.offset_top, 65.0))
page.call("_set_index_open", true, false)
await process_frame
_validate_index_content_bounds(page)
page.call("_set_index_open", false, false)
page.set_compact_presentation(false)
await process_frame
assert(outer_margin.get_theme_constant("margin_left") == 52)
@ -158,6 +507,39 @@ func _validate_page() -> void:
)
var initial_detail_body := page.get("_detail_body") as VBoxContainer
assert(not initial_detail_body.get_parent() is ScrollContainer)
var index_tab := page.get("_index_tab") as Button
var index_body := page.get("_index_body") as VBoxContainer
assert(index_tab != null and index_body != null)
assert(index_tab.size == LogbookPage.INDEX_TAB_SIZE)
assert(
not index_tab.get_global_rect().intersects(
(category_tabs.back() as Button).get_global_rect()
)
)
page.call("_set_index_open", true, false)
await process_frame
assert(index_body.visible)
assert(not initial_detail_body.visible)
assert((page.get("_index_option_buttons") as Dictionary).size() == 10)
_validate_index_content_bounds(page)
page.call(
"_cycle_index_option",
&"show",
1,
)
await process_frame
assert((page.get("_entry_buttons") as Dictionary).is_empty())
assert(
(page.get("_empty_state") as Label).text
== "No entries match this index."
)
page.call("_reset_index")
await process_frame
assert((page.get("_entry_buttons") as Dictionary).size() == 108)
page.call("_set_index_open", false, false)
await process_frame
assert(not index_body.visible)
assert(initial_detail_body.visible)
assert(
page.call("_entry_label_text", "flathead catfish")
== "flathead\ncatfish"
@ -458,8 +840,19 @@ func _validate_page() -> void:
(page.get("_portrait_overlay_backdrop") as Button).pressed.emit()
await process_frame
var live_index_options := page.get("_index_options") as Dictionary
live_index_options["holding"] = LogbookCatalog.HoldingFilter.IN_COOLER
page.call("_refresh_catalog")
await process_frame
assert(
(page.get("_entry_buttons") as Dictionary).keys()
== [&"bluegill"]
)
inventory.remove_catch_by_id(fish_catch.catch_id)
await process_frame
assert((page.get("_entry_buttons") as Dictionary).is_empty())
page.call("_reset_index")
await process_frame
assert(not _detail_text(page).contains("number owned"))
page.queue_free()
collection.queue_free()
@ -474,6 +867,54 @@ func _detail_text(page: LogbookPage) -> String:
return "\n".join(values)
func _validate_index_content_bounds(page: LogbookPage) -> void:
var body := page.get("_index_body") as VBoxContainer
assert(body != null and body.visible)
var right_page := body.get_parent() as Control
assert(right_page != null)
var page_rect := right_page.get_global_rect()
var body_rect := body.get_global_rect()
var protected_rect := Rect2(
page_rect.position + Vector2(
LogbookPage.INDEX_CONTENT_LEFT_INSET,
LogbookPage.INDEX_CONTENT_TOP_INSET,
),
page_rect.size - Vector2(
LogbookPage.INDEX_CONTENT_LEFT_INSET
+ LogbookPage.INDEX_CONTENT_RIGHT_INSET,
LogbookPage.INDEX_CONTENT_TOP_INSET
+ LogbookPage.INDEX_CONTENT_BOTTOM_INSET,
),
)
assert(
body_rect.position.x
>= page_rect.position.x + LogbookPage.INDEX_CONTENT_LEFT_INSET - 1.0
)
assert(
body_rect.end.x
<= page_rect.end.x - LogbookPage.INDEX_CONTENT_RIGHT_INSET + 1.0
)
assert(
body_rect.position.y >= page_rect.position.y,
"Index starts above the authored page: body=%s page=%s"
% [body_rect, page_rect],
)
assert(
body_rect.end.y <= page_rect.end.y,
"Index extends below the authored page: body=%s page=%s"
% [body_rect, page_rect],
)
var controls: Array = page.get("_index_controls") as Array
for value: Variant in controls:
var control := value as Control
if control != null and control.visible:
assert(
protected_rect.grow(2.0).encloses(control.get_global_rect()),
"Index control crossed the authored right-page boundary: %s"
% control.name,
)
func _descendant_label_text(parent: Node) -> String:
var values: PackedStringArray = []
for node: Node in parent.find_children("*", "Label", true, false):