diff --git a/scripts/dolphin/DolphinController.gd b/scripts/dolphin/DolphinController.gd index 90627f1..6a12c8d 100644 --- a/scripts/dolphin/DolphinController.gd +++ b/scripts/dolphin/DolphinController.gd @@ -317,6 +317,10 @@ func take_damage(amount: float) -> void: player_died.emit() +func apply_knockback(impulse: Vector3) -> void: + velocity += impulse + + func heal(amount: float) -> void: health = min(max_health, health + amount) _emit_stats() diff --git a/scripts/inventory/CraftingRecipes.gd b/scripts/inventory/CraftingRecipes.gd index 2e6e48b..310a226 100644 --- a/scripts/inventory/CraftingRecipes.gd +++ b/scripts/inventory/CraftingRecipes.gd @@ -32,6 +32,16 @@ static var RECIPES: Array = [ "inputs": [{"item_id": 105, "count": 2}, {"item_id": 4, "count": 1}], "output": {"item_id": 106, "count": 1} }, + { + "name": "Amulette Tier 2", + "inputs": [{"item_id": 107, "count": 2}, {"item_id": 106, "count": 1}], + "output": {"item_id": 109, "count": 1} + }, + { + "name": "Lampe Portable", + "inputs": [{"item_id": 108, "count": 2}, {"item_id": 100, "count": 1}], + "output": {"item_id": 110, "count": 1} + }, ] diff --git a/scripts/inventory/ItemDatabase.gd b/scripts/inventory/ItemDatabase.gd index 80b5eee..e3fc684 100644 --- a/scripts/inventory/ItemDatabase.gd +++ b/scripts/inventory/ItemDatabase.gd @@ -18,6 +18,10 @@ const ITEM_NAMES: Dictionary = { 104: "Armure ecailles", 105: "Perle", 106: "Amulette de soin", + 107: "Dent de Requin", + 108: "Gelée Bioluminescente", + 109: "Amulette Tier 2", + 110: "Lampe Portable", } const ITEM_COLORS: Dictionary = { @@ -38,6 +42,10 @@ const ITEM_COLORS: Dictionary = { 104: Color(0.1, 0.55, 0.5), 105: Color(0.95, 0.95, 1.0), 106: Color(1.0, 0.85, 0.4), + 107: Color(0.9, 0.9, 0.85), + 108: Color(0.2, 0.85, 0.65), + 109: Color(1.0, 0.75, 0.15), + 110: Color(0.5, 0.9, 1.0), } const PLACEABLE_IDS: Array = [2, 3, 4, 5, 6, 7, 8] diff --git a/scripts/mobs/FishSchool.gd b/scripts/mobs/FishSchool.gd index 36c2d85..7f73d24 100644 --- a/scripts/mobs/FishSchool.gd +++ b/scripts/mobs/FishSchool.gd @@ -110,13 +110,20 @@ func _update_boids(dt: float) -> void: if center_offset.length() > school_radius: vel += -center_offset.normalized() * 1.5 * dt * 4.0 - # --- Player avoidance --- + # --- Player avoidance (boosted player = bigger + faster flee) --- if is_instance_valid(_player): var world_fish_pos: Vector3 = global_position + fish.position var dist_to_player: float = world_fish_pos.distance_to(_player.global_position) - if dist_to_player < 3.0: + var player_boosting: bool = _player.get("is_boosting") if "is_boosting" in _player else false + var flee_radius: float = 6.0 if player_boosting else 3.0 + var flee_force: float = 9.0 if player_boosting else 4.0 + if dist_to_player < flee_radius: var flee: Vector3 = (world_fish_pos - _player.global_position).normalized() - vel += flee * 4.0 * dt * (3.0 - dist_to_player) + # Only flee if player is moving toward the school + var player_vel: Vector3 = _player.velocity if "velocity" in _player else Vector3.ZERO + var toward: bool = player_vel.dot((world_fish_pos - _player.global_position).normalized()) > 0.2 + if toward or player_boosting: + vel += flee * flee_force * dt * (flee_radius - dist_to_player) # Clamp speed if vel.length() > swim_speed * 1.5: diff --git a/scripts/mobs/Jellyfish.gd b/scripts/mobs/Jellyfish.gd index 84b26c4..8e87536 100644 --- a/scripts/mobs/Jellyfish.gd +++ b/scripts/mobs/Jellyfish.gd @@ -160,4 +160,21 @@ func _pick_wander_target() -> void: func take_damage(dmg: float) -> void: health -= dmg if health <= 0.0: + _drop_loot() queue_free() + + +func _drop_loot() -> void: + if not is_instance_valid(_player): + return + var dist: float = global_position.distance_to(_player.global_position) + if dist > 10.0: + return + var main: Node = get_tree().get_first_node_in_group("main") + if main == null or main.get("inventory") == null: + return + # Drop 1 gelée bioluminescente + main.inventory.add_item(108, 1) + var pp: Node = get_node_or_null("/root/PlayerProgress") + if pp != null: + pp.award(8, "méduse", global_position) diff --git a/scripts/mobs/MobSpawner.gd b/scripts/mobs/MobSpawner.gd index 3fd8ed8..8d33ee1 100644 --- a/scripts/mobs/MobSpawner.gd +++ b/scripts/mobs/MobSpawner.gd @@ -178,10 +178,11 @@ func _load_and_instantiate(scene_path: String, pos: Vector3) -> Node3D: func _connect_mob_signal(mob: Node3D) -> void: if mob.has_signal("attacked_player"): if not mob.is_connected("attacked_player", _on_mob_attacked_player): + # Use variadic-safe connect: bind by checking signal params mob.attacked_player.connect(_on_mob_attacked_player) -func _on_mob_attacked_player(dmg: float) -> void: +func _on_mob_attacked_player(dmg: float, kb_dir: Vector3 = Vector3.ZERO) -> void: if is_instance_valid(_player_node): if _player_node.has_method("take_damage"): _player_node.take_damage(dmg) diff --git a/scripts/mobs/Shark.gd b/scripts/mobs/Shark.gd index 1b7f20a..0dac0ed 100644 --- a/scripts/mobs/Shark.gd +++ b/scripts/mobs/Shark.gd @@ -1,12 +1,13 @@ extends CharacterBody3D -signal attacked_player(damage: float) +signal attacked_player(damage: float, knockback_dir: Vector3) @export var max_health: float = 50.0 -@export var damage: float = 15.0 -@export var detection_radius: float = 12.0 +@export var damage: float = 20.0 +@export var detection_radius: float = 15.0 # chase trigger distance (15 units) @export var move_speed: float = 4.0 @export var chase_speed: float = 7.0 +@export var knockback_force: float = 14.0 enum State { PATROL, CHASE, ATTACK } @@ -153,7 +154,13 @@ func _physics_process(delta: float) -> void: State.ATTACK: if is_instance_valid(_player) and _attack_cooldown <= 0.0: - attacked_player.emit(damage) + var kb_dir: Vector3 = (_player.global_position - global_position).normalized() + attacked_player.emit(damage, kb_dir) + # Apply knockback directly on player + if _player.has_method("apply_knockback"): + _player.call("apply_knockback", kb_dir * knockback_force) + elif "velocity" in _player: + _player.velocity += kb_dir * knockback_force _attack_cooldown = 2.0 if player_dist > 3.0: _state = State.CHASE @@ -186,4 +193,26 @@ func _do_patrol(delta: float) -> void: func take_damage(dmg: float) -> void: health -= dmg if health <= 0.0: + _drop_loot() queue_free() + + +func _drop_loot() -> void: + # Give shark tooth to nearby player inventory + if not is_instance_valid(_player): + return + var dist: float = global_position.distance_to(_player.global_position) + if dist > 12.0: + return + var main: Node = get_tree().get_first_node_in_group("main") + if main == null or main.get("inventory") == null: + return + # Drop 1-2 shark teeth + var count: int = randi_range(1, 2) + main.inventory.add_item(107, count) + # Visual popup + if main.has_method("_spawn_xp_popup"): + main.call("_spawn_xp_popup", 0, global_position) + var pp: Node = get_node_or_null("/root/PlayerProgress") + if pp != null: + pp.award(15, "requin", global_position)