Working on location exterior

This commit is contained in:
Vladislav Khorev committed 2026-05-21 20:30:49 +03:00
1 parent 3a73f3fbde
commit ffd5bd01a4
35 files changed
+72176 -124

No files matched your search

+114
View File
@@ -8,6 +8,7 @@
#include <cmath>
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <functional>
#include <memory>
#include <cfloat>
@@ -499,6 +500,82 @@ namespace ZL
std::cout << "[NAV_EDITOR] Reloaded navigation maps (" << navigationMapPaths.size() << " maps)\n";
}
void Location::gameObjectEditorPlaceTree()
{
if (!player) return;
static std::mt19937 rng(std::random_device{}());
std::uniform_real_distribution<float> scaleDist(0.8f, 1.2f);
std::uniform_real_distribution<float> rotDist(0.0f, 360.0f);
GameObjectData data;
data.name = "editor_tree_" + std::to_string(++editorPlacedObjectCounter);
data.texturePath = "resources/w/exterior/tree001.png";
data.meshPath = "resources/w/exterior/tree003.txt";
data.rotationX = 0.0f;
data.rotationY = rotDist(rng);
data.rotationZ = 0.0f;
data.positionX = player->position.x();
data.positionY = player->position.y();
data.positionZ = player->position.z();
data.scale = scaleDist(rng);
LoadedGameObject obj = GameObjectLoader::buildLoadedObject(data, renderer, CONST_ZIP_FILE);
obj.mesh.data.Move({ data.positionX, data.positionY, data.positionZ });
obj.mesh.RefreshVBO();
gameObjects[data.name] = std::move(obj);
editorPlacedObjects.push_back(data);
std::cout << "[GAME_EDITOR] Placed '" << data.name << "' at ("
<< data.positionX << ", " << data.positionZ
<< ") scale=" << data.scale << " rotY=" << data.rotationY << "\n";
}
void Location::gameObjectEditorSave()
{
if (editorPlacedObjects.empty()) {
std::cout << "[GAME_EDITOR] No editor-placed objects to save\n";
return;
}
std::string baseName;
for (int i = 1; ; ++i) {
char buf[32];
snprintf(buf, sizeof(buf), "saved_objects%03d", i);
baseName = buf;
if (!std::filesystem::exists(baseName + ".json")) break;
}
using json = nlohmann::json;
json j;
j["objects"] = json::array();
for (const auto& d : editorPlacedObjects) {
json obj;
obj["name"] = d.name;
obj["texturePath"] = d.texturePath;
obj["meshPath"] = d.meshPath;
obj["rotationX"] = d.rotationX;
obj["rotationY"] = d.rotationY;
obj["rotationZ"] = d.rotationZ;
obj["positionX"] = d.positionX;
obj["positionY"] = d.positionY;
obj["positionZ"] = d.positionZ;
obj["scale"] = d.scale;
j["objects"].push_back(obj);
}
const std::string filename = baseName + ".json";
std::ofstream out(filename);
if (out.is_open()) {
out << j.dump(4);
std::cout << "[GAME_EDITOR] Saved " << editorPlacedObjects.size()
<< " object(s) to " << filename << "\n";
} else {
std::cerr << "[GAME_EDITOR] Failed to open " << filename << " for writing\n";
}
}
InteractiveObject* Location::raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir) {
if (interactiveObjects.empty()) {
@@ -983,6 +1060,37 @@ namespace ZL
return navigation->setAreaAvailable(areaName, available);
}
int Location::findNpcIndex(const Character* npc) const
{
for (int i = 0; i < static_cast<int>(npcs.size()); ++i) {
if (npcs[i].get() == npc) return i;
}
return -1;
}
void Location::fireBumpCallbacks(Character* mover, Character* standing)
{
if (mover->isPlayer) {
// Player walked into a standing NPC
const int idx = findNpcIndex(standing);
if (idx < 0) return;
auto& cooldown = npcBumpedByPlayerCooldown[idx];
if (cooldown <= 0.f) {
cooldown = NPC_BUMP_CALLBACK_COOLDOWN;
scriptEngine.callNpcBumpedByPlayerCallback(idx);
}
} else if (standing->isPlayer) {
// Moving NPC walked into the standing player
const int idx = findNpcIndex(mover);
if (idx < 0) return;
auto& cooldown = npcBumpsPlayerCooldown[idx];
if (cooldown <= 0.f) {
cooldown = NPC_BUMP_CALLBACK_COOLDOWN;
scriptEngine.callNpcBumpsPlayerCallback(idx);
}
}
}
void Location::nudgeCharacterAside(Character* standing, const Eigen::Vector3f& awayFrom)
{
if (!standing || standing->isPlayer) return;
@@ -1093,8 +1201,10 @@ namespace ZL
if (aWasMoving && !bWasMoving) {
nudgeCharacterAside(b, a->position);
fireBumpCallbacks(a, b);
} else if (bWasMoving && !aWasMoving) {
nudgeCharacterAside(a, b->position);
fireBumpCallbacks(b, a);
}
}
}
@@ -1188,6 +1298,10 @@ namespace ZL
resolveCharacterCollisions();
updateDynamicReplans(delta);
const float deltaS = static_cast<float>(delta) / 1000.f;
for (auto& [idx, t] : npcBumpedByPlayerCooldown) t -= deltaS;
for (auto& [idx, t] : npcBumpsPlayerCooldown) t -= deltaS;
// Check if player reached target interactive object
if (targetInteractiveObject && player && !targetInteractiveObject->isAnimating) {
float distToObject = (player->position - targetInteractiveObject->position).norm();