Refine movement, water recovery, and UI baseline
This commit is contained in:
parent
d2fe367891
commit
e2067e3bf4
23 changed files with 905 additions and 146 deletions
|
|
@ -71,6 +71,7 @@ var _cast_position: Vector3
|
||||||
var _pickup_position: Vector3
|
var _pickup_position: Vector3
|
||||||
var _active_tween: Tween
|
var _active_tween: Tween
|
||||||
var _rod_tween: Tween
|
var _rod_tween: Tween
|
||||||
|
var _bite_tween: Tween
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
@ -179,29 +180,30 @@ func show_bite() -> void:
|
||||||
if _mode != VisualMode.FISHING:
|
if _mode != VisualMode.FISHING:
|
||||||
return
|
return
|
||||||
|
|
||||||
_kill_active_tween()
|
_kill_bite_tween()
|
||||||
var bite_position: Vector3 = _with_water_height(_bobber.global_position)
|
_bobber.scale = Vector3.ONE
|
||||||
_bobber.global_position = bite_position
|
_bite_tween = create_tween()
|
||||||
_active_tween = create_tween()
|
_bite_tween.set_trans(Tween.TRANS_QUAD)
|
||||||
_active_tween.set_trans(Tween.TRANS_QUAD)
|
_bite_tween.set_ease(Tween.EASE_IN_OUT)
|
||||||
_active_tween.tween_property(
|
_bite_tween.tween_property(
|
||||||
_bobber,
|
_bobber,
|
||||||
"global_position:y",
|
"scale",
|
||||||
get_water_surface_height() - 0.25,
|
Vector3.ONE * 0.68,
|
||||||
0.11
|
0.08
|
||||||
)
|
)
|
||||||
_active_tween.tween_property(
|
_bite_tween.tween_property(
|
||||||
_bobber,
|
_bobber,
|
||||||
"global_position:y",
|
"scale",
|
||||||
get_water_surface_height() + 0.05,
|
Vector3.ONE * 1.2,
|
||||||
0.14
|
0.1
|
||||||
)
|
)
|
||||||
_active_tween.tween_property(
|
_bite_tween.tween_property(
|
||||||
_bobber,
|
_bobber,
|
||||||
"global_position:y",
|
"scale",
|
||||||
bite_position.y,
|
Vector3.ONE,
|
||||||
0.12
|
0.1
|
||||||
)
|
)
|
||||||
|
_bite_tween.finished.connect(_on_bite_tween_finished)
|
||||||
|
|
||||||
|
|
||||||
func show_withdrawal_position(position: Vector3) -> void:
|
func show_withdrawal_position(position: Vector3) -> void:
|
||||||
|
|
@ -225,7 +227,6 @@ func show_reel_position(position: Vector3, _input_held: bool) -> void:
|
||||||
return
|
return
|
||||||
|
|
||||||
_kill_active_tween()
|
_kill_active_tween()
|
||||||
_bobber.scale = Vector3.ONE
|
|
||||||
_bobber.global_position = _with_water_height(position)
|
_bobber.global_position = _with_water_height(position)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -235,6 +236,7 @@ func play_outcome(outcome: StringName) -> void:
|
||||||
return
|
return
|
||||||
|
|
||||||
_kill_active_tween()
|
_kill_active_tween()
|
||||||
|
_kill_bite_tween()
|
||||||
_kill_rod_tween()
|
_kill_rod_tween()
|
||||||
_restore_rod_neutral()
|
_restore_rod_neutral()
|
||||||
_mode = VisualMode.OUTCOME
|
_mode = VisualMode.OUTCOME
|
||||||
|
|
@ -274,15 +276,6 @@ func play_outcome(outcome: StringName) -> void:
|
||||||
get_water_surface_height() - 0.4,
|
get_water_surface_height() - 0.4,
|
||||||
0.2
|
0.2
|
||||||
)
|
)
|
||||||
&"miss":
|
|
||||||
_active_tween.set_parallel(true)
|
|
||||||
_active_tween.tween_property(
|
|
||||||
_bobber,
|
|
||||||
"global_position:y",
|
|
||||||
get_water_surface_height() - 0.4,
|
|
||||||
0.3
|
|
||||||
)
|
|
||||||
_active_tween.tween_property(_bobber, "scale", Vector3.ONE * 0.65, 0.3)
|
|
||||||
&"invalid":
|
&"invalid":
|
||||||
var return_target: Vector3 = _bobber.global_position
|
var return_target: Vector3 = _bobber.global_position
|
||||||
if _rod_tip != null:
|
if _rod_tip != null:
|
||||||
|
|
@ -310,6 +303,7 @@ func play_outcome(outcome: StringName) -> void:
|
||||||
|
|
||||||
func cleanup() -> void:
|
func cleanup() -> void:
|
||||||
_kill_active_tween()
|
_kill_active_tween()
|
||||||
|
_kill_bite_tween()
|
||||||
_kill_rod_tween()
|
_kill_rod_tween()
|
||||||
_restore_rod_neutral()
|
_restore_rod_neutral()
|
||||||
_mode = VisualMode.NONE
|
_mode = VisualMode.NONE
|
||||||
|
|
@ -752,6 +746,18 @@ func _kill_active_tween() -> void:
|
||||||
_active_tween = null
|
_active_tween = null
|
||||||
|
|
||||||
|
|
||||||
|
func _kill_bite_tween() -> void:
|
||||||
|
if _bite_tween != null and _bite_tween.is_valid():
|
||||||
|
_bite_tween.kill()
|
||||||
|
_bite_tween = null
|
||||||
|
if is_instance_valid(_bobber):
|
||||||
|
_bobber.scale = Vector3.ONE
|
||||||
|
|
||||||
|
|
||||||
|
func _on_bite_tween_finished() -> void:
|
||||||
|
_bite_tween = null
|
||||||
|
|
||||||
|
|
||||||
func _kill_rod_tween() -> void:
|
func _kill_rod_tween() -> void:
|
||||||
if _rod_tween != null and _rod_tween.is_valid():
|
if _rod_tween != null and _rod_tween.is_valid():
|
||||||
_rod_tween.kill()
|
_rod_tween.kill()
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ enum FishingState {
|
||||||
AIMING_CAST,
|
AIMING_CAST,
|
||||||
CASTING,
|
CASTING,
|
||||||
WAITING_FOR_BITE,
|
WAITING_FOR_BITE,
|
||||||
BITE_ACTIVE,
|
|
||||||
FIGHTING,
|
FIGHTING,
|
||||||
SHOWING_CATCH,
|
SHOWING_CATCH,
|
||||||
COOLDOWN,
|
COOLDOWN,
|
||||||
|
|
@ -62,7 +61,6 @@ enum FishingState {
|
||||||
|
|
||||||
@export_category("Timing")
|
@export_category("Timing")
|
||||||
@export_range(0.1, 30.0, 0.1) var wait_time: float = 2.0
|
@export_range(0.1, 30.0, 0.1) var wait_time: float = 2.0
|
||||||
@export_range(0.1, 10.0, 0.1) var bite_window_duration: float = 1.5
|
|
||||||
@export_range(0.1, 10.0, 0.1) var cooldown_duration: float = 1.0
|
@export_range(0.1, 10.0, 0.1) var cooldown_duration: float = 1.0
|
||||||
|
|
||||||
@export_category("Selection")
|
@export_category("Selection")
|
||||||
|
|
@ -80,6 +78,7 @@ enum FishingState {
|
||||||
@onready var _presentation: FishingPresentationType = %FishingPresentation
|
@onready var _presentation: FishingPresentationType = %FishingPresentation
|
||||||
|
|
||||||
var state: FishingState = FishingState.READY
|
var state: FishingState = FishingState.READY
|
||||||
|
var _external_input_blocked: bool = false
|
||||||
var _local_player: PlayerType
|
var _local_player: PlayerType
|
||||||
var _local_inventory: FishInventoryType
|
var _local_inventory: FishInventoryType
|
||||||
var _local_collection_log: CollectionLogType
|
var _local_collection_log: CollectionLogType
|
||||||
|
|
@ -127,12 +126,46 @@ func setup(
|
||||||
|
|
||||||
|
|
||||||
func can_open_player_menu() -> bool:
|
func can_open_player_menu() -> bool:
|
||||||
return state in [
|
return not _external_input_blocked and state in [
|
||||||
FishingState.READY,
|
FishingState.READY,
|
||||||
FishingState.WAITING_FOR_BITE,
|
FishingState.WAITING_FOR_BITE,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
func begin_water_recovery() -> void:
|
||||||
|
_external_input_blocked = true
|
||||||
|
if state in [
|
||||||
|
FishingState.AIMING_CAST,
|
||||||
|
FishingState.CASTING,
|
||||||
|
FishingState.WAITING_FOR_BITE,
|
||||||
|
FishingState.FIGHTING,
|
||||||
|
]:
|
||||||
|
_cancel_attempt()
|
||||||
|
elif state == FishingState.SHOWING_CATCH:
|
||||||
|
_secure_showcase_catch_for_recovery()
|
||||||
|
|
||||||
|
|
||||||
|
func end_water_recovery() -> void:
|
||||||
|
_external_input_blocked = false
|
||||||
|
|
||||||
|
|
||||||
|
func _secure_showcase_catch_for_recovery() -> void:
|
||||||
|
if (
|
||||||
|
_pending_catch != null
|
||||||
|
and _local_inventory != null
|
||||||
|
and _local_collection_log != null
|
||||||
|
):
|
||||||
|
_local_inventory.add_catch(_pending_catch)
|
||||||
|
_local_collection_log.mark_discovered(_pending_catch.fish_id)
|
||||||
|
_pending_catch = null
|
||||||
|
_showcase_ready = false
|
||||||
|
_put_away_press_armed = false
|
||||||
|
showcase_changed.emit("", "", 0.0, false)
|
||||||
|
if _active_player != null:
|
||||||
|
_active_player.end_catch_showcase(Callable(), true)
|
||||||
|
_cleanup_attempt()
|
||||||
|
|
||||||
|
|
||||||
func _exit_tree() -> void:
|
func _exit_tree() -> void:
|
||||||
_showcase_restore_generation += 1
|
_showcase_restore_generation += 1
|
||||||
if (
|
if (
|
||||||
|
|
@ -174,10 +207,6 @@ func _process(delta: float) -> void:
|
||||||
_confirm_cast()
|
_confirm_cast()
|
||||||
FishingState.WAITING_FOR_BITE:
|
FishingState.WAITING_FOR_BITE:
|
||||||
_update_waiting_for_bite(delta)
|
_update_waiting_for_bite(delta)
|
||||||
FishingState.BITE_ACTIVE:
|
|
||||||
_state_time_remaining -= delta
|
|
||||||
if _state_time_remaining <= 0.0:
|
|
||||||
_miss_bite()
|
|
||||||
FishingState.FIGHTING:
|
FishingState.FIGHTING:
|
||||||
if not Input.is_action_pressed("fish_primary"):
|
if not Input.is_action_pressed("fish_primary"):
|
||||||
_catch_controller.set_reel_input(false)
|
_catch_controller.set_reel_input(false)
|
||||||
|
|
@ -188,6 +217,8 @@ func _process(delta: float) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if _external_input_blocked:
|
||||||
|
return
|
||||||
if (
|
if (
|
||||||
event.is_action_pressed("ui_cancel")
|
event.is_action_pressed("ui_cancel")
|
||||||
and state == FishingState.SHOWING_CATCH
|
and state == FishingState.SHOWING_CATCH
|
||||||
|
|
@ -202,7 +233,6 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||||
FishingState.AIMING_CAST,
|
FishingState.AIMING_CAST,
|
||||||
FishingState.CASTING,
|
FishingState.CASTING,
|
||||||
FishingState.WAITING_FOR_BITE,
|
FishingState.WAITING_FOR_BITE,
|
||||||
FishingState.BITE_ACTIVE,
|
|
||||||
FishingState.FIGHTING,
|
FishingState.FIGHTING,
|
||||||
]
|
]
|
||||||
):
|
):
|
||||||
|
|
@ -226,8 +256,6 @@ func _unhandled_input(event: InputEvent) -> void:
|
||||||
_presentation.set_line_mode(
|
_presentation.set_line_mode(
|
||||||
FishingPresentationType.LineMode.TAUT
|
FishingPresentationType.LineMode.TAUT
|
||||||
)
|
)
|
||||||
FishingState.BITE_ACTIVE:
|
|
||||||
_confirm_hook()
|
|
||||||
FishingState.FIGHTING:
|
FishingState.FIGHTING:
|
||||||
_catch_controller.handle_primary_pressed()
|
_catch_controller.handle_primary_pressed()
|
||||||
_presentation.set_line_mode(
|
_presentation.set_line_mode(
|
||||||
|
|
@ -442,19 +470,8 @@ func _activate_bite() -> void:
|
||||||
if state != FishingState.WAITING_FOR_BITE:
|
if state != FishingState.WAITING_FOR_BITE:
|
||||||
return
|
return
|
||||||
|
|
||||||
state = FishingState.BITE_ACTIVE
|
|
||||||
_state_time_remaining = bite_window_duration
|
|
||||||
_withdrawal_input_held = false
|
|
||||||
bite_activated.emit()
|
|
||||||
status_changed.emit("Bite! Left click to hook")
|
|
||||||
_presentation.set_line_mode(FishingPresentationType.LineMode.TAUT)
|
|
||||||
_presentation.show_bite()
|
|
||||||
|
|
||||||
|
|
||||||
func _confirm_hook() -> void:
|
|
||||||
if (
|
if (
|
||||||
state != FishingState.BITE_ACTIVE
|
_active_player == null
|
||||||
or _active_player == null
|
|
||||||
or _selected_fish == null
|
or _selected_fish == null
|
||||||
or _selected_fish.catch_profile == null
|
or _selected_fish.catch_profile == null
|
||||||
):
|
):
|
||||||
|
|
@ -463,8 +480,10 @@ func _confirm_hook() -> void:
|
||||||
|
|
||||||
state = FishingState.FIGHTING
|
state = FishingState.FIGHTING
|
||||||
_state_time_remaining = 0.0
|
_state_time_remaining = 0.0
|
||||||
|
_withdrawal_input_held = false
|
||||||
_fight_start_position = _bobber_water_position
|
_fight_start_position = _bobber_water_position
|
||||||
status_changed.emit("Hold left click to reel")
|
bite_activated.emit()
|
||||||
|
status_changed.emit("Fish on!")
|
||||||
_presentation.set_line_mode(FishingPresentationType.LineMode.TAUT)
|
_presentation.set_line_mode(FishingPresentationType.LineMode.TAUT)
|
||||||
_presentation.begin_reeling()
|
_presentation.begin_reeling()
|
||||||
_catch_controller.start_encounter(
|
_catch_controller.start_encounter(
|
||||||
|
|
@ -472,7 +491,10 @@ func _confirm_hook() -> void:
|
||||||
_active_player.reel_speed,
|
_active_player.reel_speed,
|
||||||
_active_player.click_power
|
_active_player.click_power
|
||||||
)
|
)
|
||||||
_catch_controller.set_reel_input(true)
|
_catch_controller.set_reel_input(
|
||||||
|
Input.is_action_pressed("fish_primary")
|
||||||
|
)
|
||||||
|
_presentation.show_bite()
|
||||||
|
|
||||||
|
|
||||||
func _on_catch_encounter_updated(
|
func _on_catch_encounter_updated(
|
||||||
|
|
@ -613,12 +635,6 @@ func _finish_showcase_put_away(
|
||||||
_cleanup_attempt(cooldown_message)
|
_cleanup_attempt(cooldown_message)
|
||||||
|
|
||||||
|
|
||||||
func _miss_bite() -> void:
|
|
||||||
if state != FishingState.BITE_ACTIVE:
|
|
||||||
return
|
|
||||||
_cleanup_attempt("The fish got away.", &"miss")
|
|
||||||
|
|
||||||
|
|
||||||
func _cleanup_attempt(
|
func _cleanup_attempt(
|
||||||
cooldown_message: String = "",
|
cooldown_message: String = "",
|
||||||
visual_outcome: StringName = &"",
|
visual_outcome: StringName = &"",
|
||||||
|
|
|
||||||
14
main/main.gd
14
main/main.gd
|
|
@ -5,13 +5,19 @@ const FishBuyerProfileType = preload("res://economy/fish_buyer_profile.gd")
|
||||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||||
const GameUIType = preload("res://ui/game_ui.gd")
|
const GameUIType = preload("res://ui/game_ui.gd")
|
||||||
const PlayerType = preload("res://player/player.gd")
|
const PlayerType = preload("res://player/player.gd")
|
||||||
|
const TestWorldType = preload("res://world/test_world.gd")
|
||||||
|
const WaterRecoveryControllerType = preload(
|
||||||
|
"res://world/water_recovery_controller.gd"
|
||||||
|
)
|
||||||
|
|
||||||
@export var fish_catalog: FishPoolType
|
@export var fish_catalog: FishPoolType
|
||||||
@export var pelican_buyer_profile: FishBuyerProfileType
|
@export var pelican_buyer_profile: FishBuyerProfileType
|
||||||
|
|
||||||
|
@onready var _test_world: TestWorldType = $TestWorld
|
||||||
@onready var _player: PlayerType = %Player
|
@onready var _player: PlayerType = %Player
|
||||||
@onready var _fishing_spot: FishingSpotType = %FishingSpot
|
@onready var _fishing_spot: FishingSpotType = %FishingSpot
|
||||||
@onready var _game_ui: GameUIType = %GameUI
|
@onready var _game_ui: GameUIType = %GameUI
|
||||||
|
@onready var _water_recovery: WaterRecoveryControllerType = %WaterRecovery
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
@ -34,3 +40,11 @@ func _ready() -> void:
|
||||||
fish_catalog,
|
fish_catalog,
|
||||||
_fishing_spot
|
_fishing_spot
|
||||||
)
|
)
|
||||||
|
_water_recovery.setup(
|
||||||
|
_player,
|
||||||
|
_fishing_spot,
|
||||||
|
_game_ui,
|
||||||
|
_game_ui.get_screen_fade(),
|
||||||
|
_test_world.get_player_water_trigger(),
|
||||||
|
_test_world.get_safe_respawn_points()
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=8 format=3]
|
[gd_scene load_steps=9 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"]
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
[ext_resource type="PackedScene" path="res://ui/game_ui.tscn" id="5_ui"]
|
[ext_resource type="PackedScene" path="res://ui/game_ui.tscn" id="5_ui"]
|
||||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="6_pool"]
|
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="6_pool"]
|
||||||
[ext_resource type="Resource" path="res://economy/buyers/pelicans.tres" id="7_pelicans"]
|
[ext_resource type="Resource" path="res://economy/buyers/pelicans.tres" id="7_pelicans"]
|
||||||
|
[ext_resource type="Script" path="res://world/water_recovery_controller.gd" id="8_recovery"]
|
||||||
|
|
||||||
[node name="Main" type="Node3D"]
|
[node name="Main" type="Node3D"]
|
||||||
script = ExtResource("3_main")
|
script = ExtResource("3_main")
|
||||||
|
|
@ -25,5 +26,9 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 5)
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
position = Vector3(0, 1.02, -18)
|
position = Vector3(0, 1.02, -18)
|
||||||
|
|
||||||
|
[node name="WaterRecovery" type="Node" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
script = ExtResource("8_recovery")
|
||||||
|
|
||||||
[node name="GameUI" parent="." instance=ExtResource("5_ui")]
|
[node name="GameUI" parent="." instance=ExtResource("5_ui")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@ class ShowcaseCameraSnapshot:
|
||||||
@export var sprint_speed: float = 8.0
|
@export var sprint_speed: float = 8.0
|
||||||
@export var sneak_speed: float = 2.0
|
@export var sneak_speed: float = 2.0
|
||||||
@export var slow_walk_speed: float = 3.25
|
@export var slow_walk_speed: float = 3.25
|
||||||
@export var jump_velocity: float = 6.0
|
@export_range(0.1, 20.0, 0.1) var jump_velocity: float = 4.6
|
||||||
|
@export_range(0.1, 5.0, 0.05) var upward_gravity_multiplier: float = 1.35
|
||||||
|
@export_range(0.1, 5.0, 0.05) var fall_gravity_multiplier: float = 2.1
|
||||||
|
@export_range(0.1, 3.0, 0.05) var body_center_height: float = 0.9
|
||||||
@export var body_rotation_speed: float = 12.0
|
@export var body_rotation_speed: float = 12.0
|
||||||
|
|
||||||
@export_category("Control")
|
@export_category("Control")
|
||||||
|
|
@ -73,6 +76,7 @@ var _gravity: float = float(ProjectSettings.get_setting("physics/3d/default_grav
|
||||||
var _camera_dragging: bool = false
|
var _camera_dragging: bool = false
|
||||||
var _camera_input_enabled: bool = true
|
var _camera_input_enabled: bool = true
|
||||||
var _movement_enabled: bool = true
|
var _movement_enabled: bool = true
|
||||||
|
var _water_recovery_active: bool = false
|
||||||
var _target_zoom: float = 5.0
|
var _target_zoom: float = 5.0
|
||||||
var _showcase_rod_visibility: bool = true
|
var _showcase_rod_visibility: bool = true
|
||||||
var _showcase_rod_state_stored: bool = false
|
var _showcase_rod_state_stored: bool = false
|
||||||
|
|
@ -92,8 +96,17 @@ func _ready() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
|
if _water_recovery_active:
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
return
|
||||||
|
|
||||||
if not is_on_floor():
|
if not is_on_floor():
|
||||||
velocity.y -= _gravity * delta
|
var gravity_multiplier: float = (
|
||||||
|
upward_gravity_multiplier
|
||||||
|
if velocity.y > 0.0
|
||||||
|
else fall_gravity_multiplier
|
||||||
|
)
|
||||||
|
velocity.y -= _gravity * gravity_multiplier * delta
|
||||||
elif (
|
elif (
|
||||||
local_control_enabled
|
local_control_enabled
|
||||||
and _movement_enabled
|
and _movement_enabled
|
||||||
|
|
@ -248,6 +261,19 @@ func is_camera_input_enabled() -> bool:
|
||||||
return _camera_input_enabled
|
return _camera_input_enabled
|
||||||
|
|
||||||
|
|
||||||
|
func set_water_recovery_active(active: bool) -> void:
|
||||||
|
_water_recovery_active = active
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
|
||||||
|
|
||||||
|
func get_body_center_position() -> Vector3:
|
||||||
|
return global_position + Vector3.UP * body_center_height
|
||||||
|
|
||||||
|
|
||||||
|
func get_body_center_height() -> float:
|
||||||
|
return body_center_height
|
||||||
|
|
||||||
|
|
||||||
func get_fishing_rod_tip() -> Marker3D:
|
func get_fishing_rod_tip() -> Marker3D:
|
||||||
return _fishing_rod_tip
|
return _fishing_rod_tip
|
||||||
|
|
||||||
|
|
|
||||||
174
ui/game_theme.tres
Normal file
174
ui/game_theme.tres
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
[gd_resource type="Theme" load_steps=12 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="Panel"]
|
||||||
|
bg_color = Color(0.075, 0.145, 0.17, 0.96)
|
||||||
|
border_width_left = 2
|
||||||
|
border_width_top = 2
|
||||||
|
border_width_right = 2
|
||||||
|
border_width_bottom = 2
|
||||||
|
border_color = Color(0.2, 0.55, 0.59, 0.65)
|
||||||
|
corner_radius_top_left = 10
|
||||||
|
corner_radius_top_right = 10
|
||||||
|
corner_radius_bottom_right = 10
|
||||||
|
corner_radius_bottom_left = 10
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="ButtonNormal"]
|
||||||
|
content_margin_left = 12.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 12.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.13, 0.27, 0.31, 1)
|
||||||
|
corner_radius_top_left = 7
|
||||||
|
corner_radius_top_right = 7
|
||||||
|
corner_radius_bottom_right = 7
|
||||||
|
corner_radius_bottom_left = 7
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="ButtonHover"]
|
||||||
|
content_margin_left = 12.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 12.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.14, 0.48, 0.52, 1)
|
||||||
|
corner_radius_top_left = 7
|
||||||
|
corner_radius_top_right = 7
|
||||||
|
corner_radius_bottom_right = 7
|
||||||
|
corner_radius_bottom_left = 7
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="ButtonPressed"]
|
||||||
|
content_margin_left = 12.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 12.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.208, 0.725, 0.78, 1)
|
||||||
|
corner_radius_top_left = 7
|
||||||
|
corner_radius_top_right = 7
|
||||||
|
corner_radius_bottom_right = 7
|
||||||
|
corner_radius_bottom_left = 7
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="ButtonDisabled"]
|
||||||
|
content_margin_left = 12.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 12.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.12, 0.18, 0.2, 0.8)
|
||||||
|
corner_radius_top_left = 7
|
||||||
|
corner_radius_top_right = 7
|
||||||
|
corner_radius_bottom_right = 7
|
||||||
|
corner_radius_bottom_left = 7
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="DangerNormal"]
|
||||||
|
content_margin_left = 12.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 12.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.55, 0.17, 0.19, 1)
|
||||||
|
corner_radius_top_left = 7
|
||||||
|
corner_radius_top_right = 7
|
||||||
|
corner_radius_bottom_right = 7
|
||||||
|
corner_radius_bottom_left = 7
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="DangerHover"]
|
||||||
|
content_margin_left = 12.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 12.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.82, 0.26, 0.29, 1)
|
||||||
|
corner_radius_top_left = 7
|
||||||
|
corner_radius_top_right = 7
|
||||||
|
corner_radius_bottom_right = 7
|
||||||
|
corner_radius_bottom_left = 7
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="CardNormal"]
|
||||||
|
content_margin_left = 7.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 7.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.105, 0.205, 0.235, 1)
|
||||||
|
border_width_left = 2
|
||||||
|
border_width_top = 2
|
||||||
|
border_width_right = 2
|
||||||
|
border_width_bottom = 2
|
||||||
|
border_color = Color(0.2, 0.36, 0.4, 1)
|
||||||
|
corner_radius_top_left = 8
|
||||||
|
corner_radius_top_right = 8
|
||||||
|
corner_radius_bottom_right = 8
|
||||||
|
corner_radius_bottom_left = 8
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="CardHover"]
|
||||||
|
content_margin_left = 7.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 7.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.13, 0.28, 0.32, 1)
|
||||||
|
border_width_left = 2
|
||||||
|
border_width_top = 2
|
||||||
|
border_width_right = 2
|
||||||
|
border_width_bottom = 2
|
||||||
|
border_color = Color(0.208, 0.725, 0.78, 1)
|
||||||
|
corner_radius_top_left = 8
|
||||||
|
corner_radius_top_right = 8
|
||||||
|
corner_radius_bottom_right = 8
|
||||||
|
corner_radius_bottom_left = 8
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="CardPressed"]
|
||||||
|
content_margin_left = 7.0
|
||||||
|
content_margin_top = 7.0
|
||||||
|
content_margin_right = 7.0
|
||||||
|
content_margin_bottom = 7.0
|
||||||
|
bg_color = Color(0.11, 0.36, 0.4, 1)
|
||||||
|
border_width_left = 3
|
||||||
|
border_width_top = 3
|
||||||
|
border_width_right = 3
|
||||||
|
border_width_bottom = 3
|
||||||
|
border_color = Color(1, 0.82, 0.4, 1)
|
||||||
|
corner_radius_top_left = 8
|
||||||
|
corner_radius_top_right = 8
|
||||||
|
corner_radius_bottom_right = 8
|
||||||
|
corner_radius_bottom_left = 8
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="LineEdit"]
|
||||||
|
content_margin_left = 8.0
|
||||||
|
content_margin_top = 5.0
|
||||||
|
content_margin_right = 8.0
|
||||||
|
content_margin_bottom = 5.0
|
||||||
|
bg_color = Color(0.08, 0.16, 0.19, 1)
|
||||||
|
border_width_left = 1
|
||||||
|
border_width_top = 1
|
||||||
|
border_width_right = 1
|
||||||
|
border_width_bottom = 1
|
||||||
|
border_color = Color(0.2, 0.45, 0.5, 1)
|
||||||
|
corner_radius_top_left = 6
|
||||||
|
corner_radius_top_right = 6
|
||||||
|
corner_radius_bottom_right = 6
|
||||||
|
corner_radius_bottom_left = 6
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
default_font_size = 15
|
||||||
|
Label/colors/font_color = Color(0.956, 0.972, 0.976, 1)
|
||||||
|
Label/colors/font_shadow_color = Color(0, 0, 0, 0)
|
||||||
|
PanelContainer/styles/panel = SubResource("Panel")
|
||||||
|
Button/colors/font_color = Color(0.956, 0.972, 0.976, 1)
|
||||||
|
Button/colors/font_hover_color = Color(1, 1, 1, 1)
|
||||||
|
Button/colors/font_pressed_color = Color(0.04, 0.12, 0.14, 1)
|
||||||
|
Button/colors/font_disabled_color = Color(0.48, 0.55, 0.58, 1)
|
||||||
|
Button/styles/normal = SubResource("ButtonNormal")
|
||||||
|
Button/styles/hover = SubResource("ButtonHover")
|
||||||
|
Button/styles/pressed = SubResource("ButtonPressed")
|
||||||
|
Button/styles/focus = SubResource("ButtonHover")
|
||||||
|
Button/styles/disabled = SubResource("ButtonDisabled")
|
||||||
|
OptionButton/styles/normal = SubResource("ButtonNormal")
|
||||||
|
OptionButton/styles/hover = SubResource("ButtonHover")
|
||||||
|
OptionButton/styles/pressed = SubResource("ButtonPressed")
|
||||||
|
OptionButton/styles/focus = SubResource("ButtonHover")
|
||||||
|
DangerButton/base_type = &"Button"
|
||||||
|
DangerButton/styles/normal = SubResource("DangerNormal")
|
||||||
|
DangerButton/styles/hover = SubResource("DangerHover")
|
||||||
|
DangerButton/styles/pressed = SubResource("DangerHover")
|
||||||
|
DangerButton/styles/focus = SubResource("DangerHover")
|
||||||
|
CardButton/base_type = &"Button"
|
||||||
|
CardButton/styles/normal = SubResource("CardNormal")
|
||||||
|
CardButton/styles/hover = SubResource("CardHover")
|
||||||
|
CardButton/styles/pressed = SubResource("CardPressed")
|
||||||
|
CardButton/styles/focus = SubResource("CardHover")
|
||||||
|
CardButton/colors/font_pressed_color = Color(0.956, 0.972, 0.976, 1)
|
||||||
|
LineEdit/styles/normal = SubResource("LineEdit")
|
||||||
|
|
@ -21,8 +21,10 @@ const PlayerWalletType = preload("res://economy/player_wallet.gd")
|
||||||
@onready var _showcase_details: Label = %ShowcaseDetails
|
@onready var _showcase_details: Label = %ShowcaseDetails
|
||||||
@onready var _fishing_panel: PanelContainer = %FishingPanel
|
@onready var _fishing_panel: PanelContainer = %FishingPanel
|
||||||
@onready var _player_menu: PlayerMenuType = %PlayerMenu
|
@onready var _player_menu: PlayerMenuType = %PlayerMenu
|
||||||
|
@onready var _screen_fade: ScreenFade = %ScreenFade
|
||||||
|
|
||||||
var _showcase_active: bool = false
|
var _showcase_active: bool = false
|
||||||
|
var _player_menu_open: bool = false
|
||||||
|
|
||||||
|
|
||||||
func setup(
|
func setup(
|
||||||
|
|
@ -53,11 +55,36 @@ func setup(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func close_player_menu() -> void:
|
||||||
|
_player_menu.close_menu()
|
||||||
|
|
||||||
|
|
||||||
|
func get_screen_fade() -> ScreenFade:
|
||||||
|
return _screen_fade
|
||||||
|
|
||||||
|
|
||||||
func _on_fishing_status_changed(status: String) -> void:
|
func _on_fishing_status_changed(status: String) -> void:
|
||||||
if _showcase_active:
|
if _showcase_active:
|
||||||
return
|
return
|
||||||
_status_label.text = status
|
_set_fishing_status(status)
|
||||||
_status_label.visible = not status.is_empty()
|
|
||||||
|
|
||||||
|
func _set_fishing_status(text: String) -> void:
|
||||||
|
var normalized_text: String = text.strip_edges()
|
||||||
|
_status_label.text = normalized_text
|
||||||
|
_status_label.visible = not normalized_text.is_empty()
|
||||||
|
_refresh_fishing_panel_visibility()
|
||||||
|
|
||||||
|
|
||||||
|
func _refresh_fishing_panel_visibility() -> void:
|
||||||
|
var has_content: bool = (
|
||||||
|
not _status_label.text.strip_edges().is_empty()
|
||||||
|
or not _showcase_details.text.strip_edges().is_empty()
|
||||||
|
or _catch_track.visible
|
||||||
|
or _barrier_summary.visible
|
||||||
|
or _barrier_health.visible
|
||||||
|
)
|
||||||
|
_fishing_panel.visible = has_content and not _player_menu_open
|
||||||
|
|
||||||
|
|
||||||
func _on_catch_display_changed(
|
func _on_catch_display_changed(
|
||||||
|
|
@ -78,6 +105,7 @@ func _on_catch_display_changed(
|
||||||
_clear_barrier_markers()
|
_clear_barrier_markers()
|
||||||
_barrier_summary.text = ""
|
_barrier_summary.text = ""
|
||||||
_barrier_health.text = ""
|
_barrier_health.text = ""
|
||||||
|
_refresh_fishing_panel_visibility()
|
||||||
return
|
return
|
||||||
|
|
||||||
_update_barrier_markers(
|
_update_barrier_markers(
|
||||||
|
|
@ -128,6 +156,7 @@ func _on_catch_display_changed(
|
||||||
visible
|
visible
|
||||||
and (active_barrier_index >= 0 or chase_gap <= 0.05)
|
and (active_barrier_index >= 0 or chase_gap <= 0.05)
|
||||||
)
|
)
|
||||||
|
_refresh_fishing_panel_visibility()
|
||||||
|
|
||||||
|
|
||||||
func _update_barrier_markers(
|
func _update_barrier_markers(
|
||||||
|
|
@ -142,9 +171,13 @@ func _update_barrier_markers(
|
||||||
barrier_index < health.size()
|
barrier_index < health.size()
|
||||||
and health[barrier_index] <= 0
|
and health[barrier_index] <= 0
|
||||||
)
|
)
|
||||||
marker.color = Color(0.35, 0.38, 0.42, 0.8) if defeated else Color(1.0, 0.82, 0.2, 1.0)
|
marker.color = (
|
||||||
|
UIPalette.DISABLED
|
||||||
|
if defeated
|
||||||
|
else UIPalette.SECONDARY
|
||||||
|
)
|
||||||
if barrier_index == active_index:
|
if barrier_index == active_index:
|
||||||
marker.color = Color(1.0, 1.0, 1.0, 1.0)
|
marker.color = UIPalette.TEXT
|
||||||
marker.set_anchors_preset(Control.PRESET_TOP_LEFT)
|
marker.set_anchors_preset(Control.PRESET_TOP_LEFT)
|
||||||
marker.anchor_left = positions[barrier_index]
|
marker.anchor_left = positions[barrier_index]
|
||||||
marker.anchor_right = positions[barrier_index]
|
marker.anchor_right = positions[barrier_index]
|
||||||
|
|
@ -169,23 +202,22 @@ func _on_showcase_changed(
|
||||||
) -> void:
|
) -> void:
|
||||||
_showcase_active = visible
|
_showcase_active = visible
|
||||||
if not visible:
|
if not visible:
|
||||||
_status_label.text = ""
|
|
||||||
_status_label.visible = false
|
|
||||||
_showcase_details.text = ""
|
_showcase_details.text = ""
|
||||||
_showcase_details.visible = false
|
_showcase_details.visible = false
|
||||||
|
_set_fishing_status("")
|
||||||
return
|
return
|
||||||
_catch_track.visible = false
|
_catch_track.visible = false
|
||||||
_barrier_summary.visible = false
|
_barrier_summary.visible = false
|
||||||
_barrier_health.visible = false
|
_barrier_health.visible = false
|
||||||
_clear_barrier_markers()
|
_clear_barrier_markers()
|
||||||
_status_label.text = "You caught a %s!" % fish_name
|
|
||||||
_status_label.visible = true
|
|
||||||
_showcase_details.text = (
|
_showcase_details.text = (
|
||||||
"%.1f lb • %s\nLeft click or Escape to put away"
|
"%.1f lb • %s\nLeft click or Escape to put away"
|
||||||
% [weight_lb, rarity_name]
|
% [weight_lb, rarity_name]
|
||||||
)
|
)
|
||||||
_showcase_details.visible = true
|
_showcase_details.visible = true
|
||||||
|
_set_fishing_status("You caught a %s!" % fish_name)
|
||||||
|
|
||||||
|
|
||||||
func _on_player_menu_visibility_changed(is_open: bool) -> void:
|
func _on_player_menu_visibility_changed(is_open: bool) -> void:
|
||||||
_fishing_panel.visible = not is_open
|
_player_menu_open = is_open
|
||||||
|
_refresh_fishing_panel_visibility()
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,30 @@
|
||||||
[gd_scene load_steps=7 format=3]
|
[gd_scene load_steps=9 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://ui/game_ui.gd" id="1_ui"]
|
[ext_resource type="Script" path="res://ui/game_ui.gd" id="1_ui"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/player_menu.tscn" id="2_menu"]
|
[ext_resource type="PackedScene" path="res://ui/player_menu.tscn" id="2_menu"]
|
||||||
|
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="3_theme"]
|
||||||
|
[ext_resource type="Script" path="res://ui/screen_fade.gd" id="4_fade"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBox_chase_background"]
|
[sub_resource type="StyleBoxFlat" id="StyleBox_chase_background"]
|
||||||
bg_color = Color(0.08, 0.08, 0.1, 0.9)
|
bg_color = Color(0.055, 0.105, 0.125, 1)
|
||||||
|
corner_radius_top_left = 6
|
||||||
|
corner_radius_top_right = 6
|
||||||
|
corner_radius_bottom_right = 6
|
||||||
|
corner_radius_bottom_left = 6
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBox_chase_fill"]
|
[sub_resource type="StyleBoxFlat" id="StyleBox_chase_fill"]
|
||||||
bg_color = Color(0.85, 0.12, 0.12, 0.95)
|
bg_color = Color(0.937, 0.357, 0.384, 0.95)
|
||||||
|
corner_radius_top_left = 6
|
||||||
|
corner_radius_top_right = 6
|
||||||
|
corner_radius_bottom_right = 6
|
||||||
|
corner_radius_bottom_left = 6
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBox_catch_fill"]
|
[sub_resource type="StyleBoxFlat" id="StyleBox_catch_fill"]
|
||||||
bg_color = Color(0.16, 0.82, 0.28, 0.9)
|
bg_color = Color(0.275, 0.784, 0.471, 0.92)
|
||||||
|
corner_radius_top_left = 6
|
||||||
|
corner_radius_top_right = 6
|
||||||
|
corner_radius_bottom_right = 6
|
||||||
|
corner_radius_bottom_left = 6
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBox_transparent"]
|
[sub_resource type="StyleBoxFlat" id="StyleBox_transparent"]
|
||||||
bg_color = Color(0, 0, 0, 0)
|
bg_color = Color(0, 0, 0, 0)
|
||||||
|
|
@ -20,32 +34,36 @@ script = ExtResource("1_ui")
|
||||||
|
|
||||||
[node name="FishingPanel" type="PanelContainer" parent="."]
|
[node name="FishingPanel" type="PanelContainer" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
anchors_preset = 7
|
anchors_preset = 7
|
||||||
anchor_left = 0.5
|
anchor_left = 0.5
|
||||||
anchor_top = 1.0
|
anchor_top = 1.0
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
offset_left = -160.0
|
offset_left = -210.0
|
||||||
offset_top = -100.0
|
offset_top = -130.0
|
||||||
offset_right = 160.0
|
offset_right = 210.0
|
||||||
offset_bottom = -20.0
|
offset_bottom = -24.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 0
|
grow_vertical = 0
|
||||||
mouse_filter = 2
|
mouse_filter = 2
|
||||||
|
theme = ExtResource("3_theme")
|
||||||
|
|
||||||
[node name="MarginContainer" type="MarginContainer" parent="FishingPanel"]
|
[node name="MarginContainer" type="MarginContainer" parent="FishingPanel"]
|
||||||
theme_override_constants/margin_left = 12
|
theme_override_constants/margin_left = 18
|
||||||
theme_override_constants/margin_top = 8
|
theme_override_constants/margin_top = 12
|
||||||
theme_override_constants/margin_right = 12
|
theme_override_constants/margin_right = 18
|
||||||
theme_override_constants/margin_bottom = 8
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
[node name="VBoxContainer" type="VBoxContainer" parent="FishingPanel/MarginContainer"]
|
[node name="VBoxContainer" type="VBoxContainer" parent="FishingPanel/MarginContainer"]
|
||||||
|
theme_override_constants/separation = 6
|
||||||
|
|
||||||
[node name="StatusLabel" type="Label" parent="FishingPanel/MarginContainer/VBoxContainer"]
|
[node name="StatusLabel" type="Label" parent="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 = 17
|
||||||
|
|
||||||
[node name="ShowcaseDetails" type="Label" parent="FishingPanel/MarginContainer/VBoxContainer"]
|
[node name="ShowcaseDetails" type="Label" parent="FishingPanel/MarginContainer/VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
@ -55,7 +73,7 @@ horizontal_alignment = 1
|
||||||
[node name="CatchTrack" type="Control" parent="FishingPanel/MarginContainer/VBoxContainer"]
|
[node name="CatchTrack" type="Control" parent="FishingPanel/MarginContainer/VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
visible = false
|
visible = false
|
||||||
custom_minimum_size = Vector2(0, 18)
|
custom_minimum_size = Vector2(0, 22)
|
||||||
|
|
||||||
[node name="GreenCatchProgress" type="ProgressBar" parent="FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
[node name="GreenCatchProgress" type="ProgressBar" parent="FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
@ -107,3 +125,16 @@ horizontal_alignment = 1
|
||||||
|
|
||||||
[node name="PlayerMenu" parent="." instance=ExtResource("2_menu")]
|
[node name="PlayerMenu" parent="." instance=ExtResource("2_menu")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
||||||
|
[node name="ScreenFade" type="ColorRect" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
z_index = 100
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 0
|
||||||
|
color = Color(0, 0, 0, 1)
|
||||||
|
script = ExtResource("4_fade")
|
||||||
|
|
|
||||||
|
|
@ -328,37 +328,103 @@ func _compare_catches(left: FishCatchType, right: FishCatchType) -> bool:
|
||||||
|
|
||||||
func _create_inventory_card(fish_catch: FishCatchType) -> Button:
|
func _create_inventory_card(fish_catch: FishCatchType) -> Button:
|
||||||
var card := Button.new()
|
var card := Button.new()
|
||||||
card.custom_minimum_size = Vector2(170.0, 160.0)
|
card.theme_type_variation = &"CardButton"
|
||||||
|
card.custom_minimum_size = Vector2(152.0, 140.0)
|
||||||
card.toggle_mode = true
|
card.toggle_mode = true
|
||||||
card.button_pressed = fish_catch.catch_id == _selected_catch_id
|
card.button_pressed = fish_catch.catch_id == _selected_catch_id
|
||||||
card.tooltip_text = String(fish_catch.catch_id)
|
|
||||||
card.pressed.connect(_select_catch.bind(fish_catch.catch_id))
|
card.pressed.connect(_select_catch.bind(fish_catch.catch_id))
|
||||||
|
_apply_inventory_card_styles(
|
||||||
|
card,
|
||||||
|
UIPalette.get_rarity_color(fish_catch.fish.rarity)
|
||||||
|
)
|
||||||
|
|
||||||
var content := VBoxContainer.new()
|
var content := VBoxContainer.new()
|
||||||
content.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT, Control.PRESET_MODE_MINSIZE, 8)
|
content.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT, Control.PRESET_MODE_MINSIZE, 8)
|
||||||
|
content.add_theme_constant_override("separation", 3)
|
||||||
content.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
content.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
card.add_child(content)
|
card.add_child(content)
|
||||||
content.add_child(_create_texture_frame(fish_catch.fish.display_texture, Vector2(138.0, 82.0)))
|
content.add_child(_create_texture_frame(
|
||||||
|
fish_catch.fish.display_texture,
|
||||||
|
Vector2(124.0, 78.0)
|
||||||
|
))
|
||||||
var name_label := Label.new()
|
var name_label := Label.new()
|
||||||
name_label.text = fish_catch.fish.display_name
|
name_label.text = fish_catch.fish.display_name
|
||||||
name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
name_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
name_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
content.add_child(name_label)
|
content.add_child(name_label)
|
||||||
var data_label := Label.new()
|
var weight_label := Label.new()
|
||||||
data_label.text = "%.2f lb • %s\nCatch #%d" % [
|
weight_label.text = "%.2f lb" % fish_catch.weight_lb
|
||||||
fish_catch.weight_lb,
|
weight_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
fish_catch.fish.get_rarity_name(),
|
weight_label.add_theme_color_override(
|
||||||
fish_catch.catch_sequence,
|
"font_color",
|
||||||
]
|
UIPalette.MUTED_TEXT
|
||||||
data_label.text += "\nBase value: $%d" % fish_catch.sale_value
|
)
|
||||||
|
weight_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
content.add_child(weight_label)
|
||||||
if fish_catch.is_favorited:
|
if fish_catch.is_favorited:
|
||||||
data_label.text += " • ★"
|
var favorite_marker := Label.new()
|
||||||
data_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
favorite_marker.text = "★"
|
||||||
data_label.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
favorite_marker.add_theme_color_override(
|
||||||
content.add_child(data_label)
|
"font_color",
|
||||||
|
UIPalette.SECONDARY
|
||||||
|
)
|
||||||
|
favorite_marker.add_theme_font_size_override("font_size", 18)
|
||||||
|
favorite_marker.set_anchors_preset(Control.PRESET_TOP_RIGHT)
|
||||||
|
favorite_marker.offset_left = -28.0
|
||||||
|
favorite_marker.offset_top = 5.0
|
||||||
|
favorite_marker.offset_right = -8.0
|
||||||
|
favorite_marker.offset_bottom = 29.0
|
||||||
|
favorite_marker.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
favorite_marker.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
card.add_child(favorite_marker)
|
||||||
return card
|
return card
|
||||||
|
|
||||||
|
|
||||||
|
func _apply_inventory_card_styles(
|
||||||
|
card: Button,
|
||||||
|
rarity_color: Color,
|
||||||
|
) -> void:
|
||||||
|
card.add_theme_stylebox_override(
|
||||||
|
"normal",
|
||||||
|
_create_inventory_card_style(rarity_color, 0)
|
||||||
|
)
|
||||||
|
card.add_theme_stylebox_override(
|
||||||
|
"hover",
|
||||||
|
_create_inventory_card_style(rarity_color, 1)
|
||||||
|
)
|
||||||
|
card.add_theme_stylebox_override(
|
||||||
|
"focus",
|
||||||
|
_create_inventory_card_style(rarity_color, 1)
|
||||||
|
)
|
||||||
|
card.add_theme_stylebox_override(
|
||||||
|
"pressed",
|
||||||
|
_create_inventory_card_style(rarity_color, 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _create_inventory_card_style(
|
||||||
|
rarity_color: Color,
|
||||||
|
state_index: int,
|
||||||
|
) -> StyleBoxFlat:
|
||||||
|
var style := StyleBoxFlat.new()
|
||||||
|
match state_index:
|
||||||
|
1:
|
||||||
|
style.bg_color = UIPalette.ELEVATED_PANEL.lightened(0.1)
|
||||||
|
2:
|
||||||
|
style.bg_color = UIPalette.PRIMARY.darkened(0.48)
|
||||||
|
_:
|
||||||
|
style.bg_color = UIPalette.ELEVATED_PANEL
|
||||||
|
style.border_color = rarity_color
|
||||||
|
var border_width: int = 4 if state_index == 2 else 2
|
||||||
|
style.set_border_width_all(border_width)
|
||||||
|
style.set_corner_radius_all(8)
|
||||||
|
style.content_margin_left = 7.0
|
||||||
|
style.content_margin_top = 7.0
|
||||||
|
style.content_margin_right = 7.0
|
||||||
|
style.content_margin_bottom = 7.0
|
||||||
|
return style
|
||||||
|
|
||||||
|
|
||||||
func _select_catch(catch_id: StringName) -> void:
|
func _select_catch(catch_id: StringName) -> void:
|
||||||
if _inventory == null:
|
if _inventory == null:
|
||||||
return
|
return
|
||||||
|
|
@ -395,13 +461,11 @@ func _update_inventory_detail(fish_catch: FishCatchType) -> void:
|
||||||
_default_buyer.display_name,
|
_default_buyer.display_name,
|
||||||
buyer_offer,
|
buyer_offer,
|
||||||
]
|
]
|
||||||
_detail_data.text = "%.2f lb\n%s\nBase value: $%d\n%s\nCatch #%d\n%s" % [
|
_detail_data.text = "%.2f lb\n%s\nBase value: $%d\n%s" % [
|
||||||
fish_catch.weight_lb,
|
fish_catch.weight_lb,
|
||||||
fish_catch.fish.get_rarity_name(),
|
fish_catch.fish.get_rarity_name(),
|
||||||
fish_catch.sale_value,
|
fish_catch.sale_value,
|
||||||
buyer_offer_text,
|
buyer_offer_text,
|
||||||
fish_catch.catch_sequence,
|
|
||||||
String(fish_catch.catch_id),
|
|
||||||
]
|
]
|
||||||
_favorite_button.disabled = false
|
_favorite_button.disabled = false
|
||||||
_favorite_button.text = (
|
_favorite_button.text = (
|
||||||
|
|
@ -601,16 +665,16 @@ func _create_logbook_card(fish: FishDataType) -> Control:
|
||||||
and _collection_log.has_discovered(fish.id)
|
and _collection_log.has_discovered(fish.id)
|
||||||
)
|
)
|
||||||
var card := PanelContainer.new()
|
var card := PanelContainer.new()
|
||||||
card.custom_minimum_size = Vector2(190.0, 170.0)
|
card.custom_minimum_size = Vector2(158.0, 154.0)
|
||||||
var content := VBoxContainer.new()
|
var content := VBoxContainer.new()
|
||||||
content.add_theme_constant_override("separation", 4)
|
content.add_theme_constant_override("separation", 4)
|
||||||
card.add_child(content)
|
card.add_child(content)
|
||||||
var texture_frame: TextureRect = _create_texture_frame(
|
var texture_frame: TextureRect = _create_texture_frame(
|
||||||
fish.display_texture,
|
fish.display_texture,
|
||||||
Vector2(170.0, 92.0)
|
Vector2(142.0, 82.0)
|
||||||
)
|
)
|
||||||
if not discovered:
|
if not discovered:
|
||||||
texture_frame.modulate = Color(0.08, 0.1, 0.12, 1.0)
|
texture_frame.modulate = UIPalette.PANEL
|
||||||
content.add_child(texture_frame)
|
content.add_child(texture_frame)
|
||||||
var name_label := Label.new()
|
var name_label := Label.new()
|
||||||
name_label.text = fish.display_name if discovered else "???"
|
name_label.text = fish.display_name if discovered else "???"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
[gd_scene load_steps=2 format=3]
|
[gd_scene load_steps=3 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://ui/player_menu.gd" id="1_menu"]
|
[ext_resource type="Script" path="res://ui/player_menu.gd" id="1_menu"]
|
||||||
|
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="2_theme"]
|
||||||
|
|
||||||
[node name="PlayerMenu" type="Control"]
|
[node name="PlayerMenu" type="Control"]
|
||||||
process_mode = 3
|
process_mode = 3
|
||||||
|
|
@ -12,6 +13,7 @@ anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
mouse_filter = 0
|
mouse_filter = 0
|
||||||
|
theme = ExtResource("2_theme")
|
||||||
script = ExtResource("1_menu")
|
script = ExtResource("1_menu")
|
||||||
|
|
||||||
[node name="Dimmer" type="ColorRect" parent="."]
|
[node name="Dimmer" type="ColorRect" parent="."]
|
||||||
|
|
@ -26,59 +28,60 @@ color = Color(0.015, 0.02, 0.03, 0.72)
|
||||||
|
|
||||||
[node name="MenuPanel" type="PanelContainer" parent="."]
|
[node name="MenuPanel" type="PanelContainer" parent="."]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 8
|
anchor_left = 0.055
|
||||||
anchor_left = 0.5
|
anchor_top = 0.045
|
||||||
anchor_top = 0.5
|
anchor_right = 0.945
|
||||||
anchor_right = 0.5
|
anchor_bottom = 0.955
|
||||||
anchor_bottom = 0.5
|
|
||||||
offset_left = -480.0
|
|
||||||
offset_top = -310.0
|
|
||||||
offset_right = 480.0
|
|
||||||
offset_bottom = 310.0
|
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
|
||||||
[node name="Margin" type="MarginContainer" parent="MenuPanel"]
|
[node name="Margin" type="MarginContainer" parent="MenuPanel"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/margin_left = 18
|
theme_override_constants/margin_left = 22
|
||||||
theme_override_constants/margin_top = 14
|
theme_override_constants/margin_top = 18
|
||||||
theme_override_constants/margin_right = 18
|
theme_override_constants/margin_right = 22
|
||||||
theme_override_constants/margin_bottom = 16
|
theme_override_constants/margin_bottom = 20
|
||||||
|
|
||||||
[node name="Layout" type="VBoxContainer" parent="MenuPanel/Margin"]
|
[node name="Layout" type="VBoxContainer" parent="MenuPanel/Margin"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/separation = 10
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
[node name="Header" type="HBoxContainer" parent="MenuPanel/Margin/Layout"]
|
[node name="Header" type="HBoxContainer" parent="MenuPanel/Margin/Layout"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
|
||||||
[node name="Title" type="Label" parent="MenuPanel/Margin/Layout/Header"]
|
[node name="Title" type="Label" parent="MenuPanel/Margin/Layout/Header"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
theme_override_font_sizes/font_size = 24
|
theme_override_colors/font_color = Color(0.208, 0.725, 0.78, 1)
|
||||||
|
theme_override_font_sizes/font_size = 26
|
||||||
text = "Player Menu"
|
text = "Player Menu"
|
||||||
|
|
||||||
[node name="WalletBalance" type="Label" parent="MenuPanel/Margin/Layout/Header"]
|
[node name="WalletBalance" type="Label" parent="MenuPanel/Margin/Layout/Header"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Wallet: $0"
|
text = "Wallet: $0"
|
||||||
|
theme_override_colors/font_color = Color(1, 0.82, 0.4, 1)
|
||||||
|
|
||||||
[node name="InventoryTab" type="Button" parent="MenuPanel/Margin/Layout/Header"]
|
[node name="InventoryTab" type="Button" parent="MenuPanel/Margin/Layout/Header"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
toggle_mode = true
|
toggle_mode = true
|
||||||
text = "Inventory"
|
text = "Inventory"
|
||||||
|
custom_minimum_size = Vector2(104, 36)
|
||||||
|
|
||||||
[node name="LogbookTab" type="Button" parent="MenuPanel/Margin/Layout/Header"]
|
[node name="LogbookTab" type="Button" parent="MenuPanel/Margin/Layout/Header"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
toggle_mode = true
|
toggle_mode = true
|
||||||
text = "Logbook"
|
text = "Logbook"
|
||||||
|
custom_minimum_size = Vector2(104, 36)
|
||||||
|
|
||||||
[node name="CloseButton" type="Button" parent="MenuPanel/Margin/Layout/Header"]
|
[node name="CloseButton" type="Button" parent="MenuPanel/Margin/Layout/Header"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Close"
|
text = "Close"
|
||||||
|
custom_minimum_size = Vector2(76, 36)
|
||||||
|
|
||||||
[node name="Separator" type="HSeparator" parent="MenuPanel/Margin/Layout"]
|
[node name="Separator" type="HSeparator" parent="MenuPanel/Margin/Layout"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
@ -88,9 +91,11 @@ unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = ""
|
text = ""
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
theme_override_colors/font_color = Color(1, 0.82, 0.4, 1)
|
||||||
|
theme_override_font_sizes/font_size = 16
|
||||||
|
|
||||||
[node name="Content" type="Control" parent="MenuPanel/Margin/Layout"]
|
[node name="Content" type="Control" parent="MenuPanel/Margin/Layout"]
|
||||||
custom_minimum_size = Vector2(0, 530)
|
custom_minimum_size = Vector2(0, 390)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
|
@ -102,9 +107,11 @@ anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
[node name="SortBar" type="HBoxContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection"]
|
[node name="SortBar" type="HBoxContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 8
|
||||||
|
|
||||||
[node name="SortLabel" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
[node name="SortLabel" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
@ -113,12 +120,12 @@ text = "Sort:"
|
||||||
[node name="SortOption" type="OptionButton" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
[node name="SortOption" type="OptionButton" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
custom_minimum_size = Vector2(160, 0)
|
custom_minimum_size = Vector2(145, 36)
|
||||||
|
|
||||||
[node name="SortDirection" type="Button" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
[node name="SortDirection" type="Button" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
custom_minimum_size = Vector2(130, 0)
|
custom_minimum_size = Vector2(125, 36)
|
||||||
text = "Newest first"
|
text = "Newest first"
|
||||||
|
|
||||||
[node name="SortSpacer" type="Control" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
[node name="SortSpacer" type="Control" parent="MenuPanel/Margin/Layout/Content/InventorySection/SortBar"]
|
||||||
|
|
@ -129,25 +136,28 @@ size_flags_horizontal = 3
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Held fish base value: $0"
|
text = "Held fish base value: $0"
|
||||||
|
theme_override_colors/font_color = Color(0.682, 0.733, 0.761, 1)
|
||||||
|
|
||||||
[node name="InventoryBody" type="HSplitContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection"]
|
[node name="InventoryBody" type="HSplitContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
split_offset = 620
|
split_offset = 560
|
||||||
|
theme_override_constants/separation = 12
|
||||||
|
|
||||||
[node name="InventoryList" type="PanelContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody"]
|
[node name="InventoryList" type="PanelContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody"]
|
||||||
custom_minimum_size = Vector2(610, 0)
|
custom_minimum_size = Vector2(400, 0)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
||||||
[node name="InventoryListMargin" type="MarginContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/InventoryList"]
|
[node name="InventoryListMargin" type="MarginContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/InventoryList"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/margin_left = 8
|
theme_override_constants/margin_left = 12
|
||||||
theme_override_constants/margin_top = 8
|
theme_override_constants/margin_top = 12
|
||||||
theme_override_constants/margin_right = 8
|
theme_override_constants/margin_right = 12
|
||||||
theme_override_constants/margin_bottom = 8
|
theme_override_constants/margin_bottom = 12
|
||||||
|
|
||||||
[node name="InventoryStack" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/InventoryList/InventoryListMargin"]
|
[node name="InventoryStack" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/InventoryList/InventoryListMargin"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
[node name="InventoryEmpty" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/InventoryList/InventoryListMargin/InventoryStack"]
|
[node name="InventoryEmpty" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/InventoryList/InventoryListMargin/InventoryStack"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
@ -164,20 +174,20 @@ horizontal_scroll_mode = 0
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
theme_override_constants/h_separation = 8
|
theme_override_constants/h_separation = 10
|
||||||
theme_override_constants/v_separation = 8
|
theme_override_constants/v_separation = 10
|
||||||
columns = 3
|
columns = 3
|
||||||
|
|
||||||
[node name="DetailPanel" type="PanelContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody"]
|
[node name="DetailPanel" type="PanelContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody"]
|
||||||
custom_minimum_size = Vector2(270, 0)
|
custom_minimum_size = Vector2(240, 0)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
||||||
[node name="DetailMargin" type="MarginContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel"]
|
[node name="DetailMargin" type="MarginContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/margin_left = 12
|
theme_override_constants/margin_left = 16
|
||||||
theme_override_constants/margin_top = 12
|
theme_override_constants/margin_top = 14
|
||||||
theme_override_constants/margin_right = 12
|
theme_override_constants/margin_right = 16
|
||||||
theme_override_constants/margin_bottom = 12
|
theme_override_constants/margin_bottom = 14
|
||||||
|
|
||||||
[node name="DetailStack" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin"]
|
[node name="DetailStack" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
@ -185,7 +195,7 @@ theme_override_constants/separation = 10
|
||||||
|
|
||||||
[node name="DetailTexture" type="TextureRect" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin/DetailStack"]
|
[node name="DetailTexture" type="TextureRect" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin/DetailStack"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
custom_minimum_size = Vector2(240, 180)
|
custom_minimum_size = Vector2(208, 140)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
expand_mode = 1
|
expand_mode = 1
|
||||||
stretch_mode = 5
|
stretch_mode = 5
|
||||||
|
|
@ -194,6 +204,7 @@ texture_filter = 1
|
||||||
[node name="DetailName" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin/DetailStack"]
|
[node name="DetailName" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin/DetailStack"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
theme_override_colors/font_color = Color(0.208, 0.725, 0.78, 1)
|
||||||
theme_override_font_sizes/font_size = 22
|
theme_override_font_sizes/font_size = 22
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
|
@ -214,6 +225,7 @@ unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
text = "Sell"
|
text = "Sell"
|
||||||
|
theme_type_variation = &"DangerButton"
|
||||||
|
|
||||||
[node name="SaleUnavailable" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin/DetailStack"]
|
[node name="SaleUnavailable" type="Label" parent="MenuPanel/Margin/Layout/Content/InventorySection/InventoryBody/DetailPanel/DetailMargin/DetailStack"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
@ -221,6 +233,7 @@ visible = false
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
autowrap_mode = 2
|
autowrap_mode = 2
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
theme_override_colors/font_color = Color(1, 0.702, 0.278, 1)
|
||||||
|
|
||||||
[node name="LogbookSection" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content"]
|
[node name="LogbookSection" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
@ -231,6 +244,7 @@ anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
theme_override_constants/separation = 10
|
||||||
|
|
||||||
[node name="LogbookEmpty" type="Label" parent="MenuPanel/Margin/Layout/Content/LogbookSection"]
|
[node name="LogbookEmpty" type="Label" parent="MenuPanel/Margin/Layout/Content/LogbookSection"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
@ -247,8 +261,8 @@ horizontal_scroll_mode = 0
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
theme_override_constants/h_separation = 12
|
theme_override_constants/h_separation = 10
|
||||||
theme_override_constants/v_separation = 12
|
theme_override_constants/v_separation = 10
|
||||||
columns = 4
|
columns = 4
|
||||||
|
|
||||||
[node name="SaleConfirmation" type="PanelContainer" parent="MenuPanel/Margin/Layout/Content"]
|
[node name="SaleConfirmation" type="PanelContainer" parent="MenuPanel/Margin/Layout/Content"]
|
||||||
|
|
@ -260,19 +274,19 @@ anchor_left = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
anchor_bottom = 0.5
|
anchor_bottom = 0.5
|
||||||
offset_left = -220.0
|
offset_left = -230.0
|
||||||
offset_top = -90.0
|
offset_top = -105.0
|
||||||
offset_right = 220.0
|
offset_right = 230.0
|
||||||
offset_bottom = 90.0
|
offset_bottom = 105.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
|
||||||
[node name="ConfirmationMargin" type="MarginContainer" parent="MenuPanel/Margin/Layout/Content/SaleConfirmation"]
|
[node name="ConfirmationMargin" type="MarginContainer" parent="MenuPanel/Margin/Layout/Content/SaleConfirmation"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_constants/margin_left = 18
|
theme_override_constants/margin_left = 22
|
||||||
theme_override_constants/margin_top = 16
|
theme_override_constants/margin_top = 20
|
||||||
theme_override_constants/margin_right = 18
|
theme_override_constants/margin_right = 22
|
||||||
theme_override_constants/margin_bottom = 16
|
theme_override_constants/margin_bottom = 20
|
||||||
|
|
||||||
[node name="ConfirmationLayout" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content/SaleConfirmation/ConfirmationMargin"]
|
[node name="ConfirmationLayout" type="VBoxContainer" parent="MenuPanel/Margin/Layout/Content/SaleConfirmation/ConfirmationMargin"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
@ -292,8 +306,11 @@ alignment = 1
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Confirm"
|
text = "Confirm"
|
||||||
|
theme_type_variation = &"DangerButton"
|
||||||
|
custom_minimum_size = Vector2(120, 38)
|
||||||
|
|
||||||
[node name="CancelSaleButton" type="Button" parent="MenuPanel/Margin/Layout/Content/SaleConfirmation/ConfirmationMargin/ConfirmationLayout/ConfirmationButtons"]
|
[node name="CancelSaleButton" type="Button" parent="MenuPanel/Margin/Layout/Content/SaleConfirmation/ConfirmationMargin/ConfirmationLayout/ConfirmationButtons"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Cancel"
|
text = "Cancel"
|
||||||
|
custom_minimum_size = Vector2(120, 38)
|
||||||
|
|
|
||||||
65
ui/screen_fade.gd
Normal file
65
ui/screen_fade.gd
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
class_name ScreenFade
|
||||||
|
extends ColorRect
|
||||||
|
|
||||||
|
signal transition_completed(generation: int, faded_to_black: bool)
|
||||||
|
|
||||||
|
@export_range(0.01, 3.0, 0.01) var fade_out_duration: float = 0.4
|
||||||
|
@export_range(0.01, 3.0, 0.01) var fade_in_duration: float = 0.45
|
||||||
|
|
||||||
|
var _fade_tween: Tween
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
modulate.a = 0.0
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func fade_to_black(generation: int) -> void:
|
||||||
|
_start_fade(1.0, fade_out_duration, generation, true)
|
||||||
|
|
||||||
|
|
||||||
|
func fade_from_black(generation: int) -> void:
|
||||||
|
visible = true
|
||||||
|
modulate.a = 1.0
|
||||||
|
_start_fade(0.0, fade_in_duration, generation, false)
|
||||||
|
|
||||||
|
|
||||||
|
func reset_immediately() -> void:
|
||||||
|
if _fade_tween != null and _fade_tween.is_valid():
|
||||||
|
_fade_tween.kill()
|
||||||
|
_fade_tween = null
|
||||||
|
modulate.a = 0.0
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
|
||||||
|
func _start_fade(
|
||||||
|
target_alpha: float,
|
||||||
|
duration: float,
|
||||||
|
generation: int,
|
||||||
|
faded_to_black: bool,
|
||||||
|
) -> void:
|
||||||
|
if _fade_tween != null and _fade_tween.is_valid():
|
||||||
|
_fade_tween.kill()
|
||||||
|
visible = true
|
||||||
|
_fade_tween = create_tween()
|
||||||
|
_fade_tween.set_trans(Tween.TRANS_QUAD)
|
||||||
|
_fade_tween.set_ease(
|
||||||
|
Tween.EASE_IN if faded_to_black else Tween.EASE_OUT
|
||||||
|
)
|
||||||
|
_fade_tween.tween_property(
|
||||||
|
self,
|
||||||
|
"modulate:a",
|
||||||
|
target_alpha,
|
||||||
|
maxf(duration, 0.01)
|
||||||
|
)
|
||||||
|
_fade_tween.finished.connect(
|
||||||
|
_on_fade_finished.bind(generation, faded_to_black),
|
||||||
|
CONNECT_ONE_SHOT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_fade_finished(generation: int, faded_to_black: bool) -> void:
|
||||||
|
_fade_tween = null
|
||||||
|
if not faded_to_black:
|
||||||
|
visible = false
|
||||||
|
transition_completed.emit(generation, faded_to_black)
|
||||||
1
ui/screen_fade.gd.uid
Normal file
1
ui/screen_fade.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cypipneoh61j3
|
||||||
33
ui/ui_palette.gd
Normal file
33
ui/ui_palette.gd
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
class_name UIPalette
|
||||||
|
extends RefCounted
|
||||||
|
|
||||||
|
const PRIMARY := Color("35b9c7")
|
||||||
|
const SECONDARY := Color("ffd166")
|
||||||
|
const SUCCESS := Color("46c878")
|
||||||
|
const WARNING := Color("ffb347")
|
||||||
|
const DANGER := Color("ef5b62")
|
||||||
|
const TEXT := Color("f4f7f8")
|
||||||
|
const MUTED_TEXT := Color("aebbc2")
|
||||||
|
const DISABLED := Color("66747b")
|
||||||
|
const PANEL := Color("19313a")
|
||||||
|
const ELEVATED_PANEL := Color("244550")
|
||||||
|
|
||||||
|
const RARITY_COMMON := Color("e8eef0")
|
||||||
|
const RARITY_UNCOMMON := Color("58d279")
|
||||||
|
const RARITY_RARE := Color("5596f6")
|
||||||
|
const RARITY_EPIC := Color("b176e8")
|
||||||
|
const RARITY_LEGENDARY := Color("f276b3")
|
||||||
|
|
||||||
|
|
||||||
|
static func get_rarity_color(rarity: int) -> Color:
|
||||||
|
match rarity:
|
||||||
|
1:
|
||||||
|
return RARITY_UNCOMMON
|
||||||
|
2:
|
||||||
|
return RARITY_RARE
|
||||||
|
3:
|
||||||
|
return RARITY_EPIC
|
||||||
|
4:
|
||||||
|
return RARITY_LEGENDARY
|
||||||
|
_:
|
||||||
|
return RARITY_COMMON
|
||||||
1
ui/ui_palette.gd.uid
Normal file
1
ui/ui_palette.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://d4g6ks171n65j
|
||||||
46
world/player_water_trigger.gd
Normal file
46
world/player_water_trigger.gd
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
class_name PlayerWaterTrigger
|
||||||
|
extends Area3D
|
||||||
|
|
||||||
|
signal recovery_requested(player: Player, surface_height: float)
|
||||||
|
|
||||||
|
@export var surface_height: float = 0.2
|
||||||
|
@export_range(0.0, 2.0, 0.05) var entry_depth_threshold: float = 0.35
|
||||||
|
|
||||||
|
var _tracked_players: Array[Player] = []
|
||||||
|
var _triggered_players: Dictionary[StringName, bool] = {}
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
body_entered.connect(_on_body_entered)
|
||||||
|
body_exited.connect(_on_body_exited)
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(_delta: float) -> void:
|
||||||
|
for player: Player in _tracked_players.duplicate():
|
||||||
|
if not is_instance_valid(player):
|
||||||
|
_tracked_players.erase(player)
|
||||||
|
continue
|
||||||
|
var player_key: StringName = StringName(str(player.get_instance_id()))
|
||||||
|
if _triggered_players.has(player_key):
|
||||||
|
continue
|
||||||
|
if (
|
||||||
|
player.get_body_center_position().y
|
||||||
|
<= surface_height - entry_depth_threshold
|
||||||
|
):
|
||||||
|
_triggered_players[player_key] = true
|
||||||
|
recovery_requested.emit(player, surface_height)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
var player: Player = body as Player
|
||||||
|
if player == null or player in _tracked_players:
|
||||||
|
return
|
||||||
|
_tracked_players.append(player)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_exited(body: Node3D) -> void:
|
||||||
|
var player: Player = body as Player
|
||||||
|
if player == null:
|
||||||
|
return
|
||||||
|
_tracked_players.erase(player)
|
||||||
|
_triggered_players.erase(StringName(str(player.get_instance_id())))
|
||||||
1
world/player_water_trigger.gd.uid
Normal file
1
world/player_water_trigger.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dnlbnlimgxoc2
|
||||||
9
world/safe_respawn_point.gd
Normal file
9
world/safe_respawn_point.gd
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
class_name SafeRespawnPoint
|
||||||
|
extends Marker3D
|
||||||
|
|
||||||
|
@export var enabled: bool = true
|
||||||
|
|
||||||
|
|
||||||
|
func get_horizontal_distance_squared(world_position: Vector3) -> float:
|
||||||
|
var offset: Vector3 = global_position - world_position
|
||||||
|
return Vector2(offset.x, offset.z).length_squared()
|
||||||
1
world/safe_respawn_point.gd.uid
Normal file
1
world/safe_respawn_point.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://df2lsduguegxh
|
||||||
18
world/test_world.gd
Normal file
18
world/test_world.gd
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
class_name TestWorld
|
||||||
|
extends Node3D
|
||||||
|
|
||||||
|
@onready var _water_trigger: PlayerWaterTrigger = %PlayerWaterTrigger
|
||||||
|
@onready var _safe_respawn_points: Node3D = %SafeRespawnPoints
|
||||||
|
|
||||||
|
|
||||||
|
func get_player_water_trigger() -> PlayerWaterTrigger:
|
||||||
|
return _water_trigger
|
||||||
|
|
||||||
|
|
||||||
|
func get_safe_respawn_points() -> Array[SafeRespawnPoint]:
|
||||||
|
var points: Array[SafeRespawnPoint] = []
|
||||||
|
for child: Node in _safe_respawn_points.get_children():
|
||||||
|
var point: SafeRespawnPoint = child as SafeRespawnPoint
|
||||||
|
if point != null:
|
||||||
|
points.append(point)
|
||||||
|
return points
|
||||||
1
world/test_world.gd.uid
Normal file
1
world/test_world.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bclc786v5xw8c
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
[gd_scene load_steps=14 format=3]
|
[gd_scene load_steps=18 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="1_water_region"]
|
[ext_resource type="Script" path="res://world/fishable_water_region.gd" id="1_water_region"]
|
||||||
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="2_fish_pool"]
|
[ext_resource type="Resource" path="res://fish/pools/test_water_pool.tres" id="2_fish_pool"]
|
||||||
|
[ext_resource type="Script" path="res://world/test_world.gd" id="3_world"]
|
||||||
|
[ext_resource type="Script" path="res://world/player_water_trigger.gd" id="4_water_trigger"]
|
||||||
|
[ext_resource type="Script" path="res://world/safe_respawn_point.gd" id="5_safe_point"]
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="GroundShape"]
|
[sub_resource type="BoxShape3D" id="GroundShape"]
|
||||||
size = Vector3(30, 1, 30)
|
size = Vector3(30, 1, 30)
|
||||||
|
|
@ -30,6 +33,12 @@ size = Vector3(40, 0.16, 19.5)
|
||||||
[sub_resource type="BoxShape3D" id="FishableShoreShape"]
|
[sub_resource type="BoxShape3D" id="FishableShoreShape"]
|
||||||
size = Vector3(17.5, 0.16, 5.5)
|
size = Vector3(17.5, 0.16, 5.5)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="PlayerWaterShape"]
|
||||||
|
size = Vector3(40, 5, 19.5)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="PlayerWaterShoreShape"]
|
||||||
|
size = Vector3(17.5, 5, 5.5)
|
||||||
|
|
||||||
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
[sub_resource type="StandardMaterial3D" id="WaterMaterial"]
|
||||||
transparency = 1
|
transparency = 1
|
||||||
albedo_color = Color(0.1, 0.45, 0.7, 0.72)
|
albedo_color = Color(0.1, 0.45, 0.7, 0.72)
|
||||||
|
|
@ -43,6 +52,7 @@ ambient_light_color = Color(0.65, 0.72, 0.8, 1)
|
||||||
ambient_light_energy = 0.65
|
ambient_light_energy = 0.65
|
||||||
|
|
||||||
[node name="TestWorld" type="Node3D"]
|
[node name="TestWorld" type="Node3D"]
|
||||||
|
script = ExtResource("3_world")
|
||||||
|
|
||||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
environment = SubResource("Environment")
|
environment = SubResource("Environment")
|
||||||
|
|
@ -94,3 +104,41 @@ shape = SubResource("FishableShoreShape")
|
||||||
[node name="ShoreRight" type="CollisionShape3D" parent="FishableWater"]
|
[node name="ShoreRight" type="CollisionShape3D" parent="FishableWater"]
|
||||||
position = Vector3(11.25, 0, 12.5)
|
position = Vector3(11.25, 0, 12.5)
|
||||||
shape = SubResource("FishableShoreShape")
|
shape = SubResource("FishableShoreShape")
|
||||||
|
|
||||||
|
[node name="PlayerWaterTrigger" type="Area3D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
position = Vector3(0, -2.3, -29.75)
|
||||||
|
collision_layer = 8
|
||||||
|
collision_mask = 2
|
||||||
|
script = ExtResource("4_water_trigger")
|
||||||
|
surface_height = 0.2
|
||||||
|
|
||||||
|
[node name="DeepWater" type="CollisionShape3D" parent="PlayerWaterTrigger"]
|
||||||
|
shape = SubResource("PlayerWaterShape")
|
||||||
|
|
||||||
|
[node name="ShoreLeft" type="CollisionShape3D" parent="PlayerWaterTrigger"]
|
||||||
|
position = Vector3(-11.25, 0, 12.5)
|
||||||
|
shape = SubResource("PlayerWaterShoreShape")
|
||||||
|
|
||||||
|
[node name="ShoreRight" type="CollisionShape3D" parent="PlayerWaterTrigger"]
|
||||||
|
position = Vector3(11.25, 0, 12.5)
|
||||||
|
shape = SubResource("PlayerWaterShoreShape")
|
||||||
|
|
||||||
|
[node name="SafeRespawnPoints" type="Node3D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
|
||||||
|
[node name="DockApproach" type="Marker3D" parent="SafeRespawnPoints"]
|
||||||
|
position = Vector3(0, 0.58, -9)
|
||||||
|
script = ExtResource("5_safe_point")
|
||||||
|
|
||||||
|
[node name="WestShore" type="Marker3D" parent="SafeRespawnPoints"]
|
||||||
|
position = Vector3(-11.5, 0.58, -11.5)
|
||||||
|
script = ExtResource("5_safe_point")
|
||||||
|
|
||||||
|
[node name="EastShore" type="Marker3D" parent="SafeRespawnPoints"]
|
||||||
|
position = Vector3(11.5, 0.58, -11.5)
|
||||||
|
script = ExtResource("5_safe_point")
|
||||||
|
|
||||||
|
[node name="DockEnd" type="Marker3D" parent="SafeRespawnPoints"]
|
||||||
|
position = Vector3(0, 1.08, -17)
|
||||||
|
script = ExtResource("5_safe_point")
|
||||||
|
|
|
||||||
149
world/water_recovery_controller.gd
Normal file
149
world/water_recovery_controller.gd
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
class_name WaterRecoveryController
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
enum RecoveryState {
|
||||||
|
IDLE,
|
||||||
|
BOBBING,
|
||||||
|
FADING_OUT,
|
||||||
|
FADING_IN,
|
||||||
|
}
|
||||||
|
|
||||||
|
@export_range(-1.0, 1.0, 0.01) var water_center_offset: float = 0.0
|
||||||
|
@export_range(0.0, 0.5, 0.005) var bob_amplitude: float = 0.08
|
||||||
|
@export_range(0.1, 10.0, 0.1) var bob_speed: float = 2.4
|
||||||
|
@export_range(0.0, 5.0, 0.05) var pre_fade_bob_duration: float = 1.0
|
||||||
|
@export_range(0.0, 1.0, 0.01) var respawn_height_offset: float = 0.08
|
||||||
|
|
||||||
|
var state: RecoveryState = RecoveryState.IDLE
|
||||||
|
var _player: Player
|
||||||
|
var _fishing_spot: FishingSpot
|
||||||
|
var _game_ui: GameUI
|
||||||
|
var _screen_fade: ScreenFade
|
||||||
|
var _water_trigger: PlayerWaterTrigger
|
||||||
|
var _safe_points: Array[SafeRespawnPoint] = []
|
||||||
|
var _initial_spawn_transform: Transform3D
|
||||||
|
var _entry_position: Vector3
|
||||||
|
var _bob_base_position: Vector3
|
||||||
|
var _bob_elapsed: float = 0.0
|
||||||
|
var _prior_movement_enabled: bool = true
|
||||||
|
var _prior_camera_input_enabled: bool = true
|
||||||
|
var _generation: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
func setup(
|
||||||
|
player: Player,
|
||||||
|
fishing_spot: FishingSpot,
|
||||||
|
game_ui: GameUI,
|
||||||
|
screen_fade: ScreenFade,
|
||||||
|
water_trigger: PlayerWaterTrigger,
|
||||||
|
safe_points: Array[SafeRespawnPoint],
|
||||||
|
) -> void:
|
||||||
|
_player = player
|
||||||
|
_fishing_spot = fishing_spot
|
||||||
|
_game_ui = game_ui
|
||||||
|
_screen_fade = screen_fade
|
||||||
|
_water_trigger = water_trigger
|
||||||
|
_safe_points = safe_points
|
||||||
|
_initial_spawn_transform = player.global_transform
|
||||||
|
if not _water_trigger.recovery_requested.is_connected(
|
||||||
|
_on_recovery_requested
|
||||||
|
):
|
||||||
|
_water_trigger.recovery_requested.connect(_on_recovery_requested)
|
||||||
|
if not _screen_fade.transition_completed.is_connected(
|
||||||
|
_on_fade_transition_completed
|
||||||
|
):
|
||||||
|
_screen_fade.transition_completed.connect(
|
||||||
|
_on_fade_transition_completed
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
if state != RecoveryState.BOBBING or _player == null:
|
||||||
|
return
|
||||||
|
_bob_elapsed += delta
|
||||||
|
var bob_offset: float = sin(_bob_elapsed * bob_speed * TAU) * bob_amplitude
|
||||||
|
_player.global_position = _bob_base_position + Vector3.UP * bob_offset
|
||||||
|
if _bob_elapsed >= pre_fade_bob_duration:
|
||||||
|
state = RecoveryState.FADING_OUT
|
||||||
|
_screen_fade.fade_to_black(_generation)
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
_generation += 1
|
||||||
|
if _screen_fade != null and is_instance_valid(_screen_fade):
|
||||||
|
_screen_fade.reset_immediately()
|
||||||
|
if _player != null and is_instance_valid(_player):
|
||||||
|
_player.set_water_recovery_active(false)
|
||||||
|
_player.set_movement_enabled(_prior_movement_enabled)
|
||||||
|
_player.set_camera_input_enabled(_prior_camera_input_enabled)
|
||||||
|
state = RecoveryState.IDLE
|
||||||
|
|
||||||
|
|
||||||
|
func _on_recovery_requested(
|
||||||
|
triggered_player: Player,
|
||||||
|
surface_height: float,
|
||||||
|
) -> void:
|
||||||
|
if (
|
||||||
|
state != RecoveryState.IDLE
|
||||||
|
or triggered_player != _player
|
||||||
|
or not is_instance_valid(triggered_player)
|
||||||
|
):
|
||||||
|
return
|
||||||
|
_generation += 1
|
||||||
|
_entry_position = _player.global_position
|
||||||
|
_game_ui.close_player_menu()
|
||||||
|
_fishing_spot.begin_water_recovery()
|
||||||
|
_prior_movement_enabled = _player.is_movement_enabled()
|
||||||
|
_prior_camera_input_enabled = _player.is_camera_input_enabled()
|
||||||
|
_player.set_movement_enabled(false)
|
||||||
|
_player.set_camera_input_enabled(false)
|
||||||
|
_player.set_water_recovery_active(true)
|
||||||
|
_bob_base_position = _player.global_position
|
||||||
|
_bob_base_position.y = (
|
||||||
|
surface_height
|
||||||
|
+ water_center_offset
|
||||||
|
- _player.get_body_center_height()
|
||||||
|
)
|
||||||
|
_player.global_position = _bob_base_position
|
||||||
|
_bob_elapsed = 0.0
|
||||||
|
state = RecoveryState.BOBBING
|
||||||
|
|
||||||
|
|
||||||
|
func _on_fade_transition_completed(
|
||||||
|
generation: int,
|
||||||
|
faded_to_black: bool,
|
||||||
|
) -> void:
|
||||||
|
if generation != _generation:
|
||||||
|
return
|
||||||
|
if faded_to_black and state == RecoveryState.FADING_OUT:
|
||||||
|
_respawn_player()
|
||||||
|
state = RecoveryState.FADING_IN
|
||||||
|
_screen_fade.fade_from_black(_generation)
|
||||||
|
elif not faded_to_black and state == RecoveryState.FADING_IN:
|
||||||
|
_finish_recovery()
|
||||||
|
|
||||||
|
|
||||||
|
func _respawn_player() -> void:
|
||||||
|
var target_transform: Transform3D = _initial_spawn_transform
|
||||||
|
var nearest_distance: float = INF
|
||||||
|
for point: SafeRespawnPoint in _safe_points:
|
||||||
|
if point == null or not is_instance_valid(point) or not point.enabled:
|
||||||
|
continue
|
||||||
|
var distance: float = point.get_horizontal_distance_squared(
|
||||||
|
_entry_position
|
||||||
|
)
|
||||||
|
if distance < nearest_distance:
|
||||||
|
nearest_distance = distance
|
||||||
|
target_transform = point.global_transform
|
||||||
|
target_transform.origin.y += respawn_height_offset
|
||||||
|
_player.global_transform = target_transform
|
||||||
|
_player.velocity = Vector3.ZERO
|
||||||
|
|
||||||
|
|
||||||
|
func _finish_recovery() -> void:
|
||||||
|
_player.set_water_recovery_active(false)
|
||||||
|
_player.set_movement_enabled(_prior_movement_enabled)
|
||||||
|
_player.set_camera_input_enabled(_prior_camera_input_enabled)
|
||||||
|
_fishing_spot.end_water_recovery()
|
||||||
|
state = RecoveryState.IDLE
|
||||||
|
_bob_elapsed = 0.0
|
||||||
1
world/water_recovery_controller.gd.uid
Normal file
1
world/water_recovery_controller.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dvv0ublaoj4gr
|
||||||
Loading…
Add table
Add a link
Reference in a new issue