added so player can cast Flame spell

This commit is contained in:
2026-01-24 01:03:48 +01:00
parent 9b4135b175
commit 262ce5b351
70 changed files with 2352 additions and 65 deletions

View File

@@ -21,6 +21,13 @@ var knockback_time: float = 0.0
var knockback_duration: float = 0.3
var knockback_force: float = 125.0 # Scaled down for 1x scale
# Burn debuff
var burn_debuff_timer: float = 0.0 # Timer for burn debuff
var burn_debuff_duration: float = 5.0 # Burn lasts 5 seconds
var burn_debuff_damage_per_second: float = 1.0 # 1 HP per second
var burn_debuff_visual: Node2D = null # Visual indicator for burn debuff
var burn_damage_timer: float = 0.0 # Timer for burn damage ticks
# Z-axis for flying enemies
var position_z: float = 0.0
var velocity_z: float = 0.0
@@ -95,6 +102,19 @@ func _physics_process(delta):
# Only server (authority) runs AI and physics
if multiplayer.has_multiplayer_peer() and not is_multiplayer_authority():
# Clients only interpolate position (handled by _sync_position)
# But still update burn visual animation on clients
if burn_debuff_visual and is_instance_valid(burn_debuff_visual):
if burn_debuff_visual is Sprite2D:
var burn_sprite = burn_debuff_visual as Sprite2D
var anim_timer = burn_sprite.get_meta("burn_animation_timer", 0.0)
anim_timer += delta
if anim_timer >= 0.1: # ~10 FPS
anim_timer = 0.0
var frame = burn_sprite.get_meta("burn_animation_frame", 0)
frame = (frame + 1) % 16
burn_sprite.frame = frame
burn_sprite.set_meta("burn_animation_frame", frame)
burn_sprite.set_meta("burn_animation_timer", anim_timer)
return
# Update attack timer
@@ -125,6 +145,53 @@ func _physics_process(delta):
# Check collisions with interactable objects
_check_interactable_object_collision()
# Update burn debuff
if burn_debuff_timer > 0.0:
burn_debuff_timer -= delta
burn_damage_timer += delta
# Deal burn damage every second (no knockback)
if burn_damage_timer >= 1.0:
burn_damage_timer = 0.0
# Deal burn damage directly (no knockback, no animation)
if character_stats:
var old_hp = character_stats.hp
character_stats.modify_health(-burn_debuff_damage_per_second)
current_health = character_stats.hp
if character_stats.hp <= 0:
character_stats.no_health.emit()
var actual_damage = old_hp - character_stats.hp
LogManager.log(str(name) + " takes " + str(actual_damage) + " burn damage! Health: " + str(current_health) + "/" + str(character_stats.maxhp), LogManager.CATEGORY_ENEMY)
# Show damage number for burn damage
_show_damage_number(actual_damage, global_position, false, false, false) # Show burn damage number
# Sync burn damage visual to clients
if multiplayer.has_multiplayer_peer() and is_inside_tree():
var enemy_name = name
var enemy_index = get_meta("enemy_index") if has_meta("enemy_index") else -1
var game_world = get_tree().get_first_node_in_group("game_world")
if game_world and game_world.has_method("_sync_enemy_damage_visual"):
game_world._rpc_to_ready_peers("_sync_enemy_damage_visual", [enemy_name, enemy_index, actual_damage, global_position, false])
# Animate burn visual if it's a sprite (only on authority/server)
if is_multiplayer_authority() and burn_debuff_visual and is_instance_valid(burn_debuff_visual):
if burn_debuff_visual is Sprite2D:
var burn_sprite = burn_debuff_visual as Sprite2D
var anim_timer = burn_sprite.get_meta("burn_animation_timer", 0.0)
anim_timer += delta
if anim_timer >= 0.1: # ~10 FPS
anim_timer = 0.0
var frame = burn_sprite.get_meta("burn_animation_frame", 0)
frame = (frame + 1) % 16
burn_sprite.frame = frame
burn_sprite.set_meta("burn_animation_frame", frame)
burn_sprite.set_meta("burn_animation_timer", anim_timer)
# Remove burn debuff when timer expires
if burn_debuff_timer <= 0.0:
burn_debuff_timer = 0.0
burn_damage_timer = 0.0
_remove_burn_debuff()
# Sync position and animation to clients (only server sends)
if multiplayer.has_multiplayer_peer() and is_multiplayer_authority():
# Get state value if enemy has a state variable (for bats/slimes)
@@ -284,7 +351,7 @@ func _find_nearest_player_to_position(pos: Vector2, max_range: float = 100.0) ->
return nearest
func take_damage(amount: float, from_position: Vector2, is_critical: bool = false):
func take_damage(amount: float, from_position: Vector2, is_critical: bool = false, is_burn_damage: bool = false, apply_burn_debuff: bool = false):
# Only process damage on server/authority
if not is_multiplayer_authority():
return
@@ -335,11 +402,17 @@ func take_damage(amount: float, from_position: Vector2, is_critical: bool = fals
actual_damage = amount
LogManager.log(str(name) + " took " + str(amount) + " damage! Health: " + str(current_health) + " (critical: " + str(is_critical) + ")", LogManager.CATEGORY_ENEMY)
# Calculate knockback direction (away from attacker)
var knockback_direction = (global_position - from_position).normalized()
velocity = knockback_direction * knockback_force
is_knocked_back = true
knockback_time = 0.0
# Only apply knockback if not burn damage
if not is_burn_damage:
# Calculate knockback direction (away from attacker)
var knockback_direction = (global_position - from_position).normalized()
velocity = knockback_direction * knockback_force
is_knocked_back = true
knockback_time = 0.0
# Apply burn debuff if requested
if apply_burn_debuff:
_apply_burn_debuff()
_on_take_damage(from_position)
@@ -379,10 +452,10 @@ func take_damage(amount: float, from_position: Vector2, is_critical: bool = fals
call_deferred("_notify_doors_enemy_died")
@rpc("any_peer", "reliable")
func rpc_take_damage(amount: float, from_position: Vector2, is_critical: bool = false):
func rpc_take_damage(amount: float, from_position: Vector2, is_critical: bool = false, is_burn_damage: bool = false, apply_burn_debuff: bool = false):
# RPC version - only process on server/authority
if is_multiplayer_authority():
take_damage(amount, from_position, is_critical)
take_damage(amount, from_position, is_critical, is_burn_damage, apply_burn_debuff)
func _show_damage_number(amount: float, from_position: Vector2, is_critical: bool = false, is_miss: bool = false, is_dodged: bool = false):
# Show damage number (red/orange for crits, cyan for dodge, gray for miss, using dmg_numbers.png font) above enemy
@@ -475,6 +548,91 @@ func _set_animation(_anim_name: String):
# (e.g., enemy_humanoid.gd uses player-like animation system)
pass
func _apply_burn_debuff():
# Apply burn debuff to enemy
if burn_debuff_timer > 0.0:
# Already burning - refresh duration
burn_debuff_timer = burn_debuff_duration
burn_damage_timer = 0.0 # Reset damage timer
LogManager.log(str(name) + " burn debuff refreshed", LogManager.CATEGORY_ENEMY)
return
# Start burn debuff
burn_debuff_timer = burn_debuff_duration
burn_damage_timer = 0.0
LogManager.log(str(name) + " applied burn debuff (" + str(burn_debuff_duration) + " seconds)", LogManager.CATEGORY_ENEMY)
# Create visual indicator
_create_burn_debuff_visual()
# Sync burn debuff to clients
if multiplayer.has_multiplayer_peer() and is_inside_tree():
var enemy_name = name
var enemy_index = get_meta("enemy_index") if has_meta("enemy_index") else -1
var game_world = get_tree().get_first_node_in_group("game_world")
if game_world and game_world.has_method("_sync_enemy_burn_debuff"):
game_world._rpc_to_ready_peers("_sync_enemy_burn_debuff", [enemy_name, enemy_index, true])
func _create_burn_debuff_visual():
# Remove existing visual if any
if burn_debuff_visual and is_instance_valid(burn_debuff_visual):
burn_debuff_visual.queue_free()
# Load burn debuff scene
var burn_debuff_scene = load("res://scenes/debuff_burn.tscn")
if burn_debuff_scene:
burn_debuff_visual = burn_debuff_scene.instantiate()
add_child(burn_debuff_visual)
# Position on enemy (centered)
burn_debuff_visual.position = Vector2(0, 0)
burn_debuff_visual.z_index = 5 # Above enemy sprite
LogManager.log(str(name) + " created burn debuff visual", LogManager.CATEGORY_ENEMY)
else:
# Fallback: create simple sprite if scene doesn't exist
var burn_texture = load("res://assets/gfx/fx/burn.png")
if burn_texture:
var burn_sprite = Sprite2D.new()
burn_sprite.name = "BurnDebuffSprite"
burn_sprite.texture = burn_texture
burn_sprite.hframes = 4
burn_sprite.vframes = 4
burn_sprite.frame = 0
burn_sprite.position = Vector2(0, 0)
burn_sprite.z_index = 5 # Above enemy sprite
burn_sprite.set_meta("burn_animation_frame", 0)
burn_sprite.set_meta("burn_animation_timer", 0.0)
add_child(burn_sprite)
burn_debuff_visual = burn_sprite
func _remove_burn_debuff():
# Remove burn debuff visual
if burn_debuff_visual and is_instance_valid(burn_debuff_visual):
burn_debuff_visual.queue_free()
burn_debuff_visual = null
LogManager.log(str(name) + " burn debuff removed", LogManager.CATEGORY_ENEMY)
# Sync burn debuff removal to clients
if multiplayer.has_multiplayer_peer() and is_inside_tree():
var enemy_name = name
var enemy_index = get_meta("enemy_index") if has_meta("enemy_index") else -1
var game_world = get_tree().get_first_node_in_group("game_world")
if game_world and game_world.has_method("_sync_enemy_burn_debuff"):
game_world._rpc_to_ready_peers("_sync_enemy_burn_debuff", [enemy_name, enemy_index, false])
func _sync_burn_debuff(apply: bool):
# Client-side sync of burn debuff visual
if apply:
if burn_debuff_timer <= 0.0:
# Only create visual if not already burning
_create_burn_debuff_visual()
burn_debuff_timer = burn_debuff_duration
burn_damage_timer = 0.0
else:
# Remove visual
_remove_burn_debuff()
burn_debuff_timer = 0.0
burn_damage_timer = 0.0
func _die():
if is_dead:
return