space-game001/src/dialogue/DialogueDatabase.cpp
2026-06-06 22:04:42 +03:00

178 lines
5.3 KiB
C++

#include "dialogue/DialogueDatabase.h"
#include "utils/Utils.h"
#include <iostream>
namespace ZL
{
extern const char* CONST_ZIP_FILE;
}
namespace ZL::Dialogue {
NodeType DialogueDatabase::parseNodeType(const std::string& value) {
if (value == "Choice") return NodeType::Choice;
if (value == "Condition") return NodeType::Condition;
if (value == "SetFlag") return NodeType::SetFlag;
if (value == "Jump") return NodeType::Jump;
if (value == "End") return NodeType::End;
if (value == "CutsceneStart") return NodeType::CutsceneStart;
return NodeType::Line;
}
ChoiceKind DialogueDatabase::parseChoiceKind(const std::string& value) {
if (value == "Optional") return ChoiceKind::Optional;
if (value == "Exit") return ChoiceKind::Exit;
return ChoiceKind::Main;
}
ComparisonOp DialogueDatabase::parseComparisonOp(const std::string& value) {
if (value == "==" || value == "Equals") return ComparisonOp::Equals;
if (value == "!=" || value == "NotEquals") return ComparisonOp::NotEquals;
if (value == ">=" || value == "GreaterOrEqual") return ComparisonOp::GreaterOrEqual;
if (value == "<=" || value == "LessOrEqual") return ComparisonOp::LessOrEqual;
return ComparisonOp::Exists;
}
Condition DialogueDatabase::parseCondition(const json& j) {
Condition c;
c.flag = j.value("flag", "");
c.op = parseComparisonOp(j.value("op", "Exists"));
c.value = j.value("value", 1);
return c;
}
Effect DialogueDatabase::parseEffect(const json& j) {
Effect e;
e.flag = j.value("flag", "");
e.value = j.value("value", 1);
e.relative = j.value("relative", false);
return e;
}
Choice DialogueDatabase::parseChoice(const json& j) {
Choice c;
c.id = j.value("id", "");
c.text = j.value("text", "");
c.next = j.value("next", "");
c.kind = parseChoiceKind(j.value("kind", "Main"));
c.consumeOnce = j.value("consumeOnce", false);
if (j.contains("conditions") && j["conditions"].is_array()) {
for (const auto& item : j["conditions"]) {
c.conditions.push_back(parseCondition(item));
}
}
if (j.contains("effects") && j["effects"].is_array()) {
for (const auto& item : j["effects"]) {
c.effects.push_back(parseEffect(item));
}
}
return c;
}
Node DialogueDatabase::parseNode(const json& j) {
Node node;
node.id = j.value("id", "");
node.type = parseNodeType(j.value("type", "Line"));
node.speaker = j.value("speaker", "");
node.text = j.value("text", "");
node.portrait = j.value("portrait", "");
node.next = j.value("next", "");
node.trueNext = j.value("trueNext", "");
node.falseNext = j.value("falseNext", "");
node.cutsceneId = j.value("cutsceneId", "");
node.luaCallback= j.value("luaCallback", "");
node.chatBubble = j.value("chatBubble", "");
node.questUnlock = j.value("questUnlock", "");
node.questComplete = j.value("questComplete", "");
node.questFail = j.value("questFail", "");
node.objectiveComplete = j.value("objectiveComplete", "");
node.objectiveVisible = j.value("objectiveVisible", "");
if (j.contains("conditions") && j["conditions"].is_array()) {
for (const auto& item : j["conditions"]) {
node.conditions.push_back(parseCondition(item));
}
}
if (j.contains("effects") && j["effects"].is_array()) {
for (const auto& item : j["effects"]) {
node.effects.push_back(parseEffect(item));
}
}
if (j.contains("choices") && j["choices"].is_array()) {
for (const auto& item : j["choices"]) {
node.choices.push_back(parseChoice(item));
}
}
return node;
}
DialogueDefinition DialogueDatabase::parseDialogue(const json& j) {
DialogueDefinition result;
result.id = j.value("id", "");
result.displayName = j.value("displayName", result.id);
result.startNode = j.value("start", "");
result.uninterruptible= j.value("uninterruptible", false);
if (j.contains("nodes") && j["nodes"].is_array()) {
for (const auto& item : j["nodes"]) {
Node node = parseNode(item);
if (!node.id.empty()) {
result.nodes[node.id] = std::move(node);
}
}
}
return result;
}
bool DialogueDatabase::loadFromFile(const std::string& path) {
dialogues.clear();
std::string raw;
try {
if (strlen(CONST_ZIP_FILE) == 0) {
raw = readTextFile(path);
}
else {
auto buf = readFileFromZIP(path, CONST_ZIP_FILE);
if (buf.empty()) {
std::cerr << "[dialogue] Failed to read " << path << " from zip\n";
throw std::runtime_error("Failed to load dialogue file: " + path);
}
raw.assign(buf.begin(), buf.end());
}
}
catch (const std::exception& e) {
std::cerr << "[dialogue] Failed to open " << path << ": " << e.what() << "\n";
throw std::runtime_error("Failed to load dialogue file: " + path);
}
json root;
try {
root = json::parse(raw);
}
catch (const std::exception& e) {
std::cerr << "[dialogue] JSON parse error in " << path << ": " << e.what() << "\n";
return false;
}
if (root.contains("dialogues") && root["dialogues"].is_array()) {
for (const auto& item : root["dialogues"]) {
DialogueDefinition dialogue = parseDialogue(item);
if (!dialogue.id.empty()) {
dialogues[dialogue.id] = std::move(dialogue);
}
}
}
return !dialogues.empty();
}
const DialogueDefinition* DialogueDatabase::findDialogue(const std::string& id) const {
auto it = dialogues.find(id);
return (it != dialogues.end()) ? &it->second : nullptr;
}
} // namespace ZL::Dialogue