From 8e0936836ee9c108a34a7a4f01e86be4e3119cfd Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Sun, 19 Apr 2026 07:56:42 +0300 Subject: [PATCH] Some quests --- resources/dialogue/sample_dialogues.json | 136 +++++++++++++++++++++++ src/Location.cpp | 94 ++++++++++++++-- src/Location.h | 6 +- 3 files changed, 226 insertions(+), 10 deletions(-) diff --git a/resources/dialogue/sample_dialogues.json b/resources/dialogue/sample_dialogues.json index 5a5a28b..4552d48 100644 --- a/resources/dialogue/sample_dialogues.json +++ b/resources/dialogue/sample_dialogues.json @@ -83,6 +83,74 @@ "type": "End" } ] + }, + { + "id": "dialogue_gas2", + "start": "line_2", + "nodes": [ + { + "id": "line_2", + "type": "Line", + "speaker": "Кассир", + "portrait": "resources/ghost_avatar.png", + "text": "[Смотрит подозрительно]", + "next": "line_3" + }, + { + "id": "line_3", + "type": "Line", + "speaker": "Игрок", + "portrait": "resources/w/gg/gg2_s_podsvetkoy5.png", + "text": "Что-то случилось?", + "next": "line_4" + }, + { + "id": "line_4", + "type": "Line", + "speaker": "Кассир", + "portrait": "resources/ghost_avatar.png", + "text": "Поставьте машину чуть ближе к колонке пожалуйста.", + "next": "end_1" + }, + { + "id": "end_1", + "type": "End" + } + ] + }, + { + "id": "dialogue_gas3", + "start": "line_2", + "nodes": [ + { + "id": "line_2", + "type": "Line", + "speaker": "Кассир", + "portrait": "resources/ghost_avatar.png", + "text": "[Смотрит подозрительно]", + "next": "line_3" + }, + { + "id": "line_3", + "type": "Line", + "speaker": "Игрок", + "portrait": "resources/w/gg/gg2_s_podsvetkoy5.png", + "text": "Что-то случилось?", + "next": "line_4" + }, + { + "id": "line_4", + "type": "Line", + "speaker": "Кассир", + "portrait": "resources/ghost_avatar.png", + "text": "У вас уже заправлен полный бак.", + "next": "end_1" + }, + { + "id": "end_1", + "type": "End" + } + ] }, { "id": "driving_dialogue_offroad", @@ -169,6 +237,74 @@ "type": "End" } ] + }, + { + "id": "dialogue_girlfriend1", + "start": "line_1", + "nodes": [ + { + "id": "line_1", + "type": "Line", + "speaker": "Ghost", + "portrait": "resources/ghost_avatar.png", + "text": "Ты видел? Он так на меня смотрел, как будто узнал меня.", + "next": "line_2" + }, + { + "id": "line_2", + "type": "Line", + "speaker": "Hero", + "portrait": "resources/w/gg/gg2_s_podsvetkoy5.png", + "text": "Что-то мне стремно, давай поедем отсюда быстрее", + "next": "end_1" + }, + { + "id": "end_1", + "type": "End" + } + ] + }, + { + "id": "dialogue_phone1", + "start": "line_1", + "nodes": [ + { + "id": "line_1", + "type": "Line", + "speaker": "Hero", + "portrait": "resources/w/gg/gg2_s_podsvetkoy5.png", + "text": "Phone 1 У нас бензин кончается.", + "next": "line_2" + }, + { + "id": "line_2", + "type": "Line", + "speaker": "Hero", + "portrait": "resources/w/gg/gg2_s_podsvetkoy5.png", + "text": "Надо заправиться.", + "next": "line_3" + }, + { + "id": "line_3", + "type": "Line", + "speaker": "Ghost", + "portrait": "resources/ghost_avatar.png", + "text": "Хорошо, только давай быстро.", + "next": "line_4" + }, + { + "id": "line_4", + "type": "Line", + "speaker": "Ghost", + "portrait": "resources/ghost_avatar.png", + "text": "Мне как-то не по себе.", + "next": "end_1" + }, + { + "id": "end_1", + "type": "End" + } + ] }, { "id": "test_line_dialogue", diff --git a/src/Location.cpp b/src/Location.cpp index a9d6801..7de726d 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -165,7 +165,8 @@ void Location::setup() { std::cout << "[LOCATION] Setting up FOREST location (custom models only)" << std::endl; - carPosition = { 7, 0, -7 + 200 }; + carPosition ={ 7, 0, -7 + 200 }; + npcCar.position = Vector3f(9, 0, -235); girlfriend->position = Vector3f{ 5, 0, 0.9 + 200 }; girlfriend->setTarget(girlfriend->position); @@ -235,6 +236,7 @@ void Location::setup() else // default { carPosition = { 5.4005, 0, -3.811283 }; + npcCar.position = Vector3f(9, 0, -100); player->position = { 9.43527, 0, 0.952688 }; player->setTarget(player->position); @@ -361,9 +363,9 @@ void Location::setup() carWheelMesh.RefreshVBO(); npcCar.texture = std::make_shared(CreateTextureDataFromPng("resources/e/car_black001.png", CONST_ZIP_FILE)); - npcCar.position = carPosition + Eigen::Vector3f(0, 0.f, 14.f);//Eigen::Vector3f(-12.f, 0.f, 8.f); + //npcCar.position = carPosition + Eigen::Vector3f(0, 0.f, 14.f);//Eigen::Vector3f(-12.f, 0.f, 8.f); npcCar.rotation = 0.f; - npcCar.mode = NpcCar::Mode::FOLLOW_PLAYER; + npcCar.mode = NpcCar::Mode::NONE; /*npcCar.mode = NpcCar::Mode::FOLLOW_WAYPOINTS; npcCar.waypoints = { Eigen::Vector3f(-12.f, 0.f, 8.f), @@ -1144,7 +1146,6 @@ void Location::setup() player->position = carPosition; } - if (girlfriendInCar) { if (!dialoguePlayedDrivingGas1 && !dialogueSystem.isActive()) { @@ -1154,6 +1155,12 @@ void Location::setup() } } + if (!policeFollow && player->position.z() < -240) + { + policeFollow = true; + npcCar.mode = NpcCar::Mode::FOLLOW_PLAYER; + } + } @@ -1216,6 +1223,33 @@ void Location::setup() if (targetInteractiveObject && player) { }*/ + + // After the gas-station sale, once the player has walked away from the + // salesperson, the girlfriend chimes in — fires once. + if (!dialoguePlayedGirlfriend1 && dialoguePlayedGas1 && salesperson && player && !dialogueSystem.isActive()) { + constexpr float minDistance = 8.0f; + const float dx = player->position.x() - salesperson->position.x(); + const float dz = player->position.z() - salesperson->position.z(); + if (std::hypot(dx, dz) > minDistance) { + if (dialogueSystem.startDialogue("dialogue_girlfriend1")) { + dialoguePlayedGirlfriend1 = true; + } + } + } + + // Phone rings once the player drives far from the gas station — fires once, + // and only after the gas-station sale. + if (inCar && dialoguePlayedGas1 && !dialoguePlayedPhone1 && !dialogueSystem.isActive()) { + constexpr float minDistance = 50.0f; + const Eigen::Vector3f gasStationPos(-3.f, 0.f, -11.f); + const float dx = carPosition.x() - gasStationPos.x(); + const float dz = carPosition.z() - gasStationPos.z(); + if (std::hypot(dx, dz) > minDistance) { + if (dialogueSystem.startDialogue("dialogue_phone1")) { + dialoguePlayedPhone1 = true; + } + } + } } void Location::updateNpcCar(int64_t deltaMs) @@ -1241,7 +1275,7 @@ void Location::setup() hasTarget = true; } } - else { + else if (npcCar.mode == NpcCar::Mode::FOLLOW_PLAYER) { //if (x > 0.5) { @@ -1269,10 +1303,10 @@ void Location::setup() } hasTarget = dist > 0.5f; } - /*else - { - throttle = 0.f; - }*/ + } + else + { + throttle = 0.f; } float targetHeading = npcCar.rotation; @@ -1463,7 +1497,49 @@ void Location::setup() return; } + if (salesperson && player && !dialogueSystem.isActive()) { + constexpr float maxTalkDistance = 4.0f; + // cos(45°) — salesperson must lie within the ±45° half-cone in front + // of the player (90° total field of view). + constexpr float coneCosThreshold = 0.7071067f; + + Eigen::Vector3f toSales = salesperson->position - player->position; + toSales.y() = 0.f; + const float dist = toSales.norm(); + + if (dist > 1e-4f && dist <= maxTalkDistance) { + const Eigen::Vector3f playerForward(std::sin(cameraAzimuth), 0.f, -std::cos(cameraAzimuth)); + const Eigen::Vector3f toSalesDir = toSales / dist; + + if (playerForward.dot(toSalesDir) >= coneCosThreshold) { + const Eigen::Vector3f gasStationPos(-3.f, 0.f, -11.f); + const float carDistToStation = std::hypot( + carPosition.x() - gasStationPos.x(), + carPosition.z() - gasStationPos.z()); + + std::string dialogueId; + if (dialoguePlayedGas1) { + dialogueId = "dialogue_gas3"; + } else if (carDistToStation <= 10.f) { + dialogueId = "dialogue_gas1"; + } else { + dialogueId = "dialogue_gas2"; + } + + if (dialogueSystem.startDialogue(dialogueId)) { + // Face each other. cameraAzimuth also drives the player's + // targetFacingAngle, so updating it rotates the player toward + // the salesperson. + cameraAzimuth = std::atan2(toSales.x(), -toSales.z()); + salesperson->targetFacingAngle = std::atan2(-toSales.x(), toSales.z()); + if (dialogueId == "dialogue_gas1") { + dialoguePlayedGas1 = true; + } + } + } + } + } } void Location::handleUp(int64_t fingerId, int mx, int my) { diff --git a/src/Location.h b/src/Location.h index 97a7b01..0aff772 100644 --- a/src/Location.h +++ b/src/Location.h @@ -15,7 +15,7 @@ namespace ZL struct NpcCar { - enum class Mode { FOLLOW_WAYPOINTS, FOLLOW_PLAYER }; + enum class Mode { FOLLOW_WAYPOINTS, FOLLOW_PLAYER, NONE }; Eigen::Vector3f position = Eigen::Vector3f::Zero(); float rotation = 0.f; @@ -110,7 +110,11 @@ namespace ZL bool dialoguePlayedOffroad = false; bool dialoguePlayedCrash = false; bool dialoguePlayedDrivingGas1 = false; + bool dialoguePlayedGas1 = false; + bool dialoguePlayedGirlfriend1 = false; + bool dialoguePlayedPhone1 = false; + bool policeFollow = false; ScriptEngine scriptEngine; Dialogue::DialogueSystem dialogueSystem;