Add unified inventory and animated menu backdrop

This commit is contained in:
Alexander Sellite 2026-07-30 16:07:36 -04:00
parent 4985cc3374
commit 28ce6fedcb
16 changed files with 865 additions and 123 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d0o3ym81t1sxs"
path="res://.godot/imported/pattern_bluedot.png-2880ee070284314ed1e7b46e1dbc0570.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://art/patterns/pattern_bluedot.png"
dest_files=["res://.godot/imported/pattern_bluedot.png-2880ee070284314ed1e7b46e1dbc0570.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

View file

@ -433,7 +433,6 @@ func _unhandled_input(event: InputEvent) -> void:
get_viewport().set_input_as_handled() get_viewport().set_input_as_handled()
return return
if not has_active_fishing_rod(): if not has_active_fishing_rod():
status_changed.emit("select a fishing rod to cast.")
get_viewport().set_input_as_handled() get_viewport().set_input_as_handled()
return return
if ( if (

View file

@ -9,6 +9,7 @@ enum Category {
UTILITY, UTILITY,
QUEST, QUEST,
COSMETIC, COSMETIC,
LURE,
} }
@export var item_id: StringName @export var item_id: StringName

View file

@ -72,6 +72,8 @@ const NetworkProfileServiceType = preload(
) )
const TITLE_MUSIC_SILENCE_DB: float = -80.0 const TITLE_MUSIC_SILENCE_DB: float = -80.0
const PLAYER_MENU_PATTERN_SCALE: float = 0.85
const PLAYER_MENU_PATTERN_SCROLL_VELOCITY := Vector2(-7.0, -5.0)
@export var fish_catalog: FishPoolType @export var fish_catalog: FishPoolType
@export var pelican_buyer_profile: FishBuyerProfileType @export var pelican_buyer_profile: FishBuyerProfileType
@ -143,6 +145,7 @@ var _title_music_requested: bool = false
var _quit_in_progress: bool = false var _quit_in_progress: bool = false
var _join_requested_from_title: bool = false var _join_requested_from_title: bool = false
var _join_requested_from_pause: bool = false var _join_requested_from_pause: bool = false
var _player_menu_backdrop_tween: Tween
var _pending_join_endpoint: String = "" var _pending_join_endpoint: String = ""
var _server_trust_dialog: ConfirmationDialog var _server_trust_dialog: ConfirmationDialog
var _pending_trust_changed: bool = false var _pending_trust_changed: bool = false
@ -158,6 +161,18 @@ var _local_recovery_attempt_id: String = ""
func _ready() -> void: func _ready() -> void:
DisplayServer.window_set_title("NETfishing") DisplayServer.window_set_title("NETfishing")
var menu_pattern_material := (
_player_menu_backdrop.material as ShaderMaterial
)
if menu_pattern_material != null:
menu_pattern_material.set_shader_parameter(
"display_scale",
PLAYER_MENU_PATTERN_SCALE,
)
menu_pattern_material.set_shader_parameter(
"scroll_velocity_pixels",
PLAYER_MENU_PATTERN_SCROLL_VELOCITY,
)
get_window().size_changed.connect(_resize_native_overlays) get_window().size_changed.connect(_resize_native_overlays)
_resize_native_overlays() _resize_native_overlays()
if not _settings_manager.settings_changed.is_connected( if not _settings_manager.settings_changed.is_connected(
@ -906,7 +921,38 @@ func _set_gameplay_active(active: bool) -> void:
func _set_player_menu_backdrop_visible(is_visible: bool) -> void: func _set_player_menu_backdrop_visible(is_visible: bool) -> void:
_player_menu_backdrop.visible = is_visible and _gameplay_started if _player_menu_backdrop_tween != null:
_player_menu_backdrop_tween.kill()
_player_menu_backdrop_tween = null
var should_show: bool = is_visible and _gameplay_started
if should_show:
var was_visible: bool = _player_menu_backdrop.visible
_player_menu_backdrop.visible = true
if not was_visible:
_player_menu_backdrop.modulate.a = 0.0
_player_menu_backdrop_tween = create_tween()
_player_menu_backdrop_tween.tween_property(
_player_menu_backdrop,
"modulate:a",
1.0,
UIMotion.UTILITY_ENTER_DURATION,
).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
return
if not _player_menu_backdrop.visible:
return
_player_menu_backdrop_tween = create_tween()
_player_menu_backdrop_tween.tween_property(
_player_menu_backdrop,
"modulate:a",
0.0,
UIMotion.UTILITY_EXIT_DURATION,
).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
_player_menu_backdrop_tween.finished.connect(
func() -> void:
_player_menu_backdrop.visible = false
_player_menu_backdrop.modulate.a = 1.0
_player_menu_backdrop_tween = null
)
func _resize_native_overlays() -> void: func _resize_native_overlays() -> void:

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=42 format=3] [gd_scene load_steps=45 format=3]
[ext_resource type="PackedScene" path="res://world/test_world.tscn" id="1_world"] [ext_resource type="PackedScene" path="res://world/test_world.tscn" id="1_world"]
[ext_resource type="PackedScene" path="res://player/player.tscn" id="2_player"] [ext_resource type="PackedScene" path="res://player/player.tscn" id="2_player"]
@ -40,10 +40,19 @@
[ext_resource type="Script" path="res://network/identity_backup_service.gd" id="38_identity_backup"] [ext_resource type="Script" path="res://network/identity_backup_service.gd" id="38_identity_backup"]
[ext_resource type="Script" path="res://ui/interface_font_controller.gd" id="39_fonts"] [ext_resource type="Script" path="res://ui/interface_font_controller.gd" id="39_fonts"]
[ext_resource type="Shader" path="res://ui/title_water_background.gdshader" id="40_title_water"] [ext_resource type="Shader" path="res://ui/title_water_background.gdshader" id="40_title_water"]
[ext_resource type="Texture2D" path="res://art/patterns/pattern_bluedot.png" id="41_menu_pattern"]
[ext_resource type="Shader" path="res://ui/player_menu_pattern.gdshader" id="42_menu_pattern"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_title_water_native"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_title_water_native"]
shader = ExtResource("40_title_water") shader = ExtResource("40_title_water")
[sub_resource type="ShaderMaterial" id="ShaderMaterial_player_menu_pattern"]
shader = ExtResource("42_menu_pattern")
shader_parameter/pattern_texture = ExtResource("41_menu_pattern")
shader_parameter/source_tile_size = Vector2(128, 128)
shader_parameter/display_scale = 0.85
shader_parameter/scroll_velocity_pixels = Vector2(-7, -5)
[node name="Main" type="Node3D"] [node name="Main" type="Node3D"]
script = ExtResource("3_main") script = ExtResource("3_main")
fish_catalog = ExtResource("6_pool") fish_catalog = ExtResource("6_pool")
@ -70,7 +79,8 @@ unique_name_in_owner = true
visible = false visible = false
z_index = 10 z_index = 10
mouse_filter = 2 mouse_filter = 2
color = Color(0.015, 0.02, 0.03, 0.72) material = SubResource("ShaderMaterial_player_menu_pattern")
color = Color(1, 1, 1, 1)
[node name="InterfaceFontController" type="Node" parent="."] [node name="InterfaceFontController" type="Node" parent="."]
unique_name_in_owner = true unique_name_in_owner = true

View file

@ -42,6 +42,7 @@ signal interactive_pointer_ui_changed(is_open: bool)
signal player_menu_backdrop_visibility_changed(is_visible: bool) signal player_menu_backdrop_visibility_changed(is_visible: bool)
@onready var _status_label: Label = %StatusLabel @onready var _status_label: Label = %StatusLabel
@onready var _gameplay_transient_hud: Control = %GameplayTransientHUD
@onready var _catch_track: Control = %CatchTrack @onready var _catch_track: Control = %CatchTrack
@onready var _green_catch_progress: ProgressBar = %GreenCatchProgress @onready var _green_catch_progress: ProgressBar = %GreenCatchProgress
@onready var _red_chase_progress: ProgressBar = %RedChaseProgress @onready var _red_chase_progress: ProgressBar = %RedChaseProgress
@ -72,6 +73,7 @@ var _gameplay_ui_enabled: bool = false
var _fishing_spot: FishingSpotType var _fishing_spot: FishingSpotType
var _system_menu_open: bool = false var _system_menu_open: bool = false
var _shop_open: bool = false var _shop_open: bool = false
var _player_menu_hotbar_visible: bool = false
var _item_effects: PlayerItemEffectsType var _item_effects: PlayerItemEffectsType
@ -137,6 +139,10 @@ func setup(
_player_menu.menu_visibility_changed.connect( _player_menu.menu_visibility_changed.connect(
_on_player_menu_visibility_changed _on_player_menu_visibility_changed
) )
_player_menu.menu_exit_started.connect(_on_player_menu_exit_started)
_player_menu.inventory_hotbar_context_changed.connect(
_on_inventory_hotbar_context_changed
)
_player_menu.setup( _player_menu.setup(
player, player,
inventory, inventory,
@ -251,16 +257,17 @@ func get_pause_menu() -> PauseMenuType:
func set_gameplay_ui_enabled(enabled: bool) -> void: func set_gameplay_ui_enabled(enabled: bool) -> void:
_gameplay_ui_enabled = enabled _gameplay_ui_enabled = enabled
_gameplay_transient_hud.visible = enabled and not _player_menu_open
_refresh_chat_availability() _refresh_chat_availability()
if not enabled: if not enabled:
close_player_menu_for_session_end() close_player_menu_for_session_end()
_fishing_shop.close_for_session_end() _fishing_shop.close_for_session_end()
_fishing_panel.visible = false _fishing_panel.visible = false
_shop_prompt.hide() _shop_prompt.hide()
_hotbar_ui.hide() _hotbar_ui.set_presentation_visible(false, false)
_hotbar_ui.set_gameplay_input_enabled(false) _hotbar_ui.set_gameplay_input_enabled(false)
else: else:
_hotbar_ui.show() _refresh_hotbar_visibility()
_hotbar_ui.set_gameplay_input_enabled(true) _hotbar_ui.set_gameplay_input_enabled(true)
_refresh_fishing_panel_visibility() _refresh_fishing_panel_visibility()
@ -268,9 +275,7 @@ func set_gameplay_ui_enabled(enabled: bool) -> void:
func set_system_menu_open(is_open: bool) -> void: func set_system_menu_open(is_open: bool) -> void:
_system_menu_open = is_open _system_menu_open = is_open
_refresh_chat_availability() _refresh_chat_availability()
_hotbar_ui.visible = ( _refresh_hotbar_visibility()
_gameplay_ui_enabled and not is_open and not _shop_open
)
_hotbar_ui.set_gameplay_input_enabled( _hotbar_ui.set_gameplay_input_enabled(
_gameplay_ui_enabled _gameplay_ui_enabled
and not is_open and not is_open
@ -495,24 +500,42 @@ func _on_showcase_changed(
func _on_player_menu_visibility_changed(is_open: bool) -> void: func _on_player_menu_visibility_changed(is_open: bool) -> void:
_player_menu_open = is_open _player_menu_open = is_open
_gameplay_transient_hud.visible = _gameplay_ui_enabled and not is_open
if is_open:
_hotbar_ui.set_presentation_visible(false, false)
if _player_menu_hotbar_visible:
_hotbar_ui.set_player_menu_context(true)
_hotbar_ui.set_presentation_visible(true, true)
else:
_player_menu_hotbar_visible = false
_hotbar_ui.set_presentation_visible(false, false)
_hotbar_ui.set_player_menu_context(false)
player_menu_backdrop_visibility_changed.emit(is_open) player_menu_backdrop_visibility_changed.emit(is_open)
_refresh_chat_availability() _refresh_chat_availability()
_hotbar_ui.set_gameplay_input_enabled( _hotbar_ui.set_gameplay_input_enabled(
_gameplay_ui_enabled and not is_open _gameplay_ui_enabled and not is_open
) )
_hotbar_ui.set_drag_enabled(is_open) _hotbar_ui.set_drag_enabled(is_open)
_refresh_hotbar_visibility()
_refresh_fishing_panel_visibility() _refresh_fishing_panel_visibility()
_emit_interactive_pointer_ui_changed() _emit_interactive_pointer_ui_changed()
if is_open: if is_open:
_shop_prompt.hide() _shop_prompt.hide()
else:
_refresh_fishing_panel_visibility()
func _on_player_menu_exit_started() -> void:
if not _player_menu_open:
return
_hotbar_ui.set_drag_enabled(false)
_hotbar_ui.set_presentation_visible(false, true)
func _on_shop_visibility_changed(is_open: bool) -> void: func _on_shop_visibility_changed(is_open: bool) -> void:
_shop_open = is_open _shop_open = is_open
_refresh_chat_availability() _refresh_chat_availability()
_hotbar_ui.visible = ( _refresh_hotbar_visibility()
_gameplay_ui_enabled and not is_open and not _system_menu_open
)
_hotbar_ui.set_gameplay_input_enabled( _hotbar_ui.set_gameplay_input_enabled(
_gameplay_ui_enabled _gameplay_ui_enabled
and not is_open and not is_open
@ -524,6 +547,31 @@ func _on_shop_visibility_changed(is_open: bool) -> void:
_emit_interactive_pointer_ui_changed() _emit_interactive_pointer_ui_changed()
func _on_inventory_hotbar_context_changed(show_hotbar: bool) -> void:
var context_changed: bool = _player_menu_hotbar_visible != show_hotbar
_player_menu_hotbar_visible = show_hotbar
if _player_menu_open and show_hotbar and context_changed:
_hotbar_ui.set_presentation_visible(false, false)
_hotbar_ui.set_player_menu_context(true)
_hotbar_ui.set_drag_enabled(_player_menu_open and show_hotbar)
if not context_changed:
return
_refresh_hotbar_visibility()
func _refresh_hotbar_visibility() -> void:
_hotbar_ui.set_presentation_visible(
_gameplay_ui_enabled
and not _system_menu_open
and not _shop_open
and (
not _player_menu_open
or _player_menu_hotbar_visible
),
_player_menu_open,
)
func _emit_interactive_pointer_ui_changed() -> void: func _emit_interactive_pointer_ui_changed() -> void:
interactive_pointer_ui_changed.emit( interactive_pointer_ui_changed.emit(
_system_menu_open or _player_menu_open or _shop_open _system_menu_open or _player_menu_open or _shop_open

View file

@ -41,7 +41,17 @@ script = ExtResource("1_ui")
unique_name_in_owner = true unique_name_in_owner = true
mouse_filter = 2 mouse_filter = 2
[node name="FishingPanel" type="PanelContainer" parent="UIRoot"] [node name="GameplayTransientHUD" type="Control" parent="UIRoot"]
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
[node name="FishingPanel" type="PanelContainer" parent="UIRoot/GameplayTransientHUD"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
z_index = 60 z_index = 60
@ -59,33 +69,33 @@ grow_vertical = 0
mouse_filter = 2 mouse_filter = 2
theme = ExtResource("3_theme") theme = ExtResource("3_theme")
[node name="MarginContainer" type="MarginContainer" parent="UIRoot/FishingPanel"] [node name="MarginContainer" type="MarginContainer" parent="UIRoot/GameplayTransientHUD/FishingPanel"]
theme_override_constants/margin_left = 14 theme_override_constants/margin_left = 14
theme_override_constants/margin_top = 8 theme_override_constants/margin_top = 8
theme_override_constants/margin_right = 14 theme_override_constants/margin_right = 14
theme_override_constants/margin_bottom = 8 theme_override_constants/margin_bottom = 8
[node name="VBoxContainer" type="VBoxContainer" parent="UIRoot/FishingPanel/MarginContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer"]
theme_override_constants/separation = 4 theme_override_constants/separation = 4
[node name="StatusLabel" type="Label" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer"] [node name="StatusLabel" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
text = "" text = ""
horizontal_alignment = 1 horizontal_alignment = 1
theme_override_font_sizes/font_size = 16 theme_override_font_sizes/font_size = 16
[node name="ShowcaseDetails" type="Label" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer"] [node name="ShowcaseDetails" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
horizontal_alignment = 1 horizontal_alignment = 1
[node name="CatchTrack" type="Control" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer"] [node name="CatchTrack" type="Control" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
custom_minimum_size = Vector2(0, 20) custom_minimum_size = Vector2(0, 20)
[node name="GreenCatchProgress" type="ProgressBar" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"] [node name="GreenCatchProgress" type="ProgressBar" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 15
@ -99,7 +109,7 @@ theme_override_styles/fill = SubResource("StyleBox_catch_fill")
value = 0.0 value = 0.0
show_percentage = false show_percentage = false
[node name="RedChaseProgress" type="ProgressBar" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"] [node name="RedChaseProgress" type="ProgressBar" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 15
@ -113,7 +123,7 @@ theme_override_styles/fill = SubResource("StyleBox_chase_fill")
value = 0.0 value = 0.0
show_percentage = false show_percentage = false
[node name="BarrierMarkers" type="Control" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"] [node name="BarrierMarkers" type="Control" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 1 layout_mode = 1
anchors_preset = 15 anchors_preset = 15
@ -123,12 +133,12 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
mouse_filter = 2 mouse_filter = 2
[node name="BarrierSummary" type="Label" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer"] [node name="BarrierSummary" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
horizontal_alignment = 1 horizontal_alignment = 1
[node name="BarrierHealth" type="Label" parent="UIRoot/FishingPanel/MarginContainer/VBoxContainer"] [node name="BarrierHealth" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
horizontal_alignment = 1 horizontal_alignment = 1
@ -139,7 +149,7 @@ unique_name_in_owner = true
[node name="Hotbar" parent="UIRoot" instance=ExtResource("7_hotbar")] [node name="Hotbar" parent="UIRoot" instance=ExtResource("7_hotbar")]
unique_name_in_owner = true unique_name_in_owner = true
[node name="ShopPrompt" type="PanelContainer" parent="UIRoot"] [node name="ShopPrompt" type="PanelContainer" parent="UIRoot/GameplayTransientHUD"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
z_index = 55 z_index = 55
@ -157,14 +167,14 @@ grow_vertical = 0
mouse_filter = 2 mouse_filter = 2
theme = ExtResource("3_theme") theme = ExtResource("3_theme")
[node name="Margin" type="MarginContainer" parent="UIRoot/ShopPrompt"] [node name="Margin" type="MarginContainer" parent="UIRoot/GameplayTransientHUD/ShopPrompt"]
layout_mode = 2 layout_mode = 2
theme_override_constants/margin_left = 12 theme_override_constants/margin_left = 12
theme_override_constants/margin_top = 7 theme_override_constants/margin_top = 7
theme_override_constants/margin_right = 12 theme_override_constants/margin_right = 12
theme_override_constants/margin_bottom = 7 theme_override_constants/margin_bottom = 7
[node name="Label" type="Label" parent="UIRoot/ShopPrompt/Margin"] [node name="Label" type="Label" parent="UIRoot/GameplayTransientHUD/ShopPrompt/Margin"]
layout_mode = 2 layout_mode = 2
text = "press e to open fishing shop" text = "press e to open fishing shop"
horizontal_alignment = 1 horizontal_alignment = 1
@ -172,7 +182,7 @@ horizontal_alignment = 1
[node name="FishingShop" parent="UIRoot" instance=ExtResource("8_shop")] [node name="FishingShop" parent="UIRoot" instance=ExtResource("8_shop")]
unique_name_in_owner = true unique_name_in_owner = true
[node name="EffectStatus" type="Label" parent="UIRoot"] [node name="EffectStatus" type="Label" parent="UIRoot/GameplayTransientHUD"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
z_index = 54 z_index = 54

View file

@ -13,6 +13,7 @@ const DESKTOP_REFERENCE_SIZE := Vector2(1280.0, 720.0)
const COMPACT_REFERENCE_SIZE := Vector2(640.0, 480.0) const COMPACT_REFERENCE_SIZE := Vector2(640.0, 480.0)
const HOTBAR_PRESENTATION_SCALE: float = 0.60 const HOTBAR_PRESENTATION_SCALE: float = 0.60
const HOTBAR_CANONICAL_POSITION := Vector2(256.0, 288.0) const HOTBAR_CANONICAL_POSITION := Vector2(256.0, 288.0)
const HOTBAR_MENU_POSITION := Vector2(80.0, 198.0)
@onready var _presentation_scale_root: Control = %HotbarPresentationScaleRoot @onready var _presentation_scale_root: Control = %HotbarPresentationScaleRoot
@onready var _bubble_field: Control = %BubbleField @onready var _bubble_field: Control = %BubbleField
@ -30,6 +31,9 @@ var _hovered_slot_index: int = -1
var _item_name_suppressed: bool = false var _item_name_suppressed: bool = false
var _motion_elapsed: float = 0.0 var _motion_elapsed: float = 0.0
var _compact_layout: bool = false var _compact_layout: bool = false
var _player_menu_context: bool = false
var _visibility_tween: Tween
var _visibility_generation: int = 0
func _ready() -> void: func _ready() -> void:
@ -82,6 +86,57 @@ func set_drag_enabled(enabled: bool) -> void:
_hide_item_name() _hide_item_name()
func set_player_menu_context(enabled: bool) -> void:
if _player_menu_context == enabled:
return
_player_menu_context = enabled
_presentation_scale_root.position = (
HOTBAR_MENU_POSITION if enabled else HOTBAR_CANONICAL_POSITION
)
func set_presentation_visible(should_show: bool, animate: bool = true) -> void:
_visibility_generation += 1
var generation: int = _visibility_generation
if _visibility_tween != null:
_visibility_tween.kill()
_visibility_tween = null
if should_show:
visible = true
if not animate:
modulate.a = 1.0
return
_visibility_tween = create_tween()
_visibility_tween.tween_property(
self,
"modulate:a",
1.0,
UIMotion.UTILITY_ENTER_DURATION,
)
else:
if not visible:
return
if not animate:
visible = false
modulate.a = 1.0
return
_visibility_tween = create_tween()
_visibility_tween.tween_property(
self,
"modulate:a",
0.0,
UIMotion.UTILITY_EXIT_DURATION,
)
_visibility_tween.finished.connect(
func() -> void:
if generation != _visibility_generation:
return
visible = false
modulate.a = 1.0
_visibility_tween = null
)
func set_item_name_suppressed(suppressed: bool) -> void: func set_item_name_suppressed(suppressed: bool) -> void:
_item_name_suppressed = suppressed _item_name_suppressed = suppressed
if suppressed: if suppressed:
@ -145,7 +200,11 @@ func _apply_layout() -> void:
_presentation_scale_root.scale = ( _presentation_scale_root.scale = (
Vector2.ONE * HOTBAR_PRESENTATION_SCALE Vector2.ONE * HOTBAR_PRESENTATION_SCALE
) )
_presentation_scale_root.position = HOTBAR_CANONICAL_POSITION _presentation_scale_root.position = (
HOTBAR_MENU_POSITION
if _player_menu_context
else HOTBAR_CANONICAL_POSITION
)
var field_size := ( var field_size := (
Vector2(580.0, 82.0) Vector2(580.0, 82.0)
if _compact_layout if _compact_layout

View file

@ -7,7 +7,7 @@
[node name="Hotbar" type="Control"] [node name="Hotbar" type="Control"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
z_index = 20 z_index = 35
layout_mode = 3 layout_mode = 3
anchors_preset = 15 anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0

View file

@ -110,7 +110,7 @@ func set_interactive(value: bool) -> void:
func _build_ui() -> void: func _build_ui() -> void:
var paper := PanelContainer.new() var paper := PanelContainer.new()
paper.position = Vector2(116, 126) paper.position = Vector2(116, 126)
paper.size = Vector2(1048, 470) paper.size = Vector2(1048, 540)
paper.add_theme_stylebox_override("panel", UtilityPageStyle.panel_style()) paper.add_theme_stylebox_override("panel", UtilityPageStyle.panel_style())
add_child(paper) add_child(paper)
var margin := MarginContainer.new() var margin := MarginContainer.new()
@ -128,7 +128,7 @@ func _build_ui() -> void:
page.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) page.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
root.add_child(page) root.add_child(page)
_status = Label.new() _status = Label.new()
_status.position = Vector2(18, 430) _status.position = Vector2(18, 448)
_status.size = Vector2(900, 28) _status.size = Vector2(900, 28)
_status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
_status.add_theme_color_override("font_color", Color("4a3f31")) _status.add_theme_color_override("font_color", Color("4a3f31"))
@ -163,7 +163,7 @@ func _build_inbox() -> Control:
page.add_child(archive_view) page.add_child(archive_view)
var scroll := ScrollContainer.new() var scroll := ScrollContainer.new()
scroll.position = Vector2(12, 62) scroll.position = Vector2(12, 62)
scroll.size = Vector2(958, 342) scroll.size = Vector2(958, 374)
page.add_child(scroll) page.add_child(scroll)
_inbox_list = VBoxContainer.new() _inbox_list = VBoxContainer.new()
_inbox_list.custom_minimum_size = Vector2(930, 0) _inbox_list.custom_minimum_size = Vector2(930, 0)

View file

@ -79,16 +79,29 @@ const COOLER_RARITY_EPIC := Color("a979cf")
const COOLER_RARITY_LEGENDARY := Color("db78a7") const COOLER_RARITY_LEGENDARY := Color("db78a7")
signal menu_visibility_changed(is_open: bool) signal menu_visibility_changed(is_open: bool)
signal inventory_hotbar_context_changed(show_hotbar: bool)
signal menu_exit_started
enum Section { enum Section {
COOLER, COOLER,
BAG, BAG,
TACKLE_BOX,
LOGBOOK, LOGBOOK,
MAIL, MAIL,
PROFILE, PROFILE,
PLAYERS, PLAYERS,
} }
enum BagView {
EQUIPMENT,
CONSUMABLES,
}
enum TackleView {
BAIT,
LURES,
}
enum SortMode { enum SortMode {
CATCH_ORDER, CATCH_ORDER,
NAME, NAME,
@ -142,6 +155,21 @@ enum CloseReason {
@onready var _favorite_bubble: NotepadInkActionType = %FavoriteBubble @onready var _favorite_bubble: NotepadInkActionType = %FavoriteBubble
@onready var _sell_bubble: NotepadInkActionType = %SellBubble @onready var _sell_bubble: NotepadInkActionType = %SellBubble
@onready var _bag_page: Control = %BagPage @onready var _bag_page: Control = %BagPage
@onready var _tackle_box_page: Control = %TackleBoxPage
@onready var _inventory_sub_tabs: HBoxContainer = %InventorySubTabs
@onready var _cooler_sub_tab: Button = %CoolerSubTab
@onready var _bag_sub_tab: Button = %BagSubTab
@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 _tackle_detail_text: Label = %TackleDetailText
@onready var _tackle_item_list: VBoxContainer = %TackleItemList
@onready var _bag_outer_wall: PanelContainer = %BagOuterWall @onready var _bag_outer_wall: PanelContainer = %BagOuterWall
@onready var _bag_inner_liner: PanelContainer = %BagInnerLiner @onready var _bag_inner_liner: PanelContainer = %BagInnerLiner
@onready var _bag_scroll: ScrollContainer = %BagScroll @onready var _bag_scroll: ScrollContainer = %BagScroll
@ -171,7 +199,6 @@ enum CloseReason {
@onready var _logbook_next: BubbleButtonType = %LogbookNext @onready var _logbook_next: BubbleButtonType = %LogbookNext
@onready var _logbook_page_status: BubbleStatusBubbleType = %LogbookPageStatus @onready var _logbook_page_status: BubbleStatusBubbleType = %LogbookPageStatus
@onready var _inventory_tab: BubbleButtonType = %InventoryTab @onready var _inventory_tab: BubbleButtonType = %InventoryTab
@onready var _bag_tab: BubbleButtonType = %BagTab
@onready var _logbook_tab: BubbleButtonType = %LogbookTab @onready var _logbook_tab: BubbleButtonType = %LogbookTab
@onready var _mail_tab: BubbleButtonType = %MailTab @onready var _mail_tab: BubbleButtonType = %MailTab
@onready var _profile_tab: BubbleButtonType = %ProfileTab @onready var _profile_tab: BubbleButtonType = %ProfileTab
@ -240,6 +267,10 @@ var _hotbar: PlayerHotbarType
var _item_catalog: ItemCatalogType var _item_catalog: ItemCatalogType
var _cooler_capacity: PlayerCoolerCapacityType var _cooler_capacity: PlayerCoolerCapacityType
var _current_section: Section = Section.COOLER 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 _sort_mode: SortMode = SortMode.CATCH_ORDER var _sort_mode: SortMode = SortMode.CATCH_ORDER
var _sort_descending: bool = true var _sort_descending: bool = true
var _fish_selection := FishBatchSelectionType.new() var _fish_selection := FishBatchSelectionType.new()
@ -265,6 +296,7 @@ var _presentation_rest_position: Vector2 = Vector2.ZERO
var _content_rest_position: Vector2 = Vector2.ZERO var _content_rest_position: Vector2 = Vector2.ZERO
var _cooler_rest_position: Vector2 = Vector2.ZERO var _cooler_rest_position: Vector2 = Vector2.ZERO
var _bag_rest_position: Vector2 = Vector2.ZERO var _bag_rest_position: Vector2 = Vector2.ZERO
var _tackle_rest_position: Vector2 = Vector2.ZERO
var _logbook_rest_position: Vector2 = Vector2.ZERO var _logbook_rest_position: Vector2 = Vector2.ZERO
var _mail_rest_position: Vector2 = Vector2.ZERO var _mail_rest_position: Vector2 = Vector2.ZERO
var _profile_rest_position: Vector2 = Vector2.ZERO var _profile_rest_position: Vector2 = Vector2.ZERO
@ -286,10 +318,16 @@ var _logbook_page_tween: Tween
func _ready() -> void: func _ready() -> void:
_inventory_tab.pressed.connect( _inventory_tab.pressed.connect(_show_last_inventory_section)
_show_section.bind(Section.COOLER) _cooler_sub_tab.pressed.connect(_show_section.bind(Section.COOLER))
_bag_sub_tab.pressed.connect(_show_section.bind(Section.BAG))
_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)
) )
_bag_tab.pressed.connect(_show_section.bind(Section.BAG)) _bait_filter.pressed.connect(_set_tackle_view.bind(TackleView.BAIT))
_lures_filter.pressed.connect(_set_tackle_view.bind(TackleView.LURES))
_logbook_tab.pressed.connect( _logbook_tab.pressed.connect(
_show_section.bind(Section.LOGBOOK) _show_section.bind(Section.LOGBOOK)
) )
@ -319,7 +357,6 @@ func _ready() -> void:
_update_sort_direction_text() _update_sort_direction_text()
_navigation_cluster.configure([ _navigation_cluster.configure([
_inventory_tab, _inventory_tab,
_bag_tab,
_logbook_tab, _logbook_tab,
_mail_tab, _mail_tab,
_profile_tab, _profile_tab,
@ -328,6 +365,10 @@ func _ready() -> void:
]) ])
_configure_navigation_focus() _configure_navigation_focus()
_apply_navigation_styles() _apply_navigation_styles()
_apply_inventory_styles()
# Full-page Inventory controls are later siblings and otherwise win GUI
# picking over the tab row even though the tabs draw above them.
_inventory_sub_tabs.move_to_front()
_apply_cooler_control_styles() _apply_cooler_control_styles()
_apply_cooler_wall_styles() _apply_cooler_wall_styles()
_apply_cooler_notepad_style() _apply_cooler_notepad_style()
@ -442,6 +483,8 @@ func setup(
_fishing_spot.bite_activated.connect(_on_bite_activated) _fishing_spot.bite_activated.connect(_on_bite_activated)
if not _bag.contents_changed.is_connected(_on_bag_changed): if not _bag.contents_changed.is_connected(_on_bag_changed):
_bag.contents_changed.connect(_on_bag_changed) _bag.contents_changed.connect(_on_bag_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( if not _cooler_capacity.capacity_changed.is_connected(
_on_cooler_capacity_changed _on_cooler_capacity_changed
): ):
@ -452,6 +495,9 @@ func setup(
func _input(event: InputEvent) -> void: func _input(event: InputEvent) -> void:
if event is InputEventKey and event.echo: if event is InputEventKey and event.echo:
return return
if _handle_inventory_shortcut(event):
get_viewport().set_input_as_handled()
return
if visible: if visible:
if event.is_action_pressed("open_backpack"): if event.is_action_pressed("open_backpack"):
if not _transitioning and not _page_transitioning: if not _transitioning and not _page_transitioning:
@ -467,6 +513,54 @@ func _input(event: InputEvent) -> void:
get_viewport().set_input_as_handled() get_viewport().set_input_as_handled()
func _handle_inventory_shortcut(event: InputEvent) -> bool:
var key_event := event as InputEventKey
if (
key_event == null
or not key_event.pressed
or _is_text_input_active()
):
return false
var physical_key: Key = key_event.physical_keycode
var inventory_requested: bool = physical_key == KEY_I
var tackle_requested: bool = (
physical_key == KEY_V
or event.is_action_pressed("open_tacklebox")
)
if not inventory_requested and not tackle_requested:
return false
var requested_section: Section = (
Section.TACKLE_BOX if tackle_requested else _last_inventory_section
)
if visible:
if (
_current_section == requested_section
and not _transitioning
and not _page_transitioning
):
close_menu()
elif not _transitioning and not _page_transitioning:
_show_section(requested_section)
else:
if (
_fishing_spot == null
or not _fishing_spot.can_open_player_menu()
):
return false
_current_section = requested_section
open_menu()
return true
func _is_text_input_active() -> bool:
var focus_owner: Control = get_viewport().gui_get_focus_owner()
return (
focus_owner != null
and focus_owner.is_visible_in_tree()
and (focus_owner is LineEdit or focus_owner is TextEdit)
)
func consume_escape() -> bool: func consume_escape() -> bool:
if not visible: if not visible:
return false return false
@ -537,6 +631,7 @@ func close_menu(
CloseReason.TEARDOWN, CloseReason.TEARDOWN,
]: ]:
_fish_selection.clear() _fish_selection.clear()
menu_exit_started.emit()
_begin_menu_exit(reason, restore_controls) _begin_menu_exit(reason, restore_controls)
@ -618,11 +713,15 @@ func _show_section(section: Section) -> void:
func _show_section_immediate(section: Section) -> void: func _show_section_immediate(section: Section) -> void:
_current_section = section _current_section = section
if _is_inventory_section(section):
_last_inventory_section = section
if not is_node_ready(): if not is_node_ready():
return return
_configure_navigation_focus() _configure_navigation_focus()
_cooler_page.visible = section == Section.COOLER _cooler_page.visible = section == Section.COOLER
_bag_page.visible = section == Section.BAG _bag_page.visible = section == Section.BAG
_tackle_box_page.visible = section == Section.TACKLE_BOX
_inventory_sub_tabs.visible = _is_inventory_section(section)
_logbook_page.visible = section == Section.LOGBOOK _logbook_page.visible = section == Section.LOGBOOK
_mail_page.visible = section == Section.MAIL _mail_page.visible = section == Section.MAIL
_profile_page.visible = section == Section.PROFILE _profile_page.visible = section == Section.PROFILE
@ -643,6 +742,7 @@ func _show_section_immediate(section: Section) -> void:
_close_bag_detail() _close_bag_detail()
else: else:
_update_bag_detail() _update_bag_detail()
_refresh_tackle_box()
if section != Section.LOGBOOK: if section != Section.LOGBOOK:
_cancel_logbook_page_transition(true) _cancel_logbook_page_transition(true)
if section == Section.MAIL: if section == Section.MAIL:
@ -657,21 +757,36 @@ func _show_section_immediate(section: Section) -> void:
_players_page.activate() _players_page.activate()
else: else:
_players_page.deactivate() _players_page.deactivate()
_inventory_tab.button_pressed = section == Section.COOLER _inventory_tab.button_pressed = _is_inventory_section(section)
_bag_tab.button_pressed = section == Section.BAG _cooler_sub_tab.button_pressed = section == Section.COOLER
_bag_sub_tab.button_pressed = section == Section.BAG
_tackle_sub_tab.button_pressed = section == Section.TACKLE_BOX
_logbook_tab.button_pressed = section == Section.LOGBOOK _logbook_tab.button_pressed = section == Section.LOGBOOK
_mail_tab.button_pressed = section == Section.MAIL _mail_tab.button_pressed = section == Section.MAIL
_profile_tab.button_pressed = section == Section.PROFILE _profile_tab.button_pressed = section == Section.PROFILE
_players_tab.button_pressed = section == Section.PLAYERS _players_tab.button_pressed = section == Section.PLAYERS
_update_navigation_selection() _update_navigation_selection()
_configure_active_page_focus() _configure_active_page_focus()
inventory_hotbar_context_changed.emit(
section in [Section.COOLER, Section.BAG]
)
func _is_inventory_section(section: Section) -> bool:
return section in [Section.COOLER, Section.BAG, Section.TACKLE_BOX]
func _show_last_inventory_section() -> void:
_show_section(_last_inventory_section)
func _focus_current_section() -> void: func _focus_current_section() -> void:
if _current_section == Section.COOLER: if _current_section == Section.COOLER:
_inventory_tab.grab_focus() _cooler_sub_tab.grab_focus()
elif _current_section == Section.BAG: elif _current_section == Section.BAG:
_bag_tab.grab_focus() _bag_sub_tab.grab_focus()
elif _current_section == Section.TACKLE_BOX:
_tackle_sub_tab.grab_focus()
elif _current_section == Section.LOGBOOK: elif _current_section == Section.LOGBOOK:
_logbook_tab.grab_focus() _logbook_tab.grab_focus()
elif _current_section == Section.MAIL: elif _current_section == Section.MAIL:
@ -704,7 +819,6 @@ func _process(delta: float) -> void:
func _configure_navigation_focus() -> void: func _configure_navigation_focus() -> void:
var navigation: Array[BubbleButtonType] = [ var navigation: Array[BubbleButtonType] = [
_inventory_tab, _inventory_tab,
_bag_tab,
_logbook_tab, _logbook_tab,
_mail_tab, _mail_tab,
_profile_tab, _profile_tab,
@ -723,6 +837,26 @@ func _configure_navigation_focus() -> void:
bubble.focus_neighbor_right = bubble.get_path_to(next) bubble.focus_neighbor_right = bubble.get_path_to(next)
bubble.focus_neighbor_top = bubble.focus_neighbor_left bubble.focus_neighbor_top = bubble.focus_neighbor_left
bubble.focus_neighbor_bottom = bubble.focus_neighbor_right bubble.focus_neighbor_bottom = bubble.focus_neighbor_right
var inventory_tabs: Array[Button] = [
_cooler_sub_tab,
_bag_sub_tab,
_tackle_sub_tab,
]
for index: int in inventory_tabs.size():
var tab: Button = inventory_tabs[index]
tab.focus_neighbor_left = tab.get_path_to(
inventory_tabs[maxi(index - 1, 0)]
)
tab.focus_neighbor_right = tab.get_path_to(
inventory_tabs[mini(index + 1, inventory_tabs.size() - 1)]
)
tab.focus_neighbor_top = tab.get_path_to(_inventory_tab)
_inventory_tab.focus_neighbor_bottom = _inventory_tab.get_path_to(
inventory_tabs[int(_last_inventory_section)]
)
_tackle_sub_tab.focus_neighbor_bottom = _tackle_sub_tab.get_path_to(
_bait_filter
)
func _configure_sale_confirmation_focus() -> void: func _configure_sale_confirmation_focus() -> void:
@ -762,6 +896,8 @@ func _configure_active_page_focus() -> void:
_configure_cooler_fish_focus() _configure_cooler_fish_focus()
Section.BAG: Section.BAG:
_configure_bag_item_focus() _configure_bag_item_focus()
Section.TACKLE_BOX:
_bait_filter.grab_focus()
Section.LOGBOOK: Section.LOGBOOK:
_configure_logbook_focus() _configure_logbook_focus()
Section.MAIL: Section.MAIL:
@ -770,6 +906,132 @@ func _configure_active_page_focus() -> void:
_profile_page.activate() _profile_page.activate()
func _apply_inventory_styles() -> void:
for button: Button in [
_cooler_sub_tab,
_bag_sub_tab,
_tackle_sub_tab,
_equipment_filter,
_consumables_filter,
_bait_filter,
_lures_filter,
]:
UtilityPageStyle.apply_button(button)
for panel: PanelContainer in [_tackle_main_panel, _tackle_detail_panel]:
panel.add_theme_stylebox_override(
"panel",
UtilityPageStyle.panel_style(),
)
for label: Label in [_tackle_empty, _tackle_detail_text]:
label.add_theme_font_override("font", UtilityPageStyle.TuffyFont)
label.add_theme_color_override(
"font_color",
UtilityPageStyle.INK,
)
func _set_bag_view(view: BagView) -> void:
if _bag_view == view:
return
_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()
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] = []
if _bag != null and _item_catalog != null:
for owned: OwnedItemType in _bag.get_all_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:
var item: ItemDataType = _item_catalog.get_item_by_id(owned.item_id)
var row := Button.new()
row.text = "%s ×%d" % [item.display_name, owned.quantity]
row.icon = item.icon
row.alignment = HORIZONTAL_ALIGNMENT_LEFT
row.toggle_mode = true
row.button_pressed = owned.item_id == _selected_tackle_item_id
UtilityPageStyle.apply_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()
func _select_tackle_item(item_id: StringName) -> void:
_selected_tackle_item_id = item_id
_refresh_tackle_box()
func _update_tackle_detail() -> void:
var item: ItemDataType = (
_item_catalog.get_item_by_id(_selected_tackle_item_id)
if _item_catalog != null and not _selected_tackle_item_id.is_empty()
else null
)
if item == null:
_tackle_detail_text.text = (
"Select bait for details."
if _tackle_view == TackleView.BAIT
else "Select a lure for details."
)
return
var quantity: int = _bag.get_quantity(item.item_id) if _bag != null else 0
var assigned_slot: int = -1
if _hotbar != null:
for slot_index: int in range(PlayerHotbarType.SLOT_COUNT):
if _hotbar.get_item_id(slot_index) == item.item_id:
assigned_slot = slot_index
break
var state_text: String = (
"hotbar slot %d" % (assigned_slot + 1)
if assigned_slot >= 0
else "not assigned"
)
_tackle_detail_text.text = (
"%s\n\nType: %s\nQuantity: %d\n%s\n\n%s"
% [
item.display_name,
item.get_category_name(),
quantity,
state_text,
item.description,
]
)
func _apply_cooler_control_styles() -> void: func _apply_cooler_control_styles() -> void:
var profile: BubbleMenuProfile = _inventory_tab.profile var profile: BubbleMenuProfile = _inventory_tab.profile
if profile == null: if profile == null:
@ -858,7 +1120,6 @@ func _apply_navigation_styles() -> void:
var disabled := _make_navigation_style(profile.disabled_fill, 1, 0.14) var disabled := _make_navigation_style(profile.disabled_fill, 1, 0.14)
for bubble: BubbleButtonType in [ for bubble: BubbleButtonType in [
_inventory_tab, _inventory_tab,
_bag_tab,
_logbook_tab, _logbook_tab,
_mail_tab, _mail_tab,
_profile_tab, _profile_tab,
@ -890,7 +1151,6 @@ func _make_navigation_style(
func _apply_navigation_selection_presentation() -> void: func _apply_navigation_selection_presentation() -> void:
for bubble: BubbleButtonType in [ for bubble: BubbleButtonType in [
_inventory_tab, _inventory_tab,
_bag_tab,
_logbook_tab, _logbook_tab,
_mail_tab, _mail_tab,
_profile_tab, _profile_tab,
@ -998,8 +1258,7 @@ func _on_mail_unread_count_changed(count: int) -> void:
func _set_navigation_target(section: Section) -> void: func _set_navigation_target(section: Section) -> void:
_inventory_tab.button_pressed = section == Section.COOLER _inventory_tab.button_pressed = _is_inventory_section(section)
_bag_tab.button_pressed = section == Section.BAG
_logbook_tab.button_pressed = section == Section.LOGBOOK _logbook_tab.button_pressed = section == Section.LOGBOOK
_mail_tab.button_pressed = section == Section.MAIL _mail_tab.button_pressed = section == Section.MAIL
_profile_tab.button_pressed = section == Section.PROFILE _profile_tab.button_pressed = section == Section.PROFILE
@ -1033,16 +1292,16 @@ func _update_shell_layout() -> void:
_cooler_rest_position = Vector2.ZERO _cooler_rest_position = Vector2.ZERO
_layout_cooler_fish(false) _layout_cooler_fish(false)
_cooler_outer_wall.position = ( _cooler_outer_wall.position = (
Vector2(14.0, 154.0) if compact else Vector2(54.0, 126.0) Vector2(14.0, 154.0) if compact else Vector2(54.0, 166.0)
) )
_cooler_outer_wall.size = ( _cooler_outer_wall.size = (
Vector2(300.0, 206.0) if compact else Vector2(866.0, 476.0) Vector2(300.0, 218.0) if compact else Vector2(882.0, 484.0)
) )
_detail_constellation.position = ( _detail_constellation.position = (
Vector2(320.0, 154.0) if compact else Vector2(942.0, 126.0) Vector2(320.0, 154.0) if compact else Vector2(952.0, 166.0)
) )
_detail_constellation.size = ( _detail_constellation.size = (
Vector2(306.0, 196.0) if compact else Vector2(288.0, 476.0) Vector2(306.0, 196.0) if compact else Vector2(278.0, 436.0)
) )
_notepad_binding.position = Vector2(44.0, 1.0) if compact else Vector2(28.0, 4.0) _notepad_binding.position = Vector2(44.0, 1.0) if compact else Vector2(28.0, 4.0)
_notepad_binding.size = Vector2(218.0, 20.0) if compact else Vector2(232.0, 27.0) _notepad_binding.size = Vector2(218.0, 20.0) if compact else Vector2(232.0, 27.0)
@ -1126,13 +1385,13 @@ func _update_shell_layout() -> void:
Vector2(74.0, 42.0) if compact else Vector2(118.0, 50.0) Vector2(74.0, 42.0) if compact else Vector2(118.0, 50.0)
) )
_favorite_bubble.position = ( _favorite_bubble.position = (
Vector2(144.0, 148.0) if compact else Vector2(26.0, 400.0) Vector2(144.0, 148.0) if compact else Vector2(26.0, 378.0)
) )
_favorite_bubble.size = ( _favorite_bubble.size = (
Vector2(72.0, 42.0) if compact else Vector2(108.0, 50.0) Vector2(72.0, 42.0) if compact else Vector2(108.0, 50.0)
) )
_sell_bubble.position = ( _sell_bubble.position = (
Vector2(222.0, 148.0) if compact else Vector2(144.0, 400.0) Vector2(222.0, 148.0) if compact else Vector2(144.0, 378.0)
) )
_sell_bubble.size = ( _sell_bubble.size = (
Vector2(74.0, 42.0) if compact else Vector2(118.0, 50.0) Vector2(74.0, 42.0) if compact else Vector2(118.0, 50.0)
@ -1147,27 +1406,30 @@ func _update_shell_layout() -> void:
_bag_page.size = reference_size _bag_page.size = reference_size
_bag_page.position = Vector2.ZERO _bag_page.position = Vector2.ZERO
_bag_rest_position = Vector2.ZERO _bag_rest_position = Vector2.ZERO
_tackle_box_page.size = reference_size
_tackle_box_page.position = Vector2.ZERO
_tackle_rest_position = Vector2.ZERO
_bag_outer_wall.position = ( _bag_outer_wall.position = (
Vector2(14.0, 170.0) if compact else Vector2(122.0, 132.0) Vector2(14.0, 170.0) if compact else Vector2(54.0, 214.0)
) )
_bag_outer_wall.size = ( _bag_outer_wall.size = (
Vector2(612.0, 200.0) if compact else Vector2(896.0, 442.0) Vector2(612.0, 212.0) if compact else Vector2(882.0, 436.0)
) )
_bag_host.custom_minimum_size = ( _bag_host.custom_minimum_size = (
Vector2(520.0, 140.0) if compact else Vector2(820.0, 350.0) Vector2(520.0, 152.0) if compact else Vector2(820.0, 380.0)
) )
_bag_scroll.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED _bag_scroll.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
_bag_detail_constellation.position = ( _bag_detail_constellation.position = (
Vector2.ZERO if compact else Vector2(984.0, 266.0) Vector2.ZERO if compact else Vector2(952.0, 166.0)
) )
_bag_detail_constellation.size = ( _bag_detail_constellation.size = (
Vector2(640.0, 390.0) if compact else Vector2(272.0, 304.0) Vector2(640.0, 390.0) if compact else Vector2(278.0, 436.0)
) )
_bag_sprite_detail_bubble.position = ( _bag_sprite_detail_bubble.position = (
Vector2(170.0, 164.0) if compact else Vector2.ZERO Vector2(170.0, 164.0) if compact else Vector2.ZERO
) )
_bag_sprite_detail_bubble.size = ( _bag_sprite_detail_bubble.size = (
Vector2(300.0, 188.0) if compact else Vector2(272.0, 304.0) Vector2(300.0, 188.0) if compact else Vector2(278.0, 436.0)
) )
_bag_sprite_detail_texture.custom_minimum_size = ( _bag_sprite_detail_texture.custom_minimum_size = (
Vector2(72.0, 48.0) if compact else Vector2(100.0, 72.0) Vector2(72.0, 48.0) if compact else Vector2(100.0, 72.0)
@ -1180,6 +1442,18 @@ func _update_shell_layout() -> void:
"font_size", "font_size",
12 if compact else 15, 12 if compact else 15,
) )
_tackle_main_panel.position = (
Vector2(14.0, 154.0) if compact else Vector2(54.0, 166.0)
)
_tackle_main_panel.size = (
Vector2(418.0, 218.0) if compact else Vector2(882.0, 484.0)
)
_tackle_detail_panel.position = (
Vector2(438.0, 154.0) if compact else Vector2(952.0, 166.0)
)
_tackle_detail_panel.size = (
Vector2(188.0, 218.0) if compact else Vector2(278.0, 484.0)
)
_logbook_page.size = reference_size _logbook_page.size = reference_size
_logbook_page.position = Vector2.ZERO _logbook_page.position = Vector2.ZERO
_logbook_rest_position = Vector2.ZERO _logbook_rest_position = Vector2.ZERO
@ -1191,11 +1465,14 @@ func _update_shell_layout() -> void:
_profile_page.position = Vector2(42.0, 104.0) _profile_page.position = Vector2(42.0, 104.0)
_profile_page.size = Vector2(1196.0, 608.0) _profile_page.size = Vector2(1196.0, 608.0)
_profile_rest_position = _profile_page.position _profile_rest_position = _profile_page.position
_players_page.set_anchors_preset(Control.PRESET_TOP_LEFT)
_players_page.position = Vector2.ZERO
_players_page.size = reference_size
_book_backing.position = ( _book_backing.position = (
Vector2(14.0, 164.0) if compact else Vector2(58.0, 128.0) Vector2(14.0, 164.0) if compact else Vector2(58.0, 128.0)
) )
_book_backing.size = ( _book_backing.size = (
Vector2(612.0, 210.0) if compact else Vector2(1164.0, 460.0) Vector2(612.0, 232.0) if compact else Vector2(1164.0, 522.0)
) )
_right_page.visible = not compact _right_page.visible = not compact
_book_gutter.visible = not compact _book_gutter.visible = not compact
@ -1214,17 +1491,17 @@ func _update_shell_layout() -> void:
Vector2(400.0, 52.0) if compact else Vector2(476.0, 52.0) Vector2(400.0, 52.0) if compact else Vector2(476.0, 52.0)
) )
_logbook_previous.apply_layout( _logbook_previous.apply_layout(
Vector2(58.0, 310.0) if compact else Vector2(116.0, 530.0), Vector2(58.0, 332.0) if compact else Vector2(116.0, 622.0),
Vector2(66.0, 62.0) if compact else Vector2(76.0, 72.0), Vector2(66.0, 62.0) if compact else Vector2(76.0, 72.0),
0.18, 0.18,
) )
_logbook_next.apply_layout( _logbook_next.apply_layout(
Vector2(582.0, 310.0) if compact else Vector2(1164.0, 530.0), Vector2(582.0, 332.0) if compact else Vector2(1164.0, 622.0),
Vector2(66.0, 62.0) if compact else Vector2(76.0, 72.0), Vector2(66.0, 62.0) if compact else Vector2(76.0, 72.0),
0.18, 0.18,
) )
_logbook_page_status.position = ( _logbook_page_status.position = (
Vector2(255.0, 286.0) if compact else Vector2(555.0, 524.0) Vector2(255.0, 308.0) if compact else Vector2(555.0, 608.0)
) )
_logbook_page_status.size = ( _logbook_page_status.size = (
Vector2(130.0, 46.0) if compact else Vector2(170.0, 56.0) Vector2(130.0, 46.0) if compact else Vector2(170.0, 56.0)
@ -1238,7 +1515,7 @@ func _update_shell_layout() -> void:
) )
_cooler_host.custom_minimum_size = Vector2( _cooler_host.custom_minimum_size = Vector2(
520.0 if compact else 810.0, 520.0 if compact else 810.0,
500.0 if compact else 412.0, 512.0 if compact else 420.0,
) )
_bag_grid.columns = 2 if compact else 3 _bag_grid.columns = 2 if compact else 3
_logbook_grid.columns = 3 if compact else 4 _logbook_grid.columns = 3 if compact else 4
@ -1250,14 +1527,18 @@ func _update_shell_layout() -> void:
_content_shell.position = _presentation_rest_position _content_shell.position = _presentation_rest_position
_cooler_page.position = _cooler_rest_position _cooler_page.position = _cooler_rest_position
_bag_page.position = _bag_rest_position _bag_page.position = _bag_rest_position
_tackle_box_page.position = _tackle_rest_position
_logbook_page.position = _logbook_rest_position _logbook_page.position = _logbook_rest_position
_mail_page.position = _mail_rest_position _mail_page.position = _mail_rest_position
_profile_page.position = _profile_rest_position _profile_page.position = _profile_rest_position
_players_page.position = Vector2.ZERO
_cooler_page.modulate.a = 1.0 _cooler_page.modulate.a = 1.0
_bag_page.modulate.a = 1.0 _bag_page.modulate.a = 1.0
_tackle_box_page.modulate.a = 1.0
_logbook_page.modulate.a = 1.0 _logbook_page.modulate.a = 1.0
_mail_page.modulate.a = 1.0 _mail_page.modulate.a = 1.0
_profile_page.modulate.a = 1.0 _profile_page.modulate.a = 1.0
_players_page.modulate.a = 1.0
if not _page_transitioning: if not _page_transitioning:
_content_stage.position = _content_rest_position _content_stage.position = _content_rest_position
_layout_cooler_fish(false) _layout_cooler_fish(false)
@ -1339,9 +1620,13 @@ func _begin_menu_entry() -> void:
_content_shell.position = _presentation_rest_position + Vector2.DOWN * start_offset _content_shell.position = _presentation_rest_position + Vector2.DOWN * start_offset
_cooler_page.position = _cooler_rest_position + Vector2.DOWN * start_offset _cooler_page.position = _cooler_rest_position + Vector2.DOWN * start_offset
_bag_page.position = _bag_rest_position + Vector2.DOWN * start_offset _bag_page.position = _bag_rest_position + Vector2.DOWN * start_offset
_tackle_box_page.position = (
_tackle_rest_position + Vector2.DOWN * start_offset
)
_logbook_page.position = _logbook_rest_position + Vector2.DOWN * start_offset _logbook_page.position = _logbook_rest_position + Vector2.DOWN * start_offset
_mail_page.position = _mail_rest_position + Vector2.DOWN * start_offset _mail_page.position = _mail_rest_position + Vector2.DOWN * start_offset
_profile_page.position = _profile_rest_position + Vector2.DOWN * start_offset _profile_page.position = _profile_rest_position + Vector2.DOWN * start_offset
_players_page.position = Vector2.DOWN * start_offset
var navigation_rest: Vector2 = _navigation_cluster.position var navigation_rest: Vector2 = _navigation_cluster.position
_navigation_cluster.position = navigation_rest + Vector2.DOWN * start_offset _navigation_cluster.position = navigation_rest + Vector2.DOWN * start_offset
var transition_duration := UIMotion.bubble_duration(start_offset) var transition_duration := UIMotion.bubble_duration(start_offset)
@ -1364,6 +1649,12 @@ func _begin_menu_entry() -> void:
_bag_rest_position, _bag_rest_position,
transition_duration transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) ).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property(
_tackle_box_page,
"position",
_tackle_rest_position,
transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property( _presentation_tween.tween_property(
_logbook_page, _logbook_page,
"position", "position",
@ -1382,6 +1673,12 @@ func _begin_menu_entry() -> void:
_profile_rest_position, _profile_rest_position,
transition_duration transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) ).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property(
_players_page,
"position",
Vector2.ZERO,
transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property( _presentation_tween.tween_property(
_navigation_cluster, _navigation_cluster,
"position", "position",
@ -1439,6 +1736,12 @@ func _begin_menu_exit(reason: CloseReason, restore_controls: bool) -> void:
-_bag_page.size.y - TRANSITION_SAFE_MARGIN, -_bag_page.size.y - TRANSITION_SAFE_MARGIN,
transition_duration transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) ).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property(
_tackle_box_page,
"position:y",
-_tackle_box_page.size.y - TRANSITION_SAFE_MARGIN,
transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property( _presentation_tween.tween_property(
_logbook_page, _logbook_page,
"position:y", "position:y",
@ -1457,6 +1760,12 @@ func _begin_menu_exit(reason: CloseReason, restore_controls: bool) -> void:
-_profile_page.size.y - TRANSITION_SAFE_MARGIN, -_profile_page.size.y - TRANSITION_SAFE_MARGIN,
transition_duration transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT) ).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property(
_players_page,
"position:y",
-_players_page.size.y - TRANSITION_SAFE_MARGIN,
transition_duration
).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
_presentation_tween.tween_property( _presentation_tween.tween_property(
_navigation_cluster, _navigation_cluster,
"position:y", "position:y",
@ -1518,12 +1827,16 @@ func _get_section_root(section: Section) -> Control:
return _cooler_page return _cooler_page
Section.BAG: Section.BAG:
return _bag_page return _bag_page
Section.TACKLE_BOX:
return _tackle_box_page
Section.LOGBOOK: Section.LOGBOOK:
return _logbook_page return _logbook_page
Section.MAIL: Section.MAIL:
return _mail_page return _mail_page
_: Section.PROFILE:
return _profile_page return _profile_page
_:
return _players_page
func _get_section_rest_position(section: Section) -> Vector2: func _get_section_rest_position(section: Section) -> Vector2:
@ -1532,12 +1845,16 @@ func _get_section_rest_position(section: Section) -> Vector2:
return _cooler_rest_position return _cooler_rest_position
Section.BAG: Section.BAG:
return _bag_rest_position return _bag_rest_position
Section.TACKLE_BOX:
return _tackle_rest_position
Section.LOGBOOK: Section.LOGBOOK:
return _logbook_rest_position return _logbook_rest_position
Section.MAIL: Section.MAIL:
return _mail_rest_position return _mail_rest_position
_: Section.PROFILE:
return _profile_rest_position return _profile_rest_position
_:
return Vector2.ZERO
func _begin_page_transition(section: Section) -> void: func _begin_page_transition(section: Section) -> void:
@ -1615,7 +1932,6 @@ func _set_shell_interactive(interactive: bool) -> void:
_set_content_interactive(interactive) _set_content_interactive(interactive)
for bubble: BubbleButtonType in [ for bubble: BubbleButtonType in [
_inventory_tab, _inventory_tab,
_bag_tab,
_logbook_tab, _logbook_tab,
_mail_tab, _mail_tab,
_profile_tab, _profile_tab,
@ -1646,6 +1962,25 @@ func _set_content_interactive(interactive: bool) -> void:
if interactive and _current_section == Section.BAG if interactive and _current_section == Section.BAG
else Control.MOUSE_FILTER_IGNORE else Control.MOUSE_FILTER_IGNORE
) )
_tackle_box_page.mouse_filter = (
Control.MOUSE_FILTER_PASS
if interactive and _current_section == Section.TACKLE_BOX
else Control.MOUSE_FILTER_IGNORE
)
for tab: Button in [
_cooler_sub_tab, _bag_sub_tab, _tackle_sub_tab,
]:
var tab_interactive: bool = (
interactive and _is_inventory_section(_current_section)
)
tab.focus_mode = (
Control.FOCUS_ALL if tab_interactive else Control.FOCUS_NONE
)
tab.mouse_filter = (
Control.MOUSE_FILTER_STOP
if tab_interactive
else Control.MOUSE_FILTER_IGNORE
)
_logbook_page.mouse_filter = ( _logbook_page.mouse_filter = (
Control.MOUSE_FILTER_PASS Control.MOUSE_FILTER_PASS
if interactive and _current_section == Section.LOGBOOK if interactive and _current_section == Section.LOGBOOK
@ -1728,8 +2063,13 @@ func _cancel_page_tween() -> void:
func _reset_page_transition_visuals() -> void: func _reset_page_transition_visuals() -> void:
for section: Section in [ for section: Section in [
Section.COOLER, Section.BAG, Section.LOGBOOK, Section.MAIL, Section.COOLER,
Section.BAG,
Section.TACKLE_BOX,
Section.LOGBOOK,
Section.MAIL,
Section.PROFILE, Section.PROFILE,
Section.PLAYERS,
]: ]:
var page: Control = _get_section_root(section) var page: Control = _get_section_root(section)
page.position = _get_section_rest_position(section) page.position = _get_section_rest_position(section)
@ -1793,6 +2133,12 @@ func _refresh_all() -> void:
func _on_bag_changed() -> void: func _on_bag_changed() -> void:
_refresh_bag() _refresh_bag()
_refresh_tackle_box()
func _on_hotbar_changed() -> void:
_update_bag_detail()
_update_tackle_detail()
func _refresh_bag() -> void: func _refresh_bag() -> void:
@ -1801,10 +2147,42 @@ func _refresh_bag() -> void:
var owned_items: Array[OwnedItemType] = ( var owned_items: Array[OwnedItemType] = (
_bag.get_all_items() if _bag != null else [] _bag.get_all_items() if _bag != null else []
) )
var filtered_items: Array[OwnedItemType] = []
for owned: OwnedItemType in owned_items:
var item: ItemDataType = (
_item_catalog.get_item_by_id(owned.item_id)
if _item_catalog != null
else null
)
if item == null:
continue
var is_consumable: bool = (
item.category == ItemDataType.Category.CONSUMABLE
)
if (
(_bag_view == BagView.CONSUMABLES and is_consumable)
or (
_bag_view == BagView.EQUIPMENT
and not is_consumable
and item.category != ItemDataType.Category.BAIT
and item.category != ItemDataType.Category.LURE
)
):
filtered_items.append(owned)
owned_items = filtered_items
owned_items.sort_custom(_sort_bag_items) owned_items.sort_custom(_sort_bag_items)
_sorted_bag_items = owned_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.visible = owned_items.is_empty()
_bag_empty_state.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."
)
if ( if (
not _selected_bag_item_id.is_empty() not _selected_bag_item_id.is_empty()
and (_bag == null or not _bag.owns_item(_selected_bag_item_id)) and (_bag == null or not _bag.owns_item(_selected_bag_item_id))
@ -1858,7 +2236,7 @@ func _sync_bag_item_nodes(owned_items: Array[OwnedItemType]) -> void:
continue continue
var removed := _bag_item_nodes[item_id] as BagItemSpriteType var removed := _bag_item_nodes[item_id] as BagItemSpriteType
_bag_item_nodes.erase(item_id) _bag_item_nodes.erase(item_id)
_release_focus_from(removed, _bag_tab) _release_focus_from(removed, _bag_sub_tab)
removed.queue_free() removed.queue_free()
_layout_bag_items() _layout_bag_items()
_configure_bag_item_focus() _configure_bag_item_focus()
@ -1887,7 +2265,7 @@ func _layout_bag_items() -> void:
_bag_item_field.custom_minimum_size = ( _bag_item_field.custom_minimum_size = (
Vector2(520.0, 140.0) Vector2(520.0, 140.0)
if _compact_layout if _compact_layout
else Vector2(820.0, 350.0) else Vector2(820.0, 240.0)
) )
for index: int in _sorted_bag_items.size(): for index: int in _sorted_bag_items.size():
var owned: OwnedItemType = _sorted_bag_items[index] var owned: OwnedItemType = _sorted_bag_items[index]
@ -1927,9 +2305,11 @@ func _configure_bag_item_focus() -> void:
if item_node != null: if item_node != null:
controls.append(item_node) controls.append(item_node)
if controls.is_empty(): if controls.is_empty():
_bag_tab.focus_neighbor_bottom = NodePath() _bag_sub_tab.focus_neighbor_bottom = NodePath()
return return
_bag_tab.focus_neighbor_bottom = _bag_tab.get_path_to(controls.front()) _bag_sub_tab.focus_neighbor_bottom = _bag_sub_tab.get_path_to(
controls.front()
)
for index: int in controls.size(): for index: int in controls.size():
var control: BagItemSpriteType = controls[index] var control: BagItemSpriteType = controls[index]
var column: int = index % 3 var column: int = index % 3
@ -1943,7 +2323,7 @@ func _configure_bag_item_focus() -> void:
controls[right_index] controls[right_index]
) )
control.focus_neighbor_top = ( control.focus_neighbor_top = (
control.get_path_to(_bag_tab) control.get_path_to(_bag_sub_tab)
if index < 3 if index < 3
else control.get_path_to(controls[index - 3]) else control.get_path_to(controls[index - 3])
) )
@ -1985,42 +2365,50 @@ func _update_bag_detail() -> void:
if _bag != null and item != null if _bag != null and item != null
else 0 else 0
) )
var hotbar_assignment: String = "not assigned"
if item != null and _hotbar != null:
for slot_index: int in range(PlayerHotbarType.SLOT_COUNT):
if _hotbar.get_item_id(slot_index) == item.item_id:
hotbar_assignment = "hotbar slot %d" % (slot_index + 1)
break
var item_state: String = ""
if item != null:
if item.equippable:
item_state = "equippable"
elif item.usable:
item_state = "usable"
_bag_detail_texture.texture = item.icon if item != null else null _bag_detail_texture.texture = item.icon if item != null else null
_bag_detail_name.text = item.display_name if item != null else "" _bag_detail_name.text = item.display_name if item != null else ""
_bag_detail_data.text = ( _bag_detail_data.text = (
"%s\nquantity: %d\n%s\n%s" "%s\nquantity: %d\n%s\n%s\n%s"
% [ % [
item.get_category_name(), item.get_category_name(),
quantity, quantity,
item_state,
hotbar_assignment,
item.description, item.description,
(
"can be assigned to the hotbar."
if item.hotbar_allowed
else "cannot be assigned to the hotbar."
),
] ]
if item != null if item != null
else "select a bag item for details." else "select a bag item for details."
) )
_bag_sprite_detail_texture.texture = item.icon if item != null else null _bag_sprite_detail_texture.texture = item.icon if item != null else null
_bag_sprite_detail_name.text = item.display_name if item != null else "" _bag_sprite_detail_name.text = (
item.display_name if item != null else "bag notes"
)
_bag_sprite_detail_data.text = ( _bag_sprite_detail_data.text = (
"%s • quantity: %d\n%s\n%s" "%s • quantity: %d\n%s%s\n%s"
% [ % [
item.get_category_name(), item.get_category_name(),
quantity, quantity,
item_state,
hotbar_assignment,
item.description, item.description,
(
"drag to any hotbar slot."
if item.hotbar_allowed
else "not compatible with the hotbar."
),
] ]
if item != null if item != null
else "" else "select an item for details."
) )
_bag_detail_constellation.visible = ( _bag_detail_constellation.visible = (
item != null and _current_section == Section.BAG _current_section == Section.BAG
) )
@ -2200,7 +2588,7 @@ func _layout_cooler_fish(animate: bool = true) -> void:
var visible_field_size := ( var visible_field_size := (
Vector2(218.0, 124.0) Vector2(218.0, 124.0)
if _compact_layout if _compact_layout
else Vector2(784.0, 394.0) else Vector2(810.0, 280.0)
) )
var side_margin: float = 2.0 if _compact_layout else 8.0 var side_margin: float = 2.0 if _compact_layout else 8.0
var top_margin: float = 4.0 if _compact_layout else 6.0 var top_margin: float = 4.0 if _compact_layout else 6.0
@ -2260,9 +2648,9 @@ func _configure_cooler_fish_focus() -> void:
controls.append(fish_node) controls.append(fish_node)
var columns: int = 3 if _compact_layout else 9 var columns: int = 3 if _compact_layout else 9
if controls.is_empty(): if controls.is_empty():
_inventory_tab.focus_neighbor_bottom = NodePath() _cooler_sub_tab.focus_neighbor_bottom = NodePath()
return return
_inventory_tab.focus_neighbor_bottom = _inventory_tab.get_path_to( _cooler_sub_tab.focus_neighbor_bottom = _cooler_sub_tab.get_path_to(
controls.front() controls.front()
) )
for index: int in controls.size(): for index: int in controls.size():
@ -2274,7 +2662,7 @@ func _configure_cooler_fish_focus() -> void:
controls[mini(index + 1, controls.size() - 1)] controls[mini(index + 1, controls.size() - 1)]
) )
control.focus_neighbor_top = ( control.focus_neighbor_top = (
control.get_path_to(_inventory_tab) control.get_path_to(_cooler_sub_tab)
if index < columns if index < columns
else control.get_path_to(controls[index - columns]) else control.get_path_to(controls[index - columns])
) )
@ -2460,7 +2848,7 @@ func _update_inventory_detail(fish_catch: FishCatchType) -> void:
and _reservations.is_fish_reserved(fish_catch.catch_id) and _reservations.is_fish_reserved(fish_catch.catch_id)
): ):
_cooler_detail_name.text += " • reserved in mail" _cooler_detail_name.text += " • reserved in mail"
_cooler_weight_unit.text = "lb" _cooler_weight_unit.text = "lb%s" % fish_catch.fish.get_rarity_name()
if buyer_offer >= 0 and _default_buyer != null: if buyer_offer >= 0 and _default_buyer != null:
_cooler_offer_label.text = "%s offer" % _default_buyer.display_name _cooler_offer_label.text = "%s offer" % _default_buyer.display_name
_cooler_offer_value.text = "$%d" % buyer_offer _cooler_offer_value.text = "$%d" % buyer_offer

View file

@ -60,6 +60,42 @@ offset_right = 1280.0
offset_bottom = 720.0 offset_bottom = 720.0
mouse_filter = 2 mouse_filter = 2
[node name="InventorySubTabs" type="HBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
unique_name_in_owner = true
visible = false
z_index = 50
layout_mode = 0
offset_left = 54.0
offset_top = 118.0
offset_right = 504.0
offset_bottom = 158.0
mouse_filter = 1
theme_override_constants/separation = 8
[node name="CoolerSubTab" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/InventorySubTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(132, 40)
layout_mode = 2
toggle_mode = true
button_group = null
text = "Cooler"
[node name="BagSubTab" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/InventorySubTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(132, 40)
layout_mode = 2
toggle_mode = true
button_group = null
text = "Bag"
[node name="TackleSubTab" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/InventorySubTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(154, 40)
layout_mode = 2
toggle_mode = true
button_group = null
text = "Tackle Box"
[node name="CoolerPage" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"] [node name="CoolerPage" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 0 layout_mode = 0
@ -434,6 +470,29 @@ offset_right = 1280.0
offset_bottom = 720.0 offset_bottom = 720.0
mouse_filter = 1 mouse_filter = 1
[node name="BagFilterTabs" type="HBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/BagPage"]
unique_name_in_owner = true
layout_mode = 0
offset_left = 122.0
offset_top = 166.0
offset_right = 442.0
offset_bottom = 206.0
theme_override_constants/separation = 8
[node name="EquipmentFilter" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/BagPage/BagFilterTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
toggle_mode = true
text = "Equipment"
[node name="ConsumablesFilter" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/BagPage/BagFilterTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
toggle_mode = true
text = "Consumables"
[node name="BagOuterWall" type="PanelContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/BagPage"] [node name="BagOuterWall" type="PanelContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/BagPage"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 0 layout_mode = 0
@ -539,6 +598,94 @@ theme_override_font_sizes/font_size = 15
horizontal_alignment = 1 horizontal_alignment = 1
autowrap_mode = 2 autowrap_mode = 2
[node name="TackleBoxPage" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
unique_name_in_owner = true
visible = false
layout_mode = 0
offset_right = 1280.0
offset_bottom = 720.0
mouse_filter = 1
[node name="TackleMainPanel" type="PanelContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage"]
unique_name_in_owner = true
layout_mode = 0
offset_left = 54.0
offset_top = 166.0
offset_right = 936.0
offset_bottom = 602.0
[node name="Margin" type="MarginContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel"]
layout_mode = 2
theme_override_constants/margin_left = 24
theme_override_constants/margin_top = 20
theme_override_constants/margin_right = 24
theme_override_constants/margin_bottom = 20
[node name="Layout" type="VBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel/Margin"]
layout_mode = 2
theme_override_constants/separation = 14
[node name="TackleFilterTabs" type="HBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel/Margin/Layout"]
unique_name_in_owner = true
layout_mode = 2
theme_override_constants/separation = 8
[node name="BaitFilter" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel/Margin/Layout/TackleFilterTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
toggle_mode = true
text = "Bait"
[node name="LuresFilter" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel/Margin/Layout/TackleFilterTabs"]
unique_name_in_owner = true
custom_minimum_size = Vector2(150, 40)
layout_mode = 2
toggle_mode = true
text = "Lures"
[node name="TackleScroll" type="ScrollContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel/Margin/Layout"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
horizontal_scroll_mode = 0
[node name="TackleItemList" type="VBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel/Margin/Layout/TackleScroll"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 8
[node name="TackleEmpty" type="Label" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleMainPanel/Margin/Layout"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
text = "No bait collected."
horizontal_alignment = 1
vertical_alignment = 1
[node name="TackleDetailPanel" type="PanelContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage"]
unique_name_in_owner = true
layout_mode = 0
offset_left = 952.0
offset_top = 166.0
offset_right = 1230.0
offset_bottom = 602.0
[node name="Margin" type="MarginContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/TackleBoxPage/TackleDetailPanel"]
layout_mode = 2
theme_override_constants/margin_left = 20
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"]
unique_name_in_owner = true
layout_mode = 2
text = "Select bait or a lure for details."
autowrap_mode = 2
vertical_alignment = 1
[node name="LogbookPage" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"] [node name="LogbookPage" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
@ -1209,15 +1356,15 @@ compact_reference_size = Vector2(840, 100)
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 0 layout_mode = 0
toggle_mode = true toggle_mode = true
text = "cooler" text = "inventory"
script = ExtResource("6_bubble") script = ExtResource("6_bubble")
profile = ExtResource("4_profile") profile = ExtResource("4_profile")
neutral_size = Vector2(112, 108) neutral_size = Vector2(112, 108)
desktop_anchor = Vector2(70, 60) desktop_anchor = Vector2(70, 60)
compact_anchor = Vector2(70, 73.3333) compact_anchor = Vector2(70, 73.3333)
compact_minimum_size = Vector2(84, 82) compact_minimum_size = Vector2(84, 82)
minimum_font_size = 25 minimum_font_size = 20
maximum_font_size = 25 maximum_font_size = 22
horizontal_amplitude = 1.2 horizontal_amplitude = 1.2
vertical_amplitude = 2.4 vertical_amplitude = 2.4
motion_period = 5.6 motion_period = 5.6
@ -1225,26 +1372,6 @@ motion_phase = 0.35
deformation_amplitude = 0.012 deformation_amplitude = 0.012
deformation_period = 6.4 deformation_period = 6.4
[node name="BagTab" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/NavigationCluster"]
unique_name_in_owner = true
layout_mode = 0
toggle_mode = true
text = "bag"
script = ExtResource("6_bubble")
profile = ExtResource("4_profile")
neutral_size = Vector2(112, 108)
desktop_anchor = Vector2(182, 60)
compact_anchor = Vector2(182, 73.3333)
compact_minimum_size = Vector2(84, 82)
minimum_font_size = 25
maximum_font_size = 25
horizontal_amplitude = 1.0
vertical_amplitude = 2.0
motion_period = 5.1
motion_phase = 1.65
deformation_amplitude = 0.011
deformation_period = 6.0
[node name="LogbookTab" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/NavigationCluster"] [node name="LogbookTab" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/NavigationCluster"]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 0 layout_mode = 0
@ -1253,8 +1380,8 @@ text = "logbook"
script = ExtResource("6_bubble") script = ExtResource("6_bubble")
profile = ExtResource("4_profile") profile = ExtResource("4_profile")
neutral_size = Vector2(112, 108) neutral_size = Vector2(112, 108)
desktop_anchor = Vector2(294, 60) desktop_anchor = Vector2(210, 60)
compact_anchor = Vector2(294, 73.3333) compact_anchor = Vector2(210, 73.3333)
compact_minimum_size = Vector2(84, 82) compact_minimum_size = Vector2(84, 82)
minimum_font_size = 25 minimum_font_size = 25
maximum_font_size = 25 maximum_font_size = 25
@ -1273,8 +1400,8 @@ text = "mail"
script = ExtResource("6_bubble") script = ExtResource("6_bubble")
profile = ExtResource("4_profile") profile = ExtResource("4_profile")
neutral_size = Vector2(112, 108) neutral_size = Vector2(112, 108)
desktop_anchor = Vector2(406, 60) desktop_anchor = Vector2(350, 60)
compact_anchor = Vector2(406, 73.3333) compact_anchor = Vector2(350, 73.3333)
compact_minimum_size = Vector2(84, 82) compact_minimum_size = Vector2(84, 82)
minimum_font_size = 25 minimum_font_size = 25
maximum_font_size = 25 maximum_font_size = 25
@ -1309,8 +1436,8 @@ text = "profile"
script = ExtResource("6_bubble") script = ExtResource("6_bubble")
profile = ExtResource("4_profile") profile = ExtResource("4_profile")
neutral_size = Vector2(112, 108) neutral_size = Vector2(112, 108)
desktop_anchor = Vector2(518, 60) desktop_anchor = Vector2(490, 60)
compact_anchor = Vector2(518, 73.3333) compact_anchor = Vector2(490, 73.3333)
compact_minimum_size = Vector2(84, 82) compact_minimum_size = Vector2(84, 82)
minimum_font_size = 23 minimum_font_size = 23
maximum_font_size = 25 maximum_font_size = 25

View file

@ -0,0 +1,13 @@
shader_type canvas_item;
uniform sampler2D pattern_texture : source_color, repeat_enable, filter_nearest;
uniform vec2 source_tile_size = vec2(128.0, 128.0);
uniform float display_scale : hint_range(0.5, 2.0, 0.05) = 0.85;
uniform vec2 scroll_velocity_pixels = vec2(-7.0, -5.0);
void fragment() {
vec2 viewport_pixels = 1.0 / SCREEN_PIXEL_SIZE;
vec2 display_tile_size = max(source_tile_size * display_scale, vec2(1.0));
vec2 moving_pixels = UV * viewport_pixels + TIME * scroll_velocity_pixels;
COLOR = texture(pattern_texture, moving_pixels / display_tile_size);
}

View file

@ -0,0 +1 @@
uid://byw3iub66qvog

View file

@ -38,7 +38,7 @@ func deactivate() -> void:
func _build() -> void: func _build() -> void:
var paper := PanelContainer.new() var paper := PanelContainer.new()
paper.position = Vector2(58, 128) paper.position = Vector2(58, 128)
paper.size = Vector2(1164, 476) paper.size = Vector2(1164, 538)
add_child(paper) add_child(paper)
paper.add_theme_stylebox_override("panel", UtilityPageStyle.panel_style()) paper.add_theme_stylebox_override("panel", UtilityPageStyle.panel_style())
var root := VBoxContainer.new() var root := VBoxContainer.new()
@ -59,7 +59,7 @@ func _build() -> void:
UtilityPageStyle.apply_button(button) UtilityPageStyle.apply_button(button)
_tabs.add_child(button) _tabs.add_child(button)
var scroll := ScrollContainer.new() var scroll := ScrollContainer.new()
scroll.custom_minimum_size = Vector2(0, 330) scroll.custom_minimum_size = Vector2(0, 392)
scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
root.add_child(scroll) root.add_child(scroll)
_list = VBoxContainer.new() _list = VBoxContainer.new()