/**
* @ file itemdat . cpp
*
* Implementation of all item data .
*/
# include "itemdat.h"
# include <string_view>
# include <vector>
# include <expected.hpp>
# include <fmt/format.h>
# include "data/file.hpp"
# include "data/iterators.hpp"
# include "data/record_reader.hpp"
# include "lua/lua_global.hpp"
# include "spelldat.h"
# include "utils/str_cat.hpp"
namespace devilution {
/** Contains the data related to each item ID. */
std : : vector < ItemData > AllItemsList ;
/** Contains item mapping IDs, with item indices assigned to them. This is used for loading saved games. */
ankerl : : unordered_dense : : map < int32_t , int16_t > ItemMappingIdsToIndices ;
/** Contains the mapping between unique base item ID strings and indices, used for parsing additional item data. */
ankerl : : unordered_dense : : map < std : : string , int8_t > AdditionalUniqueBaseItemStringsToIndices ;
/** Contains the data related to each unique item ID. */
std : : vector < UniqueItem > UniqueItems ;
/** Contains unique item mapping IDs, with unique item indices assigned to them. This is used for loading saved games. */
ankerl : : unordered_dense : : map < int32_t , int32_t > UniqueItemMappingIdsToIndices ;
/** Contains the data related to each item prefix. */
std : : vector < PLStruct > ItemPrefixes ;
/** Contains the data related to each item suffix. */
std : : vector < PLStruct > ItemSuffixes ;
namespace {
tl : : expected < item_class , std : : string > ParseItemClass ( std : : string_view value )
{
if ( value = = " None " ) return ICLASS_NONE ;
if ( value = = " Weapon " ) return ICLASS_WEAPON ;
if ( value = = " Armor " ) return ICLASS_ARMOR ;
if ( value = = " Misc " ) return ICLASS_MISC ;
if ( value = = " Gold " ) return ICLASS_GOLD ;
if ( value = = " Quest " ) return ICLASS_QUEST ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < item_equip_type , std : : string > ParseItemEquipType ( std : : string_view value )
{
if ( value = = " None " ) return ILOC_NONE ;
if ( value = = " One-handed " ) return ILOC_ONEHAND ;
if ( value = = " Two-handed " ) return ILOC_TWOHAND ;
if ( value = = " Armor " ) return ILOC_ARMOR ;
if ( value = = " Helm " ) return ILOC_HELM ;
if ( value = = " Ring " ) return ILOC_RING ;
if ( value = = " Amulet " ) return ILOC_AMULET ;
if ( value = = " Unequippable " ) return ILOC_UNEQUIPABLE ;
if ( value = = " Belt " ) return ILOC_BELT ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < item_cursor_graphic , std : : string > ParseItemCursorGraphic ( std : : string_view value )
{
if ( value = = " POTION_OF_FULL_MANA " ) return ICURS_POTION_OF_FULL_MANA ;
if ( value = = " SCROLL_OF " ) return ICURS_SCROLL_OF ;
if ( value = = " GOLD_SMALL " ) return ICURS_GOLD_SMALL ;
if ( value = = " GOLD_MEDIUM " ) return ICURS_GOLD_MEDIUM ;
if ( value = = " GOLD_LARGE " ) return ICURS_GOLD_LARGE ;
if ( value = = " THE_BLEEDER " ) return ICURS_THE_BLEEDER ;
if ( value = = " BRAMBLE " ) return ICURS_BRAMBLE ;
if ( value = = " RING_OF_TRUTH " ) return ICURS_RING_OF_TRUTH ;
if ( value = = " RING_OF_REGHA " ) return ICURS_RING_OF_REGHA ;
if ( value = = " RING " ) return ICURS_RING ;
if ( value = = " RING_OF_ENGAGEMENT " ) return ICURS_RING_OF_ENGAGEMENT ;
if ( value = = " CONSTRICTING_RING " ) return ICURS_CONSTRICTING_RING ;
if ( value = = " SPECTRAL_ELIXIR " ) return ICURS_SPECTRAL_ELIXIR ;
if ( value = = " ARENA_POTION " ) return ICURS_ARENA_POTION ;
if ( value = = " GOLDEN_ELIXIR " ) return ICURS_GOLDEN_ELIXIR ;
if ( value = = " EMPYREAN_BAND " ) return ICURS_EMPYREAN_BAND ;
if ( value = = " EAR_SORCERER " ) return ICURS_EAR_SORCERER ;
if ( value = = " EAR_WARRIOR " ) return ICURS_EAR_WARRIOR ;
if ( value = = " EAR_ROGUE " ) return ICURS_EAR_ROGUE ;
if ( value = = " BLOOD_STONE " ) return ICURS_BLOOD_STONE ;
if ( value = = " OIL " ) return ICURS_OIL ;
if ( value = = " ELIXIR_OF_VITALITY " ) return ICURS_ELIXIR_OF_VITALITY ;
if ( value = = " POTION_OF_HEALING " ) return ICURS_POTION_OF_HEALING ;
if ( value = = " POTION_OF_FULL_REJUVENATION " ) return ICURS_POTION_OF_FULL_REJUVENATION ;
if ( value = = " ELIXIR_OF_MAGIC " ) return ICURS_ELIXIR_OF_MAGIC ;
if ( value = = " POTION_OF_FULL_HEALING " ) return ICURS_POTION_OF_FULL_HEALING ;
if ( value = = " ELIXIR_OF_DEXTERITY " ) return ICURS_ELIXIR_OF_DEXTERITY ;
if ( value = = " POTION_OF_REJUVENATION " ) return ICURS_POTION_OF_REJUVENATION ;
if ( value = = " ELIXIR_OF_STRENGTH " ) return ICURS_ELIXIR_OF_STRENGTH ;
if ( value = = " POTION_OF_MANA " ) return ICURS_POTION_OF_MANA ;
if ( value = = " BRAIN " ) return ICURS_BRAIN ;
if ( value = = " OPTIC_AMULET " ) return ICURS_OPTIC_AMULET ;
if ( value = = " AMULET " ) return ICURS_AMULET ;
if ( value = = " WIZARDSPIKE " ) return ICURS_WIZARDSPIKE ;
if ( value = = " DAGGER " ) return ICURS_DAGGER ;
if ( value = = " BLACK_RAZOR " ) return ICURS_BLACK_RAZOR ;
if ( value = = " GONNAGALS_DIRK " ) return ICURS_GONNAGALS_DIRK ;
if ( value = = " BLADE " ) return ICURS_BLADE ;
if ( value = = " BASTARD_SWORD " ) return ICURS_BASTARD_SWORD ;
if ( value = = " THE_EXECUTIONERS_BLADE " ) return ICURS_THE_EXECUTIONERS_BLADE ;
if ( value = = " MACE " ) return ICURS_MACE ;
if ( value = = " LONG_SWORD " ) return ICURS_LONG_SWORD ;
if ( value = = " BROAD_SWORD " ) return ICURS_BROAD_SWORD ;
if ( value = = " FALCHION " ) return ICURS_FALCHION ;
if ( value = = " MORNING_STAR " ) return ICURS_MORNING_STAR ;
if ( value = = " SHORT_SWORD " ) return ICURS_SHORT_SWORD ;
if ( value = = " CLAYMORE " ) return ICURS_CLAYMORE ;
if ( value = = " CLUB " ) return ICURS_CLUB ;
if ( value = = " SABRE " ) return ICURS_SABRE ;
if ( value = = " GRYPHONS_CLAW " ) return ICURS_GRYPHONS_CLAW ;
if ( value = = " SPIKED_CLUB " ) return ICURS_SPIKED_CLUB ;
if ( value = = " SCIMITAR " ) return ICURS_SCIMITAR ;
if ( value = = " FULL_HELM " ) return ICURS_FULL_HELM ;
if ( value = = " MAGIC_ROCK " ) return ICURS_MAGIC_ROCK ;
if ( value = = " HELM_OF_SPIRITS " ) return ICURS_HELM_OF_SPIRITS ;
if ( value = = " THE_UNDEAD_CROWN " ) return ICURS_THE_UNDEAD_CROWN ;
if ( value = = " ROYAL_CIRCLET " ) return ICURS_ROYAL_CIRCLET ;
if ( value = = " FOOLS_CREST " ) return ICURS_FOOLS_CREST ;
if ( value = = " HARLEQUIN_CREST " ) return ICURS_HARLEQUIN_CREST ;
if ( value = = " HELM " ) return ICURS_HELM ;
if ( value = = " BUCKLER " ) return ICURS_BUCKLER ;
if ( value = = " VEIL_OF_STEEL " ) return ICURS_VEIL_OF_STEEL ;
if ( value = = " BOOK_GREY " ) return ICURS_BOOK_GREY ;
if ( value = = " BOOK_RED " ) return ICURS_BOOK_RED ;
if ( value = = " BOOK_BLUE " ) return ICURS_BOOK_BLUE ;
if ( value = = " BLACK_MUSHROOM " ) return ICURS_BLACK_MUSHROOM ;
if ( value = = " SKULL_CAP " ) return ICURS_SKULL_CAP ;
if ( value = = " CAP " ) return ICURS_CAP ;
if ( value = = " TORN_FLESH_OF_SOULS " ) return ICURS_TORN_FLESH_OF_SOULS ;
if ( value = = " THINKING_CAP " ) return ICURS_THINKING_CAP ;
if ( value = = " CROWN " ) return ICURS_CROWN ;
if ( value = = " MAP_OF_THE_STARS " ) return ICURS_MAP_OF_THE_STARS ;
if ( value = = " FUNGAL_TOME " ) return ICURS_FUNGAL_TOME ;
if ( value = = " GREAT_HELM " ) return ICURS_GREAT_HELM ;
if ( value = = " OVERLORDS_HELM " ) return ICURS_OVERLORDS_HELM ;
if ( value = = " BATTLE_AXE " ) return ICURS_BATTLE_AXE ;
if ( value = = " HUNTERS_BOW " ) return ICURS_HUNTERS_BOW ;
if ( value = = " FIELD_PLATE " ) return ICURS_FIELD_PLATE ;
if ( value = = " STONECLEAVER " ) return ICURS_STONECLEAVER ;
if ( value = = " SMALL_SHIELD " ) return ICURS_SMALL_SHIELD ;
if ( value = = " CLEAVER " ) return ICURS_CLEAVER ;
if ( value = = " STUDDED_LEATHER_ARMOR " ) return ICURS_STUDDED_LEATHER_ARMOR ;
if ( value = = " DEADLY_HUNTER " ) return ICURS_DEADLY_HUNTER ;
if ( value = = " SHORT_STAFF " ) return ICURS_SHORT_STAFF ;
if ( value = = " TWO_HANDED_SWORD " ) return ICURS_TWO_HANDED_SWORD ;
if ( value = = " CHAIN_MAIL " ) return ICURS_CHAIN_MAIL ;
if ( value = = " SMALL_AXE " ) return ICURS_SMALL_AXE ;
if ( value = = " KITE_SHIELD " ) return ICURS_KITE_SHIELD ;
if ( value = = " SCALE_MAIL " ) return ICURS_SCALE_MAIL ;
if ( value = = " SPLIT_SKULL_SHIELD " ) return ICURS_SPLIT_SKULL_SHIELD ;
if ( value = = " DRAGONS_BREACH " ) return ICURS_DRAGONS_BREACH ;
if ( value = = " SHORT_BOW " ) return ICURS_SHORT_BOW ;
if ( value = = " LONG_BATTLE_BOW " ) return ICURS_LONG_BATTLE_BOW ;
if ( value = = " LONG_WAR_BOW " ) return ICURS_LONG_WAR_BOW ;
if ( value = = " WAR_HAMMER " ) return ICURS_WAR_HAMMER ;
if ( value = = " MAUL " ) return ICURS_MAUL ;
if ( value = = " LONG_STAFF " ) return ICURS_LONG_STAFF ;
if ( value = = " WAR_STAFF " ) return ICURS_WAR_STAFF ;
if ( value = = " TAVERN_SIGN " ) return ICURS_TAVERN_SIGN ;
if ( value = = " HARD_LEATHER_ARMOR " ) return ICURS_HARD_LEATHER_ARMOR ;
if ( value = = " RAGS " ) return ICURS_RAGS ;
if ( value = = " QUILTED_ARMOR " ) return ICURS_QUILTED_ARMOR ;
if ( value = = " FLAIL " ) return ICURS_FLAIL ;
if ( value = = " TOWER_SHIELD " ) return ICURS_TOWER_SHIELD ;
if ( value = = " COMPOSITE_BOW " ) return ICURS_COMPOSITE_BOW ;
if ( value = = " GREAT_SWORD " ) return ICURS_GREAT_SWORD ;
if ( value = = " LEATHER_ARMOR " ) return ICURS_LEATHER_ARMOR ;
if ( value = = " SPLINT_MAIL " ) return ICURS_SPLINT_MAIL ;
if ( value = = " ROBE " ) return ICURS_ROBE ;
if ( value = = " THE_RAINBOW_CLOAK " ) return ICURS_THE_RAINBOW_CLOAK ;
if ( value = = " ANVIL_OF_FURY " ) return ICURS_ANVIL_OF_FURY ;
if ( value = = " BROAD_AXE " ) return ICURS_BROAD_AXE ;
if ( value = = " LARGE_AXE " ) return ICURS_LARGE_AXE ;
if ( value = = " GREAT_AXE " ) return ICURS_GREAT_AXE ;
if ( value = = " AXE " ) return ICURS_AXE ;
if ( value = = " BLACKOAK_SHIELD " ) return ICURS_BLACKOAK_SHIELD ;
if ( value = = " LARGE_SHIELD " ) return ICURS_LARGE_SHIELD ;
if ( value = = " GOTHIC_SHIELD " ) return ICURS_GOTHIC_SHIELD ;
if ( value = = " CLOAK " ) return ICURS_CLOAK ;
if ( value = = " CAPE " ) return ICURS_CAPE ;
if ( value = = " FULL_PLATE_MAIL " ) return ICURS_FULL_PLATE_MAIL ;
if ( value = = " GOTHIC_PLATE " ) return ICURS_GOTHIC_PLATE ;
if ( value = = " BREAST_PLATE " ) return ICURS_BREAST_PLATE ;
if ( value = = " RING_MAIL " ) return ICURS_RING_MAIL ;
if ( value = = " STAFF_OF_LAZARUS " ) return ICURS_STAFF_OF_LAZARUS ;
if ( value = = " ARKAINES_VALOR " ) return ICURS_ARKAINES_VALOR ;
if ( value = = " THE_NEEDLER " ) return ICURS_THE_NEEDLER ;
if ( value = = " NAJS_LIGHT_PLATE " ) return ICURS_NAJS_LIGHT_PLATE ;
if ( value = = " THE_GRIZZLY " ) return ICURS_THE_GRIZZLY ;
if ( value = = " THE_GRANDFATHER " ) return ICURS_THE_GRANDFATHER ;
if ( value = = " THE_PROTECTOR " ) return ICURS_THE_PROTECTOR ;
if ( value = = " MESSERSCHMIDTS_REAVER " ) return ICURS_MESSERSCHMIDTS_REAVER ;
if ( value = = " WINDFORCE " ) return ICURS_WINDFORCE ;
if ( value = = " SHORT_WAR_BOW " ) return ICURS_SHORT_WAR_BOW ;
if ( value = = " COMPOSITE_STAFF " ) return ICURS_COMPOSITE_STAFF ;
if ( value = = " SHORT_BATTLE_BOW " ) return ICURS_SHORT_BATTLE_BOW ;
if ( value = = " XORINES_RING " ) return ICURS_XORINES_RING ;
if ( value = = " AMULET_OF_WARDING " ) return ICURS_AMULET_OF_WARDING ;
if ( value = = " KARIKS_RING " ) return ICURS_KARIKS_RING ;
if ( value = = " MERCURIAL_RING " ) return ICURS_MERCURIAL_RING ;
if ( value = = " RING_OF_THUNDER " ) return ICURS_RING_OF_THUNDER ;
if ( value = = " GIANTS_KNUCKLE " ) return ICURS_GIANTS_KNUCKLE ;
if ( value = = " AURIC_AMULET " ) return ICURS_AURIC_AMULET ;
if ( value = = " RING_OF_THE_MYSTICS " ) return ICURS_RING_OF_THE_MYSTICS ;
if ( value = = " ACOLYTES_AMULET " ) return ICURS_ACOLYTES_AMULET ;
if ( value = = " RING_OF_MAGMA " ) return ICURS_RING_OF_MAGMA ;
if ( value = = " GLADIATORS_RING " ) return ICURS_GLADIATORS_RING ;
if ( value = = " RUNE_BOMB " ) return ICURS_RUNE_BOMB ;
if ( value = = " THEODORE " ) return ICURS_THEODORE ;
if ( value = = " TORN_NOTE_1 " ) return ICURS_TORN_NOTE_1 ;
if ( value = = " TORN_NOTE_2 " ) return ICURS_TORN_NOTE_2 ;
if ( value = = " TORN_NOTE_3 " ) return ICURS_TORN_NOTE_3 ;
if ( value = = " RECONSTRUCTED_NOTE " ) return ICURS_RECONSTRUCTED_NOTE ;
if ( value = = " RUNE_OF_FIRE " ) return ICURS_RUNE_OF_FIRE ;
if ( value = = " GREATER_RUNE_OF_FIRE " ) return ICURS_GREATER_RUNE_OF_FIRE ;
if ( value = = " RUNE_OF_LIGHTNING " ) return ICURS_RUNE_OF_LIGHTNING ;
if ( value = = " GREATER_RUNE_OF_LIGHTNING " ) return ICURS_GREATER_RUNE_OF_LIGHTNING ;
if ( value = = " RUNE_OF_STONE " ) return ICURS_RUNE_OF_STONE ;
if ( value = = " GREY_SUIT " ) return ICURS_GREY_SUIT ;
if ( value = = " BROWN_SUIT " ) return ICURS_BROWN_SUIT ;
if ( value = = " EATER_OF_SOULS " ) return ICURS_EATER_OF_SOULS ;
if ( value = = " ARMOR_OF_GLOOM " ) return ICURS_ARMOR_OF_GLOOM ;
if ( value = = " BONE_CHAIN_ARMOR " ) return ICURS_BONE_CHAIN_ARMOR ;
if ( value = = " THUNDERCLAP " ) return ICURS_THUNDERCLAP ;
if ( value = = " DIAMONDEDGE " ) return ICURS_DIAMONDEDGE ;
if ( value = = " FLAMBEAU " ) return ICURS_FLAMBEAU ;
if ( value = = " GNAT_STING " ) return ICURS_GNAT_STING ;
if ( value = = " BLITZEN " ) return ICURS_BLITZEN ;
if ( value = = " DEMON_PLATE_ARMOR " ) return ICURS_DEMON_PLATE_ARMOR ;
if ( value = = " BOVINE " ) return ICURS_BOVINE ;
if ( value = = " " ) return ICURS_DEFAULT ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < ItemType , std : : string > ParseItemType ( std : : string_view value )
{
if ( value = = " Misc " ) return ItemType : : Misc ;
if ( value = = " Sword " ) return ItemType : : Sword ;
if ( value = = " Axe " ) return ItemType : : Axe ;
if ( value = = " Bow " ) return ItemType : : Bow ;
if ( value = = " Mace " ) return ItemType : : Mace ;
if ( value = = " Shield " ) return ItemType : : Shield ;
if ( value = = " LightArmor " ) return ItemType : : LightArmor ;
if ( value = = " Helm " ) return ItemType : : Helm ;
if ( value = = " MediumArmor " ) return ItemType : : MediumArmor ;
if ( value = = " HeavyArmor " ) return ItemType : : HeavyArmor ;
if ( value = = " Staff " ) return ItemType : : Staff ;
if ( value = = " Gold " ) return ItemType : : Gold ;
if ( value = = " Ring " ) return ItemType : : Ring ;
if ( value = = " Amulet " ) return ItemType : : Amulet ;
if ( value = = " None " ) return ItemType : : None ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < unique_base_item , std : : string > ParseUniqueBaseItem ( std : : string_view value )
{
if ( value = = " NONE " ) return UITYPE_NONE ;
if ( value = = " SHORTBOW " ) return UITYPE_SHORTBOW ;
if ( value = = " LONGBOW " ) return UITYPE_LONGBOW ;
if ( value = = " HUNTBOW " ) return UITYPE_HUNTBOW ;
if ( value = = " COMPBOW " ) return UITYPE_COMPBOW ;
if ( value = = " WARBOW " ) return UITYPE_WARBOW ;
if ( value = = " BATTLEBOW " ) return UITYPE_BATTLEBOW ;
if ( value = = " DAGGER " ) return UITYPE_DAGGER ;
if ( value = = " FALCHION " ) return UITYPE_FALCHION ;
if ( value = = " CLAYMORE " ) return UITYPE_CLAYMORE ;
if ( value = = " BROADSWR " ) return UITYPE_BROADSWR ;
if ( value = = " SABRE " ) return UITYPE_SABRE ;
if ( value = = " SCIMITAR " ) return UITYPE_SCIMITAR ;
if ( value = = " LONGSWR " ) return UITYPE_LONGSWR ;
if ( value = = " BASTARDSWR " ) return UITYPE_BASTARDSWR ;
if ( value = = " TWOHANDSWR " ) return UITYPE_TWOHANDSWR ;
if ( value = = " GREATSWR " ) return UITYPE_GREATSWR ;
if ( value = = " CLEAVER " ) return UITYPE_CLEAVER ;
if ( value = = " LARGEAXE " ) return UITYPE_LARGEAXE ;
if ( value = = " BROADAXE " ) return UITYPE_BROADAXE ;
if ( value = = " SMALLAXE " ) return UITYPE_SMALLAXE ;
if ( value = = " BATTLEAXE " ) return UITYPE_BATTLEAXE ;
if ( value = = " GREATAXE " ) return UITYPE_GREATAXE ;
if ( value = = " MACE " ) return UITYPE_MACE ;
if ( value = = " MORNSTAR " ) return UITYPE_MORNSTAR ;
if ( value = = " SPIKCLUB " ) return UITYPE_SPIKCLUB ;
if ( value = = " MAUL " ) return UITYPE_MAUL ;
if ( value = = " WARHAMMER " ) return UITYPE_WARHAMMER ;
if ( value = = " FLAIL " ) return UITYPE_FLAIL ;
if ( value = = " LONGSTAFF " ) return UITYPE_LONGSTAFF ;
if ( value = = " SHORTSTAFF " ) return UITYPE_SHORTSTAFF ;
if ( value = = " COMPSTAFF " ) return UITYPE_COMPSTAFF ;
if ( value = = " QUARSTAFF " ) return UITYPE_QUARSTAFF ;
if ( value = = " WARSTAFF " ) return UITYPE_WARSTAFF ;
if ( value = = " SKULLCAP " ) return UITYPE_SKULLCAP ;
if ( value = = " HELM " ) return UITYPE_HELM ;
if ( value = = " GREATHELM " ) return UITYPE_GREATHELM ;
if ( value = = " CROWN " ) return UITYPE_CROWN ;
if ( value = = " RAGS " ) return UITYPE_RAGS ;
if ( value = = " STUDARMOR " ) return UITYPE_STUDARMOR ;
if ( value = = " CLOAK " ) return UITYPE_CLOAK ;
if ( value = = " ROBE " ) return UITYPE_ROBE ;
if ( value = = " CHAINMAIL " ) return UITYPE_CHAINMAIL ;
if ( value = = " LEATHARMOR " ) return UITYPE_LEATHARMOR ;
if ( value = = " BREASTPLATE " ) return UITYPE_BREASTPLATE ;
if ( value = = " CAPE " ) return UITYPE_CAPE ;
if ( value = = " PLATEMAIL " ) return UITYPE_PLATEMAIL ;
if ( value = = " FULLPLATE " ) return UITYPE_FULLPLATE ;
if ( value = = " BUCKLER " ) return UITYPE_BUCKLER ;
if ( value = = " SMALLSHIELD " ) return UITYPE_SMALLSHIELD ;
if ( value = = " LARGESHIELD " ) return UITYPE_LARGESHIELD ;
if ( value = = " KITESHIELD " ) return UITYPE_KITESHIELD ;
if ( value = = " GOTHSHIELD " ) return UITYPE_GOTHSHIELD ;
if ( value = = " RING " ) return UITYPE_RING ;
if ( value = = " AMULET " ) return UITYPE_AMULET ;
if ( value = = " SKCROWN " ) return UITYPE_SKCROWN ;
if ( value = = " INFRARING " ) return UITYPE_INFRARING ;
if ( value = = " OPTAMULET " ) return UITYPE_OPTAMULET ;
if ( value = = " TRING " ) return UITYPE_TRING ;
if ( value = = " HARCREST " ) return UITYPE_HARCREST ;
if ( value = = " MAPOFDOOM " ) return UITYPE_MAPOFDOOM ;
if ( value = = " ELIXIR " ) return UITYPE_ELIXIR ;
if ( value = = " ARMOFVAL " ) return UITYPE_ARMOFVAL ;
if ( value = = " STEELVEIL " ) return UITYPE_STEELVEIL ;
if ( value = = " GRISWOLD " ) return UITYPE_GRISWOLD ;
if ( value = = " LGTFORGE " ) return UITYPE_LGTFORGE ;
if ( value = = " LAZSTAFF " ) return UITYPE_LAZSTAFF ;
if ( value = = " BOVINE " ) return UITYPE_BOVINE ;
if ( value = = " INVALID " ) return UITYPE_INVALID ;
const auto findIt = AdditionalUniqueBaseItemStringsToIndices . find ( std : : string ( value ) ) ;
if ( findIt ! = AdditionalUniqueBaseItemStringsToIndices . end ( ) ) {
return static_cast < unique_base_item > ( findIt - > second ) ;
}
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < unique_base_item , std : : string > ParseOrAddUniqueBaseItem ( std : : string_view value )
{
const auto parseResult = ParseUniqueBaseItem ( value ) ;
if ( parseResult . has_value ( ) ) {
return parseResult . value ( ) ;
}
const size_t newUniqueBaseItemIndex = static_cast < size_t > ( NUM_DEFAULT_UITYPES ) + AdditionalUniqueBaseItemStringsToIndices . size ( ) ;
if ( newUniqueBaseItemIndex > = static_cast < size_t > ( NUM_MAX_UITYPES ) ) {
return tl : : make_unexpected ( fmt : : format ( " Could not define new unique base item \" {} \" , since the maximum number of {} has already been reached. " , value , static_cast < size_t > ( NUM_MAX_UITYPES ) ) ) ;
}
const unique_base_item newUniqueBaseItem = static_cast < unique_base_item > ( newUniqueBaseItemIndex ) ;
AdditionalUniqueBaseItemStringsToIndices [ std : : string ( value ) ] = newUniqueBaseItem ;
return newUniqueBaseItem ;
}
tl : : expected < ItemSpecialEffect , std : : string > ParseItemSpecialEffect ( std : : string_view value )
{
if ( value = = " RandomStealLife " ) return ItemSpecialEffect : : RandomStealLife ;
if ( value = = " RandomArrowVelocity " ) return ItemSpecialEffect : : RandomArrowVelocity ;
if ( value = = " FireArrows " ) return ItemSpecialEffect : : FireArrows ;
if ( value = = " FireDamage " ) return ItemSpecialEffect : : FireDamage ;
if ( value = = " LightningDamage " ) return ItemSpecialEffect : : LightningDamage ;
if ( value = = " DrainLife " ) return ItemSpecialEffect : : DrainLife ;
if ( value = = " MultipleArrows " ) return ItemSpecialEffect : : MultipleArrows ;
if ( value = = " Knockback " ) return ItemSpecialEffect : : Knockback ;
if ( value = = " StealMana3 " ) return ItemSpecialEffect : : StealMana3 ;
if ( value = = " StealMana5 " ) return ItemSpecialEffect : : StealMana5 ;
if ( value = = " StealLife3 " ) return ItemSpecialEffect : : StealLife3 ;
if ( value = = " StealLife5 " ) return ItemSpecialEffect : : StealLife5 ;
if ( value = = " QuickAttack " ) return ItemSpecialEffect : : QuickAttack ;
if ( value = = " FastAttack " ) return ItemSpecialEffect : : FastAttack ;
if ( value = = " FasterAttack " ) return ItemSpecialEffect : : FasterAttack ;
if ( value = = " FastestAttack " ) return ItemSpecialEffect : : FastestAttack ;
if ( value = = " FastHitRecovery " ) return ItemSpecialEffect : : FastHitRecovery ;
if ( value = = " FasterHitRecovery " ) return ItemSpecialEffect : : FasterHitRecovery ;
if ( value = = " FastestHitRecovery " ) return ItemSpecialEffect : : FastestHitRecovery ;
if ( value = = " FastBlock " ) return ItemSpecialEffect : : FastBlock ;
if ( value = = " LightningArrows " ) return ItemSpecialEffect : : LightningArrows ;
if ( value = = " Thorns " ) return ItemSpecialEffect : : Thorns ;
if ( value = = " NoMana " ) return ItemSpecialEffect : : NoMana ;
if ( value = = " HalfTrapDamage " ) return ItemSpecialEffect : : HalfTrapDamage ;
if ( value = = " TripleDemonDamage " ) return ItemSpecialEffect : : TripleDemonDamage ;
if ( value = = " ZeroResistance " ) return ItemSpecialEffect : : ZeroResistance ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < item_misc_id , std : : string > ParseItemMiscId ( std : : string_view value )
{
if ( value = = " NONE " ) return IMISC_NONE ;
if ( value = = " USEFIRST " ) return IMISC_USEFIRST ;
if ( value = = " FULLHEAL " ) return IMISC_FULLHEAL ;
if ( value = = " HEAL " ) return IMISC_HEAL ;
if ( value = = " MANA " ) return IMISC_MANA ;
if ( value = = " FULLMANA " ) return IMISC_FULLMANA ;
if ( value = = " ELIXSTR " ) return IMISC_ELIXSTR ;
if ( value = = " ELIXMAG " ) return IMISC_ELIXMAG ;
if ( value = = " ELIXDEX " ) return IMISC_ELIXDEX ;
if ( value = = " ELIXVIT " ) return IMISC_ELIXVIT ;
if ( value = = " REJUV " ) return IMISC_REJUV ;
if ( value = = " FULLREJUV " ) return IMISC_FULLREJUV ;
if ( value = = " USELAST " ) return IMISC_USELAST ;
if ( value = = " SCROLL " ) return IMISC_SCROLL ;
if ( value = = " SCROLLT " ) return IMISC_SCROLLT ;
if ( value = = " STAFF " ) return IMISC_STAFF ;
if ( value = = " BOOK " ) return IMISC_BOOK ;
if ( value = = " RING " ) return IMISC_RING ;
if ( value = = " AMULET " ) return IMISC_AMULET ;
if ( value = = " UNIQUE " ) return IMISC_UNIQUE ;
if ( value = = " OILFIRST " ) return IMISC_OILFIRST ;
if ( value = = " OILOF " ) return IMISC_OILOF ;
if ( value = = " OILACC " ) return IMISC_OILACC ;
if ( value = = " OILMAST " ) return IMISC_OILMAST ;
if ( value = = " OILSHARP " ) return IMISC_OILSHARP ;
if ( value = = " OILDEATH " ) return IMISC_OILDEATH ;
if ( value = = " OILSKILL " ) return IMISC_OILSKILL ;
if ( value = = " OILBSMTH " ) return IMISC_OILBSMTH ;
if ( value = = " OILFORT " ) return IMISC_OILFORT ;
if ( value = = " OILPERM " ) return IMISC_OILPERM ;
if ( value = = " OILHARD " ) return IMISC_OILHARD ;
if ( value = = " OILIMP " ) return IMISC_OILIMP ;
if ( value = = " OILLAST " ) return IMISC_OILLAST ;
if ( value = = " MAPOFDOOM " ) return IMISC_MAPOFDOOM ;
if ( value = = " EAR " ) return IMISC_EAR ;
if ( value = = " SPECELIX " ) return IMISC_SPECELIX ;
if ( value = = " RUNEFIRST " ) return IMISC_RUNEFIRST ;
if ( value = = " RUNEF " ) return IMISC_RUNEF ;
if ( value = = " RUNEL " ) return IMISC_RUNEL ;
if ( value = = " GR_RUNEL " ) return IMISC_GR_RUNEL ;
if ( value = = " GR_RUNEF " ) return IMISC_GR_RUNEF ;
if ( value = = " RUNES " ) return IMISC_RUNES ;
if ( value = = " RUNELAST " ) return IMISC_RUNELAST ;
if ( value = = " AURIC " ) return IMISC_AURIC ;
if ( value = = " NOTE " ) return IMISC_NOTE ;
if ( value = = " ARENAPOT " ) return IMISC_ARENAPOT ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < item_effect_type , std : : string > ParseItemEffectType ( std : : string_view value )
{
if ( value = = " TOHIT " ) return IPL_TOHIT ;
if ( value = = " TOHIT_CURSE " ) return IPL_TOHIT_CURSE ;
if ( value = = " DAMP " ) return IPL_DAMP ;
if ( value = = " DAMP_CURSE " ) return IPL_DAMP_CURSE ;
if ( value = = " TOHIT_DAMP " ) return IPL_TOHIT_DAMP ;
if ( value = = " TOHIT_DAMP_CURSE " ) return IPL_TOHIT_DAMP_CURSE ;
if ( value = = " ACP " ) return IPL_ACP ;
if ( value = = " ACP_CURSE " ) return IPL_ACP_CURSE ;
if ( value = = " FIRERES " ) return IPL_FIRERES ;
if ( value = = " LIGHTRES " ) return IPL_LIGHTRES ;
if ( value = = " MAGICRES " ) return IPL_MAGICRES ;
if ( value = = " ALLRES " ) return IPL_ALLRES ;
if ( value = = " SPLLVLADD " ) return IPL_SPLLVLADD ;
if ( value = = " CHARGES " ) return IPL_CHARGES ;
if ( value = = " FIREDAM " ) return IPL_FIREDAM ;
if ( value = = " LIGHTDAM " ) return IPL_LIGHTDAM ;
if ( value = = " STR " ) return IPL_STR ;
if ( value = = " STR_CURSE " ) return IPL_STR_CURSE ;
if ( value = = " MAG " ) return IPL_MAG ;
if ( value = = " MAG_CURSE " ) return IPL_MAG_CURSE ;
if ( value = = " DEX " ) return IPL_DEX ;
if ( value = = " DEX_CURSE " ) return IPL_DEX_CURSE ;
if ( value = = " VIT " ) return IPL_VIT ;
if ( value = = " VIT_CURSE " ) return IPL_VIT_CURSE ;
if ( value = = " ATTRIBS " ) return IPL_ATTRIBS ;
if ( value = = " ATTRIBS_CURSE " ) return IPL_ATTRIBS_CURSE ;
if ( value = = " GETHIT_CURSE " ) return IPL_GETHIT_CURSE ;
if ( value = = " GETHIT " ) return IPL_GETHIT ;
if ( value = = " LIFE " ) return IPL_LIFE ;
if ( value = = " LIFE_CURSE " ) return IPL_LIFE_CURSE ;
if ( value = = " MANA " ) return IPL_MANA ;
if ( value = = " MANA_CURSE " ) return IPL_MANA_CURSE ;
if ( value = = " DUR " ) return IPL_DUR ;
if ( value = = " DUR_CURSE " ) return IPL_DUR_CURSE ;
if ( value = = " INDESTRUCTIBLE " ) return IPL_INDESTRUCTIBLE ;
if ( value = = " LIGHT " ) return IPL_LIGHT ;
if ( value = = " LIGHT_CURSE " ) return IPL_LIGHT_CURSE ;
if ( value = = " MULT_ARROWS " ) return IPL_MULT_ARROWS ;
if ( value = = " FIRE_ARROWS " ) return IPL_FIRE_ARROWS ;
if ( value = = " LIGHT_ARROWS " ) return IPL_LIGHT_ARROWS ;
if ( value = = " THORNS " ) return IPL_THORNS ;
if ( value = = " NOMANA " ) return IPL_NOMANA ;
if ( value = = " FIREBALL " ) return IPL_FIREBALL ;
if ( value = = " ABSHALFTRAP " ) return IPL_ABSHALFTRAP ;
if ( value = = " KNOCKBACK " ) return IPL_KNOCKBACK ;
if ( value = = " STEALMANA " ) return IPL_STEALMANA ;
if ( value = = " STEALLIFE " ) return IPL_STEALLIFE ;
if ( value = = " TARGAC " ) return IPL_TARGAC ;
if ( value = = " FASTATTACK " ) return IPL_FASTATTACK ;
if ( value = = " FASTRECOVER " ) return IPL_FASTRECOVER ;
if ( value = = " FASTBLOCK " ) return IPL_FASTBLOCK ;
if ( value = = " DAMMOD " ) return IPL_DAMMOD ;
if ( value = = " RNDARROWVEL " ) return IPL_RNDARROWVEL ;
if ( value = = " SETDAM " ) return IPL_SETDAM ;
if ( value = = " SETDUR " ) return IPL_SETDUR ;
if ( value = = " NOMINSTR " ) return IPL_NOMINSTR ;
if ( value = = " SPELL " ) return IPL_SPELL ;
if ( value = = " ONEHAND " ) return IPL_ONEHAND ;
if ( value = = " 3XDAMVDEM " ) return IPL_3XDAMVDEM ;
if ( value = = " ALLRESZERO " ) return IPL_ALLRESZERO ;
if ( value = = " DRAINLIFE " ) return IPL_DRAINLIFE ;
if ( value = = " RNDSTEALLIFE " ) return IPL_RNDSTEALLIFE ;
if ( value = = " SETAC " ) return IPL_SETAC ;
if ( value = = " ADDACLIFE " ) return IPL_ADDACLIFE ;
if ( value = = " ADDMANAAC " ) return IPL_ADDMANAAC ;
if ( value = = " AC_CURSE " ) return IPL_AC_CURSE ;
if ( value = = " LASTDIABLO " ) return IPL_LASTDIABLO ;
if ( value = = " FIRERES_CURSE " ) return IPL_FIRERES_CURSE ;
if ( value = = " LIGHTRES_CURSE " ) return IPL_LIGHTRES_CURSE ;
if ( value = = " MAGICRES_CURSE " ) return IPL_MAGICRES_CURSE ;
if ( value = = " DEVASTATION " ) return IPL_DEVASTATION ;
if ( value = = " DECAY " ) return IPL_DECAY ;
if ( value = = " PERIL " ) return IPL_PERIL ;
if ( value = = " JESTERS " ) return IPL_JESTERS ;
if ( value = = " CRYSTALLINE " ) return IPL_CRYSTALLINE ;
if ( value = = " DOPPELGANGER " ) return IPL_DOPPELGANGER ;
if ( value = = " ACDEMON " ) return IPL_ACDEMON ;
if ( value = = " ACUNDEAD " ) return IPL_ACUNDEAD ;
if ( value = = " MANATOLIFE " ) return IPL_MANATOLIFE ;
if ( value = = " LIFETOMANA " ) return IPL_LIFETOMANA ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < AffixItemType , std : : string > ParseAffixItemType ( std : : string_view value )
{
if ( value = = " Misc " ) return AffixItemType : : Misc ;
if ( value = = " Bow " ) return AffixItemType : : Bow ;
if ( value = = " Staff " ) return AffixItemType : : Staff ;
if ( value = = " Weapon " ) return AffixItemType : : Weapon ;
if ( value = = " Shield " ) return AffixItemType : : Shield ;
if ( value = = " Armor " ) return AffixItemType : : Armor ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
tl : : expected < goodorevil , std : : string > ParseAffixAlignment ( std : : string_view value )
{
if ( value = = " Any " ) return GOE_ANY ;
if ( value = = " Evil " ) return GOE_EVIL ;
if ( value = = " Good " ) return GOE_GOOD ;
return tl : : make_unexpected ( " Unknown enum value " ) ;
}
} // namespace
void LoadItemDatFromFile ( DataFile & dataFile , std : : string_view filename , int32_t baseMappingId )
{
dataFile . skipHeaderOrDie ( filename ) ;
int32_t currentMappingId = baseMappingId ;
AllItemsList . reserve ( AllItemsList . size ( ) + dataFile . numRecords ( ) ) ;
for ( DataFileRecord record : dataFile ) {
RecordReader reader { record , filename } ;
ItemData & item = AllItemsList . emplace_back ( ) ;
reader . advance ( ) ; // Skip the first column (item ID).
reader . readInt ( " dropRate " , item . dropRate ) ;
reader . read ( " class " , item . iClass , ParseItemClass ) ;
reader . read ( " equipType " , item . iLoc , ParseItemEquipType ) ;
reader . read ( " cursorGraphic " , item . iCurs , ParseItemCursorGraphic ) ;
reader . read ( " itemType " , item . itype , ParseItemType ) ;
reader . read ( " uniqueBaseItem " , item . iItemId , ParseOrAddUniqueBaseItem ) ;
reader . readString ( " name " , item . iName ) ;
reader . readString ( " shortName " , item . iSName ) ;
reader . readInt ( " minMonsterLevel " , item . iMinMLvl ) ;
reader . readInt ( " durability " , item . iDurability ) ;
reader . readInt ( " minDamage " , item . iMinDam ) ;
reader . readInt ( " maxDamage " , item . iMaxDam ) ;
reader . readInt ( " minArmor " , item . iMinAC ) ;
reader . readInt ( " maxArmor " , item . iMaxAC ) ;
reader . readInt ( " minStrength " , item . iMinStr ) ;
reader . readInt ( " minMagic " , item . iMinMag ) ;
reader . readInt ( " minDexterity " , item . iMinDex ) ;
reader . readEnumList ( " specialEffects " , item . iFlags , ParseItemSpecialEffect ) ;
reader . read ( " miscId " , item . iMiscId , ParseItemMiscId ) ;
reader . read ( " spell " , item . iSpell , ParseSpellId ) ;
reader . readBool ( " usable " , item . iUsable ) ;
reader . readInt ( " value " , item . iValue ) ;
item . iMappingId = currentMappingId ;
const auto [ it , inserted ] = ItemMappingIdsToIndices . emplace ( item . iMappingId , static_cast < int16_t > ( AllItemsList . size ( ) ) - 1 ) ;
if ( ! inserted ) {
DisplayFatalErrorAndExit ( " Adding Item Failed " , fmt : : format ( " An item already exists for mapping ID {}. " , item . iMappingId ) ) ;
}
+ + currentMappingId ;
}
AllItemsList . shrink_to_fit ( ) ;
}
namespace {
void LoadItemDat ( )
{
const std : : string_view filename = " txtdata \\ items \\ itemdat.tsv " ;
DataFile dataFile = DataFile : : loadOrDie ( filename ) ;
AllItemsList . clear ( ) ;
AdditionalUniqueBaseItemStringsToIndices . clear ( ) ;
ItemMappingIdsToIndices . clear ( ) ;
LoadItemDatFromFile ( dataFile , filename , 0 ) ;
LuaEvent ( " ItemDataLoaded " ) ;
}
void ReadItemPower ( RecordReader & reader , std : : string_view fieldName , ItemPower & power )
{
reader . read ( fieldName , power . type , ParseItemEffectType ) ;
reader . readOptionalInt ( StrCat ( fieldName , " .value1 " ) , power . param1 ) ;
reader . readOptionalInt ( StrCat ( fieldName , " .value2 " ) , power . param2 ) ;
}
} // namespace
void LoadUniqueItemDatFromFile ( DataFile & dataFile , std : : string_view filename , int32_t baseMappingId )
{
dataFile . skipHeaderOrDie ( filename ) ;
int32_t currentMappingId = baseMappingId ;
UniqueItems . reserve ( UniqueItems . size ( ) + dataFile . numRecords ( ) ) ;
for ( DataFileRecord record : dataFile ) {
RecordReader reader { record , filename } ;
UniqueItem & item = UniqueItems . emplace_back ( ) ;
reader . readString ( " name " , item . UIName ) ;
reader . read ( " cursorGraphic " , item . UICurs , ParseItemCursorGraphic ) ;
reader . read ( " uniqueBaseItem " , item . UIItemId , ParseUniqueBaseItem ) ;
reader . readInt ( " minLevel " , item . UIMinLvl ) ;
reader . readInt ( " value " , item . UIValue ) ;
// powers (up to 6)
item . UINumPL = 0 ;
for ( size_t i = 0 ; i < 6 ; + + i ) {
if ( reader . value ( ) . empty ( ) )
break ;
ReadItemPower ( reader , StrCat ( " power " , i ) , item . powers [ item . UINumPL + + ] ) ;
}
item . mappingId = currentMappingId ;
const auto [ it , inserted ] = UniqueItemMappingIdsToIndices . emplace ( item . mappingId , static_cast < int32_t > ( UniqueItems . size ( ) ) - 1 ) ;
if ( ! inserted ) {
DisplayFatalErrorAndExit ( " Adding Unique Item Failed " , fmt : : format ( " A unique item already exists for mapping ID {}. " , item . mappingId ) ) ;
}
+ + currentMappingId ;
}
UniqueItems . shrink_to_fit ( ) ;
}
namespace {
void LoadUniqueItemDat ( )
{
const std : : string_view filename = " txtdata \\ items \\ unique_itemdat.tsv " ;
DataFile dataFile = DataFile : : loadOrDie ( filename ) ;
UniqueItems . clear ( ) ;
UniqueItemMappingIdsToIndices . clear ( ) ;
LoadUniqueItemDatFromFile ( dataFile , filename , 0 ) ;
LuaEvent ( " UniqueItemDataLoaded " ) ;
}
void LoadItemAffixesDat ( std : : string_view filename , std : : vector < PLStruct > & out )
{
DataFile dataFile = DataFile : : loadOrDie ( filename ) ;
dataFile . skipHeaderOrDie ( filename ) ;
out . clear ( ) ;
out . reserve ( dataFile . numRecords ( ) ) ;
for ( DataFileRecord record : dataFile ) {
RecordReader reader { record , filename } ;
PLStruct & item = out . emplace_back ( ) ;
reader . readString ( " name " , item . PLName ) ;
ReadItemPower ( reader , " power " , item . power ) ;
reader . readInt ( " minLevel " , item . PLMinLvl ) ;
reader . readEnumList ( " itemTypes " , item . PLIType , ParseAffixItemType ) ;
reader . read ( " alignment " , item . PLGOE , ParseAffixAlignment ) ;
reader . readInt ( " chance " , item . PLChance ) ;
reader . readBool ( " useful " , item . PLOk ) ;
reader . readInt ( " minVal " , item . minVal ) ;
reader . readInt ( " maxVal " , item . maxVal ) ;
reader . readInt ( " multVal " , item . multVal ) ;
}
out . shrink_to_fit ( ) ;
}
} // namespace
void LoadItemData ( )
{
LoadItemDat ( ) ;
LoadUniqueItemDat ( ) ;
LoadItemAffixesDat ( " txtdata \\ items \\ item_prefixes.tsv " , ItemPrefixes ) ;
LoadItemAffixesDat ( " txtdata \\ items \\ item_suffixes.tsv " , ItemSuffixes ) ;
}
std : : string_view ItemTypeToString ( ItemType itemType )
{
switch ( itemType ) {
case ItemType : : Misc : return " Misc " ;
case ItemType : : Sword : return " Sword " ;
case ItemType : : Axe : return " Axe " ;
case ItemType : : Bow : return " Bow " ;
case ItemType : : Mace : return " Mace " ;
case ItemType : : Shield : return " Shield " ;
case ItemType : : LightArmor : return " LightArmor " ;
case ItemType : : Helm : return " Helm " ;
case ItemType : : MediumArmor : return " MediumArmor " ;
case ItemType : : HeavyArmor : return " HeavyArmor " ;
case ItemType : : Staff : return " Staff " ;
case ItemType : : Gold : return " Gold " ;
case ItemType : : Ring : return " Ring " ;
case ItemType : : Amulet : return " Amulet " ;
case ItemType : : None : return " None " ;
}
return " " ;
}
} // namespace devilution