Expand fish catalog and add bait system

This commit is contained in:
Alexander Sellite 2026-08-06 01:00:52 -04:00
parent 43f57e56a0
commit 954042fd1d
134 changed files with 3134 additions and 127 deletions

View file

@ -232,7 +232,9 @@ func toggle_chat() -> void:
func refocus_gameplay() -> void:
close_chat()
_controller_refocused = true
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
func toggle_focus() -> void:

View file

@ -290,7 +290,9 @@ func close_shop(
_closing = true
_transaction_in_progress = false
hide()
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
if _fishing_spot != null and is_instance_valid(_fishing_spot):
_fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, false)
if (
@ -426,15 +428,23 @@ func _refresh_supplies() -> void:
FishingShopStockType.get_price(item_id),
_bag.get_quantity(item_id),
]
if FishingShopStockType.is_bait_topoff(item_id):
button.text = "%s\n$%d each • %d/%d" % [
item.display_name,
FishingShopStockType.get_price(item_id),
_bag.get_quantity(item_id),
FishingShopStockType.WORM_MAX_STACK,
]
button.tooltip_text = item.description
button.disabled = (
_transaction_in_progress
or _closing
or _network_shop == null
or not _network_shop.can_request_purchase()
or not _bag.can_add_item(item_id, 1)
or FishingShopStockType.get_purchase_quantity(item_id, _bag.get_quantity(item_id)) <= 0
or not _bag.can_add_item(item_id, FishingShopStockType.get_purchase_quantity(item_id, _bag.get_quantity(item_id)))
or not _wallet.can_afford(
FishingShopStockType.get_price(item_id)
FishingShopStockType.get_price(item_id) * FishingShopStockType.get_purchase_quantity(item_id, _bag.get_quantity(item_id))
)
)
button.tooltip_text = (
@ -574,10 +584,12 @@ func _purchase_supply(item_id: StringName) -> void:
if _transaction_in_progress or not _is_transaction_context_valid():
_feedback.text = "unable to complete purchase."
return
if not _bag.can_add_item(item_id, 1):
var owned: int = _bag.get_quantity(item_id)
var quantity: int = FishingShopStockType.get_purchase_quantity(item_id, owned)
if quantity <= 0 or not _bag.can_add_item(item_id, quantity):
_feedback.text = "Your Bag is full."
return
if not _wallet.can_afford(FishingShopStockType.get_price(item_id)):
if not _wallet.can_afford(FishingShopStockType.get_price(item_id) * quantity):
_feedback.text = "Not enough fish coin."
return
if _network_shop == null:

View file

@ -25,6 +25,40 @@ const CATALOG_ORDER: Array[StringName] = [
&"salmon_coho",
&"salmon_pink",
&"salmon_sockeye",
&"anchovy_european",
&"anchovy_northern",
&"chub_european",
&"chub_flame",
&"chub_lake",
&"goldfish",
&"goldfish_bubbleeye",
&"grouper_gulf",
&"grouper_red",
&"mackerel_atlantic",
&"mackerel_cero",
&"mackerel_chub",
&"mackerel_king",
&"mackerel_spanish",
&"marlin_black",
&"marlin_blue",
&"marlin_white",
&"pomfret_black",
&"pomfret_chinese",
&"pomfret_golden",
&"pomfret_white",
&"sailfish",
&"sauger",
&"saugeye",
&"snapper_lane",
&"snapper_mangrove",
&"snapper_mutton",
&"snapper_red",
&"swordfish",
&"trout_cutthroat",
&"trout_golden",
&"trout_rainbow",
&"trout_steelhead",
&"walleye",
]
# Short presentation notes are kept here with the catalog contract rather
@ -107,6 +141,142 @@ const FISH_FACTS: Dictionary[StringName, String] = {
"sockeye salmon feed heavily on plankton at sea. adults turn vivid red "
+ "as they return inland to spawn."
),
&"anchovy_european": (
"european anchovies form dense schools and feed by filtering tiny "
+ "plankton from coastal water."
),
&"anchovy_northern": (
"northern anchovies gather in huge schools along the pacific coast "
+ "and filter plankton with their fine gill rakers."
),
&"chub_european": (
"european chub are adaptable river fish. adults often patrol "
+ "shallows and feed on insects, small fish, and fruit."
),
&"chub_flame": (
"flame chubs prefer cool, clear streams. their bright breeding colors "
+ "make a small fish easy to spot in spring water."
),
&"chub_lake": (
"lake chubs school in cold northern water and use their small mouths "
+ "to pick insects and other tiny prey from the current."
),
&"goldfish": (
"goldfish can tolerate a surprisingly wide range of conditions. "
+ "their wild relatives often live in slow, weedy water."
),
&"goldfish_bubbleeye": (
"bubble-eye goldfish have delicate fluid-filled sacs beneath their "
+ "eyes, making careful handling especially important."
),
&"grouper_gulf": (
"gulf grouper are ambush predators that use a sudden gulp to pull "
+ "prey into their cavernous mouths."
),
&"grouper_red": (
"red grouper excavate shelters in reef rubble. the hollows they make "
+ "can become hiding places for many smaller animals."
),
&"mackerel_atlantic": (
"atlantic mackerel travel in fast schools across the north atlantic "
+ "and feed on plankton and small schooling fish."
),
&"mackerel_cero": (
"cero mackerel are streamlined coastal hunters. sharp teeth help "
+ "them slash through schools of smaller fish."
),
&"mackerel_chub": (
"chub mackerel school near the surface and follow plankton blooms. "
+ "their dark wavy bars help identify them at a glance."
),
&"mackerel_king": (
"king mackerel are swift coastal predators. their pointed teeth and "
+ "long body are built for sudden bursts of speed."
),
&"mackerel_spanish": (
"spanish mackerel hunt in warm coastal waters and often travel in "
+ "loose schools while chasing baitfish."
),
&"marlin_black": (
"black marlin are powerful billfish that spend much of their lives "
+ "in warm open ocean and can make blistering runs."
),
&"marlin_blue": (
"blue marlin are highly migratory open-ocean hunters. their long bill "
+ "helps them stun prey before turning back to feed."
),
&"marlin_white": (
"white marlin favor warm offshore water and use their rounded dorsal "
+ "fin and bill to weave through schools of prey."
),
&"pomfret_black": (
"black pomfret have a deep, laterally compressed body that lets them "
+ "maneuver neatly through open water."
),
&"pomfret_chinese": (
"chinese pomfret are silvery schooling fish with a tall, flattened "
+ "body and long sickle-shaped fins."
),
&"pomfret_golden": (
"golden pomfret are warm-water swimmers whose golden sheen is most "
+ "noticeable along the fins and flanks."
),
&"pomfret_white": (
"white pomfret gather over coastal grounds and use their compact, "
+ "deep bodies to turn quickly while feeding."
),
&"sailfish": (
"sailfish raise their enormous dorsal fin while herding baitfish. "
+ "they are among the fastest fish in the sea."
),
&"sauger": (
"sauger favor turbid rivers and reservoirs. their mottled backs "
+ "blend into the dim, shifting light near the bottom."
),
&"saugeye": (
"saugeye are a fertile hybrid of sauger and walleye. they combine "
+ "traits from both parent species and often grow quickly."
),
&"snapper_lane": (
"lane snapper use reef structure for cover and hunt small crustaceans "
+ "and fish when the light begins to fade."
),
&"snapper_mangrove": (
"mangrove snapper shelter among roots and docks when young, then "
+ "move toward reefs as they grow."
),
&"snapper_mutton": (
"mutton snapper have canine teeth that help them pick crabs, shrimp, "
+ "and other hard-shelled prey from the reef."
),
&"snapper_red": (
"red snapper gather around reefs, wrecks, and ledges. their diet "
+ "includes small fish, shrimp, and squid."
),
&"swordfish": (
"swordfish are fast, wide-ranging predators with a flattened bill. "
+ "they can cross deep water and warm surface layers in one day."
),
&"trout_cutthroat": (
"cutthroat trout take their name from the red slash beneath the jaw. "
+ "many populations rely on cold, well-oxygenated streams."
),
&"trout_golden": (
"golden trout evolved in clear, high-elevation california streams. "
+ "their bright flanks stand out against rocky alpine water."
),
&"trout_rainbow": (
"rainbow trout are adaptable stream hunters. the pink lateral stripe "
+ "is especially vivid when the fish is in breeding condition."
),
&"trout_steelhead": (
"steelhead are the ocean-going form of rainbow trout. adults can "
+ "leave fresh water and later return to spawn."
),
&"walleye": (
"walleye have light-sensitive eyes that help them hunt in murky water "
+ "and around dusk. their reflective layer gives the eyes a pale glow."
),
}
static func category_for(fish: FishDataType) -> WaterType.Type:

View file

@ -150,7 +150,9 @@ func open_page(preserved_endpoint: String = "") -> void:
func close_page() -> void:
_clear_edit_state()
hide()
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
func get_endpoint_text() -> String:

View file

@ -495,7 +495,9 @@ func _finish_close(reason: CloseReason, restore_controls: bool) -> void:
hide()
if _fishing_spot != null and is_instance_valid(_fishing_spot):
_fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, false)
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
if restore_controls:
_restore_controls()
else:

View file

@ -145,7 +145,6 @@ const SALE_CONFIRMATION_SIZE := Vector2(520.0, 190.0)
@onready var _cooler_inner_liner: PanelContainer = %CoolerInnerLiner
@onready var _cooler_water_surface: ColorRect = %WaterSurface
@onready var _fish_field: Control = %FishField
@onready var _cooler_empty: Label = %CoolerEmpty
@onready var _cooler_sort_controls: HBoxContainer = %CoolerSortControls
@onready var _cooler_sort_option: NotepadInkChoiceType = %CoolerSortOption
@onready var _cooler_sort_direction: NotepadInkActionType = %CoolerSortDirection
@ -190,6 +189,7 @@ const SALE_CONFIRMATION_SIZE := Vector2(520.0, 190.0)
@onready var _lures_filter: Button = %LuresFilter
@onready var _tackle_empty: Label = %TackleEmpty
@onready var _tackle_detail_text: Label = %TackleDetailText
@onready var _tackle_equip_button: Button = %TackleEquipButton
@onready var _tackle_item_list: VBoxContainer = %TackleItemList
@onready var _bag_outer_wall: PanelContainer = %BagOuterWall
@onready var _bag_inner_liner: PanelContainer = %BagInnerLiner
@ -368,6 +368,7 @@ func _ready() -> void:
)
_bait_filter.pressed.connect(_set_tackle_view.bind(TackleView.BAIT))
_lures_filter.pressed.connect(_set_tackle_view.bind(TackleView.LURES))
_tackle_equip_button.pressed.connect(_toggle_active_bait)
_logbook_tab.pressed.connect(
_show_section.bind(Section.LOGBOOK)
)
@ -566,6 +567,8 @@ func setup(
_fishing_spot.bite_activated.connect(_on_bite_activated)
if not _bag.contents_changed.is_connected(_on_bag_changed):
_bag.contents_changed.connect(_on_bag_changed)
if not _player.active_bait_changed.is_connected(_on_active_bait_changed):
_player.active_bait_changed.connect(_on_active_bait_changed)
if not _hotbar.slots_changed.is_connected(_on_hotbar_changed):
_hotbar.slots_changed.connect(_on_hotbar_changed)
if not _cooler_capacity.capacity_changed.is_connected(
@ -1369,12 +1372,14 @@ func _update_tackle_detail() -> void:
else null
)
if item == null:
_tackle_equip_button.visible = false
_tackle_detail_text.text = (
"Select bait for details."
if _tackle_view == TackleView.BAIT
else "Select a lure for details."
)
return
_tackle_equip_button.visible = item.is_bait()
var quantity: int = _bag.get_quantity(item.item_id) if _bag != null else 0
var assigned_slot: int = -1
if _hotbar != null:
@ -1397,6 +1402,30 @@ func _update_tackle_detail() -> void:
item.description,
]
)
if item.is_bait():
_tackle_equip_button.text = (
"dequip %s" % item.display_name
if _player != null and _player.active_bait_id == item.item_id
else "equip %s" % item.display_name
)
_tackle_equip_button.disabled = quantity <= 0
func _toggle_active_bait() -> void:
if _player == null or _item_catalog == null:
return
var item: ItemDataType = _item_catalog.get_item_by_id(_selected_tackle_item_id)
if item == null or not item.is_bait():
return
if _player.active_bait_id == item.item_id:
_player.unequip_bait()
else:
_player.equip_bait(item)
_update_tackle_detail()
func _on_active_bait_changed(_item_id: StringName) -> void:
_update_tackle_detail()
func _apply_cooler_control_styles() -> void:
@ -1948,7 +1977,9 @@ func _begin_menu_exit(reason: CloseReason, restore_controls: bool) -> void:
_catalog_logbook.deactivate()
elif _current_section == Section.NET:
_the_net_page.deactivate()
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
var generation: int = _transition_generation
var closing_generation: int = _menu_generation
_presentation_tween = create_tween().set_parallel(true)
@ -2003,7 +2034,9 @@ func _finish_close(
_presentation_scale_root.scale = Vector2.ONE
visible = false
set_process(false)
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
if _fishing_spot != null and is_instance_valid(_fishing_spot):
_fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, false)
if restore_controls:
@ -2062,7 +2095,9 @@ func _begin_page_transition(section: Section) -> void:
_cancel_page_tween()
_page_transitioning = true
_set_content_interactive(false)
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
var outgoing_section: Section = _current_section
var outgoing_inventory: bool = _is_inventory_section(outgoing_section)
var incoming_inventory: bool = _is_inventory_section(section)
@ -2722,7 +2757,6 @@ func _refresh_inventory() -> void:
catches.sort_custom(_compare_catches)
_sorted_catches = catches
_inventory_empty.visible = catches.is_empty()
_cooler_empty.visible = catches.is_empty()
var visible_ids: Array[StringName] = []
for fish_catch: FishCatchType in catches:
visible_ids.append(fish_catch.catch_id)
@ -3600,7 +3634,9 @@ func _release_focus_from(node: Node, fallback: Control) -> void:
)
):
return
get_viewport().gui_release_focus()
var current_viewport: Viewport = get_viewport()
if current_viewport != null:
current_viewport.gui_release_focus()
if (
visible
and not _transitioning

View file

@ -167,21 +167,6 @@ grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
[node name="CoolerEmpty" type="Label" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/CoolerPage/CoolerOuterWall/CoolerWallMargin/CoolerInnerLiner/CoolerInnerMargin/CoolerScroll/CoolerHost"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme_override_colors/font_color = Color(0.91, 0.97, 0.98, 0.82)
theme_override_font_sizes/font_size = 24
text = "the cooler is empty"
horizontal_alignment = 1
vertical_alignment = 1
[node name="DetailConstellation" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/CoolerPage"]
unique_name_in_owner = true
layout_mode = 0
@ -705,12 +690,21 @@ theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 20
theme_override_constants/margin_bottom = 20
[node name="TackleDetailText" type="Label" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleDetailPanel/Margin"]
[node name="Layout" type="VBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleDetailPanel/Margin"]
layout_mode = 2
theme_override_constants/separation = 12
[node name="TackleDetailText" type="Label" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleDetailPanel/Margin/Layout"]
unique_name_in_owner = true
layout_mode = 2
text = "Select bait or a lure for details."
autowrap_mode = 2
vertical_alignment = 1
[node name="TackleEquipButton" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleDetailPanel/Margin/Layout"]
unique_name_in_owner = true
layout_mode = 2
custom_minimum_size = Vector2(0, 44)
text = "equip worms"
[node name="LogbookPage" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
unique_name_in_owner = true

View file

@ -2,6 +2,7 @@ class_name ProfilePage
extends Control
const CHECK_DEBOUNCE_SECONDS: float = 0.4
const OPTION_GRID_COLUMNS: int = 6
const ControllerMappingManagerType = preload(
"res://settings/controller_mapping_manager.gd"
)
@ -513,7 +514,7 @@ func _build_feature_preview_options(options: Array) -> void:
scroll.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_AUTO
_option_list.add_child(scroll)
var grid := GridContainer.new()
grid.columns = 4
grid.columns = OPTION_GRID_COLUMNS
grid.add_theme_constant_override("h_separation", 8)
grid.add_theme_constant_override("v_separation", 8)
grid.size_flags_horizontal = Control.SIZE_EXPAND_FILL
@ -591,7 +592,7 @@ func _feature_preview_texture(
func _build_fur_color_options(options: Array) -> void:
var grid := GridContainer.new()
grid.columns = 4
grid.columns = OPTION_GRID_COLUMNS
grid.add_theme_constant_override("h_separation", 10)
grid.add_theme_constant_override("v_separation", 10)
_option_list.add_child(grid)