HarvestableInfo.xml, Achievements.xml, Loot.xml, NPCInfo.xml and Shops.xml.

This commit is contained in:
cdemeyer-teachx
2025-11-12 08:40:55 +09:00
parent 998313be3c
commit a0f7a0f799
11 changed files with 819 additions and 0 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ CBAssets
build

View File

@@ -0,0 +1,67 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <tinyxml2.h>
#include "constants.h"
namespace cursebreaker {
struct AchievementRequirement
{
ActionType action{};
uint16_t targetId{}; // e.g., item id, npc id, etc.
uint16_t count{};
std::string description;
};
struct Achievement
{
uint16_t id{};
uint16_t points{};
uint16_t category{};
std::string name;
std::string description;
std::string icon;
std::vector<AchievementRequirement> requirements;
Achievement() = default;
};
// Achievements configuration manager
class AchievementsConfig {
public:
static AchievementsConfig& getInstance() {
static AchievementsConfig instance;
return instance;
}
bool loadFromXML(const std::string& filepath);
const Achievement* getAchievementById(int id) const;
const std::unordered_map<int, Achievement>& getAllAchievements() const { return m_achievements; }
private:
AchievementsConfig() = default;
~AchievementsConfig() = default;
AchievementsConfig(const AchievementsConfig&) = delete;
AchievementsConfig& operator=(const AchievementsConfig&) = delete;
std::unordered_map<int, Achievement> m_achievements;
// Helper methods for parsing
void parseAchievement(tinyxml2::XMLElement* achievementElement);
void parseRequirements(tinyxml2::XMLElement* achievementElement, Achievement& achievement);
std::string getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue = "");
int getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue = 0);
bool getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue = false);
};
// Helper functions for enum conversions
ActionType stringToActionType(const std::string& str);
} // namespace cursebreaker

View File

@@ -0,0 +1,65 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <tinyxml2.h>
#include "constants.h"
#include "items.hpp" // for stringToSkillType
namespace cursebreaker {
struct HarvestableLootEntry
{
uint16_t itemId{};
uint16_t amount{};
uint16_t chance{}; // percentage chance
};
struct Harvestable
{
uint16_t id{};
uint16_t level{};
uint16_t respawnTime{}; // in seconds or minutes, TBD
SkillType skill{};
std::string name;
std::string description;
std::vector<HarvestableLootEntry> loot;
Harvestable() = default;
};
// Harvestables configuration manager
class HarvestablesConfig {
public:
static HarvestablesConfig& getInstance() {
static HarvestablesConfig instance;
return instance;
}
bool loadFromXML(const std::string& filepath);
const Harvestable* getHarvestableById(int id) const;
const std::unordered_map<int, Harvestable>& getAllHarvestables() const { return m_harvestables; }
private:
HarvestablesConfig() = default;
~HarvestablesConfig() = default;
HarvestablesConfig(const HarvestablesConfig&) = delete;
HarvestablesConfig& operator=(const HarvestablesConfig&) = delete;
std::unordered_map<int, Harvestable> m_harvestables;
// Helper methods for parsing
void parseHarvestable(tinyxml2::XMLElement* harvestableElement);
void parseLoot(tinyxml2::XMLElement* harvestableElement, Harvestable& harvestable);
std::string getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue = "");
int getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue = 0);
bool getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue = false);
};
} // namespace cursebreaker

61
include/configs/loot.hpp Normal file
View File

@@ -0,0 +1,61 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <tinyxml2.h>
#include "constants.h"
namespace cursebreaker {
struct LootEntry
{
uint16_t itemId{};
uint16_t minAmount{};
uint16_t maxAmount{};
uint16_t chance{}; // percentage chance
uint16_t level{}; // minimum level required
};
struct LootTable
{
uint16_t id{};
std::string name;
std::string description;
std::vector<LootEntry> entries;
LootTable() = default;
};
// Loot configuration manager
class LootConfig {
public:
static LootConfig& getInstance() {
static LootConfig instance;
return instance;
}
bool loadFromXML(const std::string& filepath);
const LootTable* getLootTableById(int id) const;
const std::unordered_map<int, LootTable>& getAllLootTables() const { return m_lootTables; }
private:
LootConfig() = default;
~LootConfig() = default;
LootConfig(const LootConfig&) = delete;
LootConfig& operator=(const LootConfig&) = delete;
std::unordered_map<int, LootTable> m_lootTables;
// Helper methods for parsing
void parseLootTable(tinyxml2::XMLElement* lootTableElement);
void parseEntries(tinyxml2::XMLElement* lootTableElement, LootTable& lootTable);
std::string getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue = "");
int getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue = 0);
bool getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue = false);
};
} // namespace cursebreaker

68
include/configs/npcs.hpp Normal file
View File

@@ -0,0 +1,68 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <tinyxml2.h>
#include "constants.h"
#include "items.hpp" // for stringToStatType
namespace cursebreaker {
struct NPCStat
{
StatType type{};
uint16_t value{};
};
struct NPC
{
uint16_t id{};
uint16_t level{};
uint16_t health{};
uint16_t mana{};
uint16_t experience{};
uint16_t lootTableId{};
std::string name;
std::string description;
std::string faction;
std::vector<NPCStat> stats;
std::vector<uint16_t> lootItems; // alternative simple loot
NPC() = default;
};
// NPCs configuration manager
class NPCsConfig {
public:
static NPCsConfig& getInstance() {
static NPCsConfig instance;
return instance;
}
bool loadFromXML(const std::string& filepath);
const NPC* getNPCById(int id) const;
const std::unordered_map<int, NPC>& getAllNPCs() const { return m_npcs; }
private:
NPCsConfig() = default;
~NPCsConfig() = default;
NPCsConfig(const NPCsConfig&) = delete;
NPCsConfig& operator=(const NPCsConfig&) = delete;
std::unordered_map<int, NPC> m_npcs;
// Helper methods for parsing
void parseNPC(tinyxml2::XMLElement* npcElement);
void parseStats(tinyxml2::XMLElement* npcElement, NPC& npc);
void parseLoot(tinyxml2::XMLElement* npcElement, NPC& npc);
std::string getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue = "");
int getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue = 0);
bool getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue = false);
};
} // namespace cursebreaker

61
include/configs/shops.hpp Normal file
View File

@@ -0,0 +1,61 @@
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <tinyxml2.h>
#include "constants.h"
namespace cursebreaker {
struct ShopItem
{
uint16_t itemId{};
uint16_t price{};
uint16_t stock{}; // -1 for unlimited
uint16_t levelRequired{};
};
struct Shop
{
uint16_t id{};
std::string name;
std::string description;
std::string location;
std::vector<ShopItem> inventory;
Shop() = default;
};
// Shops configuration manager
class ShopsConfig {
public:
static ShopsConfig& getInstance() {
static ShopsConfig instance;
return instance;
}
bool loadFromXML(const std::string& filepath);
const Shop* getShopById(int id) const;
const std::unordered_map<int, Shop>& getAllShops() const { return m_shops; }
private:
ShopsConfig() = default;
~ShopsConfig() = default;
ShopsConfig(const ShopsConfig&) = delete;
ShopsConfig& operator=(const ShopsConfig&) = delete;
std::unordered_map<int, Shop> m_shops;
// Helper methods for parsing
void parseShop(tinyxml2::XMLElement* shopElement);
void parseInventory(tinyxml2::XMLElement* shopElement, Shop& shop);
std::string getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue = "");
int getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue = 0);
bool getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue = false);
};
} // namespace cursebreaker

View File

@@ -0,0 +1,122 @@
#include "configs/achievements.hpp"
#include <iostream>
#include <unordered_map>
namespace cursebreaker {
ActionType stringToActionType(const std::string& str) {
static const std::unordered_map<std::string, ActionType> actionMap = {
{"NpcDeath", ActionType::NpcDeath},
{"PlayerDeath", ActionType::PlayerDeath},
{"PlayerRespawn", ActionType::PlayerRespawn},
{"NpcInteract", ActionType::NpcInteract},
{"QuestUpdate", ActionType::QuestUpdate},
{"QuestTimerEnd", ActionType::QuestTimerEnd},
{"UseItemOnItem", ActionType::UseItemOnItem},
{"UseItemOnNpc", ActionType::UseItemOnNpc},
{"ConsumeItem", ActionType::ConsumeItem},
{"NpcCombatInteract", ActionType::NpcCombatInteract},
{"NpcKilledByPlayer", ActionType::NpcKilledByPlayer},
{"EnterMap", ActionType::EnterMap},
{"VarUpdated", ActionType::VarUpdated},
{"GrantAchievement", ActionType::GrantAchievement},
{"PlayerKilledByNpc", ActionType::PlayerKilledByNpc},
{"UseItem", ActionType::UseItem},
{"CraftItem", ActionType::CraftItem},
{"HarvestItem", ActionType::HarvestItem},
{"BuyItem", ActionType::BuyItem},
{"NpcTagKilledByPlayer", ActionType::NpcTagKilledByPlayer},
{"UseAbility", ActionType::UseAbility},
{"LootItem", ActionType::LootItem},
{"UseItemCategoryOnItem", ActionType::UseItemCategoryOnItem}
};
auto it = actionMap.find(str);
return (it != actionMap.end()) ? it->second : ActionType::none;
}
bool AchievementsConfig::loadFromXML(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 achievements XML file: " << filepath << std::endl;
return false;
}
tinyxml2::XMLElement* root = doc.FirstChildElement("achievements");
if (!root) {
std::cerr << "Invalid XML structure: missing 'achievements' root element" << std::endl;
return false;
}
m_achievements.clear();
// Parse all achievements
for (tinyxml2::XMLElement* achievementElement = root->FirstChildElement("achievement");
achievementElement != nullptr;
achievementElement = achievementElement->NextSiblingElement("achievement")) {
parseAchievement(achievementElement);
}
std::cout << "Loaded " << m_achievements.size() << " achievements from XML" << std::endl;
return true;
}
void AchievementsConfig::parseAchievement(tinyxml2::XMLElement* achievementElement) {
Achievement achievement;
// Parse basic attributes
achievement.id = static_cast<uint16_t>(getAttributeValueInt(achievementElement, "id"));
achievement.name = getAttributeValue(achievementElement, "name");
achievement.description = getAttributeValue(achievementElement, "description");
achievement.icon = getAttributeValue(achievementElement, "icon");
// Parse numeric attributes
achievement.points = static_cast<uint16_t>(getAttributeValueInt(achievementElement, "points"));
achievement.category = static_cast<uint16_t>(getAttributeValueInt(achievementElement, "category"));
// Parse child elements
parseRequirements(achievementElement, achievement);
m_achievements[achievement.id] = std::move(achievement);
}
void AchievementsConfig::parseRequirements(tinyxml2::XMLElement* achievementElement, Achievement& achievement) {
for (tinyxml2::XMLElement* reqElement = achievementElement->FirstChildElement("requirement");
reqElement != nullptr;
reqElement = reqElement->NextSiblingElement("requirement")) {
AchievementRequirement req;
req.action = stringToActionType(getAttributeValue(reqElement, "action"));
req.targetId = static_cast<uint16_t>(getAttributeValueInt(reqElement, "targetid"));
req.count = static_cast<uint16_t>(getAttributeValueInt(reqElement, "count"));
req.description = getAttributeValue(reqElement, "description");
achievement.requirements.push_back(req);
}
}
const Achievement* AchievementsConfig::getAchievementById(int id) const {
auto it = m_achievements.find(id);
return (it != m_achievements.end()) ? &it->second : nullptr;
}
std::string AchievementsConfig::getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue) {
const char* value = element->Attribute(attribute);
return value ? std::string(value) : defaultValue;
}
int AchievementsConfig::getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue) {
int value = defaultValue;
element->QueryIntAttribute(attribute, &value);
return value;
}
bool AchievementsConfig::getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue) {
bool value = defaultValue;
element->QueryBoolAttribute(attribute, &value);
return value;
}
} // namespace cursebreaker

View File

@@ -0,0 +1,91 @@
#include "configs/harvestables.hpp"
#include <iostream>
#include <sstream>
#include <algorithm>
namespace cursebreaker {
bool HarvestablesConfig::loadFromXML(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 harvestables XML file: " << filepath << std::endl;
return false;
}
tinyxml2::XMLElement* root = doc.FirstChildElement("harvestables");
if (!root) {
std::cerr << "Invalid XML structure: missing 'harvestables' root element" << std::endl;
return false;
}
m_harvestables.clear();
// Parse all harvestables
for (tinyxml2::XMLElement* harvestableElement = root->FirstChildElement("harvestable");
harvestableElement != nullptr;
harvestableElement = harvestableElement->NextSiblingElement("harvestable")) {
parseHarvestable(harvestableElement);
}
std::cout << "Loaded " << m_harvestables.size() << " harvestables from XML" << std::endl;
return true;
}
void HarvestablesConfig::parseHarvestable(tinyxml2::XMLElement* harvestableElement) {
Harvestable harvestable;
// Parse basic attributes
harvestable.id = static_cast<uint16_t>(getAttributeValueInt(harvestableElement, "id"));
harvestable.name = getAttributeValue(harvestableElement, "name");
harvestable.description = getAttributeValue(harvestableElement, "description");
harvestable.skill = stringToSkillType(getAttributeValue(harvestableElement, "skill"));
// Parse numeric attributes
harvestable.level = static_cast<uint16_t>(getAttributeValueInt(harvestableElement, "level"));
harvestable.respawnTime = static_cast<uint16_t>(getAttributeValueInt(harvestableElement, "respawntime"));
// Parse child elements
parseLoot(harvestableElement, harvestable);
m_harvestables[harvestable.id] = std::move(harvestable);
}
void HarvestablesConfig::parseLoot(tinyxml2::XMLElement* harvestableElement, Harvestable& harvestable) {
for (tinyxml2::XMLElement* lootElement = harvestableElement->FirstChildElement("loot");
lootElement != nullptr;
lootElement = lootElement->NextSiblingElement("loot")) {
HarvestableLootEntry lootEntry;
lootEntry.itemId = static_cast<uint16_t>(getAttributeValueInt(lootElement, "itemid"));
lootEntry.amount = static_cast<uint16_t>(getAttributeValueInt(lootElement, "amount"));
lootEntry.chance = static_cast<uint16_t>(getAttributeValueInt(lootElement, "chance"));
harvestable.loot.push_back(lootEntry);
}
}
const Harvestable* HarvestablesConfig::getHarvestableById(int id) const {
auto it = m_harvestables.find(id);
return (it != m_harvestables.end()) ? &it->second : nullptr;
}
std::string HarvestablesConfig::getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue) {
const char* value = element->Attribute(attribute);
return value ? std::string(value) : defaultValue;
}
int HarvestablesConfig::getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue) {
int value = defaultValue;
element->QueryIntAttribute(attribute, &value);
return value;
}
bool HarvestablesConfig::getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue) {
bool value = defaultValue;
element->QueryBoolAttribute(attribute, &value);
return value;
}
} // namespace cursebreaker

86
src/configs/loot.cpp Normal file
View File

@@ -0,0 +1,86 @@
#include "configs/loot.hpp"
#include <iostream>
namespace cursebreaker {
bool LootConfig::loadFromXML(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 loot XML file: " << filepath << std::endl;
return false;
}
tinyxml2::XMLElement* root = doc.FirstChildElement("lootTables");
if (!root) {
std::cerr << "Invalid XML structure: missing 'lootTables' root element" << std::endl;
return false;
}
m_lootTables.clear();
// Parse all loot tables
for (tinyxml2::XMLElement* lootTableElement = root->FirstChildElement("lootTable");
lootTableElement != nullptr;
lootTableElement = lootTableElement->NextSiblingElement("lootTable")) {
parseLootTable(lootTableElement);
}
std::cout << "Loaded " << m_lootTables.size() << " loot tables from XML" << std::endl;
return true;
}
void LootConfig::parseLootTable(tinyxml2::XMLElement* lootTableElement) {
LootTable lootTable;
// Parse basic attributes
lootTable.id = static_cast<uint16_t>(getAttributeValueInt(lootTableElement, "id"));
lootTable.name = getAttributeValue(lootTableElement, "name");
lootTable.description = getAttributeValue(lootTableElement, "description");
// Parse child elements
parseEntries(lootTableElement, lootTable);
m_lootTables[lootTable.id] = std::move(lootTable);
}
void LootConfig::parseEntries(tinyxml2::XMLElement* lootTableElement, LootTable& lootTable) {
for (tinyxml2::XMLElement* entryElement = lootTableElement->FirstChildElement("entry");
entryElement != nullptr;
entryElement = entryElement->NextSiblingElement("entry")) {
LootEntry entry;
entry.itemId = static_cast<uint16_t>(getAttributeValueInt(entryElement, "itemid"));
entry.minAmount = static_cast<uint16_t>(getAttributeValueInt(entryElement, "minamount"));
entry.maxAmount = static_cast<uint16_t>(getAttributeValueInt(entryElement, "maxamount"));
entry.chance = static_cast<uint16_t>(getAttributeValueInt(entryElement, "chance"));
entry.level = static_cast<uint16_t>(getAttributeValueInt(entryElement, "level"));
lootTable.entries.push_back(entry);
}
}
const LootTable* LootConfig::getLootTableById(int id) const {
auto it = m_lootTables.find(id);
return (it != m_lootTables.end()) ? &it->second : nullptr;
}
std::string LootConfig::getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue) {
const char* value = element->Attribute(attribute);
return value ? std::string(value) : defaultValue;
}
int LootConfig::getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue) {
int value = defaultValue;
element->QueryIntAttribute(attribute, &value);
return value;
}
bool LootConfig::getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue) {
bool value = defaultValue;
element->QueryBoolAttribute(attribute, &value);
return value;
}
} // namespace cursebreaker

111
src/configs/npcs.cpp Normal file
View File

@@ -0,0 +1,111 @@
#include "configs/npcs.hpp"
#include <iostream>
#include <sstream>
#include <algorithm>
namespace cursebreaker {
bool NPCsConfig::loadFromXML(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;
}
m_npcs.clear();
// Parse all NPCs
for (tinyxml2::XMLElement* npcElement = root->FirstChildElement("npc");
npcElement != nullptr;
npcElement = npcElement->NextSiblingElement("npc")) {
parseNPC(npcElement);
}
std::cout << "Loaded " << m_npcs.size() << " NPCs from XML" << std::endl;
return true;
}
void NPCsConfig::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);
m_npcs[npc.id] = std::move(npc);
}
void NPCsConfig::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 NPCsConfig::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* NPCsConfig::getNPCById(int id) const {
auto it = m_npcs.find(id);
return (it != m_npcs.end()) ? &it->second : nullptr;
}
std::string NPCsConfig::getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue) {
const char* value = element->Attribute(attribute);
return value ? std::string(value) : defaultValue;
}
int NPCsConfig::getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue) {
int value = defaultValue;
element->QueryIntAttribute(attribute, &value);
return value;
}
bool NPCsConfig::getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue) {
bool value = defaultValue;
element->QueryBoolAttribute(attribute, &value);
return value;
}
} // namespace cursebreaker

86
src/configs/shops.cpp Normal file
View File

@@ -0,0 +1,86 @@
#include "configs/shops.hpp"
#include <iostream>
namespace cursebreaker {
bool ShopsConfig::loadFromXML(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 shops XML file: " << filepath << std::endl;
return false;
}
tinyxml2::XMLElement* root = doc.FirstChildElement("shops");
if (!root) {
std::cerr << "Invalid XML structure: missing 'shops' root element" << std::endl;
return false;
}
m_shops.clear();
// Parse all shops
for (tinyxml2::XMLElement* shopElement = root->FirstChildElement("shop");
shopElement != nullptr;
shopElement = shopElement->NextSiblingElement("shop")) {
parseShop(shopElement);
}
std::cout << "Loaded " << m_shops.size() << " shops from XML" << std::endl;
return true;
}
void ShopsConfig::parseShop(tinyxml2::XMLElement* shopElement) {
Shop shop;
// Parse basic attributes
shop.id = static_cast<uint16_t>(getAttributeValueInt(shopElement, "id"));
shop.name = getAttributeValue(shopElement, "name");
shop.description = getAttributeValue(shopElement, "description");
shop.location = getAttributeValue(shopElement, "location");
// Parse child elements
parseInventory(shopElement, shop);
m_shops[shop.id] = std::move(shop);
}
void ShopsConfig::parseInventory(tinyxml2::XMLElement* shopElement, Shop& shop) {
for (tinyxml2::XMLElement* itemElement = shopElement->FirstChildElement("item");
itemElement != nullptr;
itemElement = itemElement->NextSiblingElement("item")) {
ShopItem item;
item.itemId = static_cast<uint16_t>(getAttributeValueInt(itemElement, "itemid"));
item.price = static_cast<uint16_t>(getAttributeValueInt(itemElement, "price"));
item.stock = static_cast<uint16_t>(getAttributeValueInt(itemElement, "stock"));
item.levelRequired = static_cast<uint16_t>(getAttributeValueInt(itemElement, "levelrequired"));
shop.inventory.push_back(item);
}
}
const Shop* ShopsConfig::getShopById(int id) const {
auto it = m_shops.find(id);
return (it != m_shops.end()) ? &it->second : nullptr;
}
std::string ShopsConfig::getAttributeValue(tinyxml2::XMLElement* element, const char* attribute, const std::string& defaultValue) {
const char* value = element->Attribute(attribute);
return value ? std::string(value) : defaultValue;
}
int ShopsConfig::getAttributeValueInt(tinyxml2::XMLElement* element, const char* attribute, int defaultValue) {
int value = defaultValue;
element->QueryIntAttribute(attribute, &value);
return value;
}
bool ShopsConfig::getAttributeValueBool(tinyxml2::XMLElement* element, const char* attribute, bool defaultValue) {
bool value = defaultValue;
element->QueryBoolAttribute(attribute, &value);
return value;
}
} // namespace cursebreaker