75 lines
4.8 KiB
GDScript
75 lines
4.8 KiB
GDScript
extends SceneTree
|
|
|
|
const MotionPresenter = preload("res://p10_1/motion_presenter.gd")
|
|
|
|
var failures: Array[String] = []
|
|
|
|
|
|
func _initialize() -> void:
|
|
call_deferred("run_test")
|
|
|
|
|
|
func run_test() -> void:
|
|
var motion = MotionPresenter.new()
|
|
motion.reset(["front", "rear"], 2)
|
|
motion.consume({"kind": "wave_entered", "enemy_ids": ["hook"]}, 0.0)
|
|
expect(motion.front_visible_enemy() == "hook", "wave entrance exposes one enemy")
|
|
var entering: Dictionary = motion.enemy_visual("hook", 0.1, false, false)
|
|
expect(float(entering.alpha) > 0.0 and float(entering.alpha) < 1.0 and float(entering.offset.x) > 0.0, "wave enters continuously from the right")
|
|
|
|
motion.consume({"kind": "healing_denial_attached", "enemy_id": "hook", "target_id": "rear"}, 0.8)
|
|
expect(motion.healing_denied_target == "rear" and motion.healing_denial_source == "hook", "healing denial remains bound to its authoritative source and target")
|
|
motion.consume({"kind": "indexed_mud_created", "enemy_id": "hook", "target_id": "rear", "crossed_index": 2}, 1.0)
|
|
expect(motion.mud_index == 2, "indexed mud remains on its disclosed slot")
|
|
|
|
var before_order: Array = motion.actor_order.duplicate()
|
|
motion.consume({"kind": "pull_committed", "enemy_id": "hook", "target_id": "rear", "order_after": ["rear", "front"]}, 1.2)
|
|
expect(motion.actor_order != before_order, "pull commits the new visual order")
|
|
var pull_start: Dictionary = motion.actor_visual("rear", 0, -70.0, 1.2, false, false)
|
|
var pull_middle: Dictionary = motion.actor_visual("rear", 0, -70.0, 1.49, false, false)
|
|
var pull_end: Dictionary = motion.actor_visual("rear", 0, -70.0, 1.9, false, false)
|
|
expect(absf(float(pull_start.offset.x)) > absf(float(pull_middle.offset.x)) and absf(float(pull_end.offset.x)) < 0.1, "pull eases from the old slot into the new slot")
|
|
expect(float(pull_middle.offset.y) < -5.0, "pull has a visible lifted crossing arc")
|
|
|
|
motion.consume({"kind": "tide_followed", "safe_index": 3}, 2.0)
|
|
var tide_start: Dictionary = motion.actor_visual("rear", 0, -70.0, 2.0, false, false)
|
|
var tide_middle: Dictionary = motion.actor_visual("rear", 0, -70.0, 2.36, false, false)
|
|
var tide_end: Dictionary = motion.actor_visual("rear", 0, -70.0, 2.8, false, false)
|
|
expect(float(tide_start.offset.x) < float(tide_middle.offset.x) and float(tide_middle.offset.x) < float(tide_end.offset.x), "tide translation is continuous and directionally stable")
|
|
var reduced_tide: Dictionary = motion.actor_visual("rear", 0, -70.0, 2.8, true, false)
|
|
expect(absf(float(reduced_tide.offset.x)) < absf(float(tide_end.offset.x)), "reduced motion preserves state with less travel")
|
|
|
|
motion.consume({"kind": "allied_basic", "actor_id": "front", "damage": 14}, 3.0)
|
|
var anticipation: Dictionary = motion.actor_visual("front", 1, -70.0, 3.08, false, false)
|
|
var contact: Dictionary = motion.actor_visual("front", 1, -70.0, 3.34, false, false)
|
|
var recovery: Dictionary = motion.actor_visual("front", 1, -70.0, 3.70, false, false)
|
|
expect(float(anticipation.offset.x) < float(contact.offset.x) and float(contact.offset.x) > float(recovery.offset.x), "attack has anticipation, contact and recovery")
|
|
expect(String(contact.state) == "attack", "contact selects an attack animation state")
|
|
|
|
motion.consume({"kind": "enemy_basic_damage", "target_id": "rear", "damage": 10}, 3.8)
|
|
var hit: Dictionary = motion.actor_visual("rear", 0, -70.0, 4.08, false, false)
|
|
expect(String(hit.state) == "hit" and float(hit.offset.x) < float(tide_end.offset.x), "enemy contact produces target recoil")
|
|
motion.consume({"kind": "authoritative_damage", "target_id": "rear", "amount": 20, "hp_after": 0}, 4.4)
|
|
expect(motion.playback_held(4.43, false) and not motion.playback_held(4.43, true), "local impact pause respects reduced motion")
|
|
motion.consume({"kind": "recruit_fallen", "recruit_id": "rear", "permanent": true}, 4.5)
|
|
var fallen: Dictionary = motion.actor_visual("rear", 0, -70.0, 5.2, false, false)
|
|
expect(float(fallen.alpha) < 0.3 and absf(float(fallen.rotation)) > 1.0 and String(fallen.state) == "fallen", "Fallen settles into a permanent non-looping collapsed state")
|
|
|
|
for index in range(12):
|
|
motion.consume({"kind": "authoritative_damage", "target_id": "front", "amount": index + 1, "hp_after": 10}, 5.3 + index * 0.01)
|
|
expect(motion.effects.size() == MotionPresenter.MAX_EFFECTS, "overlapping feedback is capped")
|
|
motion.prune(8.0)
|
|
expect(motion.transient_resting(8.0), "transient motion returns to rest")
|
|
if failures.is_empty():
|
|
print("ABG_P10_1_MOTION_PRESENTER_OK wave=enter attack=anticipate,contact,recover pull=eased tide=eased healing_denial=persistent mud=persistent impact=held fallen=collapsed reduced_motion=bounded overlap=8 rest=true authority_mutations=0")
|
|
quit(0)
|
|
else:
|
|
for failure in failures:
|
|
push_error(failure)
|
|
quit(1)
|
|
|
|
|
|
func expect(condition: bool, message: String) -> void:
|
|
if not condition:
|
|
failures.append("P10.1 motion presenter: %s" % message)
|