From d557c4b530940fc27e4ff972678b90eb85967082 Mon Sep 17 00:00:00 2001 From: Vladislav Khorev Date: Mon, 20 Apr 2026 00:21:51 +0300 Subject: [PATCH] Working on fog, dialogs, etc --- resources/config2/menu_loose.json | 33 ++++ resources/config2/menu_win.json | 22 +++ resources/shaders/default.vertex | 4 +- resources/shaders/default_desktop.fragment | 10 +- resources/shaders/default_web.fragment | 6 +- resources/shaders/fog.vertex | 15 ++ resources/shaders/fog_desktop.fragment | 18 +++ resources/shaders/fog_skinning.vertex | 54 +++++++ resources/shaders/fog_web.fragment | 18 +++ src/Character.cpp | 5 +- src/Game.cpp | 70 ++++++--- src/Game.h | 5 +- src/Location.cpp | 172 ++++++++++++++++++++- src/Location.h | 2 + src/dialogue/DialogueRuntime.cpp | 21 +++ src/dialogue/DialogueRuntime.h | 1 + src/dialogue/DialogueSystem.cpp | 7 + src/dialogue/DialogueSystem.h | 1 + 18 files changed, 424 insertions(+), 40 deletions(-) create mode 100644 resources/config2/menu_loose.json create mode 100644 resources/config2/menu_win.json create mode 100644 resources/shaders/fog.vertex create mode 100644 resources/shaders/fog_desktop.fragment create mode 100644 resources/shaders/fog_skinning.vertex create mode 100644 resources/shaders/fog_web.fragment diff --git a/resources/config2/menu_loose.json b/resources/config2/menu_loose.json new file mode 100644 index 0000000..774e6bf --- /dev/null +++ b/resources/config2/menu_loose.json @@ -0,0 +1,33 @@ +{ + "root": { + "type": "LinearLayout", + "orientation": "vertical", + "horizontal_align": "center", + "vertical_align": "center", + "spacing": 20, + "x": 0, + "y": 0, + "width": "match_parent", + "height": "match_parent", + "children": [ + { + "type": "StaticImage", + "name": "title", + "width": 512, + "height": 512, + "texture": "resources/e/menu/final_loose.png" + }, + { + "type": "Button", + "name": "backButton", + "width": 512, + "height": 128, + "textures": { + "normal": "resources/e/menu/restart_button.png", + "hover": "resources/e/menu/restart_button.png", + "pressed": "resources/e/menu/restart_button.png" + } + } + ] + } +} \ No newline at end of file diff --git a/resources/config2/menu_win.json b/resources/config2/menu_win.json new file mode 100644 index 0000000..1aa268a --- /dev/null +++ b/resources/config2/menu_win.json @@ -0,0 +1,22 @@ +{ + "root": { + "type": "LinearLayout", + "orientation": "vertical", + "horizontal_align": "center", + "vertical_align": "center", + "spacing": 20, + "x": 0, + "y": 0, + "width": "match_parent", + "height": "match_parent", + "children": [ + { + "type": "StaticImage", + "name": "title", + "width": 512, + "height": 512, + "texture": "resources/e/menu/final_win.png" + } + ] + } +} \ No newline at end of file diff --git a/resources/shaders/default.vertex b/resources/shaders/default.vertex index b385eb9..5f484d9 100644 --- a/resources/shaders/default.vertex +++ b/resources/shaders/default.vertex @@ -4,8 +4,8 @@ varying vec2 texCoord; uniform mat4 ProjectionModelViewMatrix; -void main() +void main() { gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); texCoord = vTexCoord; -} \ No newline at end of file +} diff --git a/resources/shaders/default_desktop.fragment b/resources/shaders/default_desktop.fragment index 3f222ea..02fd68e 100644 --- a/resources/shaders/default_desktop.fragment +++ b/resources/shaders/default_desktop.fragment @@ -2,14 +2,14 @@ uniform sampler2D Texture; varying vec2 texCoord; -void main() +void main() { vec4 color = texture2D(Texture,texCoord).rgba; //gl_FragColor = vec4(color.rgb*0.1 + vec3(0.9, 0.9, 0.9), 1.0); - + if(color.a < 0.1) discard; - + gl_FragColor = color; - -} \ No newline at end of file + +} diff --git a/resources/shaders/default_web.fragment b/resources/shaders/default_web.fragment index dc45229..8bef54c 100644 --- a/resources/shaders/default_web.fragment +++ b/resources/shaders/default_web.fragment @@ -2,12 +2,12 @@ precision mediump float; uniform sampler2D Texture; varying vec2 texCoord; -void main() +void main() { vec4 color = texture2D(Texture,texCoord).rgba; //gl_FragColor = vec4(color.rgb*0.1 + vec3(0.9, 0.9, 0.9), 1.0); if(color.a < 0.1) discard; gl_FragColor = color; - -} \ No newline at end of file + +} diff --git a/resources/shaders/fog.vertex b/resources/shaders/fog.vertex new file mode 100644 index 0000000..1ba2803 --- /dev/null +++ b/resources/shaders/fog.vertex @@ -0,0 +1,15 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +varying vec2 texCoord; +varying float fogDistance; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; + +void main() +{ + vec4 eyePos = ModelViewMatrix * vec4(vPosition.xyz, 1.0); + fogDistance = length(eyePos.xyz); + gl_Position = ProjectionModelViewMatrix * vec4(vPosition.xyz, 1.0); + texCoord = vTexCoord; +} diff --git a/resources/shaders/fog_desktop.fragment b/resources/shaders/fog_desktop.fragment new file mode 100644 index 0000000..bb5b171 --- /dev/null +++ b/resources/shaders/fog_desktop.fragment @@ -0,0 +1,18 @@ +//precisionmediump float; +uniform sampler2D Texture; +varying vec2 texCoord; +varying float fogDistance; + +void main() +{ + vec4 color = texture2D(Texture,texCoord).rgba; + + if(color.a < 0.1) + discard; + + vec3 fogColor = vec3(0.53, 0.81, 0.92); + float fogFactor = clamp((fogDistance - 90.0) / 30.0, 0.0, 1.0); + vec3 finalColor = mix(color.rgb, fogColor, fogFactor); + + gl_FragColor = vec4(finalColor, color.a); +} diff --git a/resources/shaders/fog_skinning.vertex b/resources/shaders/fog_skinning.vertex new file mode 100644 index 0000000..03fb617 --- /dev/null +++ b/resources/shaders/fog_skinning.vertex @@ -0,0 +1,54 @@ +attribute vec3 vPosition; +attribute vec2 vTexCoord; +attribute vec4 aBoneIndices0; +attribute vec2 aBoneIndices1; +attribute vec4 aBoneWeights0; +attribute vec2 aBoneWeights1; + +varying vec2 texCoord; +varying float fogDistance; + +uniform mat4 ProjectionModelViewMatrix; +uniform mat4 ModelViewMatrix; +uniform mat4 uBoneMatrices[64]; + +void main() +{ + vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0); + vec4 originalPos = vec4(vPosition, 1.0); + float totalWeight = 0.0; + + if (aBoneWeights0.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x; + totalWeight += aBoneWeights0.x; + } + if (aBoneWeights0.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y; + totalWeight += aBoneWeights0.y; + } + if (aBoneWeights0.z > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z; + totalWeight += aBoneWeights0.z; + } + if (aBoneWeights0.w > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w; + totalWeight += aBoneWeights0.w; + } + if (aBoneWeights1.x > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x; + totalWeight += aBoneWeights1.x; + } + if (aBoneWeights1.y > 0.0) { + skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y; + totalWeight += aBoneWeights1.y; + } + + if (totalWeight < 0.001) { + skinnedPos = originalPos; + } + + vec4 eyePos = ModelViewMatrix * skinnedPos; + fogDistance = length(eyePos.xyz); + gl_Position = ProjectionModelViewMatrix * skinnedPos; + texCoord = vTexCoord; +} diff --git a/resources/shaders/fog_web.fragment b/resources/shaders/fog_web.fragment new file mode 100644 index 0000000..52c37a9 --- /dev/null +++ b/resources/shaders/fog_web.fragment @@ -0,0 +1,18 @@ +precision mediump float; +uniform sampler2D Texture; +varying vec2 texCoord; +varying float fogDistance; + +void main() +{ + vec4 color = texture2D(Texture,texCoord).rgba; + + if(color.a < 0.1) + discard; + + vec3 fogColor = vec3(0.53, 0.81, 0.92); + float fogFactor = clamp((fogDistance - 90.0) / 30.0, 0.0, 1.0); + vec3 finalColor = mix(color.rgb, fogColor, fogFactor); + + gl_FragColor = vec4(finalColor, color.a); +} diff --git a/src/Character.cpp b/src/Character.cpp index 82452de..576597d 100644 --- a/src/Character.cpp +++ b/src/Character.cpp @@ -291,7 +291,8 @@ void Character::draw(Renderer& renderer) { auto it = animations.find(drawState); if (it == animations.end() || texturePerMesh.empty()) return; - renderer.shaderManager.PushShader(defaultShaderName); + static const std::string fogShaderName = "fog"; + renderer.shaderManager.PushShader(fogShaderName); renderer.RenderUniform1i(textureUniformName, 0); renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, @@ -337,7 +338,7 @@ void Character::drawGpuSkinning(Renderer& renderer) { if (anim.gpuSkinningShaderData.skinningMatrices.empty()) return; } - static const std::string skinningShaderName = "skinning"; + static const std::string skinningShaderName = "fog_skinning"; static const std::string boneMatricesUniform = "uBoneMatrices[0]"; renderer.shaderManager.PushShader(skinningShaderName); diff --git a/src/Game.cpp b/src/Game.cpp index 0de18a9..fb0718e 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -133,6 +133,8 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/planet_land.vertex", "resources/shaders/planet_land_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_web.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("skinning", "resources/shaders/skinning.vertex", "resources/shaders/default_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("fog", "resources/shaders/fog.vertex", "resources/shaders/fog_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("fog_skinning", "resources/shaders/fog_skinning.vertex", "resources/shaders/fog_web.fragment", CONST_ZIP_FILE); #else renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_desktop.fragment", CONST_ZIP_FILE); @@ -142,26 +144,14 @@ namespace ZL renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/planet_land.vertex", "resources/shaders/planet_land_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_desktop.fragment", CONST_ZIP_FILE); renderer.shaderManager.AddShaderFromFiles("skinning", "resources/shaders/skinning.vertex", "resources/shaders/default_desktop.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("fog", "resources/shaders/fog.vertex", "resources/shaders/fog_desktop.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("fog_skinning", "resources/shaders/fog_skinning.vertex", "resources/shaders/fog_desktop.fragment", CONST_ZIP_FILE); #endif std::cout << "Load resurces step 4" << std::endl; - forestLocation = std::make_shared(renderer, inventory, "forest"); - forestLocation->setup(); - forestLocation->onLocationChangeRequest = [this](const std::string& locId) { - this->changeLocation(locId); - }; - - - - defaultLocation = std::make_shared(renderer, inventory, "default"); - defaultLocation->setup(); - defaultLocation->onLocationChangeRequest = [this](const std::string& locId) { - this->changeLocation(locId); - }; - - //currentLocation = defaultLocation; - currentLocation = forestLocation; + createLocations(); + //currentLocation = forestLocation; std::cout << "Load resurces step 5" << std::endl; @@ -309,6 +299,7 @@ namespace ZL menuManager.getState() == GameState::HelpScreen || menuManager.getState() == GameState::AboutMenu) { + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawUI(); return; @@ -404,6 +395,7 @@ namespace ZL void Game::render() { ZL::CheckGlError(__FILE__, __LINE__); + //glClearColor(0.53f, 0.81f, 0.92f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -599,6 +591,10 @@ namespace ZL + case SDLK_r: + restartGame(); + break; + case SDLK_p: x = x + 1; break; @@ -641,12 +637,6 @@ namespace ZL } } - if (event.type == SDL_KEYUP) { - if (event.key.keysym.sym == SDLK_r) { - std::cout << "Camera position: x=" << x << " y=" << y << " z=" << z << std::endl; - } - } - if (event.type == SDL_KEYUP) { switch (event.key.keysym.sym) { case SDLK_w: @@ -767,6 +757,42 @@ namespace ZL } } + void Game::createLocations() + { + forestLocation = std::make_shared(renderer, inventory, "forest"); + forestLocation->setup(); + forestLocation->onLocationChangeRequest = [this](const std::string& locId) { + this->changeLocation(locId); + }; + + defaultLocation = std::make_shared(renderer, inventory, "default"); + defaultLocation->setup(); + defaultLocation->onLocationChangeRequest = [this](const std::string& locId) { + this->changeLocation(locId); + }; + + currentLocation = defaultLocation; + } + + void Game::restartGame() + { + std::cout << "[GAME] Restarting..." << std::endl; + // Keep the Location objects alive to avoid reloading textures / meshes / + // skeletal animations. setup() short-circuits to resetState() on locations + // that already have assets loaded. + inventory.clear(); + pickedUpObject = nullptr; + + if (forestLocation) forestLocation->setup(); + if (defaultLocation) defaultLocation->setup(); + + currentLocation = defaultLocation; + + if (menuManager.getState() == GameState::Gameplay) { + updateMusicForLocation("default"); + } + } + void Game::changeLocation(const std::string& locId) { if (locId == "forest") { diff --git a/src/Game.h b/src/Game.h index f849d19..e9d3686 100644 --- a/src/Game.h +++ b/src/Game.h @@ -57,10 +57,13 @@ namespace ZL { MenuManager menuManager; void changeLocation(const std::string& locId); + void restartGame(); void updateMusicForGameState(GameState newState); void updateMusicForLocation(const std::string& locationId); - + private: + void createLocations(); + float mainMenuTimeout = 500.f; bool rightMouseDown = false; int lastMouseX = 0; diff --git a/src/Location.cpp b/src/Location.cpp index 9409295..ed9c2ff 100644 --- a/src/Location.cpp +++ b/src/Location.cpp @@ -45,8 +45,13 @@ namespace ZL void Location::setup() { - - + // On restart, assets (textures / meshes / skeletal animations) are reused from + // the first call. Only runtime state (positions, dialogue flags, car/NPC modes) + // is reset via resetState(). + if (assetsLoaded) { + resetState(); + return; + } tileMesh.data = LoadFromTextFile02("resources/e/land/land003.txt", CONST_ZIP_FILE); tileMesh.RefreshVBO(); @@ -258,6 +263,9 @@ void Location::setup() dialogueSystem.loadDatabase("resources/dialogue/sample_dialogues.json"); std::cout << "[FOREST] Setup complete, loaded " << gameObjects.size() << " custom models" << std::endl; + + npcCar.texture = std::make_shared(CreateTextureDataFromPng("resources/e/car003_police.png", CONST_ZIP_FILE)); + } else if (locationId == "barn") @@ -317,6 +325,9 @@ void Location::setup() firstPersonMode = false; std::cout << "[BARK] Setup complete, loaded " << gameObjects.size() << " models" << std::endl; + + npcCar.texture = std::make_shared(CreateTextureDataFromPng("resources/e/car003_police.png", CONST_ZIP_FILE)); + } else // default @@ -407,6 +418,8 @@ void Location::setup() scriptEngine.init(this, &inventory); dialogueSystem.init(renderer, CONST_ZIP_FILE); dialogueSystem.loadDatabase("resources/dialogue/sample_dialogues.json"); + + npcCar.texture = std::make_shared(CreateTextureDataFromPng("resources/e/car_bandit001.png", CONST_ZIP_FILE)); } carTexture = std::make_unique(CreateTextureDataFromPng("resources/e/car002.png", CONST_ZIP_FILE)); @@ -421,7 +434,6 @@ void Location::setup() carWheelMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix()); carWheelMesh.RefreshVBO(); - npcCar.texture = std::make_shared(CreateTextureDataFromPng("resources/e/car003_police.png", CONST_ZIP_FILE)); //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::NONE; @@ -445,8 +457,157 @@ void Location::setup() Eigen::Vector3f(-12.f, 0.f, -8.f), };*/ //npcCar.currentWaypoint = 0; + + assetsLoaded = true; } + void Location::resetState() + { + dialogueSystem.clearState(); + + targetInteractiveObject = nullptr; + rightMouseDown = false; + lastMouseX = 0; + lastMouseY = 0; + mouseInitialized = false; + wasKeyForward = false; + + keyForward = keyBackward = keyLeft = keyRight = false; + + dialoguePlayedOffroad = false; + dialoguePlayedCrash = false; + dialoguePlayedDrivingGas1 = false; + dialogueDrivingGas1Finished = false; + dialoguePlayedGas1 = false; + dialoguePlayedGirlfriend1 = false; + dialoguePlayedPhone1 = false; + dialoguePhone1Finished = false; + npcCarSpawnedAfterPhone = false; + carOutOfGas = false; + dialoguePlayedDrivingGasOut = false; + + distanceRemaining = 4000.f; + dialoguePlayedDistance7000 = false; + dialoguePlayedDistance5000 = false; + dialoguePlayedDistance2000 = false; + dialoguePlayedDistance0 = false; + npcCarSpawnedAfterDistance0 = false; + dialoguePlayedDrivingFinal = false; + + policeFollow = false; + policeEncounterStage = PoliceEncounterStage::Idle; + playerFrozen = false; + policeDrivingDialogueTimer = 8.0f; + policeChaseDistance = 0.f; + + banditFollowingPlayer = false; + dialoguePlayedBanditCaught1 = false; + dialoguePlayedBanditCaught3 = false; + banditEncounterFrozePlayer = false; + banditLastFollowTarget = Eigen::Vector3f::Zero(); + banditLastFollowTargetValid = false; + + playerOnFootSeconds = 0.f; + npcBanditCarSpawned = false; + dialoguePlayedBandit1 = false; + banditExitedNpcBanditCar = false; + dialoguePlayedDrivingChase1 = false; + + dialoguePlayedVillageRescue1 = false; + dialoguePlayedVillageIntro1 = false; + dialogueVillageIntro1Finished = false; + dialoguePlayedVillageIntro2 = false; + dialoguePlayedVillageFinal1 = false; + dialoguePlayedVillageFinal2 = false; + + girlfriendLastFollowTarget = Eigen::Vector3f::Zero(); + girlfriendLastFollowTargetValid = false; + + carVelocity = 0.f; + carSteeringAngle = 0.f; + carRotation = 0.f; + cameraAzimuth = 0.0f; + cameraInclination = M_PI * 30.f / 180.f; + firstPersonMode = false; + savedCameraAzimuth = 0.f; + savedCameraInclination = 0.f; + + if (locationId == "forest") + { + girlfriendRescued = true; + inCar = true; + girlfriendInCar = true; + + if (salesperson) { + salesperson->position = Vector3f{ -8.31099f - 17.0f, 0.f, -4.26868f }; + salesperson->setTarget(salesperson->position); + } + if (police) { + police->position = Vector3f{ 1000.f, 0.f, 10.f }; + police->setTarget(police->position); + } + if (bandit) { + bandit->position = Vector3f{ 1000.f, 0.f, 1000.f }; + bandit->setTarget(bandit->position); + } + + carPosition = Vector3f{ 7.f, 0.f, -7.f + 300.f }; + npcCar.position = Vector3f(9.f, 0.f, -335.f) + Vector3f(1000.f, 0.f, 0.f); + + if (girlfriend) { + girlfriend->position = Vector3f{ 5.f, 0.f, 0.9f + 300.f }; + girlfriend->setTarget(girlfriend->position); + } + if (player) { + player->position = Vector3f{ 9.5f, 0.f, 0.95f + 300.f }; + player->setTarget(player->position); + } + } + else // default + { + girlfriendRescued = false; + inCar = false; + girlfriendInCar = false; + + if (bandit) { + bandit->position = Vector3f{ 12.1782f, 0.f, 62.4014f }; + bandit->setTarget(bandit->position); + } + + carPosition = Vector3f{ -6.61929f, 0.f, -30.7197f - 300.f }; + carRotation = (float)M_PI; + npcCar.position = Vector3f{ 7.1782f, 0.f, 68.4014f }; + + if (player) { + player->position = Vector3f{ -6.61929f, 0.f, -40.f - 300.f }; + player->setTarget(player->position); + } + cameraAzimuth = (float)M_PI; + + if (girlfriend) { + girlfriend->position = Vector3f{ 27.6714f, 0.f, 73.3165f }; + girlfriend->setTarget(girlfriend->position); + } + } + + npcCar.rotation = 0.f; + npcCar.mode = NpcCar::Mode::NONE; + npcCar.velocity = 0.f; + npcCar.steeringAngle = 0.f; + npcCar.currentWaypoint = 0; + + npcBanditCar.rotation = 0.f; + npcBanditCar.mode = NpcCar::Mode::NONE; + npcBanditCar.maxSpeed = 26.0f; + npcBanditCar.maxReverseSpeed = 8.0f; + npcBanditCar.followMinDistance = 10.f; + npcBanditCar.followMaxDistance = 11.5f; + npcBanditCar.position = Vector3f(-1000.f, 0.f, -1000.f); + npcBanditCar.velocity = 0.f; + npcBanditCar.steeringAngle = 0.f; + npcBanditCar.currentWaypoint = 0; + } + void Location::setupNavigation() { @@ -621,11 +782,12 @@ void Location::setup() void Location::drawGame() { - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClearColor(0.53f, 0.81f, 0.92f, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - renderer.shaderManager.PushShader(defaultShaderName); + static const std::string fogShaderName = "fog"; + renderer.shaderManager.PushShader(fogShaderName); renderer.RenderUniform1i(textureUniformName, 0); renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, diff --git a/src/Location.h b/src/Location.h index 8928f25..0fb1100 100644 --- a/src/Location.h +++ b/src/Location.h @@ -184,6 +184,8 @@ namespace ZL void setup(); + void resetState(); + bool assetsLoaded = false; void setupNavigation(); InteractiveObject* raycastInteractiveObjects(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir); Character* raycastNpcs(const Eigen::Vector3f& rayOrigin, const Eigen::Vector3f& rayDir, float maxDistance = 100.0f); diff --git a/src/dialogue/DialogueRuntime.cpp b/src/dialogue/DialogueRuntime.cpp index c958b81..bf5df98 100644 --- a/src/dialogue/DialogueRuntime.cpp +++ b/src/dialogue/DialogueRuntime.cpp @@ -62,6 +62,27 @@ void DialogueRuntime::stop() { if (cb) cb(); } +void DialogueRuntime::clearState() { + // Like stop(), but also wipes flags / consumed choices so a fresh run + // can replay dialogues whose conditions depend on those. + activeDialogue = nullptr; + activeCutscene = nullptr; + currentNodeId.clear(); + pendingNodeAfterCutscene.clear(); + visibleChoices.clear(); + selectedChoice = 0; + revealCharacters = 0.0f; + currentCutsceneLine = -1; + cutsceneTimerMs = 0; + cutsceneElapsedMs = 0; + cutsceneTotalDurationMs = 0; + mode = Mode::Inactive; + presentation = {}; + onFinishedCallback = nullptr; + flags.clear(); + consumedChoices.clear(); +} + void DialogueRuntime::update(int deltaMs) { if (mode == Mode::PresentingLine) { if (!presentation.revealCompleted) { diff --git a/src/dialogue/DialogueRuntime.h b/src/dialogue/DialogueRuntime.h index 42a05e2..5f6c166 100644 --- a/src/dialogue/DialogueRuntime.h +++ b/src/dialogue/DialogueRuntime.h @@ -18,6 +18,7 @@ public: bool startDialogue(const std::string& dialogueId, std::function onFinished = nullptr); void stop(); + void clearState(); void update(int deltaMs); diff --git a/src/dialogue/DialogueSystem.cpp b/src/dialogue/DialogueSystem.cpp index 4a68a3f..9e4ffc4 100644 --- a/src/dialogue/DialogueSystem.cpp +++ b/src/dialogue/DialogueSystem.cpp @@ -151,6 +151,13 @@ void DialogueSystem::stopDialogue() { runtime.stop(); } +void DialogueSystem::clearState() { + runtime.clearState(); + triggerZones.clear(); + autoSkipTrackedText.clear(); + autoSkipTimerMs = 0.0f; +} + void DialogueSystem::addTriggerZone(const TriggerZone& zone) { triggerZones.push_back(zone); } diff --git a/src/dialogue/DialogueSystem.h b/src/dialogue/DialogueSystem.h index 1f93aa9..9a50e0d 100644 --- a/src/dialogue/DialogueSystem.h +++ b/src/dialogue/DialogueSystem.h @@ -40,6 +40,7 @@ public: bool startDialogue(const std::string& dialogueId, std::function onFinished = nullptr); void stopDialogue(); + void clearState(); bool isActive() const { return runtime.isActive(); } bool blocksGameplayInput() const { return runtime.isActive(); }