diff --git a/fish/pools/fish_catalog.tres b/fish/pools/fish_catalog.tres new file mode 100644 index 0000000..66a1c34 --- /dev/null +++ b/fish/pools/fish_catalog.tres @@ -0,0 +1,15 @@ +[gd_resource type="Resource" load_steps=10 format=3] + +[ext_resource type="Script" path="res://fish/fish_pool.gd" id="1_pool"] +[ext_resource type="Resource" path="res://fish/species/bluegill/bluegill.tres" id="2_bluegill"] +[ext_resource type="Resource" path="res://fish/species/bass/bass.tres" id="3_bass"] +[ext_resource type="Resource" path="res://fish/species/carp/carp.tres" id="4_carp"] +[ext_resource type="Resource" path="res://fish/species/sunfish/sunfish.tres" id="5_sunfish"] +[ext_resource type="Resource" path="res://fish/species/catfish_blue/catfish_blue.tres" id="6_catfish_blue"] +[ext_resource type="Resource" path="res://fish/species/catfish_channel/catfish_channel.tres" id="7_catfish_channel"] +[ext_resource type="Resource" path="res://fish/species/catfish_flathead/catfish_flathead.tres" id="8_catfish_flathead"] +[ext_resource type="Resource" path="res://fish/species/catfish_white/catfish_white.tres" id="9_catfish_white"] + +[resource] +script = ExtResource("1_pool") +candidates = [ExtResource("2_bluegill"), ExtResource("3_bass"), ExtResource("4_carp"), ExtResource("5_sunfish"), ExtResource("6_catfish_blue"), ExtResource("7_catfish_channel"), ExtResource("8_catfish_flathead"), ExtResource("9_catfish_white")] diff --git a/fish/pools/starter_pond_pool.tres b/fish/pools/starter_pond_pool.tres new file mode 100644 index 0000000..66a1c34 --- /dev/null +++ b/fish/pools/starter_pond_pool.tres @@ -0,0 +1,15 @@ +[gd_resource type="Resource" load_steps=10 format=3] + +[ext_resource type="Script" path="res://fish/fish_pool.gd" id="1_pool"] +[ext_resource type="Resource" path="res://fish/species/bluegill/bluegill.tres" id="2_bluegill"] +[ext_resource type="Resource" path="res://fish/species/bass/bass.tres" id="3_bass"] +[ext_resource type="Resource" path="res://fish/species/carp/carp.tres" id="4_carp"] +[ext_resource type="Resource" path="res://fish/species/sunfish/sunfish.tres" id="5_sunfish"] +[ext_resource type="Resource" path="res://fish/species/catfish_blue/catfish_blue.tres" id="6_catfish_blue"] +[ext_resource type="Resource" path="res://fish/species/catfish_channel/catfish_channel.tres" id="7_catfish_channel"] +[ext_resource type="Resource" path="res://fish/species/catfish_flathead/catfish_flathead.tres" id="8_catfish_flathead"] +[ext_resource type="Resource" path="res://fish/species/catfish_white/catfish_white.tres" id="9_catfish_white"] + +[resource] +script = ExtResource("1_pool") +candidates = [ExtResource("2_bluegill"), ExtResource("3_bass"), ExtResource("4_carp"), ExtResource("5_sunfish"), ExtResource("6_catfish_blue"), ExtResource("7_catfish_channel"), ExtResource("8_catfish_flathead"), ExtResource("9_catfish_white")] diff --git a/fish/species/bass/fish_bass_striped.png b/fish/species/bass/fish_bass_striped.png index 89b5b5e..efbf835 100644 Binary files a/fish/species/bass/fish_bass_striped.png and b/fish/species/bass/fish_bass_striped.png differ diff --git a/fish/species/bluegill/fish_bluegill.png b/fish/species/bluegill/fish_bluegill.png index 8569e3c..013db04 100644 Binary files a/fish/species/bluegill/fish_bluegill.png and b/fish/species/bluegill/fish_bluegill.png differ diff --git a/fish/species/carp/fish_carp_common.png b/fish/species/carp/fish_carp_common.png index 50d0b31..709f4d4 100644 Binary files a/fish/species/carp/fish_carp_common.png and b/fish/species/carp/fish_carp_common.png differ diff --git a/fish/species/catfish_blue/catfish_blue.tres b/fish/species/catfish_blue/catfish_blue.tres new file mode 100644 index 0000000..b3e05b1 --- /dev/null +++ b/fish/species/catfish_blue/catfish_blue.tres @@ -0,0 +1,32 @@ +[gd_resource type="Resource" load_steps=5 format=3] + +[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] +[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] +[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] +[ext_resource type="Texture2D" path="res://fish/species/catfish_blue/fish_catfish_blue.png" id="4_texture"] + +[sub_resource type="Resource" id="BlueCatfishAvailability"] +script = ExtResource("3_availability_script") +allowed_location_tags = Array[StringName]([&"starter_pond"]) +allow_day = true +allow_night = true +preferred_bait_tags = Array[StringName]([&"worm", &"minnow"]) +preferred_bait_weight_multiplier = 1.35 + +[resource] +script = ExtResource("1_fish_data") +id = &"catfish_blue" +display_name = "blue catfish" +rarity = 1 +base_catch_weight = 1.25 +catch_profile = ExtResource("2_profile") +availability = SubResource("BlueCatfishAvailability") +weight_min_lb = 3.0 +weight_max_lb = 12.0 +display_scale_min = 0.95 +display_scale_max = 1.55 +display_scale_curve = 0.9 +sell_value_min = 6 +sell_value_max = 9 +sell_value_curve = 0.9 +display_texture = ExtResource("4_texture") diff --git a/fish/species/catfish_blue/fish_catfish_blue.png b/fish/species/catfish_blue/fish_catfish_blue.png new file mode 100644 index 0000000..6482e15 Binary files /dev/null and b/fish/species/catfish_blue/fish_catfish_blue.png differ diff --git a/fish/species/catfish_blue/fish_catfish_blue.png.import b/fish/species/catfish_blue/fish_catfish_blue.png.import new file mode 100644 index 0000000..60d3606 --- /dev/null +++ b/fish/species/catfish_blue/fish_catfish_blue.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://7f1dtcou8moe" +path="res://.godot/imported/fish_catfish_blue.png-03480cfe99c4fdece0a97273445594bd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://fish/species/catfish_blue/fish_catfish_blue.png" +dest_files=["res://.godot/imported/fish_catfish_blue.png-03480cfe99c4fdece0a97273445594bd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/fish/species/catfish_channel/catfish_channel.tres b/fish/species/catfish_channel/catfish_channel.tres new file mode 100644 index 0000000..cbfe28a --- /dev/null +++ b/fish/species/catfish_channel/catfish_channel.tres @@ -0,0 +1,32 @@ +[gd_resource type="Resource" load_steps=5 format=3] + +[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] +[ext_resource type="Resource" path="res://fishing/common_catch_profile.tres" id="2_profile"] +[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] +[ext_resource type="Texture2D" path="res://fish/species/catfish_channel/fish_catfish_channel.png" id="4_texture"] + +[sub_resource type="Resource" id="ChannelCatfishAvailability"] +script = ExtResource("3_availability_script") +allowed_location_tags = Array[StringName]([&"starter_pond"]) +allow_day = true +allow_night = true +preferred_bait_tags = Array[StringName]([&"worm"]) +preferred_bait_weight_multiplier = 1.35 + +[resource] +script = ExtResource("1_fish_data") +id = &"catfish_channel" +display_name = "channel catfish" +rarity = 0 +base_catch_weight = 2.0 +catch_profile = ExtResource("2_profile") +availability = SubResource("ChannelCatfishAvailability") +weight_min_lb = 1.5 +weight_max_lb = 7.0 +display_scale_min = 0.85 +display_scale_max = 1.35 +display_scale_curve = 1.0 +sell_value_min = 4 +sell_value_max = 7 +sell_value_curve = 1.0 +display_texture = ExtResource("4_texture") diff --git a/fish/species/catfish_channel/fish_catfish_channel.png b/fish/species/catfish_channel/fish_catfish_channel.png new file mode 100644 index 0000000..b858806 Binary files /dev/null and b/fish/species/catfish_channel/fish_catfish_channel.png differ diff --git a/fish/species/catfish_channel/fish_catfish_channel.png.import b/fish/species/catfish_channel/fish_catfish_channel.png.import new file mode 100644 index 0000000..4a37a2d --- /dev/null +++ b/fish/species/catfish_channel/fish_catfish_channel.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dvxpk2ltt3blb" +path="res://.godot/imported/fish_catfish_channel.png-5078da9a00f276d273bfcd2b50b98937.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://fish/species/catfish_channel/fish_catfish_channel.png" +dest_files=["res://.godot/imported/fish_catfish_channel.png-5078da9a00f276d273bfcd2b50b98937.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/fish/species/catfish_flathead/catfish_flathead.tres b/fish/species/catfish_flathead/catfish_flathead.tres new file mode 100644 index 0000000..c9440df --- /dev/null +++ b/fish/species/catfish_flathead/catfish_flathead.tres @@ -0,0 +1,32 @@ +[gd_resource type="Resource" load_steps=5 format=3] + +[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] +[ext_resource type="Resource" path="res://fishing/bass_catch_profile.tres" id="2_profile"] +[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] +[ext_resource type="Texture2D" path="res://fish/species/catfish_flathead/fish_catfish_flathead.png" id="4_texture"] + +[sub_resource type="Resource" id="FlatheadCatfishAvailability"] +script = ExtResource("3_availability_script") +allowed_location_tags = Array[StringName]([&"starter_pond"]) +allow_day = true +allow_night = true +preferred_bait_tags = Array[StringName]([&"worm", &"minnow"]) +preferred_bait_weight_multiplier = 1.35 + +[resource] +script = ExtResource("1_fish_data") +id = &"catfish_flathead" +display_name = "flathead catfish" +rarity = 1 +base_catch_weight = 1.0 +catch_profile = ExtResource("2_profile") +availability = SubResource("FlatheadCatfishAvailability") +weight_min_lb = 3.0 +weight_max_lb = 14.0 +display_scale_min = 1.0 +display_scale_max = 1.6 +display_scale_curve = 0.9 +sell_value_min = 7 +sell_value_max = 10 +sell_value_curve = 0.9 +display_texture = ExtResource("4_texture") diff --git a/fish/species/catfish_flathead/fish_catfish_flathead.png b/fish/species/catfish_flathead/fish_catfish_flathead.png new file mode 100644 index 0000000..e248c02 Binary files /dev/null and b/fish/species/catfish_flathead/fish_catfish_flathead.png differ diff --git a/fish/species/catfish_flathead/fish_catfish_flathead.png.import b/fish/species/catfish_flathead/fish_catfish_flathead.png.import new file mode 100644 index 0000000..0d7eb41 --- /dev/null +++ b/fish/species/catfish_flathead/fish_catfish_flathead.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bacx63lp0yh7t" +path="res://.godot/imported/fish_catfish_flathead.png-31b800b34c27c75b84a2ee98a13ff954.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://fish/species/catfish_flathead/fish_catfish_flathead.png" +dest_files=["res://.godot/imported/fish_catfish_flathead.png-31b800b34c27c75b84a2ee98a13ff954.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/fish/species/catfish_white/catfish_white.tres b/fish/species/catfish_white/catfish_white.tres new file mode 100644 index 0000000..d0c775c --- /dev/null +++ b/fish/species/catfish_white/catfish_white.tres @@ -0,0 +1,32 @@ +[gd_resource type="Resource" load_steps=5 format=3] + +[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"] +[ext_resource type="Resource" path="res://fishing/common_catch_profile.tres" id="2_profile"] +[ext_resource type="Script" path="res://fish/fish_availability.gd" id="3_availability_script"] +[ext_resource type="Texture2D" path="res://fish/species/catfish_white/fish_catfish_white.png" id="4_texture"] + +[sub_resource type="Resource" id="WhiteCatfishAvailability"] +script = ExtResource("3_availability_script") +allowed_location_tags = Array[StringName]([&"starter_pond"]) +allow_day = true +allow_night = true +preferred_bait_tags = Array[StringName]([&"worm"]) +preferred_bait_weight_multiplier = 1.35 + +[resource] +script = ExtResource("1_fish_data") +id = &"catfish_white" +display_name = "white catfish" +rarity = 0 +base_catch_weight = 2.0 +catch_profile = ExtResource("2_profile") +availability = SubResource("WhiteCatfishAvailability") +weight_min_lb = 1.0 +weight_max_lb = 5.0 +display_scale_min = 0.8 +display_scale_max = 1.25 +display_scale_curve = 1.0 +sell_value_min = 4 +sell_value_max = 6 +sell_value_curve = 1.0 +display_texture = ExtResource("4_texture") diff --git a/fish/species/catfish_white/fish_catfish_white.png b/fish/species/catfish_white/fish_catfish_white.png new file mode 100644 index 0000000..499be44 Binary files /dev/null and b/fish/species/catfish_white/fish_catfish_white.png differ diff --git a/fish/species/catfish_white/fish_catfish_white.png.import b/fish/species/catfish_white/fish_catfish_white.png.import new file mode 100644 index 0000000..1bdd1d6 --- /dev/null +++ b/fish/species/catfish_white/fish_catfish_white.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bf6kiawwekv7g" +path="res://.godot/imported/fish_catfish_white.png-13b8ec9cfaabf9930cf00da49c81a3bd.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://fish/species/catfish_white/fish_catfish_white.png" +dest_files=["res://.godot/imported/fish_catfish_white.png-13b8ec9cfaabf9930cf00da49c81a3bd.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/fish/species/sunfish/fish_sunfish.png b/fish/species/sunfish/fish_sunfish.png index 138699e..4b7b084 100644 Binary files a/fish/species/sunfish/fish_sunfish.png and b/fish/species/sunfish/fish_sunfish.png differ diff --git a/main/main.tscn b/main/main.tscn index 8e269dd..3a100c7 100644 --- a/main/main.tscn +++ b/main/main.tscn @@ -5,7 +5,7 @@ [ext_resource type="Script" path="res://main/main.gd" id="3_main"] [ext_resource type="PackedScene" path="res://fishing/fishing_spot.tscn" id="4_spot"] [ext_resource type="PackedScene" path="res://ui/game_ui.tscn" id="5_ui"] -[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="6_pool"] +[ext_resource type="Resource" path="res://fish/pools/fish_catalog.tres" id="6_pool"] [ext_resource type="Resource" path="res://economy/buyers/pelicans.tres" id="7_pelicans"] [ext_resource type="Script" path="res://world/water_recovery_controller.gd" id="8_recovery"] [ext_resource type="Script" path="res://save/player_save_manager.gd" id="9_save"] diff --git a/tests/fish_catalog_content_validation.gd b/tests/fish_catalog_content_validation.gd new file mode 100644 index 0000000..50505c1 --- /dev/null +++ b/tests/fish_catalog_content_validation.gd @@ -0,0 +1,153 @@ +extends SceneTree + +const FishCatchType = preload("res://fish/fish_catch.gd") +const CollectionLogType = preload("res://collection/collection_log.gd") +const FishDataType = preload("res://fish/fish_data.gd") +const FishInventoryType = preload("res://inventory/fish_inventory.gd") +const FishPoolType = preload("res://fish/fish_pool.gd") +const FishSelectorType = preload("res://fish/fish_selector.gd") +const FishingContextType = preload("res://fishing/fishing_context.gd") +const NetworkSaleServiceType = preload( + "res://network/network_sale_service.gd" +) + +const Catalog: FishPoolType = preload("res://fish/pools/fish_catalog.tres") +const PondPool: FishPoolType = preload( + "res://fish/pools/starter_pond_pool.tres" +) +const OceanPool: FishPoolType = preload( + "res://fish/pools/test_water_pool.tres" +) +const PelicanBuyer = preload("res://economy/buyers/pelicans.tres") + +const ORIGINAL_IDS: Array[StringName] = [ + &"bluegill", &"bass", &"carp", &"sunfish", +] +const CATFISH_IDS: Array[StringName] = [ + &"catfish_blue", + &"catfish_channel", + &"catfish_flathead", + &"catfish_white", +] + + +func _initialize() -> void: + call_deferred("_run") + + +func _run() -> void: + _validate_catalog_and_pools() + _validate_catches_and_authoritative_sale() + print("Fish catalog content validation: PASS") + quit() + + +func _validate_catalog_and_pools() -> void: + assert(Catalog.candidates.size() == 8) + assert(PondPool.candidates.size() == 8) + assert(OceanPool.candidates.size() == 4) + for fish_id: StringName in ORIGINAL_IDS: + var original_fish: FishDataType = Catalog.get_fish_by_id(fish_id) + assert(original_fish != null) + assert(original_fish.is_selectable()) + assert(PondPool.get_fish_by_id(fish_id) != null) + assert(OceanPool.get_fish_by_id(fish_id) != null) + for fish_id: StringName in CATFISH_IDS: + var fish: FishDataType = Catalog.get_fish_by_id(fish_id) + assert(fish != null) + assert(fish.is_selectable()) + assert(PondPool.get_fish_by_id(fish_id) == fish) + assert(OceanPool.get_fish_by_id(fish_id) == null) + assert(fish.availability.allowed_location_tags == [&"starter_pond"]) + assert(LogbookCatalog.category_for(fish) == ( + LogbookCatalog.Category.FRESH_WATER + )) + + var expected_values: Dictionary[StringName, Array] = { + &"catfish_blue": [1, 1.25, 3.0, 12.0, 6, 9], + &"catfish_channel": [0, 2.0, 1.5, 7.0, 4, 7], + &"catfish_flathead": [1, 1.0, 3.0, 14.0, 7, 10], + &"catfish_white": [0, 2.0, 1.0, 5.0, 4, 6], + } + for fish_id: StringName in CATFISH_IDS: + var fish: FishDataType = Catalog.get_fish_by_id(fish_id) + var values: Array = expected_values[fish_id] + assert(int(fish.rarity) == int(values[0])) + assert(is_equal_approx(fish.base_catch_weight, float(values[1]))) + assert(is_equal_approx(fish.weight_min_lb, float(values[2]))) + assert(is_equal_approx(fish.weight_max_lb, float(values[3]))) + assert(fish.sell_value_min == int(values[4])) + assert(fish.sell_value_max == int(values[5])) + + var pond_context := FishingContextType.new() + pond_context.location_tags = [&"starter_pond"] + var ocean_context := FishingContextType.new() + ocean_context.location_tags = [&"coast", &"ocean"] + for fish_id: StringName in CATFISH_IDS: + var fish: FishDataType = Catalog.get_fish_by_id(fish_id) + assert(fish.availability.is_available(pond_context)) + assert(not fish.availability.is_available(ocean_context)) + var single_species_pool := FishPoolType.new() + single_species_pool.candidates = [fish] + var collection := CollectionLogType.new() + var selector := FishSelectorType.new() + selector.use_deterministic_test_seed = true + selector.begin_roll() + assert( + selector.select_fish( + single_species_pool, pond_context, collection + ) == fish + ) + collection.free() + + +func _validate_catches_and_authoritative_sale() -> void: + var inventory := FishInventoryType.new() + root.add_child(inventory) + var selector := FishSelectorType.new() + selector.use_deterministic_test_seed = true + selector.begin_roll() + var sale_service := NetworkSaleServiceType.new() + var session := NetworkSession.new() + root.add_child(session) + root.add_child(sale_service) + sale_service.set("_session", session) + sale_service.set("_fish_catalog", Catalog) + sale_service.set("_buyer", PelicanBuyer) + + for index: int in Catalog.candidates.size(): + var fish: FishDataType = Catalog.candidates[index] + var fish_catch: FishCatch = selector.create_catch(fish) + assert(fish_catch != null) + fish_catch.catch_sequence = index + 1 + assert(fish_catch.fish.display_texture == fish.display_texture) + + var loaded: FishCatch = FishCatchType.from_save_dict( + fish_catch.to_save_dict(), Catalog.get_fish_by_id(fish.id) + ) + assert(loaded != null) + assert(loaded.fish_id == fish.id) + assert(loaded.fish == fish) + + var replicated: FishCatch = FishCatchType.from_network_dict( + fish_catch.to_network_dict(), Catalog.get_fish_by_id(fish.id) + ) + assert(replicated != null) + assert(replicated.fish_id == fish.id) + assert(replicated.fish.display_texture == fish.display_texture) + + inventory.add_catch(loaded) + assert(inventory.contains_catch_id(loaded.catch_id)) + var sale_result: Dictionary = sale_service.call( + "_build_authoritative_result", + 1, + "catalog_sale_%d" % index, + [loaded.to_network_dict()], + ) + assert(bool(sale_result.get("accepted", false))) + assert(int(sale_result.get("base_value", -1)) == loaded.sale_value) + assert((sale_result.get("catch_ids", []) as Array).size() == 1) + + inventory.queue_free() + sale_service.queue_free() + session.queue_free() diff --git a/tests/fish_catalog_content_validation.gd.uid b/tests/fish_catalog_content_validation.gd.uid new file mode 100644 index 0000000..15244b8 --- /dev/null +++ b/tests/fish_catalog_content_validation.gd.uid @@ -0,0 +1 @@ +uid://dmocxxio0u53e diff --git a/tests/logbook_runtime_validation.gd b/tests/logbook_runtime_validation.gd index 8131739..c4802e7 100644 --- a/tests/logbook_runtime_validation.gd +++ b/tests/logbook_runtime_validation.gd @@ -1,6 +1,7 @@ extends SceneTree const MainScene = preload("res://main/main.tscn") +const FishCatchType = preload("res://fish/fish_catch.gd") func _initialize() -> void: @@ -19,6 +20,7 @@ func _run() -> void: for _frame: int in 8: await process_frame assert(bool(main.get("_gameplay_started"))) + _validate_save_round_trip(main, save_manager) var game_ui := main.get_node("%GameUI") as GameUI var player_menu := game_ui.get_node("%PlayerMenu") as PlayerMenu @@ -44,7 +46,7 @@ func _run() -> void: "_select_category", LogbookCatalog.Category.FRESH_WATER ) await create_timer(0.25).timeout - assert((logbook.get("_entry_buttons") as Dictionary).is_empty()) + assert((logbook.get("_entry_buttons") as Dictionary).size() == 4) await _capture_if_requested("-fresh") logbook.call("_select_category", LogbookCatalog.Category.SALT_WATER) await create_timer(0.25).timeout @@ -84,6 +86,71 @@ func _run() -> void: quit() +func _validate_save_round_trip( + main: Node, + save_manager: PlayerSaveManager, +) -> void: + var player := main.get("_player") as Player + var catalog := main.get("fish_catalog") as FishPool + assert(catalog != null) + assert(catalog.candidates.size() == 8) + for index: int in 4: + _add_test_catch(player, catalog.candidates[index]) + assert(save_manager.save_now()) + var no_catches: Array[FishCatch] = [] + var no_discoveries: Array[StringName] = [] + assert(player.inventory.replace_all_catches(no_catches, 1)) + assert(player.collection_log.replace_discovered_ids(no_discoveries)) + assert(save_manager.load_player_data()) + assert(player.inventory.get_all_catches().size() == 4) + for index: int in 4: + var original_fish: FishData = catalog.candidates[index] + assert(player.inventory.get_count(original_fish.id) == 1) + assert(player.collection_log.has_discovered(original_fish.id)) + + for index: int in range(4, catalog.candidates.size()): + _add_test_catch(player, catalog.candidates[index]) + assert(save_manager.save_now()) + assert(player.inventory.replace_all_catches(no_catches, 1)) + assert(player.collection_log.replace_discovered_ids(no_discoveries)) + assert(save_manager.load_player_data()) + assert(player.inventory.get_all_catches().size() == 8) + for fish: FishData in catalog.candidates: + assert(player.inventory.get_count(fish.id) == 1) + assert(player.collection_log.has_discovered(fish.id)) + for fish_id: StringName in [ + &"catfish_blue", + &"catfish_channel", + &"catfish_flathead", + &"catfish_white", + ]: + var fish_catch: FishCatch = ( + player.inventory.get_catches_by_fish_id(fish_id).front() + ) + player.begin_catch_showcase(fish_catch) + var catch_sprite := player.get_node( + "%CatchSprite" + ) as Sprite3D + assert(catch_sprite.texture == fish_catch.fish.display_texture) + player.end_catch_showcase(Callable(), true) + + +func _add_test_catch(player: Player, fish: FishData) -> void: + 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.sale_value = fish.get_sale_value_for_weight( + fish_catch.weight_lb + ) + fish_catch.ensure_identity() + player.inventory.add_catch(fish_catch) + player.collection_log.mark_discovered(fish.id) + + func _capture_if_requested(suffix: String) -> void: if not OS.has_environment("NETFISHING_LOGBOOK_CAPTURE"): return diff --git a/tests/logbook_validation.gd b/tests/logbook_validation.gd index 443f0c1..98fa3b0 100644 --- a/tests/logbook_validation.gd +++ b/tests/logbook_validation.gd @@ -6,7 +6,7 @@ const FishPoolType = preload("res://fish/fish_pool.gd") const CollectionLogType = preload("res://collection/collection_log.gd") const LogbookPageScene = preload("res://ui/logbook_page.tscn") const CatalogResource: FishPoolType = preload( - "res://fish/pools/test_water_pool.tres" + "res://fish/pools/fish_catalog.tres" ) @@ -34,21 +34,29 @@ func _run() -> void: func _validate_catalog() -> void: var expected_ids: Array[StringName] = [ - &"bluegill", &"bass", &"carp", &"sunfish", + &"bluegill", + &"bass", + &"carp", + &"sunfish", + &"catfish_blue", + &"catfish_channel", + &"catfish_flathead", + &"catfish_white", ] assert(LogbookCatalog.CATALOG_ORDER == expected_ids) for index: int in expected_ids.size(): var fish := CatalogResource.get_fish_by_id(expected_ids[index]) assert(fish != null) + var expected_category: LogbookCatalog.Category = ( + LogbookCatalog.Category.OTHER + if index < 4 + else LogbookCatalog.Category.FRESH_WATER + ) assert( LogbookCatalog.category_for(fish) - == LogbookCatalog.Category.OTHER + == expected_category ) assert(LogbookCatalog.catalog_number(fish.id) == index + 1) - assert( - LogbookCatalog.empty_state(LogbookCatalog.Category.FRESH_WATER) - == "No freshwater catches cataloged yet." - ) assert( LogbookCatalog.empty_state(LogbookCatalog.Category.SALT_WATER) == "No saltwater catches cataloged yet." @@ -83,11 +91,14 @@ func _validate_page() -> void: "_select_category", LogbookCatalog.Category.FRESH_WATER ) await create_timer(0.25).timeout - assert((page.get("_entry_buttons") as Dictionary).is_empty()) - assert( - (page.get("_empty_state") as Label).text - == "No freshwater catches cataloged yet." - ) + assert((page.get("_entry_buttons") as Dictionary).size() == 4) + for entry_value: Variant in ( + page.get("_entry_buttons") as Dictionary + ).values(): + var unknown_catfish := entry_value as Button + assert(unknown_catfish != null) + assert(unknown_catfish.text.contains("???")) + assert(unknown_catfish.icon == null) page.call("_select_category", LogbookCatalog.Category.SALT_WATER) await create_timer(0.25).timeout assert((page.get("_entry_buttons") as Dictionary).is_empty()) diff --git a/ui/logbook_catalog.gd b/ui/logbook_catalog.gd index 47dc174..be7b703 100644 --- a/ui/logbook_catalog.gd +++ b/ui/logbook_catalog.gd @@ -16,10 +16,19 @@ const CATALOG_ORDER: Array[StringName] = [ &"bass", &"carp", &"sunfish", + &"catfish_blue", + &"catfish_channel", + &"catfish_flathead", + &"catfish_white", ] # These maps remain explicit until fish resources gain authored habitat fields. -const FRESH_WATER_IDS: Array[StringName] = [] +const FRESH_WATER_IDS: Array[StringName] = [ + &"catfish_blue", + &"catfish_channel", + &"catfish_flathead", + &"catfish_white", +] const SALT_WATER_IDS: Array[StringName] = [] diff --git a/world/regions/starter_island_region.tscn b/world/regions/starter_island_region.tscn index a8833c4..29962ea 100644 --- a/world/regions/starter_island_region.tscn +++ b/world/regions/starter_island_region.tscn @@ -4,6 +4,7 @@ [ext_resource type="PackedScene" uid="uid://bk38p45urtjis" path="res://art/exported/environment/terrain/starter_island.glb" id="2_island"] [ext_resource type="Script" uid="uid://b6fp2obu0y2d0" path="res://world/fishable_water_region.gd" id="3_water"] [ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="4_pool"] +[ext_resource type="Resource" path="res://fish/pools/starter_pond_pool.tres" id="12_pond_pool"] [ext_resource type="Script" uid="uid://dnlbnlimgxoc2" path="res://world/player_water_trigger.gd" id="5_trigger"] [ext_resource type="Script" uid="uid://df2lsduguegxh" path="res://world/safe_respawn_point.gd" id="6_safe"] [ext_resource type="PackedScene" path="res://world/interactables/fishing_shop_world.tscn" id="7_shop"] @@ -103,7 +104,7 @@ collision_mask = 0 monitoring = false script = ExtResource("3_water") location_tags = Array[StringName]([&"starter_pond"]) -fish_pool = ExtResource("4_pool") +fish_pool = ExtResource("12_pond_pool") selection_priority = 1 surface_height_mode = 1