Fixing bugs, added girl
This commit is contained in:
parent
d24748df1e
commit
6149182f02
@ -29,7 +29,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree001",
|
"name": "tree001",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": -1.5707963267948966,
|
"rotationY": -1.5707963267948966,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -42,7 +42,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree002",
|
"name": "tree002",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": 1.5707963267948966,
|
"rotationY": 1.5707963267948966,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -55,7 +55,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree003",
|
"name": "tree003",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -68,7 +68,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree004",
|
"name": "tree004",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": -1.5707963267948966,
|
"rotationY": -1.5707963267948966,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -81,7 +81,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree005",
|
"name": "tree005",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": 1.5707963267948966,
|
"rotationY": 1.5707963267948966,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -94,7 +94,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree006",
|
"name": "tree006",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -107,7 +107,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree007",
|
"name": "tree007",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": -1.5707963267948966,
|
"rotationY": -1.5707963267948966,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -120,7 +120,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree008",
|
"name": "tree008",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": 1.5707963267948966,
|
"rotationY": 1.5707963267948966,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -133,7 +133,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree009",
|
"name": "tree009",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": 0.0,
|
"rotationY": 0.0,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
@ -146,7 +146,7 @@
|
|||||||
{
|
{
|
||||||
"name": "tree010",
|
"name": "tree010",
|
||||||
"texturePath": "resources/w/exterior/tree001.png",
|
"texturePath": "resources/w/exterior/tree001.png",
|
||||||
"meshPath": "resources/w/exterior/tree002.txt",
|
"meshPath": "resources/w/exterior/tree003.txt",
|
||||||
"rotationX": 0.0,
|
"rotationX": 0.0,
|
||||||
"rotationY": -1.5707963267948966,
|
"rotationY": -1.5707963267948966,
|
||||||
"rotationZ": 0.0,
|
"rotationZ": 0.0,
|
||||||
|
|||||||
@ -37,16 +37,10 @@
|
|||||||
{
|
{
|
||||||
"id": "npc_02_woman",
|
"id": "npc_02_woman",
|
||||||
"name": "Студентка",
|
"name": "Студентка",
|
||||||
"animationIdlePath": "resources/w/jam/woman_idle002.anim",
|
"animationIdlePath": "resources/w/new_anims/girl_stand_idle005.txt",
|
||||||
"animationWalkPath": "resources/w/jam/woman_walk002.anim",
|
"animationWalkPath": "resources/w/new_anims/girl_walk005.txt",
|
||||||
"meshTextures": {
|
"meshTextures": {
|
||||||
"Body": "resources/w/jam/female_packed0_diffuse.png",
|
"polySurface1": "resources/w/new_anims/Chat_02_diff.png"
|
||||||
"Bottoms": "resources/w/jam/female_packed3_diffuse.png",
|
|
||||||
"Eyelashes": "resources/w/jam/female_packed0_diffuse.png",
|
|
||||||
"Eyes": "resources/w/jam/female_packed0_diffuse.png",
|
|
||||||
"Hair": "resources/w/jam/female_packed2_diffuse.png",
|
|
||||||
"Shoes": "resources/w/jam/female_packed1_diffuse.png",
|
|
||||||
"Tops": "resources/w/jam/female_packed2_diffuse.png"
|
|
||||||
},
|
},
|
||||||
"positionX": 19.5,
|
"positionX": 19.5,
|
||||||
"positionY": 0.0,
|
"positionY": 0.0,
|
||||||
@ -54,7 +48,7 @@
|
|||||||
"facingAngle" : 3.141592,
|
"facingAngle" : 3.141592,
|
||||||
"walkSpeed": 1.5,
|
"walkSpeed": 1.5,
|
||||||
"rotationSpeed": 8.0,
|
"rotationSpeed": 8.0,
|
||||||
"modelScale": 0.0001,
|
"modelScale": 0.00016,
|
||||||
"modelCorrectionRotX": 0.0,
|
"modelCorrectionRotX": 0.0,
|
||||||
"modelCorrectionRotY": 180.0,
|
"modelCorrectionRotY": 180.0,
|
||||||
"modelCorrectionRotZ": 0.0,
|
"modelCorrectionRotZ": 0.0,
|
||||||
|
|||||||
@ -22,6 +22,24 @@
|
|||||||
"hover": "resources/w/red.png",
|
"hover": "resources/w/red.png",
|
||||||
"pressed": "resources/w/red.png"
|
"pressed": "resources/w/red.png"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TextButton",
|
||||||
|
"name": "quest_journal_button",
|
||||||
|
"x": 220.0,
|
||||||
|
"y": 50.0,
|
||||||
|
"width": 170.0,
|
||||||
|
"height": 60.0,
|
||||||
|
"text": "Quests",
|
||||||
|
"fontSize": 24,
|
||||||
|
"fontPath": "resources/fonts/DroidSans.ttf",
|
||||||
|
"textCentered": true,
|
||||||
|
"color": [1.0, 1.0, 1.0, 1.0],
|
||||||
|
"textures": {
|
||||||
|
"normal": "resources/w/red.png",
|
||||||
|
"hover": "resources/w/red.png",
|
||||||
|
"pressed": "resources/w/red.png"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "FrameLayout",
|
"type": "FrameLayout",
|
||||||
|
|||||||
@ -5,24 +5,6 @@
|
|||||||
"width": "match_parent",
|
"width": "match_parent",
|
||||||
"height": "match_parent",
|
"height": "match_parent",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
|
||||||
"type": "TextButton",
|
|
||||||
"name": "quest_journal_button",
|
|
||||||
"x": 220.0,
|
|
||||||
"y": 50.0,
|
|
||||||
"width": 170.0,
|
|
||||||
"height": 60.0,
|
|
||||||
"text": "Quests",
|
|
||||||
"fontSize": 24,
|
|
||||||
"fontPath": "resources/fonts/DroidSans.ttf",
|
|
||||||
"textCentered": true,
|
|
||||||
"color": [1.0, 1.0, 1.0, 1.0],
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/w/red.png",
|
|
||||||
"hover": "resources/w/red.png",
|
|
||||||
"pressed": "resources/w/red.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "FrameLayout",
|
"type": "FrameLayout",
|
||||||
"name": "quest_journal_panel",
|
"name": "quest_journal_panel",
|
||||||
|
|||||||
5066
resources/w/exterior/tree003.txt
Normal file
5066
resources/w/exterior/tree003.txt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resources/w/new_anims/Chat_02_diff.png
(Stored with Git LFS)
Normal file
BIN
resources/w/new_anims/Chat_02_diff.png
(Stored with Git LFS)
Normal file
Binary file not shown.
155902
resources/w/new_anims/girl_stand_idle001.txt
Normal file
155902
resources/w/new_anims/girl_stand_idle001.txt
Normal file
File diff suppressed because it is too large
Load Diff
184025
resources/w/new_anims/girl_stand_idle002.txt
Normal file
184025
resources/w/new_anims/girl_stand_idle002.txt
Normal file
File diff suppressed because it is too large
Load Diff
184025
resources/w/new_anims/girl_stand_idle003.txt
Normal file
184025
resources/w/new_anims/girl_stand_idle003.txt
Normal file
File diff suppressed because it is too large
Load Diff
184025
resources/w/new_anims/girl_stand_idle005.txt
Normal file
184025
resources/w/new_anims/girl_stand_idle005.txt
Normal file
File diff suppressed because it is too large
Load Diff
108627
resources/w/new_anims/girl_walk001.txt
Normal file
108627
resources/w/new_anims/girl_walk001.txt
Normal file
File diff suppressed because it is too large
Load Diff
108480
resources/w/new_anims/girl_walk002.txt
Normal file
108480
resources/w/new_anims/girl_walk002.txt
Normal file
File diff suppressed because it is too large
Load Diff
108480
resources/w/new_anims/girl_walk003.txt
Normal file
108480
resources/w/new_anims/girl_walk003.txt
Normal file
File diff suppressed because it is too large
Load Diff
108480
resources/w/new_anims/girl_walk004.txt
Normal file
108480
resources/w/new_anims/girl_walk004.txt
Normal file
File diff suppressed because it is too large
Load Diff
108480
resources/w/new_anims/girl_walk005.txt
Normal file
108480
resources/w/new_anims/girl_walk005.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -341,7 +341,6 @@ void Character::update(int64_t deltaMs) {
|
|||||||
facingAngle += (angleDiff > 0.f ? rotStep : -rotStep);
|
facingAngle += (angleDiff > 0.f ? rotStep : -rotStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (hitSparkEmitter.isConfigured()) {
|
if (hitSparkEmitter.isConfigured()) {
|
||||||
hitSparkEmitter.update(static_cast<float>(deltaMs));
|
hitSparkEmitter.update(static_cast<float>(deltaMs));
|
||||||
|
|||||||
187
src/Game.cpp
187
src/Game.cpp
@ -236,51 +236,9 @@ namespace ZL
|
|||||||
|
|
||||||
std::cout << "Load resurces step 13" << std::endl;
|
std::cout << "Load resurces step 13" << std::endl;
|
||||||
|
|
||||||
// Load UI with inventory button
|
|
||||||
try {
|
try {
|
||||||
menuManager.uiManager.loadFromFile("resources/config2/ui_inventory.json", renderer, CONST_ZIP_FILE);
|
menuManager.setup(inventory, 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;
|
std::cout << "UI loaded successfully" << std::endl;
|
||||||
|
|
||||||
menuManager.uiManager.setNodeVisible("inventory_items_panel", false);
|
|
||||||
menuManager.uiManager.setNodeVisible("close_inventory_button", false);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Update UI with current items
|
|
||||||
const auto& items = this->inventory.getItems();
|
|
||||||
std::string itemText;
|
|
||||||
|
|
||||||
if (items.empty()) {
|
|
||||||
itemText = "Inventory (Empty)";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
itemText = "Inventory (" + std::to_string(items.size()) + " items)\n\n";
|
|
||||||
for (size_t i = 0; i < items.size(); ++i) {
|
|
||||||
itemText += std::to_string(i + 1) + ". " + items[i].name + "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->menuManager.uiManager.setText("inventory_items_text", itemText);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
menuManager.uiManager.setTextButtonCallback("close_inventory_button", [this](const std::string& name) {
|
|
||||||
std::cout << "[UI] Close button clicked" << std::endl;
|
|
||||||
menuManager.uiManager.setNodeVisible("inventory_items_panel", false);
|
|
||||||
menuManager.uiManager.setNodeVisible("close_inventory_button", false);
|
|
||||||
inventoryOpen = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
catch (const std::exception& e) {
|
catch (const std::exception& e) {
|
||||||
std::cerr << "Failed to load UI: " << e.what() << std::endl;
|
std::cerr << "Failed to load UI: " << e.what() << std::endl;
|
||||||
@ -327,147 +285,6 @@ namespace ZL
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
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() {
|
void Game::drawScene() {
|
||||||
glViewport(0, 0, Environment::width, Environment::height);
|
glViewport(0, 0, Environment::width, Environment::height);
|
||||||
if (!loadingCompleted) {
|
if (!loadingCompleted) {
|
||||||
@ -702,7 +519,7 @@ namespace ZL
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_j:
|
case SDLK_j:
|
||||||
toggleQuestJournal();
|
menuManager.toggleQuestJournal();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_RETURN:
|
case SDLK_RETURN:
|
||||||
|
|||||||
14
src/Game.h
14
src/Game.h
@ -20,8 +20,6 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "Location.h"
|
#include "Location.h"
|
||||||
#include "AudioPlayerAsync.h"
|
#include "AudioPlayerAsync.h"
|
||||||
#include "quest/QuestJournal.h"
|
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
@ -51,13 +49,6 @@ namespace ZL {
|
|||||||
Inventory inventory;
|
Inventory inventory;
|
||||||
InteractiveObject* pickedUpObject = nullptr;
|
InteractiveObject* pickedUpObject = nullptr;
|
||||||
|
|
||||||
bool inventoryOpen = false;
|
|
||||||
|
|
||||||
ZL::Quest::QuestJournal questJournal;
|
|
||||||
bool questJournalOpen = false;
|
|
||||||
int selectedQuestIndex = -1;
|
|
||||||
std::vector<std::string> visibleQuestIds;
|
|
||||||
|
|
||||||
MenuManager menuManager;
|
MenuManager menuManager;
|
||||||
|
|
||||||
void activateSlowMoEffect();
|
void activateSlowMoEffect();
|
||||||
@ -107,11 +98,6 @@ namespace ZL {
|
|||||||
void endPinch();
|
void endPinch();
|
||||||
int countNonUiPointers() const;
|
int countNonUiPointers() const;
|
||||||
|
|
||||||
void setupQuestJournalUi();
|
|
||||||
void toggleQuestJournal();
|
|
||||||
void refreshQuestJournalUi();
|
|
||||||
void selectQuestByIndex(int index);
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
#ifdef EMSCRIPTEN
|
||||||
static Game* s_instance;
|
static Game* s_instance;
|
||||||
static void onResourcesZipLoaded(const char* filename);
|
static void onResourcesZipLoaded(const char* filename);
|
||||||
|
|||||||
@ -157,6 +157,7 @@ namespace ZL
|
|||||||
teleportSparks->setUseWorldSpace(true);
|
teleportSparks->setUseWorldSpace(true);
|
||||||
teleportSparks->markConfigured();
|
teleportSparks->markConfigured();
|
||||||
|
|
||||||
|
|
||||||
// If the player happens to spawn already inside the zone, treat them
|
// If the player happens to spawn already inside the zone, treat them
|
||||||
// as in-zone so they don't immediately teleport on the first update.
|
// as in-zone so they don't immediately teleport on the first update.
|
||||||
if (player && (player->position - teleportPosition).norm() <= teleportRadius) {
|
if (player && (player->position - teleportPosition).norm() <= teleportRadius) {
|
||||||
@ -957,7 +958,7 @@ namespace ZL
|
|||||||
|
|
||||||
// Check if we clicked on an NPC
|
// Check if we clicked on an NPC
|
||||||
Character* clickedNpc = raycastNpcs(camPos, rayDir);
|
Character* clickedNpc = raycastNpcs(camPos, rayDir);
|
||||||
if (clickedNpc && player) {
|
if (clickedNpc && player && clickedNpc->hp > 0) {
|
||||||
float distance = (player->position - clickedNpc->position).norm();
|
float distance = (player->position - clickedNpc->position).norm();
|
||||||
int npcIndex = -1;
|
int npcIndex = -1;
|
||||||
for (size_t i = 0; i < npcs.size(); ++i) {
|
for (size_t i = 0; i < npcs.size(); ++i) {
|
||||||
@ -966,7 +967,7 @@ namespace ZL
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (npcIndex != -1 && clickedNpc->hp > 0) {
|
if (npcIndex != -1) {
|
||||||
targetInteractiveObject = nullptr;
|
targetInteractiveObject = nullptr;
|
||||||
|
|
||||||
if (clickedNpc->canAttack) {
|
if (clickedNpc->canAttack) {
|
||||||
|
|||||||
@ -1,392 +1,198 @@
|
|||||||
#include "MenuManager.h"
|
#include "MenuManager.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
#ifdef EMSCRIPTEN
|
#include <string>
|
||||||
#include <emscripten.h>
|
|
||||||
#include <cstdlib>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
extern bool inverseVertical;
|
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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MenuManager::MenuManager(Renderer& iRenderer) :
|
MenuManager::MenuManager(Renderer& iRenderer) :
|
||||||
renderer(iRenderer)
|
renderer(iRenderer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void MenuManager::setup(Inventory& inv, const std::string& zipFile) {
|
||||||
void MenuManager::setupMenu()
|
inventory = &inv;
|
||||||
{
|
|
||||||
mainMenuRoot = loadUiFromFile("resources/config/main_menu.json", renderer, CONST_ZIP_FILE);
|
|
||||||
aboutMenuRoot = loadUiFromFile("resources/config/about.json", renderer, CONST_ZIP_FILE);
|
|
||||||
shipSelectionRoot = loadUiFromFile("resources/config/ship_selection_menu.json", renderer, CONST_ZIP_FILE);
|
|
||||||
connectingRoot = loadUiFromFile("resources/config/connecting.json", renderer, CONST_ZIP_FILE);
|
|
||||||
connectionFailedRoot= loadUiFromFile("resources/config/connection_failed.json", renderer, CONST_ZIP_FILE);
|
|
||||||
gameplayRoot = loadUiFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
|
|
||||||
gameOverRoot = loadUiFromFile("resources/config/game_over.json", renderer, CONST_ZIP_FILE);
|
|
||||||
helpScreenRoot = loadUiFromFile("resources/config/ui_with_help.json", renderer, CONST_ZIP_FILE);
|
|
||||||
connectionLostRoot = loadUiFromFile("resources/config/connection_lost.json", renderer, CONST_ZIP_FILE);
|
|
||||||
|
|
||||||
enterMainMenu();
|
ingameRoot = loadUiFromFile("resources/config2/ui_inventory.json", renderer, zipFile);
|
||||||
|
questJournalRoot = loadUiFromFile("resources/config2/ui_quest_journal.json", renderer, zipFile);
|
||||||
|
|
||||||
|
questJournal.loadFromFile("resources/quests/quests.json", zipFile);
|
||||||
|
|
||||||
|
enterGameplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MenuManager::shouldRenderSpace() const
|
void MenuManager::enterGameplay() {
|
||||||
{
|
|
||||||
return state == GameState::Gameplay
|
|
||||||
|| state == GameState::GameOver
|
|
||||||
|| state == GameState::HelpScreen
|
|
||||||
|| state == GameState::ConnectionLost;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── State: MainMenu ──────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
void MenuManager::enterMainMenu()
|
|
||||||
{
|
|
||||||
state = GameState::MainMenu;
|
|
||||||
uiManager.replaceRoot(mainMenuRoot);
|
|
||||||
|
|
||||||
if (onMainMenuEntered) onMainMenuEntered();
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("singleButton", [this](const std::string&) {
|
|
||||||
enterShipSelectionSingle();
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("multiplayerButton", [this](const std::string&) {
|
|
||||||
enterShipSelectionMulti();
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("aboutButton", [this](const std::string&) {
|
|
||||||
enterAboutMenu();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void MenuManager::enterAboutMenu()
|
|
||||||
{
|
|
||||||
state = GameState::AboutMenu;
|
|
||||||
uiManager.replaceRoot(aboutMenuRoot);
|
|
||||||
uiManager.setButtonCallback("aboutBackButton", [this](const std::string&) {
|
|
||||||
enterMainMenu();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── State: ShipSelectionSingle ───────────────────────────────────────────
|
|
||||||
|
|
||||||
void MenuManager::enterShipSelectionSingle()
|
|
||||||
{
|
|
||||||
state = GameState::ShipSelectionSingle;
|
|
||||||
uiManager.replaceRoot(shipSelectionRoot);
|
|
||||||
|
|
||||||
std::string initialNick;
|
|
||||||
#ifdef EMSCRIPTEN
|
|
||||||
char* savedNickC = emscripten_run_script_string("localStorage.getItem('spacegame_nick') || ''");
|
|
||||||
if (savedNickC) {
|
|
||||||
initialNick = savedNickC;
|
|
||||||
free(savedNickC);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto tf = uiManager.findTextField("nicknameInput");
|
|
||||||
if (tf) {
|
|
||||||
if (!initialNick.empty()) tf->text = initialNick;
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
|
||||||
uiManager.setTextFieldCallback("nicknameInput", [](const std::string&, const std::string& value) {
|
|
||||||
EM_ASM_({
|
|
||||||
try { localStorage.setItem('spacegame_nick', UTF8ToString($0)); } catch(e) {}
|
|
||||||
}, value.c_str());
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("spaceshipButton", [this, initialNick](const std::string&) {
|
|
||||||
std::string nick = uiManager.getTextFieldValue("nicknameInput");
|
|
||||||
if (nick.empty()) nick = initialNick;
|
|
||||||
if (nick.empty()) nick = "Player";
|
|
||||||
enterGameplay();
|
|
||||||
if (onSingleplayerPressed) onSingleplayerPressed(nick, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("cargoshipButton", [this, initialNick](const std::string&) {
|
|
||||||
std::string nick = uiManager.getTextFieldValue("nicknameInput");
|
|
||||||
if (nick.empty()) nick = initialNick;
|
|
||||||
if (nick.empty()) nick = "Player";
|
|
||||||
enterGameplay();
|
|
||||||
if (onSingleplayerPressed) onSingleplayerPressed(nick, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("backButton", [this](const std::string&) {
|
|
||||||
enterMainMenu();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── State: ShipSelectionMulti ─────────────────────────────────────────────
|
|
||||||
|
|
||||||
void MenuManager::enterShipSelectionMulti()
|
|
||||||
{
|
|
||||||
state = GameState::ShipSelectionMulti;
|
|
||||||
uiManager.replaceRoot(shipSelectionRoot);
|
|
||||||
|
|
||||||
std::string initialNick;
|
|
||||||
#ifdef EMSCRIPTEN
|
|
||||||
char* savedNickC = emscripten_run_script_string("localStorage.getItem('spacegame_nick') || ''");
|
|
||||||
if (savedNickC) {
|
|
||||||
initialNick = savedNickC;
|
|
||||||
free(savedNickC);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto tf = uiManager.findTextField("nicknameInput");
|
|
||||||
if (tf) {
|
|
||||||
if (!initialNick.empty()) tf->text = initialNick;
|
|
||||||
|
|
||||||
#ifdef EMSCRIPTEN
|
|
||||||
uiManager.setTextFieldCallback("nicknameInput", [](const std::string&, const std::string& value) {
|
|
||||||
EM_ASM_({
|
|
||||||
try { localStorage.setItem('spacegame_nick', UTF8ToString($0)); } catch(e) {}
|
|
||||||
}, value.c_str());
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("spaceshipButton", [this, initialNick](const std::string&) {
|
|
||||||
std::string nick = uiManager.getTextFieldValue("nicknameInput");
|
|
||||||
if (nick.empty()) nick = initialNick;
|
|
||||||
if (nick.empty()) nick = "Player";
|
|
||||||
pendingMultiNick = nick;
|
|
||||||
pendingMultiShipType = 0;
|
|
||||||
enterConnecting();
|
|
||||||
if (onMultiplayerPressed) onMultiplayerPressed(nick, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("cargoshipButton", [this, initialNick](const std::string&) {
|
|
||||||
std::string nick = uiManager.getTextFieldValue("nicknameInput");
|
|
||||||
if (nick.empty()) nick = initialNick;
|
|
||||||
if (nick.empty()) nick = "Player";
|
|
||||||
pendingMultiNick = nick;
|
|
||||||
pendingMultiShipType = 1;
|
|
||||||
enterConnecting();
|
|
||||||
if (onMultiplayerPressed) onMultiplayerPressed(nick, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("backButton", [this](const std::string&) {
|
|
||||||
enterMainMenu();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── State: Connecting ────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
void MenuManager::enterConnecting()
|
|
||||||
{
|
|
||||||
state = GameState::Connecting;
|
|
||||||
uiManager.replaceRoot(connectingRoot);
|
|
||||||
// No interactive elements — just a static "Connecting..." image
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── State: ConnectionFailed ───────────────────────────────────────────────
|
|
||||||
|
|
||||||
void MenuManager::enterConnectionFailed()
|
|
||||||
{
|
|
||||||
state = GameState::ConnectionFailed;
|
|
||||||
uiManager.replaceRoot(connectionFailedRoot);
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("connectionFailedReconnectButton", [this](const std::string&) {
|
|
||||||
enterConnecting();
|
|
||||||
if (onMultiplayerPressed) onMultiplayerPressed(pendingMultiNick, pendingMultiShipType);
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("connectionFailedGoBack", [this](const std::string&) {
|
|
||||||
enterMainMenu();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── State: Gameplay ──────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
void MenuManager::enterGameplay()
|
|
||||||
{
|
|
||||||
state = GameState::Gameplay;
|
state = GameState::Gameplay;
|
||||||
uiManager.replaceRoot(gameplayRoot);
|
uiManager.replaceRoot(ingameRoot);
|
||||||
|
|
||||||
if (Environment::shipState.shipType == 1)
|
uiManager.setNodeVisible("inventory_items_panel", false);
|
||||||
{
|
uiManager.setNodeVisible("close_inventory_button", false);
|
||||||
uiManager.findButton("shootButton")->state = ButtonState::Disabled;
|
inventoryOpen = false;
|
||||||
uiManager.findButton("shootButton2")->state = ButtonState::Disabled;
|
|
||||||
}
|
uiManager.setTextButtonCallback("inventory_button", [this](const std::string&) {
|
||||||
else
|
std::cout << "[UI] Inventory button clicked" << std::endl;
|
||||||
{
|
uiManager.setNodeVisible("inventory_items_panel", true);
|
||||||
if (Environment::shipState.velocity < 0.1)
|
uiManager.setNodeVisible("close_inventory_button", true);
|
||||||
{
|
inventoryOpen = true;
|
||||||
uiManager.findButton("minusButton")->state = ButtonState::Disabled;
|
|
||||||
uiManager.findButton("plusButton")->state = ButtonState::Normal;
|
const auto& items = inventory->getItems();
|
||||||
uiManager.findButton("shootButton")->state = ButtonState::Normal;
|
std::string itemText;
|
||||||
uiManager.findButton("shootButton2")->state = ButtonState::Normal;
|
if (items.empty()) {
|
||||||
|
itemText = "Inventory (Empty)";
|
||||||
}
|
}
|
||||||
else if (Environment::shipState.velocity >= 0.1 && Environment::shipState.velocity <= 200)
|
else {
|
||||||
{
|
itemText = "Inventory (" + std::to_string(items.size()) + " items)\n\n";
|
||||||
uiManager.findButton("minusButton")->state = ButtonState::Normal;
|
for (size_t i = 0; i < items.size(); ++i) {
|
||||||
uiManager.findButton("plusButton")->state = ButtonState::Normal;
|
itemText += std::to_string(i + 1) + ". " + items[i].name + "\n";
|
||||||
uiManager.findButton("shootButton")->state = ButtonState::Normal;
|
}
|
||||||
uiManager.findButton("shootButton2")->state = ButtonState::Normal;
|
|
||||||
}
|
}
|
||||||
else if (Environment::shipState.velocity > 200 && Environment::shipState.velocity < 400 - 0.1)
|
uiManager.setText("inventory_items_text", itemText);
|
||||||
{
|
|
||||||
uiManager.findButton("minusButton")->state = ButtonState::Normal;
|
|
||||||
uiManager.findButton("plusButton")->state = ButtonState::Normal;
|
|
||||||
uiManager.findButton("shootButton")->state = ButtonState::Disabled;
|
|
||||||
uiManager.findButton("shootButton2")->state = ButtonState::Disabled;
|
|
||||||
}
|
|
||||||
else if (Environment::shipState.velocity >= 400 - 0.1)
|
|
||||||
{
|
|
||||||
uiManager.findButton("minusButton")->state = ButtonState::Normal;
|
|
||||||
uiManager.findButton("plusButton")->state = ButtonState::Disabled;
|
|
||||||
uiManager.findButton("shootButton")->state = ButtonState::Disabled;
|
|
||||||
uiManager.findButton("shootButton2")->state = ButtonState::Disabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forceSetupSpaceUICallback)
|
|
||||||
{
|
|
||||||
forceSetupSpaceUICallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto btn = uiManager.findButton("takeButton")) btn->state = ButtonState::Disabled;
|
|
||||||
if (auto btn = uiManager.findButton("showPlayersButton"))
|
|
||||||
{
|
|
||||||
btn->state = ButtonState::Disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uiManager.setButtonPressCallback("shootButton", [this](const std::string&) {
|
|
||||||
if (onFirePressed) onFirePressed();
|
|
||||||
});
|
|
||||||
uiManager.setButtonPressCallback("shootButton2", [this](const std::string&) {
|
|
||||||
if (onFirePressed) onFirePressed();
|
|
||||||
});
|
|
||||||
uiManager.setButtonPressCallback("plusButton", [this](const std::string&) {
|
|
||||||
int newVel = Environment::shipState.selectedVelocity + 1;
|
|
||||||
if (newVel > 4) newVel = 4;
|
|
||||||
uiManager.findButton("minusButton")->state = ButtonState::Normal;
|
|
||||||
if (newVel == 4)
|
|
||||||
{
|
|
||||||
uiManager.findButton("plusButton")->state = ButtonState::Disabled;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uiManager.findButton("plusButton")->state = ButtonState::Normal;
|
|
||||||
}
|
|
||||||
if (onVelocityChanged) onVelocityChanged(newVel);
|
|
||||||
});
|
|
||||||
uiManager.setButtonPressCallback("minusButton", [this](const std::string&) {
|
|
||||||
int newVel = Environment::shipState.selectedVelocity - 1;
|
|
||||||
if (newVel < 0) newVel = 0;
|
|
||||||
uiManager.findButton("plusButton")->state = ButtonState::Normal;
|
|
||||||
if (newVel == 0)
|
|
||||||
{
|
|
||||||
uiManager.findButton("minusButton")->state = ButtonState::Disabled;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
uiManager.findButton("minusButton")->state = ButtonState::Normal;
|
|
||||||
}
|
|
||||||
if (onVelocityChanged) onVelocityChanged(newVel);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
uiManager.setButtonPressCallback("takeButton", [this](const std::string&) {
|
uiManager.setTextButtonCallback("close_inventory_button", [this](const std::string&) {
|
||||||
if (onTakeButtonPressed) onTakeButtonPressed();
|
std::cout << "[UI] Close button clicked" << std::endl;
|
||||||
|
uiManager.setNodeVisible("inventory_items_panel", false);
|
||||||
|
uiManager.setNodeVisible("close_inventory_button", false);
|
||||||
|
inventoryOpen = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
uiManager.setButtonCallback("showPlayersButton", [this](const std::string&) {
|
uiManager.setTextButtonCallback("quest_journal_button", [this](const std::string&) {
|
||||||
if (onShowPlayersPressed) onShowPlayersPressed();
|
openQuestJournal();
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonPressCallback("inverseMouseButton", [this](const std::string&) {
|
|
||||||
inverseVertical = !inverseVertical;
|
|
||||||
std::cout << "Inverse mouse: " << (inverseVertical ? "ON" : "OFF") << std::endl;
|
|
||||||
});
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("infoButton", [this](const std::string&) {
|
|
||||||
//if (onShowPlayersPressed) onShowPlayersPressed();
|
|
||||||
enterHelp();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── State: GameOver ──────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
void MenuManager::enterGameOver(int score)
|
|
||||||
{
|
|
||||||
state = GameState::GameOver;
|
|
||||||
uiManager.replaceRoot(gameOverRoot);
|
|
||||||
|
|
||||||
uiManager.setText("scoreText", "Score: " + std::to_string(score));
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("restartButton", [this](const std::string&) {
|
|
||||||
if (onRestartPressed) onRestartPressed();
|
|
||||||
enterGameplay();
|
|
||||||
});
|
|
||||||
uiManager.setButtonCallback("gameOverExitButton", [this](const std::string&) {
|
|
||||||
enterMainMenu();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuManager::enterHelp()
|
void MenuManager::openQuestJournal() {
|
||||||
{
|
if (inventoryOpen) {
|
||||||
state = GameState::HelpScreen;
|
uiManager.setNodeVisible("inventory_items_panel", false);
|
||||||
uiManager.replaceRoot(helpScreenRoot);
|
uiManager.setNodeVisible("close_inventory_button", false);
|
||||||
|
inventoryOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
uiManager.setButtonCallback("infoButtonUnderlying_help", [this](const std::string&) {
|
state = GameState::QuestJournal;
|
||||||
enterGameplay();
|
uiManager.pushMenuFromSavedRoot(questJournalRoot);
|
||||||
|
|
||||||
|
uiManager.setTextButtonCallback("quest_close_button", [this](const std::string&) {
|
||||||
|
closeQuestJournal();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < 9; ++i) {
|
||||||
|
const std::string slotName = "quest_slot_" + std::to_string(i);
|
||||||
|
uiManager.setTextButtonCallback(slotName, [this, i](const std::string&) {
|
||||||
|
selectQuestByIndex(i);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshQuestJournalUi();
|
||||||
|
if (!visibleQuestIds.empty()) {
|
||||||
|
selectQuestByIndex(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── State: ConnectionLost ─────────────────────────────────────────────────
|
void MenuManager::closeQuestJournal() {
|
||||||
|
state = GameState::Gameplay;
|
||||||
|
selectedQuestIndex = -1;
|
||||||
|
visibleQuestIds.clear();
|
||||||
|
uiManager.popMenu();
|
||||||
|
}
|
||||||
|
|
||||||
void MenuManager::enterConnectionLost()
|
void MenuManager::toggleQuestJournal() {
|
||||||
{
|
std::cout << "[quest] toggleQuestJournal: " << (isQuestJournalOpen() ? "closing" : "opening") << std::endl;
|
||||||
state = GameState::ConnectionLost;
|
if (isQuestJournalOpen()) {
|
||||||
uiManager.replaceRoot(connectionLostRoot);
|
closeQuestJournal();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
openQuestJournal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uiManager.setButtonCallback("reconnectButton", [this](const std::string&) {
|
void MenuManager::refreshQuestJournalUi() {
|
||||||
enterConnecting();
|
visibleQuestIds.clear();
|
||||||
if (onMultiplayerPressed) onMultiplayerPressed(pendingMultiNick, pendingMultiShipType);
|
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;
|
||||||
|
return a->orderIndex > b->orderIndex;
|
||||||
});
|
});
|
||||||
uiManager.setButtonCallback("exitServerButton", [this](const std::string&) {
|
|
||||||
enterMainMenu();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Public event API ──────────────────────────────────────────────────────
|
for (int i = 0; i < 9; ++i) {
|
||||||
|
const std::string slotName = "quest_slot_" + std::to_string(i);
|
||||||
|
|
||||||
void MenuManager::notifyConnected()
|
if (i < static_cast<int>(quests.size())) {
|
||||||
{
|
const auto* quest = quests[i];
|
||||||
if (state == GameState::Connecting) {
|
visibleQuestIds.push_back(quest->definition.id);
|
||||||
enterGameplay();
|
|
||||||
|
const bool selected = (i == selectedQuestIndex);
|
||||||
|
const std::string prefix = selected ? "> " : " ";
|
||||||
|
uiManager.setTextButtonText(slotName, prefix + quest->definition.title);
|
||||||
|
uiManager.setTextButtonColor(slotName, questStatusColor(quest->status));
|
||||||
|
uiManager.setNodeVisible(slotName, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uiManager.setTextButtonText(slotName, "");
|
||||||
|
uiManager.setNodeVisible(slotName, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuManager::notifyConnectionFailed()
|
void MenuManager::selectQuestByIndex(int index) {
|
||||||
{
|
if (index < 0 || index >= static_cast<int>(visibleQuestIds.size())) {
|
||||||
if (state == GameState::Connecting) {
|
return;
|
||||||
enterConnectionFailed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectedQuestIndex = index;
|
||||||
|
Quest::QuestState* quest = questJournal.findQuest(visibleQuestIds[index]);
|
||||||
|
if (!quest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& def = quest->definition;
|
||||||
|
|
||||||
|
uiManager.setText("quest_middle_title_text", def.title);
|
||||||
|
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);
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uiManager.setText("quest_objectives_text", objectivesText);
|
||||||
|
|
||||||
|
uiManager.setText("quest_lore_title_text", "Описание задания");
|
||||||
|
uiManager.setText("quest_description_text", def.description);
|
||||||
|
|
||||||
|
refreshQuestJournalUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuManager::showGameOver(int score)
|
} // namespace ZL
|
||||||
{
|
|
||||||
if (state == GameState::Gameplay) {
|
|
||||||
enterGameOver(score);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MenuManager::showConnectionLost()
|
|
||||||
{
|
|
||||||
if (state == GameState::Gameplay) {
|
|
||||||
enterConnectionLost();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
} // namespace ZL
|
|
||||||
|
|||||||
@ -3,86 +3,51 @@
|
|||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include "render/TextureManager.h"
|
#include "render/TextureManager.h"
|
||||||
#include "UiManager.h"
|
#include "UiManager.h"
|
||||||
|
#include "items/Item.h"
|
||||||
|
#include "quest/QuestJournal.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
extern const char* CONST_ZIP_FILE;
|
extern const char* CONST_ZIP_FILE;
|
||||||
|
|
||||||
enum class GameState {
|
enum class GameState {
|
||||||
MainMenu,
|
|
||||||
AboutMenu,
|
|
||||||
ShipSelectionSingle,
|
|
||||||
ShipSelectionMulti,
|
|
||||||
Connecting,
|
|
||||||
ConnectionFailed,
|
|
||||||
Gameplay,
|
Gameplay,
|
||||||
GameOver,
|
QuestJournal
|
||||||
HelpScreen,
|
|
||||||
ConnectionLost
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class MenuManager {
|
class MenuManager {
|
||||||
protected:
|
|
||||||
Renderer& renderer;
|
|
||||||
/*
|
|
||||||
// Pre-loaded UI roots (loaded once in setupMenu)
|
|
||||||
std::shared_ptr<UiNode> mainMenuRoot;
|
|
||||||
std::shared_ptr<UiNode> aboutMenuRoot;
|
|
||||||
std::shared_ptr<UiNode> shipSelectionRoot;
|
|
||||||
std::shared_ptr<UiNode> connectingRoot;
|
|
||||||
std::shared_ptr<UiNode> connectionFailedRoot;
|
|
||||||
std::shared_ptr<UiNode> gameplayRoot;
|
|
||||||
std::shared_ptr<UiNode> gameOverRoot;
|
|
||||||
std::shared_ptr<UiNode> helpScreenRoot;
|
|
||||||
std::shared_ptr<UiNode> connectionLostRoot;
|
|
||||||
|
|
||||||
// Stored for multiplayer retry
|
|
||||||
std::string pendingMultiNick;
|
|
||||||
int pendingMultiShipType = 0;
|
|
||||||
|
|
||||||
GameState state = GameState::MainMenu;
|
|
||||||
|
|
||||||
// State transition methods
|
|
||||||
void enterMainMenu();
|
|
||||||
void enterAboutMenu();
|
|
||||||
void enterShipSelectionSingle();
|
|
||||||
void enterShipSelectionMulti();
|
|
||||||
void enterConnecting();
|
|
||||||
void enterConnectionFailed();
|
|
||||||
void enterGameplay();
|
|
||||||
void enterGameOver(int score);
|
|
||||||
void enterHelp();
|
|
||||||
void enterConnectionLost();
|
|
||||||
*/
|
|
||||||
public:
|
public:
|
||||||
UiManager uiManager;
|
UiManager uiManager;
|
||||||
|
ZL::Quest::QuestJournal questJournal;
|
||||||
|
|
||||||
MenuManager(Renderer& iRenderer);
|
MenuManager(Renderer& iRenderer);
|
||||||
|
|
||||||
//void setupMenu();
|
void setup(Inventory& inv, const std::string& zipFile);
|
||||||
|
void openQuestJournal();
|
||||||
|
void closeQuestJournal();
|
||||||
|
void toggleQuestJournal();
|
||||||
|
bool isQuestJournalOpen() const { return state == GameState::QuestJournal; }
|
||||||
|
|
||||||
/*
|
protected:
|
||||||
// Returns true for states where Space should render and run (Gameplay, GameOver, ConnectionLost)
|
Renderer& renderer;
|
||||||
bool shouldRenderSpace() const;
|
|
||||||
GameState getState() const { return state; }
|
|
||||||
|
|
||||||
// Called by game events
|
private:
|
||||||
void showGameOver(int score);
|
void enterGameplay();
|
||||||
void showConnectionLost();
|
void refreshQuestJournalUi();
|
||||||
void notifyConnected();
|
void selectQuestByIndex(int index);
|
||||||
void notifyConnectionFailed();
|
|
||||||
|
|
||||||
// Callbacks set by Game/Space
|
GameState state = GameState::Gameplay;
|
||||||
std::function<void()> onMainMenuEntered;
|
Inventory* inventory = nullptr;
|
||||||
std::function<void()> onRestartPressed;
|
|
||||||
std::function<void(float)> onVelocityChanged;
|
|
||||||
std::function<void()> onFirePressed;
|
|
||||||
std::function<void()> onTakeButtonPressed;
|
|
||||||
std::function<void(const std::string&, int)> onSingleplayerPressed;
|
|
||||||
std::function<void(const std::string&, int)> onMultiplayerPressed;
|
|
||||||
std::function<void()> onShowPlayersPressed;
|
|
||||||
|
|
||||||
std::function<void()> forceSetupSpaceUICallback;*/
|
std::shared_ptr<UiNode> ingameRoot;
|
||||||
|
std::shared_ptr<UiNode> questJournalRoot;
|
||||||
|
|
||||||
|
bool inventoryOpen = false;
|
||||||
|
int selectedQuestIndex = -1;
|
||||||
|
std::vector<std::string> visibleQuestIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user