Polish inventory shop and utility interfaces

Split inventory items and tackle views, standardize bait supply presentation, add status-effect icons, and align shop, logbook, art-kit, and shared utility layouts.
This commit is contained in:
Alexander Sellite 2026-08-15 14:28:13 -04:00
parent 84695c473b
commit a60925bf7b
21 changed files with 1150 additions and 385 deletions

View file

@ -115,11 +115,6 @@ enum BagView {
CONSUMABLES,
}
enum TackleView {
BAIT,
LURES,
}
enum SortMode {
CATCH_ORDER,
NAME,
@ -150,10 +145,9 @@ const INVENTORY_NOTEPAD_POSITION := Vector2(
INVENTORY_MAIN_POSITION.y,
)
const INVENTORY_NOTEPAD_SIZE := Vector2(278.0, 484.0)
const INVENTORY_HEADER_INSET := Vector2(24.0, 20.0)
const INVENTORY_HEADER_HEIGHT := 40.0
const INVENTORY_MAIN_CORNER_RADIUS: int = 58
const INVENTORY_INNER_CORNER_RADIUS: int = 45
const TACKLE_GRID_COLUMNS: int = 3
const SALE_CONFIRMATION_SIZE := Vector2(520.0, 190.0)
@onready var _navigation_cluster: BubbleClusterType = %NavigationCluster
@ -198,18 +192,18 @@ const SALE_CONFIRMATION_SIZE := Vector2(520.0, 190.0)
@onready var _inventory_sub_tabs: HBoxContainer = %InventorySubTabs
@onready var _cooler_sub_tab: Button = %CoolerSubTab
@onready var _bag_sub_tab: Button = %BagSubTab
@onready var _items_sub_tab: Button = %ItemsSubTab
@onready var _tackle_sub_tab: Button = %TackleSubTab
@onready var _bag_filter_tabs: HBoxContainer = %BagFilterTabs
@onready var _equipment_filter: Button = %EquipmentFilter
@onready var _consumables_filter: Button = %ConsumablesFilter
@onready var _tackle_main_panel: PanelContainer = %TackleMainPanel
@onready var _tackle_detail_panel: PanelContainer = %TackleDetailPanel
@onready var _bait_filter: Button = %BaitFilter
@onready var _lures_filter: Button = %LuresFilter
@onready var _tackle_empty: Label = %TackleEmpty
@onready var _bait_heading: Label = %BaitHeading
@onready var _lure_heading: Label = %LureHeading
@onready var _bait_empty: Label = %BaitEmpty
@onready var _lure_empty: Label = %LureEmpty
@onready var _tackle_detail_text: Label = %TackleDetailText
@onready var _tackle_equip_button: NotepadInkActionType = %TackleEquipButton
@onready var _tackle_item_list: VBoxContainer = %TackleItemList
@onready var _bait_item_list: GridContainer = %BaitItemList
@onready var _lure_item_list: GridContainer = %LureItemList
@onready var _bag_outer_wall: PanelContainer = %BagOuterWall
@onready var _bag_inner_liner: PanelContainer = %BagInnerLiner
@onready var _bag_scroll: ScrollContainer = %BagScroll
@ -312,8 +306,8 @@ var _cooler_capacity: PlayerCoolerCapacityType
var _current_section: Section = Section.COOLER
var _last_inventory_section: Section = Section.COOLER
var _bag_view: BagView = BagView.EQUIPMENT
var _tackle_view: TackleView = TackleView.BAIT
var _selected_tackle_item_id: StringName
var _tackle_item_buttons: Dictionary[StringName, Button] = {}
var _controller_ownership: ControllerOwnership = ControllerOwnership.ITEM_LIST
var _controller_source_section: Section = Section.COOLER
var _controller_source_identity: StringName
@ -377,18 +371,11 @@ func _ready() -> void:
_cooler_original_index = _cooler_page.get_index()
_confirmation_original_parent = _sale_confirmation.get_parent()
_confirmation_original_index = _sale_confirmation.get_index()
_inventory_sub_tabs.move_child(_tackle_sub_tab, 1)
_inventory_sub_tabs.move_child(_bag_sub_tab, 2)
_inventory_tab.pressed.connect(_show_last_inventory_section)
_cooler_sub_tab.pressed.connect(_show_section.bind(Section.COOLER))
_bag_sub_tab.pressed.connect(_show_section.bind(Section.BAG))
_bag_sub_tab.pressed.connect(_show_bag_view.bind(BagView.EQUIPMENT))
_items_sub_tab.pressed.connect(_show_bag_view.bind(BagView.CONSUMABLES))
_tackle_sub_tab.pressed.connect(_show_section.bind(Section.TACKLE_BOX))
_equipment_filter.pressed.connect(_set_bag_view.bind(BagView.EQUIPMENT))
_consumables_filter.pressed.connect(
_set_bag_view.bind(BagView.CONSUMABLES)
)
_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_tackle)
_logbook_tab.pressed.connect(
_show_section.bind(Section.LOGBOOK)
@ -434,7 +421,6 @@ func _ready() -> void:
# Keep the exposed tab hitboxes above the full-page roots. The individual
# main panels retain a higher z-index and cover the tab bodies below y=166.
_inventory_sub_tabs.move_to_front()
_bag_filter_tabs.move_to_front()
_apply_cooler_control_styles()
_apply_cooler_wall_styles()
_apply_cooler_notepad_style()
@ -947,17 +933,7 @@ func _restore_controller_item_focus(
elif section == Section.BAG:
target = _bag_item_nodes.get(identity) as BagItemSpriteType
elif section == Section.TACKLE_BOX:
for child: Node in _tackle_item_list.get_children():
var button := child as BaseButton
if (
button != null
and button.has_meta(&"controller_tackle_item_id")
and StringName(str(button.get_meta(
&"controller_tackle_item_id"
))) == identity
):
target = button
break
target = _tackle_item_buttons.get(identity) as Button
if (
target != null
and is_instance_valid(target)
@ -1087,23 +1063,14 @@ func _handle_controller_secondary_switch(event: InputEvent) -> bool:
):
return true
if _is_inventory_section(_current_section):
var inventory_index: int = _get_inventory_tab_index()
if (
(direction > 0 and _current_section == Section.BAG)
or (direction < 0 and _current_section == Section.COOLER)
(direction > 0 and inventory_index == 3)
or (direction < 0 and inventory_index == 0)
):
_begin_controller_hotbar_management()
return true
var inventory_sections: Array[Section] = [
Section.COOLER,
Section.TACKLE_BOX,
Section.BAG,
]
var inventory_index: int = inventory_sections.find(_current_section)
_show_section(inventory_sections[wrapi(
inventory_index + direction,
0,
inventory_sections.size(),
)])
_show_inventory_tab(inventory_index + direction)
return true
_cycle_visible_secondary_tabs(direction)
return true
@ -1129,13 +1096,31 @@ func _begin_controller_hotbar_management() -> void:
func _cycle_from_controller_hotbar_management(direction: int) -> void:
_release_controller_ownership(false, false)
var target_section: Section = (
Section.COOLER if direction > 0 else Section.BAG
)
if target_section == _current_section:
var target_index: int = 0 if direction > 0 else 3
if target_index == _get_inventory_tab_index():
call_deferred("_focus_current_section")
else:
_show_section(target_section)
_show_inventory_tab(target_index)
func _get_inventory_tab_index() -> int:
if _current_section == Section.COOLER:
return 0
if _current_section == Section.BAG:
return 2 if _bag_view == BagView.CONSUMABLES else 1
return 3
func _show_inventory_tab(index: int) -> void:
match clampi(index, 0, 3):
0:
_show_section(Section.COOLER)
1:
_show_bag_view(BagView.EQUIPMENT)
2:
_show_bag_view(BagView.CONSUMABLES)
_:
_show_section(Section.TACKLE_BOX)
func _cycle_visible_secondary_tabs(direction: int) -> bool:
@ -1575,7 +1560,9 @@ func _show_section_immediate(section: Section) -> void:
if section != Section.BAG:
_close_bag_detail()
else:
_update_bag_detail()
# BagView can change while entering from another Inventory page. Rebuild
# the filtered contents here so the visible list always matches its tab.
_refresh_bag()
_refresh_tackle_box()
if section != Section.LOGBOOK:
_cancel_logbook_page_transition(true)
@ -1600,7 +1587,12 @@ func _show_section_immediate(section: Section) -> void:
_players_page.deactivate()
_inventory_tab.button_pressed = _is_inventory_section(section)
_cooler_sub_tab.set_selected(section == Section.COOLER)
_bag_sub_tab.set_selected(section == Section.BAG)
_bag_sub_tab.set_selected(
section == Section.BAG and _bag_view == BagView.EQUIPMENT
)
_items_sub_tab.set_selected(
section == Section.BAG and _bag_view == BagView.CONSUMABLES
)
_tackle_sub_tab.set_selected(section == Section.TACKLE_BOX)
_refresh_inventory_organizer_tabs()
_logbook_tab.button_pressed = section == Section.LOGBOOK
@ -1622,8 +1614,9 @@ func _is_inventory_section(section: Section) -> bool:
func _refresh_inventory_organizer_tabs() -> void:
for tab: OrganizerTabType in [
_cooler_sub_tab,
_tackle_sub_tab,
_bag_sub_tab,
_items_sub_tab,
_tackle_sub_tab,
]:
tab.refresh_state()
@ -1633,8 +1626,9 @@ func _animate_inventory_tab_entry() -> void:
return
var tabs: Array[OrganizerTabType] = [
_cooler_sub_tab,
_tackle_sub_tab,
_bag_sub_tab,
_items_sub_tab,
_tackle_sub_tab,
]
for index: int in tabs.size():
tabs[index].animate_entrance(float(index) * 0.025)
@ -1643,8 +1637,9 @@ func _animate_inventory_tab_entry() -> void:
func _settle_inventory_tabs_for_close() -> void:
for tab: OrganizerTabType in [
_cooler_sub_tab,
_tackle_sub_tab,
_bag_sub_tab,
_items_sub_tab,
_tackle_sub_tab,
]:
tab.settle_for_close()
@ -1779,8 +1774,9 @@ func _reserve_visible_secondary_navigation() -> void:
call_deferred("_focus_current_section")
var inventory_tabs: Array[Button] = [
_cooler_sub_tab,
_tackle_sub_tab,
_bag_sub_tab,
_items_sub_tab,
_tackle_sub_tab,
]
for index: int in inventory_tabs.size():
var tab: Button = inventory_tabs[index]
@ -1794,9 +1790,7 @@ func _reserve_visible_secondary_navigation() -> void:
_inventory_tab.focus_neighbor_bottom = _inventory_tab.get_path_to(
_inventory_tab_for_section(_last_inventory_section)
)
_tackle_sub_tab.focus_neighbor_bottom = _tackle_sub_tab.get_path_to(
_bait_filter
)
_configure_tackle_item_focus()
func _inventory_tab_for_section(section: Section) -> Button:
@ -1804,7 +1798,11 @@ func _inventory_tab_for_section(section: Section) -> Button:
Section.COOLER:
return _cooler_sub_tab
Section.BAG:
return _bag_sub_tab
return (
_items_sub_tab
if _bag_view == BagView.CONSUMABLES
else _bag_sub_tab
)
_:
return _tackle_sub_tab
@ -1847,7 +1845,7 @@ func _configure_active_page_focus() -> void:
Section.BAG:
_configure_bag_item_focus()
Section.TACKLE_BOX:
_bait_filter.grab_focus()
_configure_tackle_item_focus()
Section.LOGBOOK:
_catalog_logbook.focus_initial()
Section.NET:
@ -1859,13 +1857,6 @@ func _configure_active_page_focus() -> void:
func _apply_inventory_styles() -> void:
for button: Button in [
_equipment_filter,
_consumables_filter,
_bait_filter,
_lures_filter,
]:
UtilityPageStyle.apply_ocean_button(button)
for panel: PanelContainer in [_tackle_main_panel]:
var panel_style := UtilityPageStyle.panel_style()
panel_style.set_corner_radius_all(INVENTORY_MAIN_CORNER_RADIUS)
@ -1873,7 +1864,12 @@ func _apply_inventory_styles() -> void:
"panel",
panel_style,
)
for label: Label in [_tackle_empty]:
for label: Label in [
_bait_heading,
_lure_heading,
_bait_empty,
_lure_empty,
]:
label.add_theme_font_override("font", UtilityPageStyle.TuffyFont)
label.add_theme_color_override(
"font_color",
@ -1895,124 +1891,180 @@ func _apply_inventory_styles() -> void:
UtilityPageStyle.apply_ocean_button(_cancel_sale_button)
func _set_bag_view(view: BagView) -> void:
func _show_bag_view(view: BagView) -> void:
if (
_transitioning
or _page_transitioning
or _sale_confirmation.visible
or get_viewport().gui_is_dragging()
):
return
if _current_section != Section.BAG:
_bag_view = view
_selected_bag_item_id = StringName()
_show_section(Section.BAG)
return
if _bag_view == view:
return
_release_controller_ownership(false, true)
_bag_view = view
_selected_bag_item_id = StringName()
_refresh_bag()
func _set_tackle_view(view: TackleView) -> void:
_tackle_view = view
_selected_tackle_item_id = StringName()
_refresh_tackle_box()
_bag_sub_tab.set_selected(view == BagView.EQUIPMENT)
_items_sub_tab.set_selected(view == BagView.CONSUMABLES)
_refresh_inventory_organizer_tabs()
_reserve_visible_secondary_navigation()
_set_content_interactive(true)
call_deferred("_focus_current_section")
func _refresh_tackle_box() -> void:
if not is_node_ready():
return
_bait_filter.button_pressed = _tackle_view == TackleView.BAIT
_lures_filter.button_pressed = _tackle_view == TackleView.LURES
for child: Node in _tackle_item_list.get_children():
child.queue_free()
var matching_items: Array[OwnedItemType] = []
for item_list: GridContainer in [_bait_item_list, _lure_item_list]:
for child: Node in item_list.get_children():
child.queue_free()
_tackle_item_buttons.clear()
var bait_items: Array[OwnedItemType] = []
var lure_items: Array[OwnedItemType] = []
if _bag != null and _item_catalog != null:
var available_items: Array[OwnedItemType] = (
_bag.get_unlocked_bait_items()
if _tackle_view == TackleView.BAIT
else _bag.get_all_items()
)
for owned: OwnedItemType in available_items:
for owned: OwnedItemType in _bag.get_unlocked_bait_items():
var item: ItemDataType = _item_catalog.get_item_by_id(
owned.item_id
)
if item == null:
continue
if (
_tackle_view == TackleView.BAIT
and item.category == ItemDataType.Category.BAIT
):
matching_items.append(owned)
elif (
_tackle_view == TackleView.LURES
and item.category == ItemDataType.Category.LURE
):
matching_items.append(owned)
matching_items.sort_custom(_sort_bag_items)
for owned: OwnedItemType in matching_items:
if item != null and item.category == ItemDataType.Category.BAIT:
bait_items.append(owned)
for owned: OwnedItemType in _bag.get_all_items():
var item: ItemDataType = _item_catalog.get_item_by_id(
owned.item_id
)
if item != null and item.category == ItemDataType.Category.LURE:
lure_items.append(owned)
bait_items.sort_custom(_sort_bag_items)
lure_items.sort_custom(_sort_bag_items)
_populate_tackle_column(bait_items, _bait_item_list)
_populate_tackle_column(lure_items, _lure_item_list)
if (
not _selected_tackle_item_id.is_empty()
and not _tackle_item_buttons.has(_selected_tackle_item_id)
):
_selected_tackle_item_id = StringName()
_bait_empty.visible = bait_items.is_empty()
_lure_empty.visible = lure_items.is_empty()
_configure_tackle_item_focus()
_update_tackle_detail()
_apply_tackle_interactivity(_tackle_is_interactive())
func _populate_tackle_column(
owned_items: Array[OwnedItemType],
item_list: GridContainer,
) -> void:
for owned: OwnedItemType in owned_items:
var item: ItemDataType = _item_catalog.get_item_by_id(owned.item_id)
var row := Button.new()
row.icon = item.icon
row.tooltip_text = (
"%s ×%d" % [item.display_name, owned.quantity]
if item == null:
continue
var button := Button.new()
button.icon = item.icon
button.tooltip_text = (
"%s%d/%d" % [
item.display_name,
owned.quantity,
item.max_stack,
]
if item.is_bait()
else item.display_name
)
var compact_tackle_item: bool = item.is_bait() or item.is_lure()
if compact_tackle_item:
row.custom_minimum_size = Vector2(72, 72)
row.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
row.expand_icon = item.icon != null
row.alignment = HORIZONTAL_ALIGNMENT_CENTER
row.text = "" if item.icon != null else item.display_name
if item.icon == null:
row.add_theme_font_size_override("font_size", 12)
else:
row.text = "%s ×%d" % [item.display_name, owned.quantity]
row.alignment = HORIZONTAL_ALIGNMENT_LEFT
row.toggle_mode = true
row.set_meta(&"controller_tackle_item_id", owned.item_id)
row.button_pressed = owned.item_id == _selected_tackle_item_id
if compact_tackle_item:
_apply_tackle_bait_button_style(row)
if item.is_bait():
_add_tackle_quantity_badge(row, owned.quantity)
else:
UtilityPageStyle.apply_ocean_button(row)
row.pressed.connect(_select_tackle_item.bind(owned.item_id))
_tackle_item_list.add_child(row)
_tackle_empty.text = (
"No bait collected."
if _tackle_view == TackleView.BAIT
else "No lures collected."
)
_tackle_empty.visible = matching_items.is_empty()
_update_tackle_detail()
button.custom_minimum_size = Vector2(72, 72)
button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
button.expand_icon = item.icon != null
button.alignment = HORIZONTAL_ALIGNMENT_CENTER
button.text = "" if item.icon != null else item.display_name
if item.icon == null:
button.add_theme_font_size_override("font_size", 12)
button.toggle_mode = true
button.set_meta(&"controller_tackle_item_id", owned.item_id)
button.button_pressed = owned.item_id == _selected_tackle_item_id
_apply_tackle_bait_button_style(button)
if item.is_bait():
UtilityPageStyle.add_supply_quantity_badge(
button,
owned.quantity,
item.max_stack,
&"QuantityBadge",
)
button.pressed.connect(_select_tackle_item.bind(owned.item_id))
item_list.add_child(button)
_tackle_item_buttons[owned.item_id] = button
func _add_tackle_quantity_badge(row: Button, quantity: int) -> void:
var badge := Panel.new()
badge.name = "QuantityBadge"
badge.anchor_left = 1.0
badge.anchor_right = 1.0
badge.offset_left = -27.0
badge.offset_top = 3.0
badge.offset_right = -3.0
badge.offset_bottom = 27.0
badge.mouse_filter = Control.MOUSE_FILTER_IGNORE
badge.z_index = 2
var badge_style := StyleBoxFlat.new()
badge_style.bg_color = Color("0b5558")
badge_style.set_corner_radius_all(12)
badge_style.anti_aliasing = false
badge.add_theme_stylebox_override("panel", badge_style)
row.add_child(badge)
var quantity_label := Label.new()
quantity_label.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
quantity_label.offset_left = 1.0
quantity_label.offset_right = 1.0
quantity_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
quantity_label.text = str(quantity)
quantity_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
quantity_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
quantity_label.add_theme_font_override("font", UtilityPageStyle.TuffyFont)
quantity_label.add_theme_font_size_override(
"font_size",
13 if quantity >= 100 else 15,
func _configure_tackle_item_focus() -> void:
if not is_node_ready():
return
var bait_buttons: Array[Button] = _get_tackle_column_buttons(
_bait_item_list
)
quantity_label.add_theme_color_override("font_color", Color("e7f5f4"))
badge.add_child(quantity_label)
var lure_buttons: Array[Button] = _get_tackle_column_buttons(
_lure_item_list
)
var first_button: Button = (
bait_buttons.front()
if not bait_buttons.is_empty()
else (lure_buttons.front() if not lure_buttons.is_empty() else null)
)
_tackle_sub_tab.focus_neighbor_bottom = (
_tackle_sub_tab.get_path_to(first_button)
if first_button != null
else NodePath()
)
_configure_tackle_column_focus(bait_buttons, lure_buttons, true)
_configure_tackle_column_focus(lure_buttons, bait_buttons, false)
func _get_tackle_column_buttons(item_list: GridContainer) -> Array[Button]:
var buttons: Array[Button] = []
for child: Node in item_list.get_children():
var button := child as Button
if button != null and not button.is_queued_for_deletion():
buttons.append(button)
return buttons
func _configure_tackle_column_focus(
buttons: Array[Button],
other_buttons: Array[Button],
is_left_column: bool,
) -> void:
for index: int in buttons.size():
var button: Button = buttons[index]
var column: int = index % TACKLE_GRID_COLUMNS
var row: int = floori(float(index) / float(TACKLE_GRID_COLUMNS))
var left_target: Button = button
var right_target: Button = button
if column > 0:
left_target = buttons[index - 1]
elif not is_left_column and not other_buttons.is_empty():
left_target = other_buttons[mini(
row * TACKLE_GRID_COLUMNS + TACKLE_GRID_COLUMNS - 1,
other_buttons.size() - 1,
)]
if column < TACKLE_GRID_COLUMNS - 1 and index + 1 < buttons.size():
right_target = buttons[index + 1]
elif is_left_column and not other_buttons.is_empty():
right_target = other_buttons[mini(
row * TACKLE_GRID_COLUMNS,
other_buttons.size() - 1,
)]
button.focus_neighbor_left = button.get_path_to(left_target)
button.focus_neighbor_right = button.get_path_to(right_target)
button.focus_neighbor_top = (
button.get_path_to(_tackle_sub_tab)
if index < TACKLE_GRID_COLUMNS
else button.get_path_to(buttons[index - TACKLE_GRID_COLUMNS])
)
button.focus_neighbor_bottom = button.get_path_to(
buttons[mini(index + TACKLE_GRID_COLUMNS, buttons.size() - 1)]
)
func _apply_tackle_bait_button_style(button: Button) -> void:
@ -2045,7 +2097,10 @@ func _apply_tackle_bait_button_style(button: Button) -> void:
func _select_tackle_item(item_id: StringName) -> void:
_selected_tackle_item_id = item_id
_refresh_tackle_box()
for candidate_id: StringName in _tackle_item_buttons:
var button: Button = _tackle_item_buttons[candidate_id]
button.button_pressed = candidate_id == item_id
_update_tackle_detail()
func _update_tackle_detail() -> void:
@ -2057,11 +2112,8 @@ func _update_tackle_detail() -> void:
if item == null:
_tackle_equip_button.visible = false
_tackle_equip_button.persistent_mark = false
_tackle_detail_text.text = (
"Select bait for details."
if _tackle_view == TackleView.BAIT
else "Select a lure for details."
)
_tackle_detail_text.text = "Select bait or a lure for details."
_apply_tackle_interactivity(_tackle_is_interactive())
return
_tackle_equip_button.visible = item.is_bait() or item.is_lure()
var quantity: int = _bag.get_quantity(item.item_id) if _bag != null else 0
@ -2073,7 +2125,7 @@ func _update_tackle_detail() -> void:
break
var detail_lines: Array[String] = [item.display_name, ""]
if item.is_bait():
detail_lines.append("quantity: %d" % quantity)
detail_lines.append("quantity: %d/%d" % [quantity, item.max_stack])
if assigned_slot >= 0:
detail_lines.append("hotbar slot %d" % (assigned_slot + 1))
detail_lines.append("")
@ -2096,6 +2148,42 @@ func _update_tackle_detail() -> void:
_tackle_equip_button.persistent_mark = is_equipped
_tackle_equip_button.disabled = quantity <= 0
_tackle_equip_button.refresh_ink_state()
_apply_tackle_interactivity(_tackle_is_interactive())
func _tackle_is_interactive() -> bool:
return (
visible
and _current_section == Section.TACKLE_BOX
and not _transitioning
and not _page_transitioning
and not _sale_confirmation.visible
)
func _apply_tackle_interactivity(interactive: bool) -> void:
for button: Button in _tackle_item_buttons.values():
button.focus_mode = (
Control.FOCUS_ALL if interactive else Control.FOCUS_NONE
)
button.mouse_filter = (
Control.MOUSE_FILTER_STOP
if interactive
else Control.MOUSE_FILTER_IGNORE
)
var action_interactive: bool = (
interactive
and _tackle_equip_button.visible
and not _tackle_equip_button.disabled
)
_tackle_equip_button.focus_mode = (
Control.FOCUS_ALL if action_interactive else Control.FOCUS_NONE
)
_tackle_equip_button.mouse_filter = (
Control.MOUSE_FILTER_STOP
if action_interactive
else Control.MOUSE_FILTER_IGNORE
)
func _toggle_active_tackle() -> void:
@ -2489,10 +2577,6 @@ func _update_shell_layout() -> void:
_tackle_rest_position = Vector2.ZERO
_bag_outer_wall.position = INVENTORY_MAIN_POSITION
_bag_outer_wall.size = INVENTORY_MAIN_SIZE
_bag_filter_tabs.position = (
INVENTORY_MAIN_POSITION + INVENTORY_HEADER_INSET
)
_bag_filter_tabs.size = Vector2(320.0, INVENTORY_HEADER_HEIGHT)
_bag_host.custom_minimum_size = (
Vector2(520.0, 152.0) if compact else Vector2(788.0, 358.0)
)
@ -2932,7 +3016,10 @@ func _set_content_interactive(interactive: bool) -> void:
else Control.MOUSE_FILTER_IGNORE
)
for tab: Button in [
_cooler_sub_tab, _bag_sub_tab, _tackle_sub_tab,
_cooler_sub_tab,
_bag_sub_tab,
_items_sub_tab,
_tackle_sub_tab,
]:
var tab_interactive: bool = (
interactive and _is_inventory_section(_current_section)
@ -3014,6 +3101,10 @@ func _set_content_interactive(interactive: bool) -> void:
if bag_interactive
else Control.MOUSE_FILTER_IGNORE
)
var tackle_interactive: bool = (
interactive and _current_section == Section.TACKLE_BOX
)
_apply_tackle_interactivity(tackle_interactive)
func _cancel_presentation_tween() -> void:
@ -3117,9 +3208,9 @@ func _on_hotbar_changed() -> void:
func _refresh_bag() -> void:
if not is_node_ready():
return
var owned_items: Array[OwnedItemType] = (
_bag.get_all_items() if _bag != null else []
)
var owned_items: Array[OwnedItemType] = []
if _bag != null:
owned_items = _bag.get_all_items()
var filtered_items: Array[OwnedItemType] = []
for owned: OwnedItemType in owned_items:
var item: ItemDataType = (
@ -3145,16 +3236,12 @@ func _refresh_bag() -> void:
owned_items = filtered_items
owned_items.sort_custom(_sort_bag_items)
_sorted_bag_items = owned_items
_equipment_filter.button_pressed = _bag_view == BagView.EQUIPMENT
_consumables_filter.button_pressed = (
_bag_view == BagView.CONSUMABLES
)
_bag_empty.visible = owned_items.is_empty()
_bag_empty_state.visible = owned_items.is_empty()
_bag_empty_state.text = (
"No equipment in your Bag."
if _bag_view == BagView.EQUIPMENT
else "No consumables in your Bag."
else "No items in your Bag."
)
if (
not _selected_bag_item_id.is_empty()
@ -3209,7 +3296,7 @@ func _sync_bag_item_nodes(owned_items: Array[OwnedItemType]) -> void:
continue
var removed := _bag_item_nodes[item_id] as BagItemSpriteType
_bag_item_nodes.erase(item_id)
_release_focus_from(removed, _bag_sub_tab)
_release_focus_from(removed, _active_bag_tab())
removed.queue_free()
_layout_bag_items()
_configure_bag_item_focus()
@ -3270,6 +3357,7 @@ func _layout_bag_items() -> void:
func _configure_bag_item_focus() -> void:
if _current_section != Section.BAG:
return
var active_tab: Button = _active_bag_tab()
var controls: Array[BagItemSpriteType] = []
for owned: OwnedItemType in _sorted_bag_items:
var item_node := _bag_item_nodes.get(
@ -3278,9 +3366,9 @@ func _configure_bag_item_focus() -> void:
if item_node != null:
controls.append(item_node)
if controls.is_empty():
_bag_sub_tab.focus_neighbor_bottom = NodePath()
active_tab.focus_neighbor_bottom = NodePath()
return
_bag_sub_tab.focus_neighbor_bottom = _bag_sub_tab.get_path_to(
active_tab.focus_neighbor_bottom = active_tab.get_path_to(
controls.front()
)
for index: int in controls.size():
@ -3296,7 +3384,7 @@ func _configure_bag_item_focus() -> void:
controls[right_index]
)
control.focus_neighbor_top = (
control.get_path_to(_bag_sub_tab)
control.get_path_to(active_tab)
if index < 3
else control.get_path_to(controls[index - 3])
)
@ -3305,6 +3393,14 @@ func _configure_bag_item_focus() -> void:
)
func _active_bag_tab() -> Button:
return (
_items_sub_tab
if _bag_view == BagView.CONSUMABLES
else _bag_sub_tab
)
func _sort_bag_items(a: OwnedItemType, b: OwnedItemType) -> bool:
var item_a: ItemDataType = _item_catalog.get_item_by_id(a.item_id)
var item_b: ItemDataType = _item_catalog.get_item_by_id(b.item_id)
@ -3355,7 +3451,7 @@ func _update_bag_detail() -> void:
_bag_detail_data.text = (
"%s\nquantity: %d\n%s\n%s\n%s"
% [
item.get_category_name(),
_item_category_display_name(item),
quantity,
item_state,
hotbar_assignment,
@ -3374,7 +3470,7 @@ func _update_bag_detail() -> void:
_bag_sprite_detail_data.text = (
"%s • quantity: %d\n%s%s\n%s"
% [
item.get_category_name(),
_item_category_display_name(item),
quantity,
item_state,
hotbar_assignment,
@ -3388,6 +3484,12 @@ func _update_bag_detail() -> void:
)
func _item_category_display_name(item: ItemDataType) -> String:
if item.category == ItemDataType.Category.CONSUMABLE:
return "item"
return item.get_category_name()
func _close_bag_detail() -> void:
_bag_detail_constellation.visible = false