Files
cursebreaker-parser/src/configs/npcs.cpp
cdemeyer-teachx a1c9a2e54d refactor
2025-11-12 11:34:51 +09:00

125 lines
4.5 KiB
C++

#include "configs/npcs.hpp"
#include "project_parser.h"
#include "helpers.hpp"
#include <iostream>
#include <sstream>
#include <algorithm>
namespace cursebreaker {
// Static helper functions
static std::string getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue = "");
static int getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue = 0);
static bool getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue = false);
static void parseNPC(tinyxml2::XMLElement* npcElement);
static void parseStats(tinyxml2::XMLElement* npcElement, NPC& npc);
static void parseLoot(tinyxml2::XMLElement* npcElement, NPC& npc);
bool loadNPCsFromXML(const std::string& filepath) {
tinyxml2::XMLDocument doc;
tinyxml2::XMLError result = doc.LoadFile(filepath.c_str());
if (result != tinyxml2::XML_SUCCESS) {
std::cerr << "Failed to load NPCs XML file: " << filepath << std::endl;
return false;
}
tinyxml2::XMLElement* root = doc.FirstChildElement("npcs");
if (!root) {
std::cerr << "Invalid XML structure: missing 'npcs' root element" << std::endl;
return false;
}
g_parsedProject.m_npcs.clear();
// Parse all NPCs
for (tinyxml2::XMLElement* npcElement = root->FirstChildElement("npc");
npcElement != nullptr;
npcElement = npcElement->NextSiblingElement("npc")) {
parseNPC(npcElement);
}
std::cout << "Loaded " << g_parsedProject.m_npcs.size() << " NPCs from XML" << std::endl;
return true;
}
void parseNPC(tinyxml2::XMLElement* npcElement) {
NPC npc;
// Parse basic attributes
npc.id = static_cast<uint16_t>(getAttributeValueInt(npcElement, "id"));
npc.name = getAttributeValue(npcElement, "name");
npc.description = getAttributeValue(npcElement, "description");
npc.faction = getAttributeValue(npcElement, "faction");
// Parse numeric attributes
npc.level = static_cast<uint16_t>(getAttributeValueInt(npcElement, "level"));
npc.health = static_cast<uint16_t>(getAttributeValueInt(npcElement, "health"));
npc.mana = static_cast<uint16_t>(getAttributeValueInt(npcElement, "mana"));
npc.experience = static_cast<uint16_t>(getAttributeValueInt(npcElement, "experience"));
npc.lootTableId = static_cast<uint16_t>(getAttributeValueInt(npcElement, "loottableid"));
// Parse child elements
parseStats(npcElement, npc);
parseLoot(npcElement, npc);
g_parsedProject.m_npcs[npc.id] = std::move(npc);
}
void parseStats(tinyxml2::XMLElement* npcElement, NPC& npc) {
for (tinyxml2::XMLElement* statElement = npcElement->FirstChildElement("stat");
statElement != nullptr;
statElement = statElement->NextSiblingElement("stat")) {
NPCStat stat;
std::string statTypeStr = getAttributeValue(statElement, "type");
stat.type = stringToStatType(statTypeStr);
stat.value = static_cast<uint16_t>(getAttributeValueInt(statElement, "value"));
npc.stats.push_back(stat);
}
}
void parseLoot(tinyxml2::XMLElement* npcElement, NPC& npc) {
std::string lootItemsStr = getAttributeValue(npcElement, "lootitems");
if (!lootItemsStr.empty()) {
std::stringstream ss(lootItemsStr);
std::string itemStr;
while (std::getline(ss, itemStr, ',')) {
try {
uint16_t itemId = static_cast<uint16_t>(std::stoi(itemStr));
npc.lootItems.push_back(itemId);
} catch (const std::exception&) {
// Skip invalid items
}
}
}
}
const NPC* getNPCById(uint16_t id) {
auto it = g_parsedProject.m_npcs.find(id);
return (it != g_parsedProject.m_npcs.end()) ? &it->second : nullptr;
}
const std::unordered_map<uint16_t, NPC>& getAllNPCs() {
return g_parsedProject.m_npcs;
}
std::string getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue) {
const char* value = element->Attribute(attribute);
return value ? std::string(value) : defaultValue;
}
int getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue) {
int value = defaultValue;
element->QueryIntAttribute(attribute, &value);
return value;
}
bool getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue) {
bool value = defaultValue;
element->QueryBoolAttribute(attribute, &value);
return value;
}
} // namespace cursebreaker