From 28ce6fedcb5246eeea28864e801331021d7eceaf Mon Sep 17 00:00:00 2001 From: Voyager Date: Thu, 30 Jul 2026 16:07:36 -0400 Subject: [PATCH] Add unified inventory and animated menu backdrop --- art/patterns/pattern_bluedot.png | Bin 0 -> 1657 bytes art/patterns/pattern_bluedot.png.import | 40 ++ fishing/fishing_spot.gd | 1 - items/item_data.gd | 1 + main/main.gd | 48 ++- main/main.tscn | 14 +- ui/game_ui.gd | 64 ++- ui/game_ui.tscn | 40 +- ui/hotbar.gd | 61 ++- ui/hotbar.tscn | 2 +- ui/mail_page.gd | 6 +- ui/player_menu.gd | 508 +++++++++++++++++++++--- ui/player_menu.tscn | 185 +++++++-- ui/player_menu_pattern.gdshader | 13 + ui/player_menu_pattern.gdshader.uid | 1 + ui/players_page.gd | 4 +- 16 files changed, 865 insertions(+), 123 deletions(-) create mode 100644 art/patterns/pattern_bluedot.png create mode 100644 art/patterns/pattern_bluedot.png.import create mode 100644 ui/player_menu_pattern.gdshader create mode 100644 ui/player_menu_pattern.gdshader.uid diff --git a/art/patterns/pattern_bluedot.png b/art/patterns/pattern_bluedot.png new file mode 100644 index 0000000000000000000000000000000000000000..0fab28fca383b7088486229207b1849b9e308578 GIT binary patch literal 1657 zcmV-<28Q{GP)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy24YJ`L;wi@ZUBFFpi_we000SaNLh0L04^f{04^f|c%?sf00007 zbV*G`2kHkN5*jKE*(&P*00q5CL_t(|+U;H2PAW+hU0`F62(68T%Os3OpT;M@;(XKj zOrMyiF`Pppm!qH!s0AqVFhY(B^u3#^S}W&|hxm4A@p4wQ6Z~uiG17=sZEp=G>hGFdRK&*leLu zvsd@p-J!3~2uy(UzbY`z{SWtQ)e`LE0{;2;mb;T6{BHX1$Ob+3KX3l(WH9$Xm<3|D z5r_ciXZ29)gyaMuG$()%(@^V#`Tbu>%B1^SGx5p>Y&I4MKAQP=lZjKSc=rND66c5YW1H{cWt}GgK?2B(n^q^(Itd^-oF}m{%oJiOWm2rcZS{Ey{OoUh5d{iC>O;)t z=-xYcdKNp84j)#KA^}2}gEUbuTVJ$?tIIR=`U79#Fns_?5tSfC0!WA`1t}6hLPRM@ zkpQ3&L})BX1&#v36eJSS2vX~gdcT5{5k*PzN$JQ}NiwlJf|PFptgA;~-XAtw+!@Fv zNM(Z_`$5);c+A1_iroo3DIJAcCm00~G85o_@EB^HkemQ+;U2?54NSm~cF))SIMJxt ztBXJ~`2bOLra}zu(WpfvoDh=caZfEm<0ybygysaG7C{|=&^amee(<>UTb`5_VHXcj zIQ#wFqAwng1WfViF012czu+L^F4;kk{dJrFI|=OKSSoX1=-MSa2$nYA?HQQ}z$k!WAmJ6`$x9^9kN}W( zLWeV&Y+QFn6Y0W162K=q{fD(AaNff}MgfZBSjFps$*`_7$oW|vLQHY?G%eE^+1gVd@e z-vcv907d}>2|z%F=Gfidz;`r20zi#f2|`Q*bt^S=Pl|+uvl5o`8dK2$R7;A~eO5wN z_oPTVfsrRg9`L`aDgnGEMH1l4AS5(I+RW{}cg=d`;OMvsFrK`)7GEZj6lv^bQOujD zRqT}~EW{Mu{t%-lf%)qjcQy_auq#QCWxIgWM)gCdOw-)QX`_m=UEr?983m-B6lvxR z)VB1*uT@Ggb9~Dkn-7q7Qe@?%=;;|YtcuwQR3#~rCO|UG=dY1GLr6-1&YgqVmT+%2 zo5wywm;^`}?b~00)}nSst-J{t>zK6$gBHw(~Gzde5 zSEEUyY!|+Sp-T;-+aI7SnfYNth~^pu2@rz@K>`pYfQnF2gCGGk*C0rM7&VAYhGC#` zaMK|6vKeGD8O&ebuvm})%BN?4#_QVxzycJ42qZN>VVR|MKX~;08k_`>6r0B8_#K@? zCs0ys8k^&`Mgk~u>__no2|$nlBme;w+vIzV2C}+m#K?+m(^33PPBB=O1IRu#C5#S` zx%l?omuyulTN{%iWXy=655TG%5&#-!#E<}l(#RQm(Gh@EIr3rVvL9Ji<`pY0CflwfI0*TAd3#cRP~6}LBsD7m zE_Hw`504SI{RhZBj zCv!k2P*S)J?{Zrw0SFR6X50@RL#>klP`gKf*KqJZY_M3Nzu0hh00000NkvXXu0mjf DY68Ug literal 0 HcmV?d00001 diff --git a/art/patterns/pattern_bluedot.png.import b/art/patterns/pattern_bluedot.png.import new file mode 100644 index 0000000..c32a736 --- /dev/null +++ b/art/patterns/pattern_bluedot.png.import @@ -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 diff --git a/fishing/fishing_spot.gd b/fishing/fishing_spot.gd index 1018a44..f4bae1e 100644 --- a/fishing/fishing_spot.gd +++ b/fishing/fishing_spot.gd @@ -433,7 +433,6 @@ func _unhandled_input(event: InputEvent) -> void: get_viewport().set_input_as_handled() return if not has_active_fishing_rod(): - status_changed.emit("select a fishing rod to cast.") get_viewport().set_input_as_handled() return if ( diff --git a/items/item_data.gd b/items/item_data.gd index ebcca91..f556fec 100644 --- a/items/item_data.gd +++ b/items/item_data.gd @@ -9,6 +9,7 @@ enum Category { UTILITY, QUEST, COSMETIC, + LURE, } @export var item_id: StringName diff --git a/main/main.gd b/main/main.gd index 7fc2a00..bba114d 100644 --- a/main/main.gd +++ b/main/main.gd @@ -72,6 +72,8 @@ const NetworkProfileServiceType = preload( ) 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 pelican_buyer_profile: FishBuyerProfileType @@ -143,6 +145,7 @@ var _title_music_requested: bool = false var _quit_in_progress: bool = false var _join_requested_from_title: bool = false var _join_requested_from_pause: bool = false +var _player_menu_backdrop_tween: Tween var _pending_join_endpoint: String = "" var _server_trust_dialog: ConfirmationDialog var _pending_trust_changed: bool = false @@ -158,6 +161,18 @@ var _local_recovery_attempt_id: String = "" func _ready() -> void: 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) _resize_native_overlays() 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: - _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: diff --git a/main/main.tscn b/main/main.tscn index 293805a..8e269dd 100644 --- a/main/main.tscn +++ b/main/main.tscn @@ -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://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://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="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"] 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"] script = ExtResource("3_main") fish_catalog = ExtResource("6_pool") @@ -70,7 +79,8 @@ unique_name_in_owner = true visible = false z_index = 10 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="."] unique_name_in_owner = true diff --git a/ui/game_ui.gd b/ui/game_ui.gd index f391c7f..e58967a 100644 --- a/ui/game_ui.gd +++ b/ui/game_ui.gd @@ -42,6 +42,7 @@ signal interactive_pointer_ui_changed(is_open: bool) signal player_menu_backdrop_visibility_changed(is_visible: bool) @onready var _status_label: Label = %StatusLabel +@onready var _gameplay_transient_hud: Control = %GameplayTransientHUD @onready var _catch_track: Control = %CatchTrack @onready var _green_catch_progress: ProgressBar = %GreenCatchProgress @onready var _red_chase_progress: ProgressBar = %RedChaseProgress @@ -72,6 +73,7 @@ var _gameplay_ui_enabled: bool = false var _fishing_spot: FishingSpotType var _system_menu_open: bool = false var _shop_open: bool = false +var _player_menu_hotbar_visible: bool = false var _item_effects: PlayerItemEffectsType @@ -137,6 +139,10 @@ func setup( _player_menu.menu_visibility_changed.connect( _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, inventory, @@ -251,16 +257,17 @@ func get_pause_menu() -> PauseMenuType: func set_gameplay_ui_enabled(enabled: bool) -> void: _gameplay_ui_enabled = enabled + _gameplay_transient_hud.visible = enabled and not _player_menu_open _refresh_chat_availability() if not enabled: close_player_menu_for_session_end() _fishing_shop.close_for_session_end() _fishing_panel.visible = false _shop_prompt.hide() - _hotbar_ui.hide() + _hotbar_ui.set_presentation_visible(false, false) _hotbar_ui.set_gameplay_input_enabled(false) else: - _hotbar_ui.show() + _refresh_hotbar_visibility() _hotbar_ui.set_gameplay_input_enabled(true) _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: _system_menu_open = is_open _refresh_chat_availability() - _hotbar_ui.visible = ( - _gameplay_ui_enabled and not is_open and not _shop_open - ) + _refresh_hotbar_visibility() _hotbar_ui.set_gameplay_input_enabled( _gameplay_ui_enabled and not is_open @@ -495,24 +500,42 @@ func _on_showcase_changed( func _on_player_menu_visibility_changed(is_open: bool) -> void: _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) _refresh_chat_availability() _hotbar_ui.set_gameplay_input_enabled( _gameplay_ui_enabled and not is_open ) _hotbar_ui.set_drag_enabled(is_open) + _refresh_hotbar_visibility() _refresh_fishing_panel_visibility() _emit_interactive_pointer_ui_changed() if is_open: _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: _shop_open = is_open _refresh_chat_availability() - _hotbar_ui.visible = ( - _gameplay_ui_enabled and not is_open and not _system_menu_open - ) + _refresh_hotbar_visibility() _hotbar_ui.set_gameplay_input_enabled( _gameplay_ui_enabled and not is_open @@ -524,6 +547,31 @@ func _on_shop_visibility_changed(is_open: bool) -> void: _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: interactive_pointer_ui_changed.emit( _system_menu_open or _player_menu_open or _shop_open diff --git a/ui/game_ui.tscn b/ui/game_ui.tscn index 09c98e7..2b2089a 100644 --- a/ui/game_ui.tscn +++ b/ui/game_ui.tscn @@ -41,7 +41,17 @@ script = ExtResource("1_ui") unique_name_in_owner = true 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 visible = false z_index = 60 @@ -59,33 +69,33 @@ grow_vertical = 0 mouse_filter = 2 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_top = 8 theme_override_constants/margin_right = 14 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 -[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 visible = false text = "" horizontal_alignment = 1 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 visible = false 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 visible = false 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 layout_mode = 1 anchors_preset = 15 @@ -99,7 +109,7 @@ theme_override_styles/fill = SubResource("StyleBox_catch_fill") value = 0.0 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 layout_mode = 1 anchors_preset = 15 @@ -113,7 +123,7 @@ theme_override_styles/fill = SubResource("StyleBox_chase_fill") value = 0.0 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 layout_mode = 1 anchors_preset = 15 @@ -123,12 +133,12 @@ grow_horizontal = 2 grow_vertical = 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 visible = false 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 visible = false horizontal_alignment = 1 @@ -139,7 +149,7 @@ unique_name_in_owner = true [node name="Hotbar" parent="UIRoot" instance=ExtResource("7_hotbar")] 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 visible = false z_index = 55 @@ -157,14 +167,14 @@ grow_vertical = 0 mouse_filter = 2 theme = ExtResource("3_theme") -[node name="Margin" type="MarginContainer" parent="UIRoot/ShopPrompt"] +[node name="Margin" type="MarginContainer" parent="UIRoot/GameplayTransientHUD/ShopPrompt"] layout_mode = 2 theme_override_constants/margin_left = 12 theme_override_constants/margin_top = 7 theme_override_constants/margin_right = 12 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 text = "press e to open fishing shop" horizontal_alignment = 1 @@ -172,7 +182,7 @@ horizontal_alignment = 1 [node name="FishingShop" parent="UIRoot" instance=ExtResource("8_shop")] 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 visible = false z_index = 54 diff --git a/ui/hotbar.gd b/ui/hotbar.gd index 5c5ebd6..c57f5ff 100644 --- a/ui/hotbar.gd +++ b/ui/hotbar.gd @@ -13,6 +13,7 @@ const DESKTOP_REFERENCE_SIZE := Vector2(1280.0, 720.0) const COMPACT_REFERENCE_SIZE := Vector2(640.0, 480.0) const HOTBAR_PRESENTATION_SCALE: float = 0.60 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 _bubble_field: Control = %BubbleField @@ -30,6 +31,9 @@ var _hovered_slot_index: int = -1 var _item_name_suppressed: bool = false var _motion_elapsed: float = 0.0 var _compact_layout: bool = false +var _player_menu_context: bool = false +var _visibility_tween: Tween +var _visibility_generation: int = 0 func _ready() -> void: @@ -82,6 +86,57 @@ func set_drag_enabled(enabled: bool) -> void: _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: _item_name_suppressed = suppressed if suppressed: @@ -145,7 +200,11 @@ func _apply_layout() -> void: _presentation_scale_root.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 := ( Vector2(580.0, 82.0) if _compact_layout diff --git a/ui/hotbar.tscn b/ui/hotbar.tscn index 6150b5d..ebe0099 100644 --- a/ui/hotbar.tscn +++ b/ui/hotbar.tscn @@ -7,7 +7,7 @@ [node name="Hotbar" type="Control"] unique_name_in_owner = true visible = false -z_index = 20 +z_index = 35 layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 diff --git a/ui/mail_page.gd b/ui/mail_page.gd index 751b668..430375b 100644 --- a/ui/mail_page.gd +++ b/ui/mail_page.gd @@ -110,7 +110,7 @@ func set_interactive(value: bool) -> void: func _build_ui() -> void: var paper := PanelContainer.new() paper.position = Vector2(116, 126) - paper.size = Vector2(1048, 470) + paper.size = Vector2(1048, 540) paper.add_theme_stylebox_override("panel", UtilityPageStyle.panel_style()) add_child(paper) var margin := MarginContainer.new() @@ -128,7 +128,7 @@ func _build_ui() -> void: page.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT) root.add_child(page) _status = Label.new() - _status.position = Vector2(18, 430) + _status.position = Vector2(18, 448) _status.size = Vector2(900, 28) _status.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _status.add_theme_color_override("font_color", Color("4a3f31")) @@ -163,7 +163,7 @@ func _build_inbox() -> Control: page.add_child(archive_view) var scroll := ScrollContainer.new() scroll.position = Vector2(12, 62) - scroll.size = Vector2(958, 342) + scroll.size = Vector2(958, 374) page.add_child(scroll) _inbox_list = VBoxContainer.new() _inbox_list.custom_minimum_size = Vector2(930, 0) diff --git a/ui/player_menu.gd b/ui/player_menu.gd index 3d670f2..f0422fa 100644 --- a/ui/player_menu.gd +++ b/ui/player_menu.gd @@ -79,16 +79,29 @@ const COOLER_RARITY_EPIC := Color("a979cf") const COOLER_RARITY_LEGENDARY := Color("db78a7") signal menu_visibility_changed(is_open: bool) +signal inventory_hotbar_context_changed(show_hotbar: bool) +signal menu_exit_started enum Section { COOLER, BAG, + TACKLE_BOX, LOGBOOK, MAIL, PROFILE, PLAYERS, } +enum BagView { + EQUIPMENT, + CONSUMABLES, +} + +enum TackleView { + BAIT, + LURES, +} + enum SortMode { CATCH_ORDER, NAME, @@ -142,6 +155,21 @@ enum CloseReason { @onready var _favorite_bubble: NotepadInkActionType = %FavoriteBubble @onready var _sell_bubble: NotepadInkActionType = %SellBubble @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_inner_liner: PanelContainer = %BagInnerLiner @onready var _bag_scroll: ScrollContainer = %BagScroll @@ -171,7 +199,6 @@ enum CloseReason { @onready var _logbook_next: BubbleButtonType = %LogbookNext @onready var _logbook_page_status: BubbleStatusBubbleType = %LogbookPageStatus @onready var _inventory_tab: BubbleButtonType = %InventoryTab -@onready var _bag_tab: BubbleButtonType = %BagTab @onready var _logbook_tab: BubbleButtonType = %LogbookTab @onready var _mail_tab: BubbleButtonType = %MailTab @onready var _profile_tab: BubbleButtonType = %ProfileTab @@ -240,6 +267,10 @@ var _hotbar: PlayerHotbarType var _item_catalog: ItemCatalogType 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 _sort_mode: SortMode = SortMode.CATCH_ORDER var _sort_descending: bool = true var _fish_selection := FishBatchSelectionType.new() @@ -265,6 +296,7 @@ var _presentation_rest_position: Vector2 = Vector2.ZERO var _content_rest_position: Vector2 = Vector2.ZERO var _cooler_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 _mail_rest_position: Vector2 = Vector2.ZERO var _profile_rest_position: Vector2 = Vector2.ZERO @@ -286,10 +318,16 @@ var _logbook_page_tween: Tween func _ready() -> void: - _inventory_tab.pressed.connect( - _show_section.bind(Section.COOLER) + _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)) + _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( _show_section.bind(Section.LOGBOOK) ) @@ -319,7 +357,6 @@ func _ready() -> void: _update_sort_direction_text() _navigation_cluster.configure([ _inventory_tab, - _bag_tab, _logbook_tab, _mail_tab, _profile_tab, @@ -328,6 +365,10 @@ func _ready() -> void: ]) _configure_navigation_focus() _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_wall_styles() _apply_cooler_notepad_style() @@ -442,6 +483,8 @@ func setup( _fishing_spot.bite_activated.connect(_on_bite_activated) if not _bag.contents_changed.is_connected(_on_bag_changed): _bag.contents_changed.connect(_on_bag_changed) + if not _hotbar.slots_changed.is_connected(_on_hotbar_changed): + _hotbar.slots_changed.connect(_on_hotbar_changed) if not _cooler_capacity.capacity_changed.is_connected( _on_cooler_capacity_changed ): @@ -452,6 +495,9 @@ func setup( func _input(event: InputEvent) -> void: if event is InputEventKey and event.echo: return + if _handle_inventory_shortcut(event): + get_viewport().set_input_as_handled() + return if visible: if event.is_action_pressed("open_backpack"): if not _transitioning and not _page_transitioning: @@ -467,6 +513,54 @@ func _input(event: InputEvent) -> void: 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: if not visible: return false @@ -537,6 +631,7 @@ func close_menu( CloseReason.TEARDOWN, ]: _fish_selection.clear() + menu_exit_started.emit() _begin_menu_exit(reason, restore_controls) @@ -618,11 +713,15 @@ func _show_section(section: Section) -> void: func _show_section_immediate(section: Section) -> void: _current_section = section + if _is_inventory_section(section): + _last_inventory_section = section if not is_node_ready(): return _configure_navigation_focus() _cooler_page.visible = section == Section.COOLER _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 _mail_page.visible = section == Section.MAIL _profile_page.visible = section == Section.PROFILE @@ -643,6 +742,7 @@ func _show_section_immediate(section: Section) -> void: _close_bag_detail() else: _update_bag_detail() + _refresh_tackle_box() if section != Section.LOGBOOK: _cancel_logbook_page_transition(true) if section == Section.MAIL: @@ -657,21 +757,36 @@ func _show_section_immediate(section: Section) -> void: _players_page.activate() else: _players_page.deactivate() - _inventory_tab.button_pressed = section == Section.COOLER - _bag_tab.button_pressed = section == Section.BAG + _inventory_tab.button_pressed = _is_inventory_section(section) + _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 _mail_tab.button_pressed = section == Section.MAIL _profile_tab.button_pressed = section == Section.PROFILE _players_tab.button_pressed = section == Section.PLAYERS _update_navigation_selection() _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: if _current_section == Section.COOLER: - _inventory_tab.grab_focus() + _cooler_sub_tab.grab_focus() 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: _logbook_tab.grab_focus() elif _current_section == Section.MAIL: @@ -704,7 +819,6 @@ func _process(delta: float) -> void: func _configure_navigation_focus() -> void: var navigation: Array[BubbleButtonType] = [ _inventory_tab, - _bag_tab, _logbook_tab, _mail_tab, _profile_tab, @@ -723,6 +837,26 @@ func _configure_navigation_focus() -> void: bubble.focus_neighbor_right = bubble.get_path_to(next) bubble.focus_neighbor_top = bubble.focus_neighbor_left 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: @@ -762,6 +896,8 @@ func _configure_active_page_focus() -> void: _configure_cooler_fish_focus() Section.BAG: _configure_bag_item_focus() + Section.TACKLE_BOX: + _bait_filter.grab_focus() Section.LOGBOOK: _configure_logbook_focus() Section.MAIL: @@ -770,6 +906,132 @@ func _configure_active_page_focus() -> void: _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: var profile: BubbleMenuProfile = _inventory_tab.profile if profile == null: @@ -858,7 +1120,6 @@ func _apply_navigation_styles() -> void: var disabled := _make_navigation_style(profile.disabled_fill, 1, 0.14) for bubble: BubbleButtonType in [ _inventory_tab, - _bag_tab, _logbook_tab, _mail_tab, _profile_tab, @@ -890,7 +1151,6 @@ func _make_navigation_style( func _apply_navigation_selection_presentation() -> void: for bubble: BubbleButtonType in [ _inventory_tab, - _bag_tab, _logbook_tab, _mail_tab, _profile_tab, @@ -998,8 +1258,7 @@ func _on_mail_unread_count_changed(count: int) -> void: func _set_navigation_target(section: Section) -> void: - _inventory_tab.button_pressed = section == Section.COOLER - _bag_tab.button_pressed = section == Section.BAG + _inventory_tab.button_pressed = _is_inventory_section(section) _logbook_tab.button_pressed = section == Section.LOGBOOK _mail_tab.button_pressed = section == Section.MAIL _profile_tab.button_pressed = section == Section.PROFILE @@ -1033,16 +1292,16 @@ func _update_shell_layout() -> void: _cooler_rest_position = Vector2.ZERO _layout_cooler_fish(false) _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 = ( - 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 = ( - 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 = ( - 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.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) ) _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 = ( Vector2(72.0, 42.0) if compact else Vector2(108.0, 50.0) ) _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 = ( 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.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 = ( - 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 = ( - 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 = ( - 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_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 = ( - 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 = ( Vector2(170.0, 164.0) if compact else Vector2.ZERO ) _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 = ( Vector2(72.0, 48.0) if compact else Vector2(100.0, 72.0) @@ -1180,6 +1442,18 @@ func _update_shell_layout() -> void: "font_size", 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.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.size = Vector2(1196.0, 608.0) _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 = ( Vector2(14.0, 164.0) if compact else Vector2(58.0, 128.0) ) _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 _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) ) _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), 0.18, ) _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), 0.18, ) _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 = ( 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( 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 _logbook_grid.columns = 3 if compact else 4 @@ -1250,14 +1527,18 @@ func _update_shell_layout() -> void: _content_shell.position = _presentation_rest_position _cooler_page.position = _cooler_rest_position _bag_page.position = _bag_rest_position + _tackle_box_page.position = _tackle_rest_position _logbook_page.position = _logbook_rest_position _mail_page.position = _mail_rest_position _profile_page.position = _profile_rest_position + _players_page.position = Vector2.ZERO _cooler_page.modulate.a = 1.0 _bag_page.modulate.a = 1.0 + _tackle_box_page.modulate.a = 1.0 _logbook_page.modulate.a = 1.0 _mail_page.modulate.a = 1.0 _profile_page.modulate.a = 1.0 + _players_page.modulate.a = 1.0 if not _page_transitioning: _content_stage.position = _content_rest_position _layout_cooler_fish(false) @@ -1339,9 +1620,13 @@ func _begin_menu_entry() -> void: _content_shell.position = _presentation_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 + _tackle_box_page.position = ( + _tackle_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 _profile_page.position = _profile_rest_position + Vector2.DOWN * start_offset + _players_page.position = Vector2.DOWN * start_offset var navigation_rest: Vector2 = _navigation_cluster.position _navigation_cluster.position = navigation_rest + Vector2.DOWN * start_offset var transition_duration := UIMotion.bubble_duration(start_offset) @@ -1364,6 +1649,12 @@ func _begin_menu_entry() -> void: _bag_rest_position, transition_duration ).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( _logbook_page, "position", @@ -1382,6 +1673,12 @@ func _begin_menu_entry() -> void: _profile_rest_position, transition_duration ).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( _navigation_cluster, "position", @@ -1439,6 +1736,12 @@ func _begin_menu_exit(reason: CloseReason, restore_controls: bool) -> void: -_bag_page.size.y - TRANSITION_SAFE_MARGIN, transition_duration ).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( _logbook_page, "position:y", @@ -1457,6 +1760,12 @@ func _begin_menu_exit(reason: CloseReason, restore_controls: bool) -> void: -_profile_page.size.y - TRANSITION_SAFE_MARGIN, transition_duration ).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( _navigation_cluster, "position:y", @@ -1518,12 +1827,16 @@ func _get_section_root(section: Section) -> Control: return _cooler_page Section.BAG: return _bag_page + Section.TACKLE_BOX: + return _tackle_box_page Section.LOGBOOK: return _logbook_page Section.MAIL: return _mail_page - _: + Section.PROFILE: return _profile_page + _: + return _players_page func _get_section_rest_position(section: Section) -> Vector2: @@ -1532,12 +1845,16 @@ func _get_section_rest_position(section: Section) -> Vector2: return _cooler_rest_position Section.BAG: return _bag_rest_position + Section.TACKLE_BOX: + return _tackle_rest_position Section.LOGBOOK: return _logbook_rest_position Section.MAIL: return _mail_rest_position - _: + Section.PROFILE: return _profile_rest_position + _: + return Vector2.ZERO func _begin_page_transition(section: Section) -> void: @@ -1615,7 +1932,6 @@ func _set_shell_interactive(interactive: bool) -> void: _set_content_interactive(interactive) for bubble: BubbleButtonType in [ _inventory_tab, - _bag_tab, _logbook_tab, _mail_tab, _profile_tab, @@ -1646,6 +1962,25 @@ func _set_content_interactive(interactive: bool) -> void: if interactive and _current_section == Section.BAG 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 = ( Control.MOUSE_FILTER_PASS if interactive and _current_section == Section.LOGBOOK @@ -1728,8 +2063,13 @@ func _cancel_page_tween() -> void: func _reset_page_transition_visuals() -> void: 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.PLAYERS, ]: var page: Control = _get_section_root(section) page.position = _get_section_rest_position(section) @@ -1793,6 +2133,12 @@ func _refresh_all() -> void: func _on_bag_changed() -> void: _refresh_bag() + _refresh_tackle_box() + + +func _on_hotbar_changed() -> void: + _update_bag_detail() + _update_tackle_detail() func _refresh_bag() -> void: @@ -1801,10 +2147,42 @@ func _refresh_bag() -> void: var owned_items: Array[OwnedItemType] = ( _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) _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." + ) if ( not _selected_bag_item_id.is_empty() 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 var removed := _bag_item_nodes[item_id] as BagItemSpriteType _bag_item_nodes.erase(item_id) - _release_focus_from(removed, _bag_tab) + _release_focus_from(removed, _bag_sub_tab) removed.queue_free() _layout_bag_items() _configure_bag_item_focus() @@ -1887,7 +2265,7 @@ func _layout_bag_items() -> void: _bag_item_field.custom_minimum_size = ( Vector2(520.0, 140.0) if _compact_layout - else Vector2(820.0, 350.0) + else Vector2(820.0, 240.0) ) for index: int in _sorted_bag_items.size(): var owned: OwnedItemType = _sorted_bag_items[index] @@ -1927,9 +2305,11 @@ func _configure_bag_item_focus() -> void: if item_node != null: controls.append(item_node) if controls.is_empty(): - _bag_tab.focus_neighbor_bottom = NodePath() + _bag_sub_tab.focus_neighbor_bottom = NodePath() 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(): var control: BagItemSpriteType = controls[index] var column: int = index % 3 @@ -1943,7 +2323,7 @@ func _configure_bag_item_focus() -> void: controls[right_index] ) control.focus_neighbor_top = ( - control.get_path_to(_bag_tab) + control.get_path_to(_bag_sub_tab) if 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 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_name.text = item.display_name if item != null else "" _bag_detail_data.text = ( - "%s\nquantity: %d\n%s\n%s" + "%s\nquantity: %d\n%s\n%s\n%s" % [ item.get_category_name(), quantity, + item_state, + hotbar_assignment, item.description, - ( - "can be assigned to the hotbar." - if item.hotbar_allowed - else "cannot be assigned to the hotbar." - ), ] if item != null else "select a bag item for details." ) _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 = ( - "%s • quantity: %d\n%s\n%s" + "%s • quantity: %d\n%s • %s\n%s" % [ item.get_category_name(), quantity, + item_state, + hotbar_assignment, item.description, - ( - "drag to any hotbar slot." - if item.hotbar_allowed - else "not compatible with the hotbar." - ), ] if item != null - else "" + else "select an item for details." ) _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 := ( Vector2(218.0, 124.0) 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 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) var columns: int = 3 if _compact_layout else 9 if controls.is_empty(): - _inventory_tab.focus_neighbor_bottom = NodePath() + _cooler_sub_tab.focus_neighbor_bottom = NodePath() 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() ) for index: int in controls.size(): @@ -2274,7 +2662,7 @@ func _configure_cooler_fish_focus() -> void: controls[mini(index + 1, controls.size() - 1)] ) control.focus_neighbor_top = ( - control.get_path_to(_inventory_tab) + control.get_path_to(_cooler_sub_tab) if 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) ): _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: _cooler_offer_label.text = "%s offer" % _default_buyer.display_name _cooler_offer_value.text = "$%d" % buyer_offer diff --git a/ui/player_menu.tscn b/ui/player_menu.tscn index ecb969c..adf030a 100644 --- a/ui/player_menu.tscn +++ b/ui/player_menu.tscn @@ -60,6 +60,42 @@ offset_right = 1280.0 offset_bottom = 720.0 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"] unique_name_in_owner = true layout_mode = 0 @@ -434,6 +470,29 @@ offset_right = 1280.0 offset_bottom = 720.0 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"] unique_name_in_owner = true layout_mode = 0 @@ -539,6 +598,94 @@ theme_override_font_sizes/font_size = 15 horizontal_alignment = 1 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"] unique_name_in_owner = true visible = false @@ -1209,15 +1356,15 @@ compact_reference_size = Vector2(840, 100) unique_name_in_owner = true layout_mode = 0 toggle_mode = true -text = "cooler" +text = "inventory" script = ExtResource("6_bubble") profile = ExtResource("4_profile") neutral_size = Vector2(112, 108) desktop_anchor = Vector2(70, 60) compact_anchor = Vector2(70, 73.3333) compact_minimum_size = Vector2(84, 82) -minimum_font_size = 25 -maximum_font_size = 25 +minimum_font_size = 20 +maximum_font_size = 22 horizontal_amplitude = 1.2 vertical_amplitude = 2.4 motion_period = 5.6 @@ -1225,26 +1372,6 @@ motion_phase = 0.35 deformation_amplitude = 0.012 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"] unique_name_in_owner = true layout_mode = 0 @@ -1253,8 +1380,8 @@ text = "logbook" script = ExtResource("6_bubble") profile = ExtResource("4_profile") neutral_size = Vector2(112, 108) -desktop_anchor = Vector2(294, 60) -compact_anchor = Vector2(294, 73.3333) +desktop_anchor = Vector2(210, 60) +compact_anchor = Vector2(210, 73.3333) compact_minimum_size = Vector2(84, 82) minimum_font_size = 25 maximum_font_size = 25 @@ -1273,8 +1400,8 @@ text = "mail" script = ExtResource("6_bubble") profile = ExtResource("4_profile") neutral_size = Vector2(112, 108) -desktop_anchor = Vector2(406, 60) -compact_anchor = Vector2(406, 73.3333) +desktop_anchor = Vector2(350, 60) +compact_anchor = Vector2(350, 73.3333) compact_minimum_size = Vector2(84, 82) minimum_font_size = 25 maximum_font_size = 25 @@ -1309,8 +1436,8 @@ text = "profile" script = ExtResource("6_bubble") profile = ExtResource("4_profile") neutral_size = Vector2(112, 108) -desktop_anchor = Vector2(518, 60) -compact_anchor = Vector2(518, 73.3333) +desktop_anchor = Vector2(490, 60) +compact_anchor = Vector2(490, 73.3333) compact_minimum_size = Vector2(84, 82) minimum_font_size = 23 maximum_font_size = 25 diff --git a/ui/player_menu_pattern.gdshader b/ui/player_menu_pattern.gdshader new file mode 100644 index 0000000..71f8fc6 --- /dev/null +++ b/ui/player_menu_pattern.gdshader @@ -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); +} diff --git a/ui/player_menu_pattern.gdshader.uid b/ui/player_menu_pattern.gdshader.uid new file mode 100644 index 0000000..79a35df --- /dev/null +++ b/ui/player_menu_pattern.gdshader.uid @@ -0,0 +1 @@ +uid://byw3iub66qvog diff --git a/ui/players_page.gd b/ui/players_page.gd index a142e55..6c1de33 100644 --- a/ui/players_page.gd +++ b/ui/players_page.gd @@ -38,7 +38,7 @@ func deactivate() -> void: func _build() -> void: var paper := PanelContainer.new() paper.position = Vector2(58, 128) - paper.size = Vector2(1164, 476) + paper.size = Vector2(1164, 538) add_child(paper) paper.add_theme_stylebox_override("panel", UtilityPageStyle.panel_style()) var root := VBoxContainer.new() @@ -59,7 +59,7 @@ func _build() -> void: UtilityPageStyle.apply_button(button) _tabs.add_child(button) 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 root.add_child(scroll) _list = VBoxContainer.new()