replace with multiplayer-coop files

This commit is contained in:
2026-01-08 16:47:52 +01:00
parent 1725c615ce
commit 22c7025ac4
1230 changed files with 20555 additions and 17232 deletions

232
src/scripts/enemy_slime.gd Normal file
View File

@@ -0,0 +1,232 @@
extends "res://scripts/enemy_base.gd"
# Slime Enemy - Bounces around, can do minor jumps
enum SlimeState { IDLE, MOVING, JUMPING, DAMAGED, DYING }
var state: SlimeState = SlimeState.IDLE
var state_timer: float = 0.0
var idle_duration: float = 1.0
var move_duration: float = 2.0
var jump_chance: float = 0.3 # 30% chance to jump instead of walk
var detection_range: float = 70.0 # Range to detect players (much smaller)
# Jump mechanics
var is_jumping: bool = false
var jump_anim_frames = [2, 3, 4, 5, 7, 2] # Jump animation sequence
var jump_anim_index: int = 0
# Animation frames
const FRAME_IDLE = 0
const FRAMES_MOVE = [0, 1, 2] # Slow move
const FRAMES_DAMAGE = [8, 9]
const FRAMES_DEATH = [8, 9, 10, 11, 12, 13, 14]
func _ready():
super._ready()
max_health = 20.0
current_health = max_health
move_speed = 35.0 # Slow normally (reduced from 60)
damage = 6.0
state_timer = idle_duration
# Slime is small - adjust collision
if collision_shape and collision_shape.shape:
collision_shape.shape.radius = 6.0 # 12x12 effective size
func _physics_process(delta):
# Always update animation (even when dead, and on clients)
_update_animation(delta)
# Call parent physics process (handles dead state, authority checks, etc.)
super._physics_process(delta)
func _ai_behavior(delta):
# Update state timer
state_timer -= delta
# Find nearest player within detection range
target_player = _find_nearest_player_in_range(detection_range)
# State machine
match state:
SlimeState.IDLE:
_idle_behavior(delta)
SlimeState.MOVING:
_moving_behavior(delta)
SlimeState.JUMPING:
_jumping_behavior(delta)
SlimeState.DAMAGED:
_damaged_behavior(delta)
SlimeState.DYING:
return # Do nothing while dying
# Animation is updated in _physics_process (always, even on clients)
func _idle_behavior(_delta):
velocity = Vector2.ZERO
anim_frame = FRAME_IDLE
# Check if player is nearby
if target_player:
var dist = global_position.distance_to(target_player.global_position)
if dist < detection_range:
# Start moving or jumping
if randf() < jump_chance:
_start_jump()
else:
state = SlimeState.MOVING
state_timer = move_duration
return
# Switch to moving/jumping after idle duration
if state_timer <= 0:
if randf() < jump_chance:
_start_jump()
else:
state = SlimeState.MOVING
state_timer = move_duration
func _moving_behavior(_delta):
# Move slowly towards player
if target_player and is_instance_valid(target_player):
var direction = (target_player.global_position - global_position).normalized()
velocity = direction * move_speed
else:
# Wander randomly
if randf() < 0.02:
var random_dir = Vector2(randf() - 0.5, randf() - 0.5).normalized()
velocity = random_dir * move_speed
# Randomly jump while moving
if state_timer > 0.5 and randf() < 0.01:
_start_jump()
return
# Switch back to idle after move duration
if state_timer <= 0:
state = SlimeState.IDLE
state_timer = idle_duration
func _start_jump():
state = SlimeState.JUMPING
is_jumping = true
jump_anim_index = 0
state_timer = 0.6 # Jump duration
anim_time = 0.0
# Jump towards player if nearby
if target_player and is_instance_valid(target_player):
var direction = (target_player.global_position - global_position).normalized()
velocity = direction * (move_speed * 1.8) # Faster during jump
else:
# Random jump direction
var random_dir = Vector2(randf() - 0.5, randf() - 0.5).normalized()
velocity = random_dir * (move_speed * 1.8)
func _jumping_behavior(_delta):
# Continue moving in jump direction
# Animation is handled in _update_animation
# End jump
if state_timer <= 0:
is_jumping = false
state = SlimeState.MOVING
state_timer = move_duration
func _damaged_behavior(_delta):
velocity = Vector2.ZERO
# Stay in damaged state briefly
if state_timer <= 0:
state = SlimeState.IDLE
state_timer = idle_duration
func _update_animation(delta):
if state == SlimeState.DYING or state == SlimeState.DAMAGED:
return # Animation handled elsewhere
if state == SlimeState.IDLE:
anim_frame = FRAME_IDLE
elif state == SlimeState.JUMPING:
# Animate jump sequence
anim_time += delta
if anim_time >= 0.1: # Fast jump animation
anim_time = 0.0
jump_anim_index += 1
if jump_anim_index < jump_anim_frames.size():
anim_frame = jump_anim_frames[jump_anim_index]
elif state == SlimeState.MOVING:
# Animate slow move (frames 0, 1, 2)
anim_time += delta
if anim_time >= anim_speed:
anim_time = 0.0
var move_index = FRAMES_MOVE.find(anim_frame)
if move_index == -1:
move_index = 0
else:
move_index = (move_index + 1) % FRAMES_MOVE.size()
anim_frame = FRAMES_MOVE[move_index]
# Set sprite frame (slime looks same in all directions)
if sprite:
sprite.frame = anim_frame
func _on_take_damage():
# Play damage animation
state = SlimeState.DAMAGED
state_timer = 0.3
anim_time = 0.0
# Animate damage frames
_play_damage_anim()
func _play_damage_anim():
for frame in FRAMES_DAMAGE:
anim_frame = frame
if sprite:
sprite.frame = frame
await get_tree().create_timer(0.1).timeout
func _die():
if is_dead:
return
# Remove collision layer so they don't collide with players, but still collide with walls
set_collision_layer_value(2, false) # Remove from enemy collision layer (layer 2)
# Set state before calling parent _die()
state = SlimeState.DYING
velocity = Vector2.ZERO
# Call parent _die() which handles death sync and _play_death_animation()
super._die()
func _update_client_visuals():
# Update visuals on clients based on synced state
super._update_client_visuals()
# Update animation based on synced state
_update_animation(0.0) # Update animation immediately when state changes
# Update sprite frame (slime looks same in all directions, no direction mapping)
if sprite:
sprite.frame = anim_frame
func _play_death_animation():
# Play death animation sequence
for frame in FRAMES_DEATH:
anim_frame = frame
if sprite:
sprite.frame = frame
await get_tree().create_timer(0.15).timeout
# Fade out
if sprite:
var fade_tween = create_tween()
fade_tween.tween_property(sprite, "modulate:a", 0.0, 0.3)
await fade_tween.finished
queue_free()