merge
This commit is contained in:
commit
4de8f78eca
29 files changed
+2052
-111
No files matched your search
+172
-18
@@ -53,7 +53,7 @@ namespace ZL
|
||||
if (s_instance) {
|
||||
s_instance->mainThreadHandler.EnqueueMainThreadTask([&]() {
|
||||
s_instance->setupPart2();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace ZL
|
||||
ZL::BindOpenGlFunctions();
|
||||
ZL::CheckGlError(__FILE__, __LINE__);
|
||||
renderer.InitOpenGL();
|
||||
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
// These shaders and loading.png are preloaded separately (not from zip),
|
||||
// so they are available immediately without waiting for resources.zip.
|
||||
@@ -111,9 +111,9 @@ namespace ZL
|
||||
minDimension = width;
|
||||
}
|
||||
|
||||
loadingMesh.data = CreateRect2D({ 0.0f, 0.0f }, { minDimension*0.5f, minDimension*0.5f }, 3);
|
||||
loadingMesh.data = CreateRect2D({ 0.0f, 0.0f }, { minDimension * 0.5f, minDimension * 0.5f }, 3);
|
||||
loadingMesh.RefreshVBO();
|
||||
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
// Asynchronously download resources.zip; setupPart2() is called on completion.
|
||||
// The loading screen stays visible until the download finishes.
|
||||
@@ -125,7 +125,7 @@ namespace ZL
|
||||
std::cout << "Load resurces step 2" << std::endl;
|
||||
this->setupPart2();
|
||||
std::cout << "Load resurces step 3" << std::endl;
|
||||
});
|
||||
});
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -201,7 +201,7 @@ namespace ZL
|
||||
currentLocation->player->setTarget(currentLocation->teleportPosition);
|
||||
}
|
||||
currentLocation->playerInTeleportZone = true;
|
||||
};
|
||||
};
|
||||
location2->onTeleport = [this]() {
|
||||
std::cout << "[TELEPORT] location 2 -> location 1" << std::endl;
|
||||
currentLocation = location1;
|
||||
@@ -210,12 +210,12 @@ namespace ZL
|
||||
currentLocation->player->setTarget(currentLocation->teleportPosition);
|
||||
}
|
||||
currentLocation->playerInTeleportZone = true;
|
||||
};
|
||||
};
|
||||
|
||||
currentLocation = location2;
|
||||
|
||||
std::cout << "Load resurces step 5" << std::endl;
|
||||
|
||||
|
||||
std::cout << "Load resurces step 12" << std::endl;
|
||||
|
||||
// Shadow mapping shaders
|
||||
@@ -240,6 +240,10 @@ namespace ZL
|
||||
// Load UI with inventory button
|
||||
try {
|
||||
menuManager.uiManager.loadFromFile("resources/config2/ui_inventory.json", renderer, CONST_ZIP_FILE);
|
||||
menuManager.uiManager.appendFromFile("resources/config2/ui_quest_journal.json", renderer, CONST_ZIP_FILE);
|
||||
|
||||
questJournal.loadFromFile("resources/quests/quests.json", CONST_ZIP_FILE);
|
||||
setupQuestJournalUi();
|
||||
std::cout << "UI loaded successfully" << std::endl;
|
||||
|
||||
menuManager.uiManager.setNodeVisible("inventory_items_panel", false);
|
||||
@@ -247,6 +251,9 @@ namespace ZL
|
||||
|
||||
menuManager.uiManager.setTextButtonCallback("inventory_button", [this](const std::string& name) {
|
||||
std::cout << "[UI] Inventory button clicked" << std::endl;
|
||||
if (this->questJournalOpen) {
|
||||
this->toggleQuestJournal();
|
||||
}
|
||||
this->menuManager.uiManager.setNodeVisible("inventory_items_panel", true);
|
||||
this->menuManager.uiManager.setNodeVisible("close_inventory_button", true);
|
||||
this->inventoryOpen = true;
|
||||
@@ -266,7 +273,7 @@ namespace ZL
|
||||
}
|
||||
|
||||
this->menuManager.uiManager.setText("inventory_items_text", itemText);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
menuManager.uiManager.setTextButtonCallback("close_inventory_button", [this](const std::string& name) {
|
||||
@@ -274,7 +281,7 @@ namespace ZL
|
||||
menuManager.uiManager.setNodeVisible("inventory_items_panel", false);
|
||||
menuManager.uiManager.setNodeVisible("close_inventory_button", false);
|
||||
inventoryOpen = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Failed to load UI: " << e.what() << std::endl;
|
||||
@@ -292,7 +299,7 @@ namespace ZL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Game::drawUI()
|
||||
{
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
@@ -318,7 +325,150 @@ namespace ZL
|
||||
|
||||
CheckGlError(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int questStatusPriority(Quest::QuestStatus status) {
|
||||
switch (status) {
|
||||
case Quest::QuestStatus::Active: return 0;
|
||||
case Quest::QuestStatus::Available: return 1;
|
||||
case Quest::QuestStatus::Completed: return 2;
|
||||
case Quest::QuestStatus::Failed: return 3;
|
||||
default: return 4;
|
||||
}
|
||||
}
|
||||
|
||||
static std::array<float, 4> questStatusColor(Quest::QuestStatus status) {
|
||||
switch (status) {
|
||||
case Quest::QuestStatus::Completed: return { 0.25f, 0.95f, 0.35f, 1.0f };
|
||||
case Quest::QuestStatus::Failed: return { 1.0f, 0.25f, 0.25f, 1.0f };
|
||||
case Quest::QuestStatus::Active: return { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
case Quest::QuestStatus::Available: return { 0.86f, 0.86f, 0.86f, 1.0f };
|
||||
default: return { 0.45f, 0.45f, 0.45f, 1.0f };
|
||||
}
|
||||
}
|
||||
|
||||
void Game::setupQuestJournalUi() {
|
||||
questJournalOpen = false;
|
||||
selectedQuestIndex = -1;
|
||||
visibleQuestIds.clear();
|
||||
|
||||
menuManager.uiManager.setNodeVisible("quest_journal_panel", false);
|
||||
menuManager.uiManager.setNodeVisible("quest_close_button", false);
|
||||
|
||||
menuManager.uiManager.setTextButtonCallback("quest_journal_button", [this](const std::string&) {
|
||||
toggleQuestJournal();
|
||||
});
|
||||
|
||||
menuManager.uiManager.setTextButtonCallback("quest_close_button", [this](const std::string&) {
|
||||
if (questJournalOpen) {
|
||||
toggleQuestJournal();
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
const std::string slotName = "quest_slot_" + std::to_string(i);
|
||||
menuManager.uiManager.setTextButtonCallback(slotName, [this, i](const std::string&) {
|
||||
selectQuestByIndex(i);
|
||||
});
|
||||
menuManager.uiManager.setNodeVisible(slotName, false);
|
||||
}
|
||||
}
|
||||
|
||||
void Game::toggleQuestJournal() {
|
||||
questJournalOpen = !questJournalOpen;
|
||||
std::cout << "[quest] toggleQuestJournal: " << (questJournalOpen ? "open" : "closed") << std::endl;
|
||||
|
||||
if (questJournalOpen) {
|
||||
if (inventoryOpen) {
|
||||
menuManager.uiManager.setNodeVisible("inventory_items_panel", false);
|
||||
menuManager.uiManager.setNodeVisible("close_inventory_button", false);
|
||||
inventoryOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
menuManager.uiManager.setNodeVisible("quest_journal_panel", questJournalOpen);
|
||||
menuManager.uiManager.setNodeVisible("quest_close_button", questJournalOpen);
|
||||
|
||||
if (questJournalOpen) {
|
||||
refreshQuestJournalUi();
|
||||
if (!visibleQuestIds.empty()) {
|
||||
selectQuestByIndex(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Game::refreshQuestJournalUi() {
|
||||
visibleQuestIds.clear();
|
||||
auto quests = questJournal.getVisibleQuests();
|
||||
|
||||
std::sort(quests.begin(), quests.end(), [](const Quest::QuestState* a, const Quest::QuestState* b) {
|
||||
const int pa = questStatusPriority(a->status);
|
||||
const int pb = questStatusPriority(b->status);
|
||||
if (pa != pb) return pa < pb;
|
||||
// Newer quests are shown above older quests inside the same status bucket.
|
||||
return a->orderIndex > b->orderIndex;
|
||||
});
|
||||
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
const std::string slotName = "quest_slot_" + std::to_string(i);
|
||||
|
||||
if (i < static_cast<int>(quests.size())) {
|
||||
const auto* quest = quests[i];
|
||||
visibleQuestIds.push_back(quest->definition.id);
|
||||
|
||||
const bool selected = (i == selectedQuestIndex);
|
||||
const std::string prefix = selected ? "> " : " ";
|
||||
menuManager.uiManager.setTextButtonText(slotName, prefix + quest->definition.title);
|
||||
menuManager.uiManager.setTextButtonColor(slotName, questStatusColor(quest->status));
|
||||
menuManager.uiManager.setNodeVisible(slotName, true);
|
||||
}
|
||||
else {
|
||||
menuManager.uiManager.setTextButtonText(slotName, "");
|
||||
menuManager.uiManager.setNodeVisible(slotName, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Game::selectQuestByIndex(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(visibleQuestIds.size())) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectedQuestIndex = index;
|
||||
Quest::QuestState* quest = questJournal.findQuest(visibleQuestIds[index]);
|
||||
if (!quest) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& def = quest->definition;
|
||||
|
||||
menuManager.uiManager.setText("quest_middle_title_text", def.title);
|
||||
menuManager.uiManager.setTextColor("quest_middle_title_text", questStatusColor(quest->status));
|
||||
|
||||
const std::string meta = std::string("Category: ") + Quest::toString(def.category)
|
||||
+ " | Status: " + Quest::toString(quest->status)
|
||||
+ " | Level: " + std::to_string(def.recommendedLevel);
|
||||
menuManager.uiManager.setText("quest_meta_text", meta);
|
||||
|
||||
std::string objectivesText;
|
||||
for (size_t i = 0; i < def.objectives.size(); ++i) {
|
||||
const auto& obj = def.objectives[i];
|
||||
const bool isActive = static_cast<int>(i) == quest->activeObjectiveIndex;
|
||||
const std::string mark = obj.completed ? "[x] " : (isActive ? "> [ ] " : "[ ] ");
|
||||
objectivesText += mark + obj.text;
|
||||
if (i + 1 < def.objectives.size()) {
|
||||
objectivesText += "\n";
|
||||
}
|
||||
}
|
||||
menuManager.uiManager.setText("quest_objectives_text", objectivesText);
|
||||
|
||||
menuManager.uiManager.setText("quest_lore_title_text", "Описание задания");
|
||||
menuManager.uiManager.setText("quest_description_text", def.description);
|
||||
|
||||
refreshQuestJournalUi();
|
||||
}
|
||||
|
||||
void Game::drawScene() {
|
||||
glViewport(0, 0, Environment::width, Environment::height);
|
||||
if (!loadingCompleted) {
|
||||
@@ -360,7 +510,7 @@ namespace ZL
|
||||
float height = Environment::projectionHeight;
|
||||
|
||||
renderer.PushProjectionMatrix(
|
||||
-width * 0.5f, width*0.5f,
|
||||
-width * 0.5f, width * 0.5f,
|
||||
-height * 0.5f, height * 0.5f,
|
||||
-10, 10);
|
||||
|
||||
@@ -376,13 +526,13 @@ namespace ZL
|
||||
CheckGlError(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int64_t Game::getSyncTimeMs() {
|
||||
int64_t localNow = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
return localNow;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Game::processTickCount() {
|
||||
|
||||
@@ -431,7 +581,7 @@ namespace ZL
|
||||
Environment::exitGameLoop = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||
// Обновляем размеры и сбрасываем кеш текстов, т.к. меши хранятся в пикселях
|
||||
Environment::width = event.window.data1;
|
||||
@@ -552,6 +702,10 @@ namespace ZL
|
||||
activateSlowMoEffect();
|
||||
break;
|
||||
|
||||
case SDLK_j:
|
||||
toggleQuestJournal();
|
||||
break;
|
||||
|
||||
case SDLK_RETURN:
|
||||
|
||||
default:
|
||||
@@ -584,7 +738,7 @@ namespace ZL
|
||||
}
|
||||
}
|
||||
render();
|
||||
|
||||
|
||||
mainThreadHandler.processMainThreadTasks();
|
||||
|
||||
}
|
||||
@@ -801,4 +955,4 @@ namespace ZL
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
} // namespace ZL
|
||||
Reference in new issue
Block a user