extends SceneTree var failures: Array[String] = [] var died_events := 0 func _initialize() -> void: call_deferred("_run") func _run() -> void: var manager := _create_manager() manager.player_died.connect(_on_player_died) var state: PlayerStateRecord = manager.get_player_state() _check( ( state != null and is_equal_approx(state.get_hunger(), 40.0) and is_equal_approx(state.get_energy(), 100.0) and not state.is_dead() ), "A fresh player should start with embodied needs and no death state", ) for _tick in 3: manager.simulate_tick() _check( ( is_equal_approx(state.get_hunger(), 40.375) and is_equal_approx(state.get_energy(), 99.8125) ), "Simulation ticks should advance the player's hunger and drain energy", ) state.data["hunger"] = 80.0 var hunger_before_eat: float = state.get_hunger() var eaten: float = manager.player_eat(10.0) _check( ( is_equal_approx(eaten, 10.0) and state.get_hunger() < hunger_before_eat and state.get_energy() > 80.0 ), "Eating should reduce the player's own hunger and restore energy", ) var initial_standing: float = manager.get_player_standing().get_standing() manager.get_player_standing().grant_standing(20.0, 1) var standing_after_help: float = manager.get_player_standing().get_standing() state.data["hunger"] = PlayerStateRecord.STACK_THRESHOLD state.data["starvation_ticks"] = (int(state.data["starvation_death_threshold"]) - 1) manager.simulate_tick() _check( ( died_events == 1 and state.is_dead() and is_equal_approx( manager.get_player_standing().get_standing(), standing_after_help * PlayerStateRecord.DEATH_STANDING_PENALTY ) ), "Starvation death should emit a death event and cut standing as a consequence", ) var saved_json: String = manager.serialize_state() var restored := _create_manager(902) _check( restored.restore_state_from_json(saved_json), "The dead player state should restore through the current schema" ) _check( ( restored.get_state_checksum() == manager.get_state_checksum() and restored.get_player_state().is_dead() and restored.get_player_state().get_deaths() == 1 ), "Restore should preserve the embodied death state and checksum", ) _check(manager.respawn_player(), "A dead player should be able to respawn") _check( ( not state.is_dead() and is_equal_approx(state.get_hunger(), PlayerStateRecord.RESET_HUNGER) and is_equal_approx(state.get_energy(), PlayerStateRecord.RESET_ENERGY) ), "Respawn should reset needs to the documented baseline", ) manager.free() restored.free() _finish() func _create_manager(seed_value: int = 901) -> Node: var manager: Node = load("res://simulation/SimulationManager.gd").new() manager.simulation_seed = seed_value manager.debug_logs = false var home_positions: Array[Vector3] = [ Vector3(0.0, 0.0, 0.0), Vector3(2.0, 0.0, 0.0), Vector3(10.0, 0.0, 0.0), Vector3(12.0, 0.0, 0.0), Vector3(30.0, 0.0, 30.0), Vector3(40.0, 0.0, 40.0), ] manager.home_positions = home_positions root.add_child(manager) manager.set_process(false) return manager func _on_player_died(_state: PlayerStateRecord) -> void: died_events += 1 func _check(condition: bool, message: String) -> void: if not condition: failures.append(message) func _finish() -> void: if failures.is_empty(): print("[TEST] Embodied player needs passed") quit(0) return for failure in failures: push_error("[TEST] " + failure) quit(1)