Working on state for location
This commit is contained in:
1 parent
e0968b5522
commit
b01e970554
13 files changed
+494
-101
No files matched your search
+193
-58
@@ -1,4 +1,4 @@
|
||||
#include "Location.h"
|
||||
#include "Location.h"
|
||||
#include "utils/Utils.h"
|
||||
#include "render/OpenGlExtensions.h"
|
||||
#include <iostream>
|
||||
@@ -49,6 +49,40 @@ namespace ZL
|
||||
{
|
||||
}
|
||||
|
||||
// ---- Pointer-to-index helpers ----
|
||||
|
||||
InteractiveObject* Location::getTargetInteractiveObject()
|
||||
{
|
||||
const int idx = state.targetInteractiveObjectIndex;
|
||||
if (idx < 0 || idx >= static_cast<int>(interactiveObjects.size())) return nullptr;
|
||||
return &interactiveObjects[idx];
|
||||
}
|
||||
|
||||
TeleportZone* Location::getTargetTeleportZone()
|
||||
{
|
||||
const int idx = state.targetTeleportZoneIndex;
|
||||
if (idx < 0 || idx >= static_cast<int>(teleportZones.size())) return nullptr;
|
||||
return &teleportZones[idx];
|
||||
}
|
||||
|
||||
int Location::findInteractiveObjectIndex(const InteractiveObject* obj) const
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(interactiveObjects.size()); ++i) {
|
||||
if (&interactiveObjects[i] == obj) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Location::findTeleportZoneIndex(const TeleportZone* tz) const
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(teleportZones.size()); ++i) {
|
||||
if (&teleportZones[i] == tz) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---- Setup ----
|
||||
|
||||
void Location::setup(const LocationSetup& params, Quest::QuestJournal* journal)
|
||||
{
|
||||
|
||||
@@ -68,7 +102,7 @@ namespace ZL
|
||||
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/new2/gg_stand_idle001_small.anim", CONST_ZIP_FILE);
|
||||
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/new2/gg_walk001_small.anim", CONST_ZIP_FILE);
|
||||
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/new2/gg_stand_to_action001_small.anim", CONST_ZIP_FILE);
|
||||
|
||||
|
||||
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/new2/gg_action_chop001_small.anim", CONST_ZIP_FILE);
|
||||
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK_2, "resources/w/gg/new2/gg_action_stab001_small.anim", CONST_ZIP_FILE);
|
||||
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/new2/gg_action_idle002_small.anim", CONST_ZIP_FILE);
|
||||
@@ -278,6 +312,9 @@ namespace ZL
|
||||
triggerZones.push_back(std::move(tz));
|
||||
}
|
||||
|
||||
// Resize the parallel playerInside vector in state to match
|
||||
state.triggerZonePlayerInside.assign(triggerZones.size(), false);
|
||||
|
||||
std::cout << "[TRIGGER] Loaded " << triggerZones.size() << " trigger zone(s) from " << jsonPath << std::endl;
|
||||
}
|
||||
|
||||
@@ -345,14 +382,17 @@ namespace ZL
|
||||
|
||||
void Location::updateTriggerZones(const Eigen::Vector3f& playerPos)
|
||||
{
|
||||
for (auto& tz : triggerZones) {
|
||||
for (int i = 0; i < static_cast<int>(triggerZones.size()); ++i) {
|
||||
TriggerZone& tz = triggerZones[i];
|
||||
if (!tz.enabled) continue;
|
||||
const float dist = (playerPos - tz.position).norm();
|
||||
if (!tz.playerInside && dist <= tz.radius) {
|
||||
tz.playerInside = true;
|
||||
state.triggerZonePlayerInside[i] = true;
|
||||
scriptEngine.callTriggerEnterCallback(tz.id);
|
||||
} else if (tz.playerInside && dist > tz.radius + tz.hysteresis) {
|
||||
tz.playerInside = false;
|
||||
state.triggerZonePlayerInside[i] = false;
|
||||
scriptEngine.callTriggerExitCallback(tz.id);
|
||||
}
|
||||
}
|
||||
@@ -368,7 +408,7 @@ namespace ZL
|
||||
navigationMaps[i].build(paths[i], CONST_ZIP_FILE);
|
||||
}
|
||||
|
||||
activeNavigationIndex = 0;
|
||||
state.activeNavigationIndex = 0;
|
||||
navigation = navigationMaps.empty() ? nullptr : &navigationMaps[0];
|
||||
|
||||
if (editorMode == EditorMode::Navigation && navigation) {
|
||||
@@ -424,7 +464,7 @@ namespace ZL
|
||||
std::cerr << "[NAV] switchNavigation: index " << index << " out of range\n";
|
||||
return false;
|
||||
}
|
||||
activeNavigationIndex = index;
|
||||
state.activeNavigationIndex = index;
|
||||
navigation = &navigationMaps[index];
|
||||
|
||||
// Force all characters to replan their paths against the new nav map.
|
||||
@@ -461,7 +501,7 @@ namespace ZL
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDarklands) {
|
||||
if (state.isDarklands) {
|
||||
if (!intObj.loadedObject.textureDarklands) continue;
|
||||
} else {
|
||||
if (!intObj.loadedObject.texture) continue;
|
||||
@@ -615,8 +655,8 @@ namespace ZL
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
//renderer.TranslateMatrix({ 0, -6.f, 0 });
|
||||
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
const Eigen::Vector3f& camTarget = player ? player->state.position : Eigen::Vector3f::Zero();
|
||||
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
|
||||
renderer.TranslateMatrix({ 0, -1.f, 0 });
|
||||
@@ -785,9 +825,9 @@ namespace ZL
|
||||
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
const Eigen::Vector3f& camTarget = player ? player->state.position : Eigen::Vector3f::Zero();
|
||||
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
|
||||
renderer.TranslateMatrix({ 0, -1.f, 0 });
|
||||
@@ -897,8 +937,8 @@ namespace ZL
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0, 0, -1.0f * Environment::zoom });
|
||||
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
const Eigen::Vector3f& camTarget = player ? player->state.position : Eigen::Vector3f::Zero();
|
||||
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
|
||||
renderer.TranslateMatrix({ 0, -1.f, 0 });
|
||||
@@ -1044,8 +1084,8 @@ namespace ZL
|
||||
static const float kDawnAmbient[3] = { 0.72f, 0.52f, 0.62f }; // brighter warm pink
|
||||
static const float kNightFogColor[3] = { 0.01f, 0.01f, 0.05f };
|
||||
static const float kDawnFogColor[3] = { 0.50f, 0.44f, 0.47f }; // grey with slight pink
|
||||
const float* ambientColor = isDawn ? kDawnAmbient : kNightAmbient;
|
||||
const float* fogColor = isDawn ? kDawnFogColor : kNightFogColor;
|
||||
const float* ambientColor = state.isDawn ? kDawnAmbient : kNightAmbient;
|
||||
const float* fogColor = state.isDawn ? kDawnFogColor : kNightFogColor;
|
||||
|
||||
if (hasShadows) {
|
||||
drawNightShadowDepthPass(*shadowLight);
|
||||
@@ -1079,8 +1119,8 @@ namespace ZL
|
||||
renderer.LoadIdentity();
|
||||
renderer.TranslateMatrix({ 0, 0, -1.0f * Environment::zoom });
|
||||
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraInclination, Eigen::Vector3f::UnitX())).toRotationMatrix());
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(state.cameraAzimuth, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
const Eigen::Vector3f& camTarget = player ? player->state.position : Eigen::Vector3f::Zero();
|
||||
renderer.TranslateMatrix({ -camTarget.x(), -camTarget.y(), -camTarget.z() });
|
||||
renderer.TranslateMatrix({ 0, -1.f, 0 });
|
||||
@@ -1492,63 +1532,65 @@ namespace ZL
|
||||
for (auto& [idx, t] : npcBumpsPlayerCooldown) t -= deltaS;
|
||||
|
||||
// Check if player reached target interactive object
|
||||
if (!tutorialInteractiveObjectsLocked && targetInteractiveObject && player && !targetInteractiveObject->state.isAnimating) {
|
||||
const Eigen::Vector3f& approachTarget = targetInteractiveObject->state.hasInteractionPosition
|
||||
? targetInteractiveObject->state.interactionPosition
|
||||
: targetInteractiveObject->state.position;
|
||||
if (auto* obj = getTargetInteractiveObject();
|
||||
!state.tutorialInteractiveObjectsLocked && obj && player && !obj->state.isAnimating)
|
||||
{
|
||||
const Eigen::Vector3f& approachTarget = obj->state.hasInteractionPosition
|
||||
? obj->state.interactionPosition
|
||||
: obj->state.position;
|
||||
float distToObject = (player->state.position - approachTarget).norm();
|
||||
|
||||
// If player is close enough to pick up the item
|
||||
if (distToObject <= targetInteractiveObject->state.approachRadius) {
|
||||
if (distToObject <= obj->state.approachRadius) {
|
||||
std::cout << "[PICKUP] Player reached object! Distance: " << distToObject << std::endl;
|
||||
std::cout << "[PICKUP] Calling Lua callback for: " << targetInteractiveObject->loadedObject.name << std::endl;
|
||||
std::cout << "[PICKUP] Calling Lua callback for: " << obj->loadedObject.name << std::endl;
|
||||
|
||||
// Call custom activate function if specified, otherwise use fallback
|
||||
try {
|
||||
if (!targetInteractiveObject->state.activateFunctionName.empty()) {
|
||||
std::cout << "[PICKUP] Using custom function: " << targetInteractiveObject->state.activateFunctionName << std::endl;
|
||||
scriptEngine.callActivateFunction(targetInteractiveObject->state.activateFunctionName);
|
||||
if (!obj->state.activateFunctionName.empty()) {
|
||||
std::cout << "[PICKUP] Using custom function: " << obj->state.activateFunctionName << std::endl;
|
||||
scriptEngine.callActivateFunction(obj->state.activateFunctionName);
|
||||
}
|
||||
else {
|
||||
std::cout << "[PICKUP] Using fallback callback" << std::endl;
|
||||
scriptEngine.callItemPickupCallback(targetInteractiveObject->loadedObject.name);
|
||||
scriptEngine.callItemPickupCallback(obj->loadedObject.name);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[PICKUP] Error calling function: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
targetInteractiveObject = nullptr;
|
||||
state.targetInteractiveObjectIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if player reached target NPC for interaction.
|
||||
if (targetInteractNpcIndex >= 0 && player) {
|
||||
float distToNpc = (player->state.position - npcs[targetInteractNpcIndex]->state.position).norm();
|
||||
if (state.targetInteractNpcIndex >= 0 && player) {
|
||||
float distToNpc = (player->state.position - npcs[state.targetInteractNpcIndex]->state.position).norm();
|
||||
if (distToNpc <= NPC_TALK_DISTANCE) {
|
||||
std::cout << "[NPC] Player reached NPC index " << targetInteractNpcIndex
|
||||
std::cout << "[NPC] Player reached NPC index " << state.targetInteractNpcIndex
|
||||
<< " (distance " << distToNpc << "); firing on_npc_interact" << std::endl;
|
||||
// Stop the player at the talk distance and have the NPC turn to face them.
|
||||
player->setTarget(player->state.position);
|
||||
npcs[targetInteractNpcIndex]->state.faceTargetIndex = CharacterState::kPlayerIndex;
|
||||
npcs[state.targetInteractNpcIndex]->state.faceTargetIndex = CharacterState::kPlayerIndex;
|
||||
try {
|
||||
scriptEngine.callNpcInteractCallback(targetInteractNpcIndex);
|
||||
scriptEngine.callNpcInteractCallback(state.targetInteractNpcIndex);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "[NPC] callback error: " << e.what() << std::endl;
|
||||
}
|
||||
targetInteractNpcIndex = -1;
|
||||
state.targetInteractNpcIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& tz : teleportZones) tz.update(static_cast<float>(delta));
|
||||
|
||||
if (targetTeleportZone && player) {
|
||||
float dist = (player->state.position - targetTeleportZone->position).norm();
|
||||
if (dist <= targetTeleportZone->radius) {
|
||||
std::cout << "[TELEPORT] Player reached teleport zone '" << targetTeleportZone->id << "'" << std::endl;
|
||||
if (onTeleport) onTeleport(targetTeleportZone->destinationLocation, targetTeleportZone->destinationPosition, targetTeleportZone->destinationRotationY);
|
||||
targetTeleportZone = nullptr;
|
||||
if (auto* tz = getTargetTeleportZone(); tz && player) {
|
||||
float dist = (player->state.position - tz->position).norm();
|
||||
if (dist <= tz->radius) {
|
||||
std::cout << "[TELEPORT] Player reached teleport zone '" << tz->id << "'" << std::endl;
|
||||
if (onTeleport) onTeleport(tz->destinationLocation, tz->destinationPosition, tz->destinationRotationY);
|
||||
state.targetTeleportZoneIndex = -1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1596,8 +1638,8 @@ namespace ZL
|
||||
float aspect = (float)Environment::width / (float)Environment::height;
|
||||
float tanHalfFov = tan(CAMERA_FOV_Y * 0.5f);
|
||||
|
||||
float cosAzim = cos(cameraAzimuth), sinAzim = sin(cameraAzimuth);
|
||||
float cosIncl = cos(cameraInclination), sinIncl = sin(cameraInclination);
|
||||
float cosAzim = cos(state.cameraAzimuth), sinAzim = sin(state.cameraAzimuth);
|
||||
float cosIncl = cos(state.cameraInclination), sinIncl = sin(state.cameraInclination);
|
||||
|
||||
Eigen::Vector3f camRight(cosAzim, 0.f, sinAzim);
|
||||
Eigen::Vector3f camForward(sinAzim * cosIncl, -sinIncl, -cosAzim * cosIncl);
|
||||
@@ -1639,9 +1681,9 @@ namespace ZL
|
||||
std::cout << "[CLICK] Player position: (" << player->state.position.x() << ", "
|
||||
<< player->state.position.y() << ", " << player->state.position.z() << ")" << std::endl;
|
||||
|
||||
targetInteractiveObject = clickedObject;
|
||||
targetInteractNpcIndex = -1;
|
||||
targetTeleportZone = nullptr;
|
||||
state.targetInteractiveObjectIndex = findInteractiveObjectIndex(clickedObject);
|
||||
state.targetInteractNpcIndex = -1;
|
||||
state.targetTeleportZoneIndex = -1;
|
||||
player->setTarget(clickedObject->state.hasInteractionPosition
|
||||
? clickedObject->state.interactionPosition
|
||||
: clickedObject->state.position);
|
||||
@@ -1662,13 +1704,13 @@ namespace ZL
|
||||
}
|
||||
}
|
||||
if (npcIndex != -1) {
|
||||
targetInteractiveObject = nullptr;
|
||||
targetTeleportZone = nullptr;
|
||||
state.targetInteractiveObjectIndex = -1;
|
||||
state.targetTeleportZoneIndex = -1;
|
||||
|
||||
if (clickedNpc->state.canAttack) {
|
||||
// Hostile NPC: combat logic walks the player in via attackTargetIndex.
|
||||
player->state.attackTargetIndex = npcIndex;
|
||||
targetInteractNpcIndex = -1;
|
||||
state.targetInteractNpcIndex = -1;
|
||||
|
||||
if (distance <= clickedNpc->state.interactionRadius) {
|
||||
std::cout << "[CLICK] Hostile NPC " << npcIndex << " in range; firing on_npc_interact" << std::endl;
|
||||
@@ -1685,13 +1727,13 @@ namespace ZL
|
||||
player->setTarget(player->state.position);
|
||||
npcs[npcIndex]->state.faceTargetIndex = CharacterState::kPlayerIndex;
|
||||
scriptEngine.callNpcInteractCallback(npcIndex);
|
||||
targetInteractNpcIndex = -1;
|
||||
state.targetInteractNpcIndex = -1;
|
||||
}
|
||||
else {
|
||||
std::cout << "[CLICK] NPC " << npcIndex << " out of talk range (distance " << distance
|
||||
<< " > " << NPC_TALK_DISTANCE << "); walking to NPC..." << std::endl;
|
||||
player->setTarget(clickedNpc->state.position);
|
||||
targetInteractNpcIndex = npcIndex;
|
||||
state.targetInteractNpcIndex = npcIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1712,16 +1754,16 @@ namespace ZL
|
||||
|
||||
if (clickedTeleport) {
|
||||
std::cout << "[CLICK] Clicked teleport zone '" << clickedTeleport->id << "'" << std::endl;
|
||||
targetTeleportZone = clickedTeleport;
|
||||
targetInteractiveObject = nullptr;
|
||||
targetInteractNpcIndex = -1;
|
||||
state.targetTeleportZoneIndex = findTeleportZoneIndex(clickedTeleport);
|
||||
state.targetInteractiveObjectIndex = -1;
|
||||
state.targetInteractNpcIndex = -1;
|
||||
player->setTarget(clickedTeleport->position);
|
||||
player->state.attackTargetIndex = CharacterState::kNoTarget;
|
||||
} else {
|
||||
player->setTarget(Eigen::Vector3f(hit.x(), 0.f, hit.z()));
|
||||
player->state.attackTargetIndex = CharacterState::kNoTarget;
|
||||
targetInteractNpcIndex = -1;
|
||||
targetTeleportZone = nullptr;
|
||||
state.targetInteractNpcIndex = -1;
|
||||
state.targetTeleportZoneIndex = -1;
|
||||
if (onPlayerFloorWalk) onPlayerFloorWalk();
|
||||
}
|
||||
}
|
||||
@@ -1755,12 +1797,12 @@ namespace ZL
|
||||
lastMouseY = eventY;
|
||||
|
||||
const float sensitivity = 0.005f;
|
||||
cameraAzimuth += dx * sensitivity;
|
||||
cameraInclination += dy * sensitivity;
|
||||
state.cameraAzimuth += dx * sensitivity;
|
||||
state.cameraInclination += dy * sensitivity;
|
||||
|
||||
const float minInclination = M_PI * 30.f / 180.f;
|
||||
const float maxInclination = M_PI * 0.5f;
|
||||
cameraInclination = max(minInclination, min(maxInclination, cameraInclination));
|
||||
state.cameraInclination = max(minInclination, min(maxInclination, state.cameraInclination));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1789,5 +1831,98 @@ namespace ZL
|
||||
return dialogueSystem.getFlag(flag);
|
||||
}
|
||||
|
||||
// ---- Save / Load ----
|
||||
|
||||
void Location::saveFullState(nlohmann::json& out) const
|
||||
{
|
||||
// Location-level state
|
||||
nlohmann::json locState;
|
||||
state.save(locState);
|
||||
out["locationState"] = std::move(locState);
|
||||
|
||||
// Player character state
|
||||
if (player) {
|
||||
nlohmann::json ps;
|
||||
player->state.save(ps);
|
||||
out["playerState"] = std::move(ps);
|
||||
}
|
||||
|
||||
// NPC states
|
||||
nlohmann::json npcArr = nlohmann::json::array();
|
||||
for (const auto& npc : npcs) {
|
||||
if (npc) {
|
||||
nlohmann::json ns;
|
||||
npc->state.save(ns);
|
||||
npcArr.push_back(std::move(ns));
|
||||
} else {
|
||||
npcArr.push_back(nullptr);
|
||||
}
|
||||
}
|
||||
out["npcStates"] = std::move(npcArr);
|
||||
|
||||
// Interactive object states
|
||||
nlohmann::json ioArr = nlohmann::json::array();
|
||||
for (const auto& intObj : interactiveObjects) {
|
||||
nlohmann::json ios;
|
||||
intObj.state.save(ios);
|
||||
ioArr.push_back(std::move(ios));
|
||||
}
|
||||
out["interactiveObjectStates"] = std::move(ioArr);
|
||||
|
||||
// Lua global variable state
|
||||
nlohmann::json scriptState;
|
||||
scriptEngine.saveScriptGlobals(scriptState);
|
||||
out["scriptGlobals"] = std::move(scriptState);
|
||||
}
|
||||
|
||||
void Location::loadFullState(const nlohmann::json& in)
|
||||
{
|
||||
// Location-level state
|
||||
if (in.contains("locationState")) {
|
||||
state.load(in["locationState"]);
|
||||
}
|
||||
|
||||
// Re-sync navigation pointer from restored index
|
||||
if (state.activeNavigationIndex >= 0 &&
|
||||
state.activeNavigationIndex < static_cast<int>(navigationMaps.size()))
|
||||
{
|
||||
navigation = &navigationMaps[state.activeNavigationIndex];
|
||||
}
|
||||
|
||||
// Re-sync triggerZones[i].playerInside from state
|
||||
for (int i = 0; i < static_cast<int>(triggerZones.size()); ++i) {
|
||||
if (i < static_cast<int>(state.triggerZonePlayerInside.size())) {
|
||||
triggerZones[i].playerInside = state.triggerZonePlayerInside[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Player character state
|
||||
if (player && in.contains("playerState")) {
|
||||
player->state.load(in["playerState"]);
|
||||
}
|
||||
|
||||
// NPC states
|
||||
if (in.contains("npcStates") && in["npcStates"].is_array()) {
|
||||
const auto& arr = in["npcStates"];
|
||||
for (int i = 0; i < static_cast<int>(arr.size()) && i < static_cast<int>(npcs.size()); ++i) {
|
||||
if (npcs[i] && !arr[i].is_null()) {
|
||||
npcs[i]->state.load(arr[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interactive object states
|
||||
if (in.contains("interactiveObjectStates") && in["interactiveObjectStates"].is_array()) {
|
||||
const auto& arr = in["interactiveObjectStates"];
|
||||
for (int i = 0; i < static_cast<int>(arr.size()) && i < static_cast<int>(interactiveObjects.size()); ++i) {
|
||||
interactiveObjects[i].state.load(arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Lua globals
|
||||
if (in.contains("scriptGlobals")) {
|
||||
scriptEngine.loadScriptGlobals(in["scriptGlobals"]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
Reference in new issue
Block a user