42 extraStats = std::move(stats);
45static ItemType itemTypeFromString(
const std::string &name,
int id = 0)
66static uint8_t spriteFromString(std::string_view name)
70 if (name ==
"race" || name ==
"type")
72 if (name ==
"shoes" || name ==
"boot" || name ==
"boots")
74 if (name ==
"bottomclothes" || name ==
"bottom" || name ==
"pants")
76 if (name ==
"topclothes" || name ==
"top" || name ==
"torso" || name ==
"body")
80 if (name ==
"misc2" || name ==
"scarf" || name ==
"scarfs")
84 if (name ==
"hat" || name ==
"hats")
88 if (name ==
"glove" || name ==
"gloves")
90 if (name ==
"weapon" || name ==
"weapons")
92 if (name ==
"shield" || name ==
"shields")
94 if (name ==
"amulet" || name ==
"amulets")
96 if (name ==
"ring" || name ==
"rings")
102static uint8_t directionFromString(std::string_view name)
106 if (name ==
"down" || name ==
"downall")
110 if (name ==
"up" || name ==
"upall")
152 Log::info(
"ItemDB: Warning, unknown item ID# %d",
id);
168 Log::info(
"ItemDB: Warning, unknown item name \"%s\"",
179 std::string gender = node.
getProperty(
"gender",
"unisex");
183 if (gender ==
"male" || gender ==
"unisex")
185 if (gender ==
"female" || gender ==
"unisex")
187 if (gender ==
"hidden" || gender ==
"other" || gender ==
"unisex")
193 std::string
event = node.
getProperty(
"event", std::string());
200 else if (event ==
"strike" || event ==
"miss")
206 Log::info(
"ItemDB: Ignoring unknown sound event '%s'",
213 for (
auto spriteNode : floorNode.
children())
215 if (spriteNode.name() ==
"sprite")
218 currentSprite.
sprite = spriteNode.textContent();
219 currentSprite.
variant = spriteNode.getProperty(
"variant", 0);
221 else if (spriteNode.name() ==
"particlefx")
223 display.
particles.emplace_back(spriteNode.textContent());
230 std::string_view spriteString;
231 std::string_view directionString;
233 replaceNode.
attribute(
"sprite", spriteString);
234 replaceNode.
attribute(
"direction", directionString);
236 const uint8_t sprite = spriteFromString(spriteString);
237 const uint8_t direction = directionFromString(directionString);
241 Log::info(
"ItemDB: Invalid sprite name '%s' in replace tag",
242 spriteString.data());
248 Log::info(
"ItemDB: Invalid direction name '%s' in replace tag",
249 directionString.data());
253 Replacement &replace = info.replacements.emplace_back();
257 for (
auto child : replaceNode.
children())
259 if (child.name() ==
"item")
262 child.attribute(
"from", item.
from);
263 child.attribute(
"to", item.
to);
287 Log::info(
"ItemDB: Invalid or missing item Id in %s!", filename.c_str());
292 Log::info(
"ItemDB: Redefinition of item Id %d in %s", itemInfo.
id, filename.c_str());
308 std::string typeStr = node.
getProperty(
"type",
"other");
309 itemInfo.
type = itemTypeFromString(typeStr);
312 for (
auto itemChild : node.
children())
314 if (itemChild.name() ==
"sprite")
318 else if (itemChild.name() ==
"particlefx")
322 else if (itemChild.name() ==
"sound")
326 else if (itemChild.name() ==
"floor")
330 else if (itemChild.name() ==
"replace")
339 std::string itemName = itemInfo->
name;
340 itemInfo->
name = itemName.empty() ?
_(
"unnamed") : itemName;
342 if (!itemName.empty())
350 Log::info(
"ItemDB: Duplicate name (%s) for item id %d found.",
351 temp.c_str(), itemInfo->
id);
356static void checkParameter(
int id,
const T param,
const T errorValue)
358 if (param == errorValue)
360 std::stringstream errMsg;
361 errMsg <<
"ItemDB: Missing " << param <<
" attribute for item id "
369 int id = itemInfo.
id;
372 Log::info(
"ItemDB: Missing attack range from weapon %i!",
id);
376 checkParameter(
id, itemInfo.
name, std::string());
377 checkParameter(
id, itemInfo.
description, std::string());
378 checkParameter(
id, itemInfo.
display.
image, std::string());
379 checkParameter(
id, itemInfo.
weight, 0);
387static char const *
const fields[][2] =
389 {
"attack",
N_(
"Attack %+d") },
390 {
"defense",
N_(
"Defense %+d") },
391 {
"hp",
N_(
"HP %+d") },
392 {
"mp",
N_(
"MP %+d") }
410 itemInfo->activatable = itemInfo->type ==
ITEM_USABLE;
413 std::vector<std::string> effect;
414 for (
auto field : fields)
421 for (
auto &extraStat : extraStats)
423 int value = node.
getProperty(extraStat.mTag.c_str(), 0);
426 effect.push_back(
strprintf(extraStat.mFormat.c_str(), value));
428 std::string temp = node.
getProperty(
"effect", std::string());
430 effect.push_back(temp);
432 itemInfo->effect = effect;
475 static const std::map<std::string, const char* > triggerTable = {
476 {
"existence",
" when it is in the inventory" },
477 {
"activation",
" upon activation" },
478 {
"equip",
" upon successful equip" },
479 {
"leave-inventory",
" when it leaves the inventory" },
480 {
"unequip",
" when it is unequipped" },
481 {
"equip-change",
" when it changes the way it is equipped" },
490 itemInfo->activatable =
false;
491 itemInfo->equippable =
false;
494 std::vector<std::string> effect;
495 for (
auto itemChild : node.
children())
497 if (itemChild.name() ==
"equip")
501 itemInfo->equippable =
true;
503 else if (itemChild.name() ==
"effect")
505 std::string trigger = itemChild.getProperty(
"trigger", std::string());
508 Log::info(
"Found empty trigger effect label in %s, skipping.", filename.c_str());
512 if (trigger ==
"activation")
513 itemInfo->activatable =
true;
515 auto triggerLabel = triggerTable.find(trigger);
516 if (triggerLabel == triggerTable.end())
518 Log::warn(
"Unknown trigger %s in item %d!",
519 trigger.c_str(), itemInfo->id);
523 for (
auto effectChild : itemChild.children())
525 if (effectChild.name() ==
"modifier")
527 std::string attribute = effectChild.getProperty(
"attribute", std::string());
528 double value = effectChild.getFloatProperty(
"value", 0.0);
529 int duration = effectChild.getProperty(
"duration", 0);
530 if (attribute.empty() || !value)
532 Log::warn(
"Incomplete modifier definition in %s, skipping.", filename.c_str());
535 auto it = std::find(extraStats.cbegin(), extraStats.cend(), attribute);
536 if (it == extraStats.end())
538 Log::warn(
"Unknown modifier tag %s in %s, skipping.", attribute.c_str(), filename.c_str());
544 strprintf(
"%%s%%s. This effect lasts %d ticks.", duration).c_str()
545 :
"%s%s.", it->mFormat.c_str(), triggerLabel->second).c_str(), value));
547 else if (effectChild.name() ==
"modifier")
548 effect.push_back(
strprintf(
"Provides an autoattack%s.",
549 triggerLabel->second));
550 else if (effectChild.name() ==
"consumes")
551 effect.push_back(
strprintf(
"This will be consumed%s.",
552 triggerLabel->second));
553 else if (effectChild.name() ==
"label")
554 effect.emplace_back(effectChild.textContent());
565 if (itemInfo->activatable)
567 else if (itemInfo->equippable)
571 itemInfo->effect = effect;
std::string getStringValue(const std::string &key) const
int getIntValue(const std::string &key) const
returns a value corresponding to the given key.
void addHairStyle(int id)
Add a hair style to the database.
void addItem(ItemInfo *itemInfo)
Registers the item to mItemInfos and mNamedItemsInfos.
void loadSoundRef(ItemInfo &itemInfo, XML::Node node)
Loads the sound references contained in a <sound> tag.
virtual void unload()
Frees item data.
std::map< std::string, ItemInfo * > mNamedItemInfos
void loadReplacement(ItemInfo &info, XML::Node replaceNode)
Loads the <replace> tag.
void loadCommonRef(ItemInfo &itemInfo, XML::Node node, const std::string &filename)
Permits to load item definitions which are common for each protocols to avoid code duplication.
bool exists(int id) const
std::map< int, ItemInfo * > mItemInfos
void loadSpriteRef(ItemInfo &itemInfo, XML::Node node)
Loads the sprite references contained in a <sprite> tag.
const ItemInfo & get(int id) const
void loadFloorSprite(SpriteDisplay &display, XML::Node node)
Loads the floor item references contained in a <floor> tag.
void loadEmptyItemDefinition()
Loads the empty item definition.
virtual void checkItemInfo(ItemInfo &itemInfo)
Checks the items parameters consistency.
Defines a class for storing generic item infos.
int attackRange
Attack range, will be equal to ATTACK_RANGE_NOT_SET if no weapon.
std::string description
Short description.
std::string attackAction
Attack type, in case of weapon.
std::string missileParticleFile
Effects to be shown when weapon attacks - see also effects.xml.
SpriteDisplay display
Display info (like icon)
int mView
Item ID of how this item looks.
void setSprite(const std::string &animationFile, Gender gender, int race)
int weight
Weight in grams.
void addSound(EquipmentSoundEvent event, const std::string &filename)
void readItemNode(XML::Node node, const std::string &filename) override
void checkStatus() override
void checkItemInfo(ItemInfo &itemInfo) override
Checks the items parameters consistency.
void checkStatus() override
void readItemNode(XML::Node node, const std::string &filename) override
void checkHairWeaponsRacesSpecialIds()
Check items id specific hard limits and log errors found.
void checkItemInfo(ItemInfo &itemInfo) override
Checks the items parameters consistency.
int getProperty(const char *name, int def) const
Children children() const
std::string_view textContent() const
bool attribute(const char *name, T &value) const
HairDB hairDB
Hair styles and colors info database.
Configuration paths
XML default paths information reader.
void delete_all(Container &c)
void setStatsList(std::list< ItemStat > stats)
ItemType
Enumeration of available Item types.
@ ITEM_EQUIPMENT_NECKLACE
@ ITEM_EQUIPMENT_ONE_HAND_WEAPON
@ ITEM_EQUIPMENT_TWO_HANDS_WEAPON
void warn(const char *log_text,...) LOG_PRINTF_ATTR
void info(const char *log_text,...) LOG_PRINTF_ATTR
Warning: buffers and other variables are shared, so there can be only one connection active at a time...
std::string strprintf(char const *format,...)
A safe version of sprintf that returns a std::string of the result.
std::string normalize(const std::string &name)
Normalize a string, which means lowercase and trim it.
std::vector< Item > items
std::vector< SpriteReference > sprites
std::vector< std::string > particles