Unveränderter Ausgangsstand inklusive Masterprompt und Konzeptbildern unter assets/. .godot/ und docs/screenshots/ bleiben laut .gitignore unversioniert; letztere sind unter ../backups gesichert. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
121 lines
5 KiB
GDScript
121 lines
5 KiB
GDScript
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))
|