diff --git a/scripts/Main.gd b/scripts/Main.gd index 58577bb..76c0bed 100644 --- a/scripts/Main.gd +++ b/scripts/Main.gd @@ -183,6 +183,8 @@ func _connect_dolphin_signals(dolphin: CharacterBody3D) -> void: dolphin.echolocation_triggered.connect(_on_echolocation) if dolphin.has_signal("hotbar_scroll"): dolphin.hotbar_scroll.connect(inventory.scroll_hotbar) + if dolphin.has_signal("use_consumable_requested"): + dolphin.use_consumable_requested.connect(_on_use_consumable) func _on_net_peer_connected(peer_id: int) -> void: @@ -290,6 +292,43 @@ func _on_block_place(hit_position: Vector3, normal: Vector3) -> void: inventory.remove_item_from_slot(inventory.selected_hotbar, 1) +const CONSUMABLE_EFFECTS: Dictionary = { + 102: {"oxygen": 40.0, "hp": 0.0, "hunger": 0.0, "label": "+40 O₂", "color": Color(0.3, 0.9, 1.0)}, + 103: {"oxygen": 0.0, "hp": 5.0, "hunger": 30.0, "label": "+30 🍴", "color": Color(0.6, 1.0, 0.4)}, + 106: {"oxygen": 0.0, "hp": 50.0, "hunger": 0.0, "label": "+50 ❤", "color": Color(1.0, 0.5, 0.5)}, +} + + +func _on_use_consumable() -> void: + if not is_instance_valid(_my_dolphin): + return + var slot: Variant = inventory.get_selected_item() + if slot == null: + return + var item_id: int = slot["item_id"] + if not CONSUMABLE_EFFECTS.has(item_id): + return + var effect: Dictionary = CONSUMABLE_EFFECTS[item_id] + if effect["oxygen"] > 0.0 and _my_dolphin.has_method("refill_oxygen"): + _my_dolphin.refill_oxygen(effect["oxygen"]) + if effect["hp"] > 0.0 and _my_dolphin.has_method("heal"): + _my_dolphin.heal(effect["hp"]) + if effect["hunger"] > 0.0 and _my_dolphin.has_method("feed"): + _my_dolphin.feed(effect["hunger"]) + inventory.remove_item_from_slot(inventory.selected_hotbar, 1) + AudioManager.play_bubble_sfx(_my_dolphin.global_position) + _spawn_consumable_popup(effect["label"], effect["color"]) + + +func _spawn_consumable_popup(label: String, color: Color) -> void: + if not is_instance_valid(_my_dolphin): + return + var popup_script: Script = load("res://scripts/progression/XpPopup.gd") + if popup_script == null: + return + popup_script.spawn(self, label, _my_dolphin.global_position + Vector3(0, 1.4, 0), color) + + func _on_echolocation(position: Vector3, _radius: float) -> void: AudioManager.play_bubble_sfx(position) var am: Node = get_node_or_null("/root/AchievementManager") diff --git a/scripts/dolphin/DolphinController.gd b/scripts/dolphin/DolphinController.gd index cb9bb1e..84737bb 100644 --- a/scripts/dolphin/DolphinController.gd +++ b/scripts/dolphin/DolphinController.gd @@ -18,6 +18,7 @@ signal hotbar_scroll(direction: int) signal echolocation_triggered(position: Vector3, radius: float) signal stats_changed(oxygen: float, health: float, hunger: float) signal player_died() +signal use_consumable_requested() # --- Internal State --- var oxygen: float @@ -61,6 +62,7 @@ func _setup_input_actions() -> void: "boost": KEY_CTRL, "echolocate": KEY_E, "toggle_inventory": KEY_TAB, + "use_consumable": KEY_F, } for action_name: String in actions: if not InputMap.has_action(action_name): @@ -103,6 +105,8 @@ func _input(event: InputEvent) -> void: _do_raycast_place() if event.is_action_pressed("echolocate"): _trigger_echolocation() + if event.is_action_pressed("use_consumable"): + use_consumable_requested.emit() func _physics_process(delta: float) -> void: @@ -264,6 +268,21 @@ func take_damage(amount: float) -> void: player_died.emit() +func heal(amount: float) -> void: + health = min(max_health, health + amount) + _emit_stats() + + +func feed(amount: float) -> void: + hunger = min(max_hunger, hunger + amount) + _emit_stats() + + +func refill_oxygen(amount: float) -> void: + oxygen = min(max_oxygen, oxygen + amount) + _emit_stats() + + func _trigger_echolocation() -> void: if is_echolocating: return diff --git a/scripts/dolphin/HUD.gd b/scripts/dolphin/HUD.gd index 9805fb0..7e1ac84 100644 --- a/scripts/dolphin/HUD.gd +++ b/scripts/dolphin/HUD.gd @@ -52,6 +52,7 @@ func _ready() -> void: qm.quest_completed.connect(_on_quest_completed) _on_quests_updated() _build_toast_container() + _build_consumable_hint() var am: Node = get_node_or_null("/root/AchievementManager") if am != null: am.achievement_unlocked.connect(_on_achievement_unlocked) @@ -239,6 +240,46 @@ func _on_quest_completed(q: Dictionary) -> void: am.call("play_bubble_sfx", _dolphin.global_position) +var _consumable_hint: Label = null + + +func _build_consumable_hint() -> void: + _consumable_hint = Label.new() + _consumable_hint.anchor_left = 0.5 + _consumable_hint.anchor_right = 0.5 + _consumable_hint.anchor_top = 1.0 + _consumable_hint.anchor_bottom = 1.0 + _consumable_hint.offset_left = -220.0 + _consumable_hint.offset_right = 220.0 + _consumable_hint.offset_top = -105.0 + _consumable_hint.offset_bottom = -85.0 + _consumable_hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER + _consumable_hint.add_theme_font_size_override("font_size", 11) + _consumable_hint.add_theme_color_override("font_color", Color(0.85, 0.95, 1.0, 0.9)) + _consumable_hint.add_theme_color_override("font_outline_color", Color(0, 0, 0, 0.85)) + _consumable_hint.add_theme_constant_override("outline_size", 3) + _consumable_hint.visible = false + add_child(_consumable_hint) + + +func _update_consumable_hint() -> void: + if _consumable_hint == null or not is_instance_valid(_dolphin): + return + var main: Node = get_tree().get_first_node_in_group("main") + if main == null or not ("inventory" in main): + _consumable_hint.visible = false + return + var slot: Variant = main.inventory.get_selected_item() + if slot == null: + _consumable_hint.visible = false + return + if not ItemDatabase.is_consumable(slot["item_id"]): + _consumable_hint.visible = false + return + _consumable_hint.text = "[F] Consommer : %s" % ItemDatabase.get_item_name(slot["item_id"]) + _consumable_hint.visible = true + + func _build_toast_container() -> void: _toast_container = VBoxContainer.new() _toast_container.anchor_left = 0.5 @@ -413,6 +454,7 @@ func _process(delta: float) -> void: _quest_complete_banner.modulate.a = clampf(_quest_banner_timer / 0.6, 0.0, 1.0) _update_toasts(delta) + _update_consumable_hint() if not is_instance_valid(_dolphin): return