#include "CharacterState.h" namespace ZL { bool CharacterState::isMoving() const { Eigen::Vector3f toTarget = walkTarget - position; toTarget.y() = 0.f; return !pathWaypoints.empty() || toTarget.norm() > kWalkThreshold; } Eigen::Vector3f CharacterState::getCurrentNavigationTarget() const { if (!pathWaypoints.empty() && currentWaypointIndex < pathWaypoints.size()) { return pathWaypoints[currentWaypointIndex]; } return walkTarget; } void CharacterState::stopInPlace() { walkTarget = Eigen::Vector3f(position.x(), 0.f, position.z()); requestedWalkTarget = walkTarget; pathWaypoints.clear(); currentWaypointIndex = 0; onArrivedCallback = nullptr; } void CharacterState::setHp(float newHp) { hp = newHp; if (hp < 0.f) hp = 0.f; if (onHpChanged) onHpChanged(hp, initialHp); } void CharacterState::save(nlohmann::json& out) const { out["position"] = { position.x(), position.y(), position.z() }; out["facingAngle"] = facingAngle; out["targetFacingAngle"] = targetFacingAngle; out["hp"] = hp; out["enabled"] = enabled; out["battle_state"] = battle_state; out["currentState"] = static_cast(currentState); out["attack_cooldown"] = attack_cooldown; out["showWeapon"] = showWeapon; out["attackTargetIndex"] = attackTargetIndex; out["faceTargetIndex"] = faceTargetIndex; out["homePosition"] = { homePosition.x(), homePosition.y(), homePosition.z() }; out["walkTarget"] = { walkTarget.x(), walkTarget.y(), walkTarget.z() }; out["requestedWalkTarget"] = { requestedWalkTarget.x(), requestedWalkTarget.y(), requestedWalkTarget.z() }; nlohmann::json wpArr = nlohmann::json::array(); for (const auto& wp : pathWaypoints) { wpArr.push_back({ wp.x(), wp.y(), wp.z() }); } out["pathWaypoints"] = std::move(wpArr); out["currentWaypointIndex"] = currentWaypointIndex; out["homeDriftCheckTimer"] = homeDriftCheckTimer; } void CharacterState::load(const nlohmann::json& in) { auto readVec3 = [](const nlohmann::json& j, Eigen::Vector3f def) -> Eigen::Vector3f { if (j.is_array() && j.size() == 3) return { j[0].get(), j[1].get(), j[2].get() }; return def; }; if (in.contains("position")) position = readVec3(in["position"], position); facingAngle = in.value("facingAngle", facingAngle); targetFacingAngle = in.value("targetFacingAngle", targetFacingAngle); hp = in.value("hp", hp); enabled = in.value("enabled", enabled); battle_state = in.value("battle_state", battle_state); currentState = static_cast(in.value("currentState", static_cast(currentState))); attack_cooldown = in.value("attack_cooldown", attack_cooldown); showWeapon = in.value("showWeapon", showWeapon); attackTargetIndex = in.value("attackTargetIndex", attackTargetIndex); faceTargetIndex = in.value("faceTargetIndex", faceTargetIndex); if (in.contains("homePosition")) homePosition = readVec3(in["homePosition"], homePosition); if (in.contains("walkTarget")) walkTarget = readVec3(in["walkTarget"], walkTarget); if (in.contains("requestedWalkTarget")) requestedWalkTarget = readVec3(in["requestedWalkTarget"], requestedWalkTarget); pathWaypoints.clear(); if (in.contains("pathWaypoints") && in["pathWaypoints"].is_array()) { for (const auto& wp : in["pathWaypoints"]) { pathWaypoints.push_back(readVec3(wp, Eigen::Vector3f::Zero())); } } currentWaypointIndex = in.value("currentWaypointIndex", currentWaypointIndex); homeDriftCheckTimer = in.value("homeDriftCheckTimer", homeDriftCheckTimer); } } // namespace ZL