extends RefCounted ## Shared content abilities: Glutpakt, ten neutral archetypes and five sends. var ready_time: float = 6.0 var _opening_pose_pending: bool = false func start(unit) -> void: match str(unit.data.ability): "g04": _opening_pose_pending = true "w03", "w04": ready_time = 5.0 "w09", "w10": ready_time = 4.0 "s02": unit.grant_shield(unit.max_hp * 0.15) "e08": unit.grant_shield(unit.max_hp * 0.20) func step(unit, combatants: Array, _delta: float) -> void: # Formation previews also call start(); defer the passive pose to combat. if _opening_pose_pending and unit.combat_time > 0.0: _opening_pose_pending = false unit.play_ability() if unit.combat_time + 0.000001 < ready_time: return var ability = str(unit.data.ability) var success = false match ability: "w03", "w04": if unit.hp < unit.max_hp: unit.heal(100.0 if ability == "w04" else 35.0) success = true "w09", "w10": var upgraded = ability == "w10" var allies = nearby(unit, combatants, true, unit.position, 4.5 if upgraded else 4.0, 3 if upgraded else 1, null, true) for ally in allies: if ally.hp < ally.max_hp: ally.heal(80.0 if upgraded else 65.0) ally.ability_flash = 0.5 success = true "g09", "g10": var upgraded = ability == "g10" var allies = nearby(unit, combatants, true, unit.position, 4.0 if upgraded else 3.0, 4 if upgraded else 3, null, true) for ally in allies: ally.apply_effect("hearth_warmth", "damage", 0.15 if upgraded else 0.10, 4.0) if upgraded: ally.heal(45.0) success = not allies.is_empty() "e06": var allies = nearby(unit, combatants, true, unit.position, 4.0, 100, null, true) for ally in allies: if ally.hp < ally.max_hp: # Derive the HP-wave factor exactly, not from rounded max HP. ally.heal(30.0 * float(unit.data.get("hp_factor", 1.0))) success = true break "s03", "e09": var boss = ability == "e09" var victims = nearby(unit, combatants, false, unit.position, 6.0 if boss else 3.0, 3 if boss else 4) for victim in victims: victim.apply_effect("dissonance", "attack_slow", 0.15, 3.0) success = not victims.is_empty() "s05": var victims = nearby(unit, combatants, false, unit.position, 5.0, 1) for victim in victims: victim.apply_effect("rift_wound", "healing_reduction", 0.30, 4.0) success = not victims.is_empty() if success: ready_time = unit.combat_time + (5.0 if ability in ["w03", "w04"] else (4.0 if ability in ["w09", "w10"] else 6.0)) unit.play_ability() func on_hit(unit, primary, combatants: Array, hit_count: int) -> void: var ability = str(unit.data.ability) match ability: "w01", "w02": if hit_count % 3 == 0 and primary.alive: primary.apply_effect("root_grasp", "movement_slow", 0.30 if ability == "w02" else 0.20, 3.0 if ability == "w02" else 2.0) if ability == "w02": primary.apply_effect("root_grasp_attack", "attack_slow", 0.10, 3.0) "w05", "w06": if hit_count % 4 == 0 and primary.alive: primary.apply_dot("seed_burn", 10.0 if ability == "w06" else 3.0, 4.0, int(unit.data.attack_type)) "w07", "w08": if hit_count % 3 == 0: splash(unit, primary, combatants, 0.80 if ability == "w08" else 0.60, 2.5 if ability == "w08" else 2.0, 4 if ability == "w08" else 3) "g01", "g02": if hit_count % 3 == 0 and primary.alive: primary.apply_dot("burn", 12.0 if ability == "g02" else 4.0, 3.0, int(unit.data.attack_type)) "g07": splash(unit, primary, combatants, 0.30, 1.5, 3) "g08": splash(unit, primary, combatants, 0.40, 2.0, 4) "e05": if hit_count % 4 == 0: splash(unit, primary, combatants, 0.40, 1.5, 2) "e07": if hit_count % 4 == 0: splash(unit, primary, combatants, 0.60, 2.0, 3) "e10": if hit_count % 4 == 0: splash(unit, primary, combatants, 0.60, 2.5, 4) "s04": if hit_count % 4 == 0: splash(unit, primary, combatants, 0.50, 2.0, 3) func splash(unit, primary, combatants: Array, factor: float, radius: float, maximum: int) -> void: for victim in nearby(unit, combatants, false, primary.position, radius, maximum, primary): victim.receive_damage(float(unit.data.damage) * factor, int(unit.data.attack_type)) func nearby(unit, combatants: Array, allied: bool, center: Vector3, radius: float, maximum: int, excluded = null, health_priority: bool = false) -> Array: var result: Array = [] for other in combatants: if not other.alive or other.team_id != unit.team_id or other == excluded: continue if (other.is_attacker == unit.is_attacker) != allied: continue if horizontal_distance(other.position, center) <= radius + 0.000001: result.append(other) result.sort_custom(func(a, b): if health_priority and not is_equal_approx(a.hp / a.max_hp, b.hp / b.max_hp): return a.hp / a.max_hp < b.hp / b.max_hp var ad = horizontal_distance(a.position, center) var bd = horizontal_distance(b.position, center) return a.uid < b.uid if is_equal_approx(ad, bd) else ad < bd ) if result.size() > maximum: result.resize(maximum) return result func horizontal_distance(a: Vector3, b: Vector3) -> float: return Vector2(a.x, a.z).distance_to(Vector2(b.x, b.z))