extends Node3D class_name LilguyBody const LERP_VELOCITY: float = 0.15 @export_category("Objects") @export var _character: CharacterBody3D = null @export var animation_player: AnimationPlayer = null func apply_rotation(_velocity: Vector3) -> void: var new_rotation_y = lerp_angle(rotation.y, atan2(_velocity.x, _velocity.z), LERP_VELOCITY) rotation.y = new_rotation_y func animate(_velocity: Vector3) -> void: if not animation_player: return # Don't override attack animation if it's playing if animation_player.is_playing() and animation_player.current_animation.begins_with("Attack"): return # Check if we're dashing if _character._is_dashing: if animation_player.current_animation != "Jump": _play_animation("Jump") return if not _character.is_on_floor(): if _velocity.y < 0: # Falling - use FallIdle animation _play_animation("FallIdle") else: _play_animation("Jump") return if _velocity: if _character.is_running() and _character.is_on_floor(): # Sprint animation = Run for Lilguy _play_animation("Run") return # Walk animation for normal movement _play_animation("Walk") return # Idle - use FallIdle or Idle if it exists if animation_player.has_animation("Idle"): _play_animation("Idle") else: _play_animation("FallIdle") func _play_animation(anim_name: String): if animation_player and animation_player.has_animation(anim_name): animation_player.play(anim_name) # Silently ignore if animation doesn't exist func play_attack(anim_name: String = "Attack_OneHand") -> void: if animation_player: # Play attack animation once (don't loop) if animation_player.has_animation(anim_name): animation_player.play(anim_name, -1, 1.0) animation_player.animation_set_next(anim_name, "") else: # Fallback to default if animation doesn't exist #push_warning("Animation '%s' not found, using Attack_OneHand" % anim_name) animation_player.play("Attack_OneHand", -1, 1.0) animation_player.animation_set_next("Attack_OneHand", "") ## Apply hue shift to all mesh instances in the character func set_character_color(hue_shift: float) -> void: # Find all MeshInstance3D children recursively var mesh_instances = _find_mesh_instances(self) for mesh in mesh_instances: _apply_hue_to_mesh(mesh, hue_shift) ## Recursively find all MeshInstance3D nodes func _find_mesh_instances(node: Node) -> Array[MeshInstance3D]: var meshes: Array[MeshInstance3D] = [] if node is MeshInstance3D: meshes.append(node) for child in node.get_children(): meshes.append_array(_find_mesh_instances(child)) return meshes ## Apply hue shift to a mesh instance func _apply_hue_to_mesh(mesh_instance: MeshInstance3D, hue_shift: float) -> void: if not mesh_instance: return # Get or create material for each surface for i in range(mesh_instance.get_surface_override_material_count()): var material = mesh_instance.get_surface_override_material(i) # If no override material, get the base material and duplicate it if not material: material = mesh_instance.mesh.surface_get_material(i) if material: material = material.duplicate() mesh_instance.set_surface_override_material(i, material) # Apply hue shift if it's a StandardMaterial3D if material and material is StandardMaterial3D: var std_mat = material as StandardMaterial3D # Create a modulate color from hue var color = Color.from_hsv(hue_shift, 0.6, 1.0) std_mat.albedo_color = color