class_name AttackAbility extends RunnerAbility const KNOCKBACK_ATTENUATION: float = 0.125 @export var power: float = 50.0 @export var duration: float = 0.5 @export var slowdown_factor: float = 2.0 @export var cooldown: float = 0.25 @export var hit_sound: AudioStream var timer: float = 0.0 func begin(runner: Runner) -> void: timer = duration runner.linear_velocity /= slowdown_factor func integrate_forces( runner: Runner, body_state: PhysicsDirectBodyState3D ) -> void: if timer <= 0.0: runner.change_state(&'run') else: for i in body_state.get_contact_count(): var other := ( body_state.get_contact_collider_object(i) as RigidBody3D ) var other_runner = other as Runner if other and not (other is Platform): runner.audio_player.stream = hit_sound runner.audio_player.play() if other_runner: if other_runner.state != &'ability': other_runner.knockback( runner.global_position, runner.mass*power*KNOCKBACK_ATTENUATION ) else: other.apply_force( runner.mass*( runner.impetus + runner.up_normal ).normalized()*power, body_state.get_contact_collider_position(i) - other.global_position ) func passive(_runner: Runner, delta: float, _active: bool) -> void: timer -= delta func available(_runner: Runner) -> bool: return timer < -cooldown func animation_speed(_runner: Runner) -> float: return 2.0