161 lines
5.4 KiB
C++
161 lines
5.4 KiB
C++
#pragma once
|
|
|
|
#include "render/Renderer.h"
|
|
#include "Environment.h"
|
|
#include "render/TextureManager.h"
|
|
#include "render/TextRenderer.h"
|
|
#include "items/GameObjectLoader.h"
|
|
#include "items/InteractiveObject.h"
|
|
#include "navigation/PathFinder.h"
|
|
#include "render/ShadowMap.h"
|
|
|
|
#include "ScriptEngine.h"
|
|
#include "dialogue/DialogueSystem.h"
|
|
#include "SparkEmitter.h"
|
|
#include "TeleportZone.h"
|
|
#include <functional>
|
|
#include <cstdint>
|
|
#include <unordered_map>
|
|
namespace ZL
|
|
{
|
|
|
|
struct TriggerZone
|
|
{
|
|
std::string id;
|
|
Eigen::Vector3f position = Eigen::Vector3f::Zero();
|
|
float radius = 1.5f;
|
|
float hysteresis = 0.3f; // exit fires at radius + hysteresis to prevent flickering
|
|
bool enabled = true;
|
|
bool playerInside = false; // runtime tracking state, not serialized
|
|
};
|
|
|
|
struct LocationSetup
|
|
{
|
|
std::string gameObjectsJsonPath;
|
|
std::string interactiveObjectsJsonPath;
|
|
std::string npcsJsonPath;
|
|
std::string dialoguesJsonPath;
|
|
std::vector<std::string> navigationJsonPaths;
|
|
std::string scriptPath;
|
|
std::string teleportsJsonPath;
|
|
std::string triggerZonesJsonPath;
|
|
Eigen::Vector3f playerPosition = Eigen::Vector3f::Zero();
|
|
};
|
|
|
|
class Location
|
|
{
|
|
public:
|
|
Location(Renderer& iRenderer, Inventory& iInventory);
|
|
|
|
std::unordered_map<std::string, LoadedGameObject> gameObjects;
|
|
|
|
std::vector<InteractiveObject> interactiveObjects;
|
|
|
|
|
|
std::unique_ptr<Character> player;
|
|
std::vector<std::unique_ptr<Character>> npcs;
|
|
|
|
float cameraAzimuth = 0.0f;
|
|
float cameraInclination = M_PI * 30.f / 180.f;
|
|
|
|
std::vector<PathFinder> navigationMaps;
|
|
PathFinder* navigation = nullptr;
|
|
int activeNavigationIndex = 0;
|
|
|
|
std::unique_ptr<ShadowMap> shadowMap;
|
|
Eigen::Matrix4f cameraViewMatrix = Eigen::Matrix4f::Identity();
|
|
InteractiveObject* targetInteractiveObject = nullptr;
|
|
|
|
// "Walk to NPC, then fire on_npc_interact" — mirrors targetInteractiveObject
|
|
// so a click from outside interactionRadius still leads to a Lua callback
|
|
// once the player gets close enough.
|
|
Character* targetInteractNpc = nullptr;
|
|
int targetInteractNpcIndex = -1;
|
|
|
|
std::unique_ptr<TextRenderer> npcNameText;
|
|
|
|
ScriptEngine scriptEngine;
|
|
Dialogue::DialogueSystem dialogueSystem;
|
|
|
|
std::vector<TeleportZone> teleportZones;
|
|
TeleportZone* targetTeleportZone = nullptr;
|
|
std::function<void(const std::string&, const Eigen::Vector3f&, float)> onTeleport;
|
|
|
|
std::vector<TriggerZone> triggerZones;
|
|
|
|
// Set by Game and kept in sync across location transitions.
|
|
// Read by draw functions and raycast — do not write from Location code.
|
|
bool isDarklands = false;
|
|
|
|
// Set by Game after setup(). Lua and onDeathAnimComplete call this to
|
|
// request the transition without coupling Location to Game directly.
|
|
std::function<bool()> requestDarklandsTransition;
|
|
|
|
// Navigation editor — toggle with 'N', save with 'B', right-click to finalize polygon
|
|
bool navigationEditorMode = false;
|
|
|
|
std::vector<Eigen::Vector3f> navigationEditorPoints;
|
|
VertexRenderStruct navigationEditorPointsMesh;
|
|
std::vector<VertexRenderStruct> navigationEditorNavMeshes;
|
|
std::vector<std::string> navigationMapPaths;
|
|
int navigationEditorObstacleCounter = 0;
|
|
|
|
void navigationEditorBuildNavMeshes();
|
|
void navigationEditorDrawNavigation();
|
|
void navigationEditorRebuildPointsMesh();
|
|
void navigationEditorDrawPoints();
|
|
void navigationEditorHandleLeftClick(const Eigen::Vector3f& hit, bool ctrlHeld);
|
|
void navigationEditorHandleRightClick();
|
|
void navigationEditorSave();
|
|
void navigationEditorReload();
|
|
|
|
// Set by Game when the user's primary pointer (left mouse / single touch)
|
|
// has crossed the tap-vs-drag threshold and is now rotating the camera.
|
|
bool cameraDragging = false;
|
|
int lastMouseX = 0;
|
|
int lastMouseY = 0;
|
|
|
|
|
|
void setup(const LocationSetup& params);
|
|
void setupNavigation(const std::vector<std::string>& paths);
|
|
bool switchNavigation(int index);
|
|
InteractiveObject* raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir);
|
|
Character* raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance = 100.0f);
|
|
|
|
void drawGame();
|
|
void drawShadowDepthPass();
|
|
void drawGameWithShadows();
|
|
void drawGameDarklands();
|
|
|
|
bool setNavigationAreaAvailable(const std::string& areaName, bool available);
|
|
|
|
void update(int64_t deltaMs);
|
|
|
|
void handleDown(int64_t fingerId, int eventX, int eventY, int mx, int my);
|
|
void handleUp(int64_t fingerId, int mx, int my);
|
|
void handleMotion(int64_t fingerId, int eventX, int eventY, int mx, int my);
|
|
|
|
bool requestDialogueStart(const std::string& dialogueId);
|
|
bool requestCutsceneStart(const std::string& cutsceneId);
|
|
void setOnCutsceneFinished(std::function<void(const std::string&)> cb);
|
|
void setDialogueFlag(const std::string& flag, int value);
|
|
int getDialogueFlag(const std::string& flag) const;
|
|
|
|
protected:
|
|
Renderer& renderer;
|
|
Inventory& inventory;
|
|
|
|
private:
|
|
void resolveCharacterCollisions();
|
|
void updateDynamicReplans(int64_t deltaMs);
|
|
void loadTeleportZones(const std::string& jsonPath, const char* zipFile);
|
|
void loadTriggerZones(const std::string& jsonPath, const char* zipFile);
|
|
void updateTriggerZones(const Eigen::Vector3f& playerPos);
|
|
void nudgeCharacterAside(Character* standing, const Eigen::Vector3f& awayFrom);
|
|
|
|
std::unordered_map<Character*, Eigen::Vector3f> lastCharacterPositions;
|
|
std::unordered_map<Character*, int64_t> replanCooldownRemainingMs;
|
|
};
|
|
|
|
} // namespace ZL
|