185 lines
6.0 KiB
GDScript
185 lines
6.0 KiB
GDScript
class_name P102MotionPresenter
|
|
extends "res://p10_1/motion_presenter.gd"
|
|
|
|
const FOGJAW_ID := "EN-R2-10"
|
|
|
|
var drownseed_state := ""
|
|
var drownseed_target := ""
|
|
var drownseed_started := -100.0
|
|
var medic_state := ""
|
|
var medic_target := ""
|
|
var medic_started := -100.0
|
|
var fogjaw_state := ""
|
|
var fogjaw_started := -100.0
|
|
var center_guard_state := ""
|
|
|
|
|
|
func reset(initial_order: Array, safe_index: int) -> void:
|
|
super.reset(initial_order, safe_index)
|
|
drownseed_state = ""
|
|
drownseed_target = ""
|
|
drownseed_started = -100.0
|
|
medic_state = ""
|
|
medic_target = ""
|
|
medic_started = -100.0
|
|
fogjaw_state = ""
|
|
fogjaw_started = -100.0
|
|
center_guard_state = ""
|
|
|
|
|
|
func consume(event: Dictionary, now: float) -> Array:
|
|
var kind := String(event.get("kind", ""))
|
|
var source_id := String(event.get("source_id", ""))
|
|
var target_id := String(event.get("target_id", ""))
|
|
var payload: Dictionary = Dictionary(event.get("payload", {})).duplicate(true)
|
|
var normalized := _normalized_event(event, payload)
|
|
if not normalized.is_empty():
|
|
super.consume(normalized, now)
|
|
|
|
match kind:
|
|
"drownseed_placed":
|
|
drownseed_state = "countdown"
|
|
drownseed_target = actor_order[0] if not actor_order.is_empty() else ""
|
|
drownseed_started = now
|
|
_set_enemy_action(source_id, "telegraph", now, ACTION_DURATION)
|
|
"drownseed_evaded":
|
|
drownseed_state = "evaded"
|
|
drownseed_started = now
|
|
_set_actor_action(drownseed_target, "resist", now, TIDE_DURATION)
|
|
"drownseed_burst":
|
|
drownseed_state = "burst"
|
|
drownseed_started = now
|
|
_set_actor_action(drownseed_target, "hit", now, HIT_DURATION)
|
|
_add_trauma(now, 0.62)
|
|
"mire_medic_heal":
|
|
medic_state = "healing"
|
|
medic_target = target_id
|
|
medic_started = now
|
|
_set_enemy_action(source_id, "telegraph", now, ACTION_DURATION)
|
|
_set_enemy_action(target_id, "telegraph", now, ACTION_DURATION)
|
|
"source_interrupted":
|
|
medic_state = "interrupted"
|
|
medic_started = now
|
|
_set_enemy_action(target_id, "hit", now, HIT_DURATION)
|
|
"enemy_sustain_resolved":
|
|
medic_state = "sustained"
|
|
medic_started = now
|
|
"fogjaw_hidden":
|
|
fogjaw_state = "hidden"
|
|
fogjaw_started = now
|
|
_add_visible_enemy(source_id)
|
|
"fogjaw_center_attack":
|
|
fogjaw_state = "revealed"
|
|
fogjaw_started = now
|
|
_set_enemy_action(source_id, "attack", now, ACTION_DURATION)
|
|
"center_guarded", "center_exposed":
|
|
center_guard_state = "guarded" if kind == "center_guarded" else "exposed"
|
|
var center_actor := _center_actor()
|
|
_set_actor_action(center_actor, "resist" if kind == "center_guarded" else "hit", now, HIT_DURATION)
|
|
if kind == "center_exposed":
|
|
_add_trauma(now, 0.54)
|
|
"prepared_response_succeeded":
|
|
for actor_id in actor_order:
|
|
_set_actor_action(String(actor_id), "resist", now, HIT_DURATION)
|
|
prune(now)
|
|
return actor_order.duplicate()
|
|
|
|
|
|
func enemy_visual(enemy_id: String, now: float, reduced_motion: bool, low_power: bool) -> Dictionary:
|
|
var visual: Dictionary = super.enemy_visual(enemy_id, now, reduced_motion, low_power)
|
|
if enemy_id != FOGJAW_ID:
|
|
return visual
|
|
if fogjaw_state == "hidden":
|
|
visual.alpha = 0.24
|
|
visual.scale = Vector2(0.88, 0.88)
|
|
visual.state = "telegraph"
|
|
elif fogjaw_state == "revealed" and now - fogjaw_started < 1.1:
|
|
var pulse := sin(clampf((now - fogjaw_started) / 1.1, 0.0, 1.0) * PI)
|
|
visual.alpha = 1.0
|
|
visual.scale = Vector2.ONE * (1.0 + pulse * (0.04 if reduced_motion else 0.16))
|
|
return visual
|
|
|
|
|
|
func mechanic_effects(now: float) -> Dictionary:
|
|
return {
|
|
"drownseed": {
|
|
"state": drownseed_state,
|
|
"target_id": drownseed_target,
|
|
"age": maxf(0.0, now - drownseed_started),
|
|
},
|
|
"medic": {
|
|
"state": medic_state,
|
|
"target_id": medic_target,
|
|
"age": maxf(0.0, now - medic_started),
|
|
},
|
|
"fogjaw": {
|
|
"state": fogjaw_state,
|
|
"age": maxf(0.0, now - fogjaw_started),
|
|
},
|
|
"center": {"state": center_guard_state},
|
|
}
|
|
|
|
|
|
func _normalized_event(event: Dictionary, payload: Dictionary) -> Dictionary:
|
|
var kind := String(event.get("kind", ""))
|
|
var source_id := String(event.get("source_id", ""))
|
|
var target_id := String(event.get("target_id", ""))
|
|
var normalized := event.duplicate(true)
|
|
match kind:
|
|
"battle_started", "tide_shift_warning", "battle_terminal":
|
|
_normalize_payload(normalized, payload)
|
|
return normalized
|
|
"wave_entered":
|
|
normalized["enemy_ids"] = [source_id]
|
|
return normalized
|
|
"rear_pull":
|
|
normalized["kind"] = "pull_resisted" if bool(payload.get("resisted", false)) else "pull_committed"
|
|
normalized["enemy_id"] = source_id
|
|
normalized["target_id"] = String(actor_order[-1]) if not actor_order.is_empty() else ""
|
|
if normalized.kind == "pull_committed":
|
|
var reordered := actor_order.duplicate()
|
|
if reordered.size() > 1:
|
|
reordered.push_front(reordered.pop_back())
|
|
normalized["order_after"] = reordered
|
|
return normalized
|
|
"healing_denial_attached":
|
|
normalized["enemy_id"] = source_id
|
|
normalized["target_id"] = String(actor_order[-1]) if not actor_order.is_empty() else ""
|
|
return normalized
|
|
"indexed_mud_marked":
|
|
normalized["kind"] = "indexed_bank_marked"
|
|
normalized["position_index"] = current_safe_index
|
|
return normalized
|
|
"tide_shifted":
|
|
normalized["kind"] = "tide_followed" if bool(payload.get("followed", false)) else "tide_shifted_while_holding"
|
|
normalized["safe_index"] = int(payload.get("safe_index", current_safe_index))
|
|
normalized["wet_targets"] = [] if bool(payload.get("followed", false)) else actor_order.duplicate()
|
|
return normalized
|
|
"allied_basic":
|
|
normalized["actor_id"] = source_id
|
|
return normalized
|
|
"authoritative_damage":
|
|
_normalize_payload(normalized, payload)
|
|
return normalized
|
|
"fallen":
|
|
normalized["kind"] = "recruit_fallen"
|
|
normalized["recruit_id"] = target_id
|
|
return normalized
|
|
return {}
|
|
|
|
|
|
func _normalize_payload(event: Dictionary, payload: Dictionary) -> void:
|
|
for key in payload:
|
|
event[key] = payload[key]
|
|
|
|
|
|
func _add_visible_enemy(enemy_id: String) -> void:
|
|
if not enemy_id.is_empty() and enemy_id not in visible_enemy_ids:
|
|
visible_enemy_ids.append(enemy_id)
|
|
|
|
|
|
func _center_actor() -> String:
|
|
if actor_order.is_empty():
|
|
return ""
|
|
return String(actor_order[actor_order.size() / 2])
|