diff --git a/resources/config2/npcs.json b/resources/config2/npcs.json index a63cbb5..a5a1aab 100644 --- a/resources/config2/npcs.json +++ b/resources/config2/npcs.json @@ -37,6 +37,7 @@ "modelCorrectionRotX": 0.0, "modelCorrectionRotY": 180.0, "modelCorrectionRotZ": 0.0, + "interactionRadius": 1.0, "gift": { "id": "ghost_essence", "name": "Ghost's Essence", diff --git a/resources/dialogue/sample_dialogues.json b/resources/dialogue/sample_dialogues.json index 527b7eb..f025255 100644 --- a/resources/dialogue/sample_dialogues.json +++ b/resources/dialogue/sample_dialogues.json @@ -160,7 +160,8 @@ "speaker": "Ghost", "portrait": "resources/ghost_avatar.png", "text": "Some memories never fade.", - "durationMs": 2600 + "durationMs": 2600, + "background": "resources/loading.png" } ] } diff --git a/src/Character.h b/src/Character.h index 6dd1f70..60daade 100644 --- a/src/Character.h +++ b/src/Character.h @@ -47,6 +47,8 @@ public: std::string npcName; bool giftReceived = false; + float interactionRadius = 0.0f; + private: struct AnimationData { BoneSystem model; diff --git a/src/Game.cpp b/src/Game.cpp index c641866..5dd3790 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -656,16 +656,23 @@ namespace ZL // Check if we clicked on an NPC Character* clickedNpc = raycastNpcs(camPos, rayDir); if (clickedNpc && player) { - int npcIndex = -1; - for (size_t i = 0; i < npcs.size(); ++i) { - if (npcs[i].get() == clickedNpc) { - npcIndex = static_cast(i); - break; + float distance = (player->position - clickedNpc->position).norm(); + if (distance <= clickedNpc->interactionRadius) { + int npcIndex = -1; + for (size_t i = 0; i < npcs.size(); ++i) { + if (npcs[i].get() == clickedNpc) { + npcIndex = static_cast(i); + break; + } + } + if (npcIndex != -1) { + std::cout << "[CLICK] NPC interaction (distance " << distance << ")" << std::endl; + scriptEngine.callNpcInteractCallback(npcIndex); } } - if (npcIndex != -1) { - std::cout << "[CLICK] *** SUCCESS: Clicked on NPC index: " << npcIndex << " ***" << std::endl; - scriptEngine.callNpcInteractCallback(npcIndex); + else { + std::cout << "[CLICK] Too far from NPC (distance " << distance + << " > " << clickedNpc->interactionRadius << ")" << std::endl; } } else if (rayDir.y() < -0.001f && player) { diff --git a/src/dialogue/DialogueDatabase.cpp b/src/dialogue/DialogueDatabase.cpp index 77177a3..07f17b2 100644 --- a/src/dialogue/DialogueDatabase.cpp +++ b/src/dialogue/DialogueDatabase.cpp @@ -121,6 +121,7 @@ CutsceneLine DialogueDatabase::parseCutsceneLine(const json& j) { line.text = j.value("text", ""); line.portrait = j.value("portrait", ""); line.sfx = j.value("sfx", ""); + line.background = j.value("background", ""); line.durationMs = j.value("durationMs", 0); line.waitForConfirm = j.value("waitForConfirm", false); return line; diff --git a/src/dialogue/DialogueRuntime.cpp b/src/dialogue/DialogueRuntime.cpp index e7307a2..32fccf1 100644 --- a/src/dialogue/DialogueRuntime.cpp +++ b/src/dialogue/DialogueRuntime.cpp @@ -325,6 +325,7 @@ void DialogueRuntime::startCutscene(const std::string& cutsceneId, const std::st activeCutscene = cutscene; pendingNodeAfterCutscene = nextNodeAfterCutscene; + currentCutsceneBackground = cutscene->background; mode = Mode::PlayingCutscene; currentCutsceneLine = -1; cutsceneTimerMs = 0; @@ -363,12 +364,18 @@ void DialogueRuntime::refreshCutscenePresentation() { } const CutsceneLine& line = activeCutscene->lines[currentCutsceneLine]; + + if (!line.background.empty()) { + currentCutsceneBackground = line.background; + } + presentation.mode = PresentationMode::Cutscene; presentation.speaker = line.speaker; presentation.fullText = line.text; presentation.visibleText = line.text; presentation.portraitPath = line.portrait; - presentation.backgroundPath = activeCutscene->background; + //presentation.backgroundPath = activeCutscene->background; + presentation.backgroundPath = currentCutsceneBackground; presentation.choices.clear(); presentation.selectedChoice = 0; presentation.revealCompleted = true; diff --git a/src/dialogue/DialogueRuntime.h b/src/dialogue/DialogueRuntime.h index f810834..031e9ae 100644 --- a/src/dialogue/DialogueRuntime.h +++ b/src/dialogue/DialogueRuntime.h @@ -64,6 +64,8 @@ private: int currentCutsceneLine = -1; int cutsceneTimerMs = 0; + std::string currentCutsceneBackground; + bool evaluateConditions(const std::vector& conditions) const; void applyEffects(const std::vector& effects); diff --git a/src/dialogue/DialogueTypes.h b/src/dialogue/DialogueTypes.h index 76cd925..0b6bd8b 100644 --- a/src/dialogue/DialogueTypes.h +++ b/src/dialogue/DialogueTypes.h @@ -87,6 +87,7 @@ struct CutsceneLine { std::string text; std::string portrait; std::string sfx; + std::string background; int durationMs = 0; bool waitForConfirm = false; }; diff --git a/src/items/GameObjectLoader.cpp b/src/items/GameObjectLoader.cpp index 151c090..dcff1f8 100644 --- a/src/items/GameObjectLoader.cpp +++ b/src/items/GameObjectLoader.cpp @@ -280,6 +280,7 @@ namespace ZL { data.id = item.value("id", "npc_unknown"); data.name = item.value("name", "Unknown NPC"); data.texturePath = item.value("texturePath", ""); + data.interactionRadius = item.value("interactionRadius", 0.0f); data.animationIdlePath = item.value("animationIdlePath", ""); data.animationWalkPath = item.value("animationWalkPath", ""); @@ -364,6 +365,7 @@ namespace ZL { npc->rotationSpeed = npcData.rotationSpeed; npc->modelScale = npcData.modelScale; npc->position = Eigen::Vector3f(npcData.positionX, npcData.positionY, npcData.positionZ); + npc->interactionRadius = npcData.interactionRadius; // Set NPC metadata npc->npcId = npcData.id; diff --git a/src/items/GameObjectLoader.h b/src/items/GameObjectLoader.h index 575dd00..72be42d 100644 --- a/src/items/GameObjectLoader.h +++ b/src/items/GameObjectLoader.h @@ -57,6 +57,7 @@ namespace ZL { float modelCorrectionRotY = 0.0f; float modelCorrectionRotZ = 0.0f; GiftData gift; + float interactionRadius = 0.0f; }; struct LoadedGameObject {