Working on save-load system and UI
This commit is contained in:
1 parent
901142385d
commit
d7db0faea3
29 files changed
+708
-180
No files matched your search
+161
-74
@@ -1,6 +1,7 @@
|
||||
#include "Game.h"
|
||||
#include "AnimatedModel.h"
|
||||
#include "utils/Utils.h"
|
||||
#include <fstream>
|
||||
#include "items/ItemRegistry.h"
|
||||
#include "render/OpenGlExtensions.h"
|
||||
#include <iostream>
|
||||
@@ -242,6 +243,113 @@ namespace ZL
|
||||
|
||||
ItemRegistry::instance().loadFromJson("resources/config2/items.json", CONST_ZIP_FILE);
|
||||
|
||||
createLocations();
|
||||
|
||||
renderer.textureManager.LoadFromPng("resources/w/ui/img/toast/item_received001.png", CONST_ZIP_FILE, true);
|
||||
renderer.textureManager.LoadFromPng("resources/w/ui/img/toast/item_removed001.png", CONST_ZIP_FILE, true);
|
||||
|
||||
mobileRotateTexture = renderer.textureManager.LoadFromPng(
|
||||
"resources/rotateYourDevice.png", CONST_ZIP_FILE, true);
|
||||
|
||||
|
||||
|
||||
// Wire inventory callbacks: tutorial tracking + toast notifications.
|
||||
gameState.inventory.onItemAdded = [this](const std::string& itemId) {
|
||||
menuManager.onItemPickedUp(itemId);
|
||||
const Item* item = ItemRegistry::instance().findById(itemId);
|
||||
if (item) menuManager.showToast("resources/w/ui/img/toast/item_received001.png", item->name);
|
||||
};
|
||||
gameState.inventory.onItemRemoved = [this](const std::string& itemId) {
|
||||
const Item* item = ItemRegistry::instance().findById(itemId);
|
||||
if (item) menuManager.showToast("resources/w/ui/img/toast/item_removed001.png", item->name);
|
||||
};
|
||||
|
||||
// Wire phone dialogue start function so MenuManager can trigger dialogues.
|
||||
menuManager.startDialogueFunc = [this](const std::string& id) {
|
||||
if (currentLocation()) currentLocation()->dialogueSystem.startDialogue(id);
|
||||
};
|
||||
|
||||
menuManager.startDarklandsTransitionFunc = [this]() {
|
||||
startDarklandsTransition();
|
||||
};
|
||||
|
||||
menuManager.startNightTransitionFunc = [this]() {
|
||||
startNightTransition();
|
||||
};
|
||||
|
||||
menuManager.chatOpenCallback = [this](int chatIndex) {
|
||||
if (currentLocation())
|
||||
currentLocation()->scriptEngine.callChatOpenCallback(chatIndex);
|
||||
};
|
||||
|
||||
menuManager.skipCutsceneFunc = [this]() {
|
||||
if (currentLocation()) currentLocation()->dialogueSystem.skipCutscene();
|
||||
};
|
||||
|
||||
std::cout << "Load resurces step 13" << std::endl;
|
||||
|
||||
menuManager.onResetGame = [this]() {
|
||||
gameState.currentLocationName.clear();
|
||||
gameState.isDarklands = false;
|
||||
gameState.isNight = false;
|
||||
gameState.isDawn = false;
|
||||
gameState.playerHp = 200.f;
|
||||
gameState.playerMaxHp = 200.f;
|
||||
gameState.money = 5500;
|
||||
gameState.globalInts.clear();
|
||||
gameState.globalFloats.clear();
|
||||
gameState.tutorialStep = TutorialStep::Step0;
|
||||
gameState.uniIntTutorialState = UniIntTutorialState::Step10;
|
||||
gameState.tutorialPhonePickedUp = false;
|
||||
gameState.tutorialJournalPickedUp = false;
|
||||
gameState.tutorialPhoneChatScreenOpened = false;
|
||||
gameState.tutorialJournalScreenOpened = false;
|
||||
gameState.tutorialNeedOpenTaxiScreen = false;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
gameState.chatUnread[i] = true;
|
||||
gameState.chatPreviewMsg[i].clear();
|
||||
gameState.chatHistory[i].clear();
|
||||
}
|
||||
gameState.inventory.items.clear();
|
||||
gameState.questJournal.loadFromFile("resources/quests/quests.json", CONST_ZIP_FILE);
|
||||
createLocations();
|
||||
};
|
||||
|
||||
try {
|
||||
menuManager.setup(gameState.inventory, CONST_ZIP_FILE);
|
||||
std::cout << "UI loaded successfully" << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
|
||||
std::cerr << "Failed to load UI: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
menuManager.startGameFunc = [this]() {
|
||||
gameState.currentLocationName = "location_dorm";
|
||||
currentLocation()->scriptEngine.callLocationEnterCallback();
|
||||
};
|
||||
|
||||
menuManager.onSaveGame = [this](int slot) { saveGame(slot); };
|
||||
menuManager.onLoadGame = [this](int slot) { loadGame(slot); };
|
||||
menuManager.getSlotInfoFunc = [this](int slot) { return readSlotInfo(slot); };
|
||||
|
||||
loadingCompleted = true;
|
||||
|
||||
if (audioPlayer->init()) {
|
||||
audioPlayer->setMusicVolume(100);
|
||||
audioPlayer->setSoundVolume(80);
|
||||
std::cout << "Audio initialized successfully" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "Audio initialization failed" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Game::createLocations()
|
||||
{
|
||||
gameState.locations.clear();
|
||||
|
||||
gameState.globalFloats["player_hp"] = 200;
|
||||
|
||||
LocationSetup uniInteriorParams;
|
||||
@@ -280,12 +388,12 @@ namespace ZL
|
||||
"resources/navigation/uni_interior3_n2_lr_tr_hall_aiperi.json",
|
||||
"resources/navigation/uni_interior3_darklands_all_open.json", //5
|
||||
"resources/navigation/uni_interior4_unlocked_hall.json",
|
||||
"resources/navigation/uni_interior4_unlocked_n3.json",
|
||||
"resources/navigation/uni_interior4_unlocked_n3.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s1.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s2.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s3.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_s1.json", //11
|
||||
"resources/navigation/uni_interior4_unlocked_s3_hall.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_hall.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_n3.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_n2.json",
|
||||
"resources/navigation/uni_interior4_unlocked_s3_s2.json",
|
||||
@@ -375,6 +483,7 @@ namespace ZL
|
||||
//params_dorm.gameObjectsJsonPath = "resources/config2/gameobjects_dorm.json";
|
||||
//params_dorm.gameObjectsJsonPath = "resources/config2/gameobjects_dorm_trees001.json";
|
||||
params_dorm.gameObjectsJsonPath = "resources/config2/gameobjects_dorm_new_x.json";
|
||||
|
||||
params_dorm.npcsJsonPath = "resources/config2/npcs_dorm.json";
|
||||
params_dorm.dialoguesJsonPath = "resources/dialogue/dorm_dialogues.json";
|
||||
|
||||
@@ -387,7 +496,7 @@ namespace ZL
|
||||
"resources/navigation/dorm3_b.json",
|
||||
"resources/navigation/dorm3_all_open.json",
|
||||
};*/
|
||||
/*
|
||||
|
||||
params_dorm.navigationJsonPaths = {
|
||||
"resources/navigation/dorm3_bca.txt", //0
|
||||
"resources/navigation/dorm3_ca.txt", //1
|
||||
@@ -396,15 +505,15 @@ namespace ZL
|
||||
"resources/navigation/dorm3_b.txt",
|
||||
"resources/navigation/dorm3_all_open.txt", //5
|
||||
};
|
||||
*/
|
||||
params_dorm.navigationJsonPaths = {
|
||||
|
||||
/*params_dorm.navigationJsonPaths = {
|
||||
"resources/navigation/dorm0_large.json",
|
||||
"resources/navigation/dorm0_large.json",
|
||||
"resources/navigation/dorm0_large.json",
|
||||
"resources/navigation/dorm0_large.json",
|
||||
"resources/navigation/dorm0_large.json",
|
||||
"resources/navigation/dorm0_large.json",
|
||||
};
|
||||
};*/
|
||||
params_dorm.teleportsJsonPath = "resources/config2/teleports_dorm.json";
|
||||
params_dorm.triggerZonesJsonPath = "resources/config2/trigger_zones_dorm.json";
|
||||
params_dorm.lightsJsonPath = "resources/config2/lights_dorm.json";
|
||||
@@ -509,43 +618,6 @@ namespace ZL
|
||||
};
|
||||
}
|
||||
|
||||
renderer.textureManager.LoadFromPng("resources/w/ui/img/toast/item_received001.png", CONST_ZIP_FILE, true);
|
||||
renderer.textureManager.LoadFromPng("resources/w/ui/img/toast/item_removed001.png", CONST_ZIP_FILE, true);
|
||||
|
||||
mobileRotateTexture = renderer.textureManager.LoadFromPng(
|
||||
"resources/rotateYourDevice.png", CONST_ZIP_FILE, true);
|
||||
|
||||
|
||||
|
||||
// Wire inventory callbacks: tutorial tracking + toast notifications.
|
||||
gameState.inventory.onItemAdded = [this](const std::string& itemId) {
|
||||
menuManager.onItemPickedUp(itemId);
|
||||
const Item* item = ItemRegistry::instance().findById(itemId);
|
||||
if (item) menuManager.showToast("resources/w/ui/img/toast/item_received001.png", item->name);
|
||||
};
|
||||
gameState.inventory.onItemRemoved = [this](const std::string& itemId) {
|
||||
const Item* item = ItemRegistry::instance().findById(itemId);
|
||||
if (item) menuManager.showToast("resources/w/ui/img/toast/item_removed001.png", item->name);
|
||||
};
|
||||
|
||||
// Wire phone dialogue start function so MenuManager can trigger dialogues.
|
||||
menuManager.startDialogueFunc = [this](const std::string& id) {
|
||||
if (currentLocation()) currentLocation()->dialogueSystem.startDialogue(id);
|
||||
};
|
||||
|
||||
menuManager.startDarklandsTransitionFunc = [this]() {
|
||||
startDarklandsTransition();
|
||||
};
|
||||
|
||||
menuManager.startNightTransitionFunc = [this]() {
|
||||
startNightTransition();
|
||||
};
|
||||
|
||||
menuManager.chatOpenCallback = [this](int chatIndex) {
|
||||
if (currentLocation())
|
||||
currentLocation()->scriptEngine.callChatOpenCallback(chatIndex);
|
||||
};
|
||||
|
||||
// Wire chat-bubble callback so dynamic bubbles appear as dialogue lines are shown.
|
||||
for (auto& [name, loc] : gameState.locations) {
|
||||
loc->dialogueSystem.setOnChatBubbleReady([this](const std::string& text, bool incoming) {
|
||||
@@ -562,25 +634,6 @@ namespace ZL
|
||||
menuManager.onCutsceneFinished();
|
||||
});
|
||||
}
|
||||
menuManager.skipCutsceneFunc = [this]() {
|
||||
if (currentLocation()) currentLocation()->dialogueSystem.skipCutscene();
|
||||
};
|
||||
|
||||
std::cout << "Load resurces step 13" << std::endl;
|
||||
|
||||
try {
|
||||
menuManager.setup(gameState.inventory, CONST_ZIP_FILE);
|
||||
std::cout << "UI loaded successfully" << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
|
||||
std::cerr << "Failed to load UI: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
menuManager.startGameFunc = [this]() {
|
||||
gameState.currentLocationName = "location_dorm";
|
||||
currentLocation()->scriptEngine.callLocationEnterCallback();
|
||||
};
|
||||
|
||||
// Wire HP-change callbacks so all player instances update the health bar HUD.
|
||||
for (auto& [name, loc] : gameState.locations) {
|
||||
@@ -590,18 +643,6 @@ namespace ZL
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
loadingCompleted = true;
|
||||
|
||||
if (audioPlayer->init()) {
|
||||
audioPlayer->setMusicVolume(100);
|
||||
audioPlayer->setSoundVolume(80);
|
||||
std::cout << "Audio initialized successfully" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "Audio initialization failed" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Game::drawUI()
|
||||
@@ -1515,4 +1556,50 @@ namespace ZL
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
SaveSlotInfo Game::readSlotInfo(int slot) const
|
||||
{
|
||||
std::string path = "save_slot" + std::to_string(slot) + ".json";
|
||||
std::string content = ZL::readTextFile(path);
|
||||
if (content.empty()) return {};
|
||||
try {
|
||||
nlohmann::json root = nlohmann::json::parse(content);
|
||||
SaveSlotInfo info;
|
||||
info.empty = false;
|
||||
info.locationName = root.value("currentLocationName", "");
|
||||
info.savedAt = root.value("savedAt", "");
|
||||
return info;
|
||||
} catch (...) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void Game::saveGame(int slot)
|
||||
{
|
||||
nlohmann::json root;
|
||||
gameState.save(root);
|
||||
std::string path = "save_slot" + std::to_string(slot) + ".json";
|
||||
std::ofstream file(path);
|
||||
if (file.is_open()) {
|
||||
file << root.dump(2);
|
||||
} else {
|
||||
std::cerr << "[save] Could not open " << path << " for writing" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Game::loadGame(int slot)
|
||||
{
|
||||
std::string path = "save_slot" + std::to_string(slot) + ".json";
|
||||
std::string content = ZL::readTextFile(path);
|
||||
if (content.empty()) {
|
||||
std::cerr << "[save] Save file not found or empty: " << path << std::endl;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
nlohmann::json root = nlohmann::json::parse(content);
|
||||
gameState.load(root);
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "[save] Failed to parse save file " << path << ": " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
Reference in new issue
Block a user