From f13433f299937e7984666a73d5b5817b6e9125ff Mon Sep 17 00:00:00 2001 From: ndechiara <30356480+ndechiara@users.noreply.github.com> Date: Fri, 15 Nov 2019 22:31:10 -0500 Subject: [PATCH] Switch items to dynamic load with a common struct, add misc.txt loading (#185) --- d2common/calcstring.go | 9 + d2core/engine.go | 1 + d2data/d2datadict/armor.go | 272 +------------------ d2data/d2datadict/item_common.go | 416 ++++++++++++++++++++++++++++++ d2data/d2datadict/map_helper.go | 43 +++ d2data/d2datadict/misc.go | 18 ++ d2data/d2datadict/missiles.go | 10 +- d2data/d2datadict/unique_items.go | 6 +- d2data/d2datadict/weapons.go | 279 +------------------- 9 files changed, 505 insertions(+), 549 deletions(-) create mode 100644 d2common/calcstring.go create mode 100644 d2data/d2datadict/item_common.go create mode 100644 d2data/d2datadict/map_helper.go create mode 100644 d2data/d2datadict/misc.go diff --git a/d2common/calcstring.go b/d2common/calcstring.go new file mode 100644 index 00000000..9f5372db --- /dev/null +++ b/d2common/calcstring.go @@ -0,0 +1,9 @@ +package d2common + +// a calcstring is a type of string often used in datafiles to specify +// a value that is calculated dynamically based on the stats of the relevant +// source, for instance a missile might have a movement speed of lvl*2 + +type CalcString string + +// todo: the logic for parsing these should exist here \ No newline at end of file diff --git a/d2core/engine.go b/d2core/engine.go index 8dce3529..213ab24f 100644 --- a/d2core/engine.go +++ b/d2core/engine.go @@ -73,6 +73,7 @@ func CreateEngine() Engine { d2datadict.LoadObjects(&result) d2datadict.LoadWeapons(&result) d2datadict.LoadArmors(&result) + d2datadict.LoadMiscItems(&result) d2datadict.LoadUniqueItems(&result) d2datadict.LoadMissiles(&result) d2datadict.LoadSounds(&result) diff --git a/d2data/d2datadict/armor.go b/d2data/d2datadict/armor.go index 5561b2a5..d74c7827 100644 --- a/d2data/d2datadict/armor.go +++ b/d2data/d2datadict/armor.go @@ -2,281 +2,17 @@ package d2datadict import ( "log" - "strings" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" - - dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) -type ArmorRecord struct { - Name string - - Version int // 0 = classic, 100 = expansion - CompactSave bool // if true, doesn't store any stats upon saving - Rarity int // higher, the rarer - Spawnable bool // if 0, cannot spawn in shops - - MinAC int - MaxAC int - Absorbs int // unused? - Speed int // affects movement speed of wielder, >0 = you move slower, <0 = you move faster - RequiredStrength int - Block int // chance to block, capped at 75% - Durability int // base durability 0-255 - NoDurability bool // if true, item has no durability - - Level int // base item level (controls monster drops, for instance a lv20 monster cannot drop a lv30 item) - RequiredLevel int // required level to wield - Cost int // base cost - GambleCost int // for reference only, not used - Code string // identifies the item - NameString string // seems to be identical to code? - MagicLevel int // additional magic level (for gambling?) - AutoPrefix int // prefix automatically assigned to this item on spawn, maps to group column of Automagic.txt - - AlternateGfx string // code of the DCC used when equipped - OpenBetaGfx string // unknown - NormalCode string - UberCode string - UltraCode string - - SpellOffset int // unknown - - Component int // corresponds to Composit.txt, player animation layer used by this - InventoryWidth int - InventoryHeight int - HasInventory bool // if true, item can store gems or runes - GemSockets int // number of gems to store - GemApplyType int // what kind of gem effect is applied - // 0 = weapon, 1= armor or helmet, 2 = shield - - FlippyFile string // DC6 file animation to play when item drops on the ground - InventoryFile string // DC6 file used in your inventory - UniqueInventoryFile string // DC6 file used by the unique version of this item - SetInventoryFile string // DC6 file used by the set version of this item - - // these represent how player animations and graphics change upon wearing this - // these come from ArmType.txt - AnimRightArm int - AnimLeftArm int - AnimTorso int - AnimLegs int - AnimRightShoulderPad int - AnimLeftShoulderPad int - - Useable bool // can be used via right click if true - // game knows what to do if used by item code - Throwable bool - Stackable bool // can be stacked in inventory - MinStack int // min size of stack when item is spawned, used if stackable - MaxStack int // max size of stack when item is spawned - - Type string // base type in ItemTypes.txt - Type2 string - - DropSound string // sfx for dropping - DropSfxFrame int // what frame of drop animation the sfx triggers on - UseSound string // sfx for using - - Unique bool // if true, only spawns as unique - Transparent bool // unused - TransTable int // unknown, related to blending mode? - Quivered bool // if true, requires ammo to use - LightRadius int // apparently unused - Belt bool // tells what kind of belt this item is - - Quest int // indicates that this item belongs to a given quest? - - MissileType int // missile gfx for throwing - DurabilityWarning int // controls what warning icon appears when durability is low - QuantityWarning int // controls at what quantity the low quantity warning appears - - MinDamage int - MaxDamage int - StrengthBonus int - DexterityBonus int - // final mindam = min * str / strbonus + min * dex / dexbonus - // same for maxdam - - GemOffset int // unknown - BitField1 int // 1 = leather item, 3 = metal - - Vendors map[string]*ItemVendorParams // controls vendor settings - - SourceArt string // unused? - GameArt string // unused? - ColorTransform int // colormap to use for player's gfx - InventoryColorTransform int // colormap to use for inventory's gfx - - SkipName bool // if true, don't include the base name in the item description - NightmareUpgrade string // upgraded in higher difficulties - HellUpgrade string - - UnusedMinDamage int - UnusedMaxDamage int - - Nameable bool // if true, item can be personalized -} - -type ArmorVendorParams struct { - Min int // minimum of this item they can stock - Max int // max they can stock - MagicMin int - MagicMax int - MagicLevel uint8 -} - -func createArmorRecord(line string) ArmorRecord { - r := strings.Split(line, "\t") - i := -1 - inc := func() int { - i++ - return i - } - result := ArmorRecord{ - Name: r[inc()], - - Version: dh.StringToInt(dh.EmptyToZero(r[inc()])), - CompactSave: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Rarity: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Spawnable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - - MinAC: dh.StringToInt(dh.EmptyToZero(r[inc()])), - MaxAC: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Absorbs: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Speed: dh.StringToInt(dh.EmptyToZero(r[inc()])), - RequiredStrength: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Block: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Durability: dh.StringToInt(dh.EmptyToZero(r[inc()])), - NoDurability: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - - Level: dh.StringToInt(dh.EmptyToZero(r[inc()])), - RequiredLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Cost: dh.StringToInt(dh.EmptyToZero(r[inc()])), - GambleCost: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Code: r[inc()], - NameString: r[inc()], - MagicLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])), - AutoPrefix: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - AlternateGfx: r[inc()], - OpenBetaGfx: r[inc()], - NormalCode: r[inc()], - UberCode: r[inc()], - UltraCode: r[inc()], - - SpellOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - Component: dh.StringToInt(dh.EmptyToZero(r[inc()])), - InventoryWidth: dh.StringToInt(dh.EmptyToZero(r[inc()])), - InventoryHeight: dh.StringToInt(dh.EmptyToZero(r[inc()])), - HasInventory: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - GemSockets: dh.StringToInt(dh.EmptyToZero(r[inc()])), - GemApplyType: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - FlippyFile: r[inc()], - InventoryFile: r[inc()], - UniqueInventoryFile: r[inc()], - SetInventoryFile: r[inc()], - - AnimRightArm: dh.StringToInt(dh.EmptyToZero(r[inc()])), - AnimLeftArm: dh.StringToInt(dh.EmptyToZero(r[inc()])), - AnimTorso: dh.StringToInt(dh.EmptyToZero(r[inc()])), - AnimLegs: dh.StringToInt(dh.EmptyToZero(r[inc()])), - AnimRightShoulderPad: dh.StringToInt(dh.EmptyToZero(r[inc()])), - AnimLeftShoulderPad: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - Useable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - - Throwable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Stackable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - MinStack: dh.StringToInt(dh.EmptyToZero(r[inc()])), - MaxStack: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - Type: r[inc()], - Type2: r[inc()], - - DropSound: r[inc()], - DropSfxFrame: dh.StringToInt(dh.EmptyToZero(r[inc()])), - UseSound: r[inc()], - - Unique: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Transparent: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - TransTable: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Quivered: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - LightRadius: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Belt: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - - Quest: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - MissileType: dh.StringToInt(dh.EmptyToZero(r[inc()])), - DurabilityWarning: dh.StringToInt(dh.EmptyToZero(r[inc()])), - QuantityWarning: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - MinDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), - MaxDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), - StrengthBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])), - DexterityBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - GemOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])), - BitField1: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - Vendors: createArmorVendorParams(&r, inc), - - SourceArt: r[inc()], - GameArt: r[inc()], - ColorTransform: dh.StringToInt(dh.EmptyToZero(r[inc()])), - InventoryColorTransform: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - SkipName: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - NightmareUpgrade: r[inc()], - HellUpgrade: r[inc()], - - UnusedMinDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), - UnusedMaxDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), - - Nameable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - } - return result -} - -func createArmorVendorParams(r *[]string, inc func() int) map[string]*ItemVendorParams { - vs := make([]string, 17) - vs[0] = "Charsi" - vs[1] = "Gheed" - vs[2] = "Akara" - vs[3] = "Fara" - vs[4] = "Lysander" - vs[5] = "Drognan" - vs[6] = "Hralti" - vs[7] = "Alkor" - vs[8] = "Ormus" - vs[9] = "Elzix" - vs[10] = "Asheara" - vs[11] = "Cain" - vs[12] = "Halbu" - vs[13] = "Jamella" - vs[14] = "Larzuk" - vs[15] = "Malah" - vs[16] = "Drehya" - - return CreateItemVendorParams(r, inc, vs) -} - -var Armors map[string]*ArmorRecord +var Armors map[string]*ItemCommonRecord func LoadArmors(fileProvider d2interface.FileProvider) { - Armors = make(map[string]*ArmorRecord) - data := strings.Split(string(fileProvider.LoadFile(d2resource.Armor)), "\r\n")[1:] - for _, line := range data { - if len(line) == 0 { - continue - } - rec := createArmorRecord(line) - Armors[rec.Code] = &rec - } + Armors = *LoadCommonItems(fileProvider, d2resource.Armor, d2enum.InventoryItemTypeArmor) log.Printf("Loaded %d armors", len(Armors)) } diff --git a/d2data/d2datadict/item_common.go b/d2data/d2datadict/item_common.go new file mode 100644 index 00000000..2113ca72 --- /dev/null +++ b/d2data/d2datadict/item_common.go @@ -0,0 +1,416 @@ +package d2datadict + +import ( + "strings" + "strconv" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" +) + +type ItemCommonRecord struct { + Source d2enum.InventoryItemType + + Name string + + Version int // 0 = classic, 100 = expansion + CompactSave bool // if true, doesn't store any stats upon saving + Rarity int // higher, the rarer + Spawnable bool // if 0, cannot spawn in shops + + MinAC int + MaxAC int + Absorbs int // unused? + Speed int // affects movement speed of wielder, >0 = you move slower, <0 = you move faster + RequiredStrength int + Block int // chance to block, capped at 75% + Durability int // base durability 0-255 + NoDurability bool // if true, item has no durability + + Level int // base item level (controls monster drops, for instance a lv20 monster cannot drop a lv30 item) + RequiredLevel int // required level to wield + Cost int // base cost + GambleCost int // for reference only, not used + Code string // identifies the item + NameString string // seems to be identical to code? + MagicLevel int // additional magic level (for gambling?) + AutoPrefix int // prefix automatically assigned to this item on spawn, maps to group column of Automagic.txt + + AlternateGfx string // code of the DCC used when equipped + OpenBetaGfx string // unknown + NormalCode string + UberCode string + UltraCode string + + SpellOffset int // unknown + + Component int // corresponds to Composit.txt, player animation layer used by this + InventoryWidth int + InventoryHeight int + HasInventory bool // if true, item can store gems or runes + GemSockets int // number of gems to store + GemApplyType int // what kind of gem effect is applied + // 0 = weapon, 1= armor or helmet, 2 = shield + + FlippyFile string // DC6 file animation to play when item drops on the ground + InventoryFile string // DC6 file used in your inventory + UniqueInventoryFile string // DC6 file used by the unique version of this item + SetInventoryFile string // DC6 file used by the set version of this item + + // these represent how player animations and graphics change upon wearing this + // these come from ArmType.txt + AnimRightArm int + AnimLeftArm int + AnimTorso int + AnimLegs int + AnimRightShoulderPad int + AnimLeftShoulderPad int + + Useable bool // can be used via right click if true + // game knows what to do if used by item code + Throwable bool + Stackable bool // can be stacked in inventory + MinStack int // min size of stack when item is spawned, used if stackable + MaxStack int // max size of stack when item is spawned + + Type string // base type in ItemTypes.txt + Type2 string + + DropSound string // sfx for dropping + DropSfxFrame int // what frame of drop animation the sfx triggers on + UseSound string // sfx for using + + Unique bool // if true, only spawns as unique + Transparent bool // unused + TransTable int // unknown, related to blending mode? + Quivered bool // if true, requires ammo to use + LightRadius int // apparently unused + Belt bool // tells what kind of belt this item is + + Quest int // indicates that this item belongs to a given quest? + + MissileType int // missile gfx for throwing + DurabilityWarning int // controls what warning icon appears when durability is low + QuantityWarning int // controls at what quantity the low quantity warning appears + + MinDamage int + MaxDamage int + StrengthBonus int + DexterityBonus int + // final mindam = min * str / strbonus + min * dex / dexbonus + // same for maxdam + + GemOffset int // unknown + BitField1 int // 1 = leather item, 3 = metal + + Vendors map[string]*ItemVendorParams // controls vendor settings + + SourceArt string // unused? + GameArt string // unused? + ColorTransform int // colormap to use for player's gfx + InventoryColorTransform int // colormap to use for inventory's gfx + + SkipName bool // if true, don't include the base name in the item description + NightmareUpgrade string // upgraded in higher difficulties + HellUpgrade string + + Nameable bool // if true, item can be personalized + + + // weapon params + BarbOneOrTwoHanded bool // if true, barb can wield this in one or two hands + UsesTwoHands bool // if true, it's a 2handed weapon + Min2HandDamage int + Max2HandDamage int + MinMissileDamage int // ranged damage stats + MaxMissileDamage int + MissileSpeed int // unknown, affects movement speed of wielder during ranged attacks? + ExtraRange int // base range = 1, if this is non-zero add this to the range + // final mindam = min * str / strbonus + min * dex / dexbonus + // same for maxdam + RequiredDexterity int + + WeaponClass string // what kind of attack does this weapon have (i.e. determines attack animations) + WeaponClass2Hand string // what kind of attack when wielded with two hands + HitClass string // determines sounds/graphic effects when attacking + SpawnStack int // unknown, something to do with stack size when spawned (sold maybe?) + + SpecialFeature string // Just a comment + + QuestDifficultyCheck bool // if true, item only works in the difficulty it was found in + + PermStoreItem bool // if true, vendor will always sell this + + // misc params + FlavorText string // unknown, probably just for reference + + Transmogrify bool // if true, can be turned into another item via right click + TransmogCode string // the 3 char code representing the item this becomes via transmog + TransmogMin int // min amount of the transmog item to create + TransmogMax int // max '' + + AutoBelt bool // if true, item is put into your belt when picked up + + SpellIcon int // which icon to display when used? Is this always -1? + SpellType int // determines what kind of function is used when you use this item + OverlayState string // name of the overlay state to be applied upon use of this item + CureOverlayStates [2]string // name of the overlay states that are removed upon use of this item + EffectLength int // timer for timed usage effects + UsageStats [3]ItemUsageStat // stat boosts applied upon usage + + SpellDescriptionType int // specifies how to format the usage description + // 0 = none, 1 = use desc string, 2 = use desc string + calc value + SpellDescriptionString string // points to a string containing the description + SpellDescriptionCalc d2common.CalcString // a calc string what value to display + + BetterGem string // 3 char code pointing to the gem this upgrades to (non if not applicable) + + Multibuy bool // if true, when you buy via right click + shift it will fill your belt automatically +} + +type ItemUsageStat struct { + Stat string // name of the stat to add to + Calc d2common.CalcString // calc string representing the amount to add +} + +type ItemVendorParams struct { + Min int // minimum of this item they can stock + Max int // max they can stock + MagicMin int + MagicMax int + MagicLevel uint8 +} + + + +// Loading Functions +var CommonItems map[string]*ItemCommonRecord + +func LoadCommonItems(fileProvider d2interface.FileProvider, filepath string, source d2enum.InventoryItemType) *map[string]*ItemCommonRecord { + if CommonItems == nil { + CommonItems = make(map[string]*ItemCommonRecord) + } + items := make(map[string]*ItemCommonRecord) + data := strings.Split(string(fileProvider.LoadFile(filepath)), "\r\n") + mapping := MapHeaders(data[0]) + for lineno, line := range data { + if lineno == 0 { + continue + } + if len(line) == 0 { + continue + } + rec := createCommonItemRecord(line, &mapping, source) + items[rec.Code] = &rec + CommonItems[rec.Code] = &rec + } + return &items +} + +func createCommonItemRecord(line string, mapping *map[string]int, source d2enum.InventoryItemType) ItemCommonRecord { + r := strings.Split(line, "\t") + result := ItemCommonRecord{ + Source: source, + + Name: MapLoadString(&r, mapping, "name"), + + Version: MapLoadInt(&r, mapping, "version"), + CompactSave: MapLoadBool(&r, mapping, "compactsave"), + Rarity: MapLoadInt(&r, mapping, "rarity"), + Spawnable: MapLoadBool(&r, mapping, "spawnable"), + + MinAC: MapLoadInt(&r, mapping, "minac"), + MaxAC: MapLoadInt(&r, mapping, "maxac"), + Absorbs: MapLoadInt(&r, mapping, "absorbs"), + Speed: MapLoadInt(&r, mapping, "speed"), + RequiredStrength: MapLoadInt(&r, mapping, "reqstr"), + Block: MapLoadInt(&r, mapping, "block"), + Durability: MapLoadInt(&r, mapping, "durability"), + NoDurability: MapLoadBool(&r, mapping, "nodurability"), + + Level: MapLoadInt(&r, mapping, "level"), + RequiredLevel: MapLoadInt(&r, mapping, "levelreq"), + Cost: MapLoadInt(&r, mapping, "cost"), + GambleCost: MapLoadInt(&r, mapping, "gamble cost"), + Code: MapLoadString(&r, mapping, "code"), + NameString: MapLoadString(&r, mapping, "namestr"), + MagicLevel: MapLoadInt(&r, mapping, "magic lvl"), + AutoPrefix: MapLoadInt(&r, mapping, "auto prefix"), + + AlternateGfx: MapLoadString(&r, mapping, "alternategfx"), + OpenBetaGfx: MapLoadString(&r, mapping, "OpenBetaGfx"), + NormalCode: MapLoadString(&r, mapping, "normcode"), + UberCode: MapLoadString(&r, mapping, "ubercode"), + UltraCode: MapLoadString(&r, mapping, "ultracode"), + + SpellOffset: MapLoadInt(&r, mapping, "spelloffset"), + + Component: MapLoadInt(&r, mapping, "component"), + InventoryWidth: MapLoadInt(&r, mapping, "invwidth"), + InventoryHeight: MapLoadInt(&r, mapping, "invheight"), + HasInventory: MapLoadBool(&r, mapping, "hasinv"), + GemSockets: MapLoadInt(&r, mapping, "gemsockets"), + GemApplyType: MapLoadInt(&r, mapping, "gemapplytype"), + + FlippyFile: MapLoadString(&r, mapping, "flippyfile"), + InventoryFile: MapLoadString(&r, mapping, "invfile"), + UniqueInventoryFile: MapLoadString(&r, mapping, "uniqueinvfile"), + SetInventoryFile: MapLoadString(&r, mapping, "setinvfile"), + + AnimRightArm: MapLoadInt(&r, mapping, "rArm"), + AnimLeftArm: MapLoadInt(&r, mapping, "lArm"), + AnimTorso: MapLoadInt(&r, mapping, "Torso"), + AnimLegs: MapLoadInt(&r, mapping, "Legs"), + AnimRightShoulderPad: MapLoadInt(&r, mapping, "rSPad"), + AnimLeftShoulderPad: MapLoadInt(&r, mapping, "lSPad"), + + Useable: MapLoadBool(&r, mapping, "useable"), + + Throwable: MapLoadBool(&r, mapping, "throwable"), + Stackable: MapLoadBool(&r, mapping, "stackable"), + MinStack: MapLoadInt(&r, mapping, "minstack"), + MaxStack: MapLoadInt(&r, mapping, "maxstack"), + + Type: MapLoadString(&r, mapping, "type"), + Type2: MapLoadString(&r, mapping, "type2"), + + DropSound: MapLoadString(&r, mapping, "dropsound"), + DropSfxFrame: MapLoadInt(&r, mapping, "dropsfxframe"), + UseSound: MapLoadString(&r, mapping, "usesound"), + + Unique: MapLoadBool(&r, mapping, "unique"), + Transparent: MapLoadBool(&r, mapping, "transparent"), + TransTable: MapLoadInt(&r, mapping, "transtbl"), + Quivered: MapLoadBool(&r, mapping, "quivered"), + LightRadius: MapLoadInt(&r, mapping, "lightradius"), + Belt: MapLoadBool(&r, mapping, "belt"), + + Quest: MapLoadInt(&r, mapping, "quest"), + + MissileType: MapLoadInt(&r, mapping, "missiletype"), + DurabilityWarning: MapLoadInt(&r, mapping, "durwarning"), + QuantityWarning: MapLoadInt(&r, mapping, "qntwarning"), + + MinDamage: MapLoadInt(&r, mapping, "mindam"), + MaxDamage: MapLoadInt(&r, mapping, "maxdam"), + StrengthBonus: MapLoadInt(&r, mapping, "StrBonus"), + DexterityBonus: MapLoadInt(&r, mapping, "DexBonus"), + + GemOffset: MapLoadInt(&r, mapping, "gemoffset"), + BitField1: MapLoadInt(&r, mapping, "bitfield1"), + + Vendors: createItemVendorParams(&r, mapping), + + SourceArt: MapLoadString(&r, mapping, "Source Art"), + GameArt: MapLoadString(&r, mapping, "Game Art"), + ColorTransform: MapLoadInt(&r, mapping, "Transform"), + InventoryColorTransform: MapLoadInt(&r, mapping, "InvTrans"), + + SkipName: MapLoadBool(&r, mapping, "SkipName"), + NightmareUpgrade: MapLoadString(&r, mapping, "NightmareUpgrade"), + HellUpgrade: MapLoadString(&r, mapping, "HellUpgrade"), + + Nameable: MapLoadBool(&r, mapping, "Nameable"), + + // weapon params + BarbOneOrTwoHanded: MapLoadBool(&r, mapping, "1or2handed"), + UsesTwoHands: MapLoadBool(&r, mapping, "2handed"), + Min2HandDamage: MapLoadInt(&r, mapping, "2handmindam"), + Max2HandDamage: MapLoadInt(&r, mapping, "2handmaxdam"), + MinMissileDamage: MapLoadInt(&r, mapping, "minmisdam"), + MaxMissileDamage: MapLoadInt(&r, mapping, "maxmisdam"), + MissileSpeed: MapLoadInt(&r, mapping, "misspeed"), + ExtraRange: MapLoadInt(&r, mapping, "rangeadder"), + + RequiredDexterity: MapLoadInt(&r, mapping, "reqdex"), + + WeaponClass: MapLoadString(&r, mapping, "wclass"), + WeaponClass2Hand: MapLoadString(&r, mapping, "2handedwclass"), + + HitClass: MapLoadString(&r, mapping, "hit class"), + SpawnStack: MapLoadInt(&r, mapping, "spawnstack"), + + SpecialFeature: MapLoadString(&r, mapping, "special"), + + QuestDifficultyCheck: MapLoadBool(&r, mapping, "questdiffcheck"), + + PermStoreItem: MapLoadBool(&r, mapping, "PermStoreItem"), + + // misc params + FlavorText: MapLoadString(&r, mapping, "szFlavorText"), + + Transmogrify: MapLoadBool(&r, mapping, "Transmogrify"), + TransmogCode: MapLoadString(&r, mapping, "TMogType"), + TransmogMin: MapLoadInt(&r, mapping, "TMogMin"), + TransmogMax: MapLoadInt(&r, mapping, "TMogMax"), + + AutoBelt: MapLoadBool(&r, mapping, "autobelt"), + + SpellIcon: MapLoadInt(&r, mapping, "spellicon"), + SpellType: MapLoadInt(&r, mapping, "pSpell"), + OverlayState: MapLoadString(&r, mapping, "state"), + CureOverlayStates: [2]string{ + MapLoadString(&r, mapping, "cstate1"), + MapLoadString(&r, mapping, "cstate2"), + }, + EffectLength: MapLoadInt(&r, mapping, "len"), + UsageStats: createItemUsageStats(&r, mapping), + + SpellDescriptionType: MapLoadInt(&r, mapping, "spelldesc"), + // 0 = none, 1 = use desc string, 2 = use desc string + calc value + SpellDescriptionString: MapLoadString(&r, mapping, "spelldescstr"), + SpellDescriptionCalc: d2common.CalcString(MapLoadString(&r, mapping, "spelldesccalc")), + + BetterGem: MapLoadString(&r, mapping, "BetterGem"), + + Multibuy: MapLoadBool(&r, mapping, "multibuy"), + } + return result +} + +func createItemVendorParams(r *[]string, mapping *map[string]int) map[string]*ItemVendorParams { + vs := make([]string, 17) + vs[0] = "Charsi" + vs[1] = "Gheed" + vs[2] = "Akara" + vs[3] = "Fara" + vs[4] = "Lysander" + vs[5] = "Drognan" + vs[6] = "Hralti" + vs[7] = "Alkor" + vs[8] = "Ormus" + vs[9] = "Elzix" + vs[10] = "Asheara" + vs[11] = "Cain" + vs[12] = "Halbu" + vs[13] = "Jamella" + vs[14] = "Larzuk" + vs[15] = "Malah" + vs[16] = "Drehya" + + result := make(map[string]*ItemVendorParams) + + for _, name := range vs { + wvp := ItemVendorParams{ + Min: MapLoadInt(r, mapping, name + "Min"), + Max: MapLoadInt(r, mapping, name + "Max"), + MagicMin: MapLoadInt(r, mapping, name + "MagicMin"), + MagicMax: MapLoadInt(r, mapping, name + "MagicMax"), + MagicLevel: MapLoadUint8(r, mapping, name + "MagicLvl"), + } + result[name] = &wvp + } + return result +} + +func createItemUsageStats(r *[]string, mapping *map[string]int) [3]ItemUsageStat { + result := [3]ItemUsageStat{} + for i := 0; i < 3; i++ { + result[i].Stat = MapLoadString(r, mapping, "stat" + strconv.Itoa(i)) + result[i].Calc = d2common.CalcString(MapLoadString(r, mapping, "calc" + strconv.Itoa(i))) + } + return result +} \ No newline at end of file diff --git a/d2data/d2datadict/map_helper.go b/d2data/d2datadict/map_helper.go new file mode 100644 index 00000000..b8862428 --- /dev/null +++ b/d2data/d2datadict/map_helper.go @@ -0,0 +1,43 @@ +package d2datadict + +import ( + "strings" + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" +) + +func MapHeaders(line string) map[string]int { + m := make(map[string]int) + r := strings.Split(line, "\t") + for index, header := range r { + m[header] = index + } + return m +} + +func MapLoadInt(r *[]string, mapping *map[string]int, field string) int { + index, ok := (*mapping)[field] + if ok { + return dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty((*r)[index]))) + } + return 0 +} + +func MapLoadString(r *[]string, mapping *map[string]int, field string) string { + index, ok := (*mapping)[field] + if ok { + return dh.AsterToEmpty((*r)[index]) + } + return "" +} + +func MapLoadBool(r *[]string, mapping *map[string]int, field string) bool { + return MapLoadInt(r, mapping, field) == 1 +} + +func MapLoadUint8(r *[]string, mapping *map[string]int, field string) uint8 { + index, ok := (*mapping)[field] + if ok { + return dh.StringToUint8(dh.EmptyToZero(dh.AsterToEmpty((*r)[index]))) + } + return 0 +} \ No newline at end of file diff --git a/d2data/d2datadict/misc.go b/d2data/d2datadict/misc.go new file mode 100644 index 00000000..2540605a --- /dev/null +++ b/d2data/d2datadict/misc.go @@ -0,0 +1,18 @@ +package d2datadict + +import ( + "log" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" +) + +var MiscItems map[string]*ItemCommonRecord + +func LoadMiscItems(fileProvider d2interface.FileProvider) { + MiscItems = *LoadCommonItems(fileProvider, d2resource.Misc, d2enum.InventoryItemTypeItem) + log.Printf("Loaded %d misc items", len(MiscItems)) +} diff --git a/d2data/d2datadict/missiles.go b/d2data/d2datadict/missiles.go index 7767711f..55deb87c 100644 --- a/d2data/d2datadict/missiles.go +++ b/d2data/d2datadict/missiles.go @@ -4,6 +4,8 @@ import ( "log" "strings" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" @@ -17,7 +19,7 @@ type MissileCalcParam struct { } type MissileCalc struct { - Calc string + Calc d2common.CalcString Desc string Params []MissileCalcParam } @@ -64,7 +66,7 @@ type MissileDamage struct { MinLevelDamage [5]int // additional damage per missile level // [0]: lvs 2-8, [1]: lvs 9-16, [2]: lvs 17-22, [3]: lvs 23-28, [4]: lv 29+ MaxLevelDamage [5]int // see above - DamageSynergyPerCalc string // works like synergy in skills.txt, not clear + DamageSynergyPerCalc d2common.CalcString // works like synergy in skills.txt, not clear } type MissileElementalDamage struct { @@ -318,7 +320,7 @@ func loadMissileCalcParam(r *[]string, inc func() int) MissileCalcParam { func loadMissileCalc(r *[]string, inc func() int, params int) MissileCalc { result := MissileCalc{ - Calc: (*r)[inc()], + Calc: d2common.CalcString((*r)[inc()]), Desc: (*r)[inc()], } result.Params = make([]MissileCalcParam, params) @@ -389,7 +391,7 @@ func loadMissileDamage(r *[]string, inc func() int) MissileDamage { dh.StringToInt(dh.EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])), }, - DamageSynergyPerCalc: (*r)[inc()], + DamageSynergyPerCalc: d2common.CalcString((*r)[inc()]), } return result } diff --git a/d2data/d2datadict/unique_items.go b/d2data/d2datadict/unique_items.go index 4e8abfd2..7500d2cb 100644 --- a/d2data/d2datadict/unique_items.go +++ b/d2data/d2datadict/unique_items.go @@ -4,6 +4,8 @@ import ( "log" "strings" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" @@ -47,7 +49,7 @@ type UniqueItemRecord struct { type UniqueItemProperty struct { Property string - Parameter string // depending on the property, this may be an int (usually), or a string + Parameter d2common.CalcString // depending on the property, this may be an int (usually), or a string Min int Max int } @@ -109,7 +111,7 @@ func createUniqueItemRecord(r []string) UniqueItemRecord { func createUniqueItemProperty(r *[]string, inc func() int) UniqueItemProperty { result := UniqueItemProperty{ Property: (*r)[inc()], - Parameter: (*r)[inc()], + Parameter: d2common.CalcString((*r)[inc()]), Min: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), Max: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), } diff --git a/d2data/d2datadict/weapons.go b/d2data/d2datadict/weapons.go index 3f68d2d9..22fc08ac 100644 --- a/d2data/d2datadict/weapons.go +++ b/d2data/d2datadict/weapons.go @@ -2,288 +2,17 @@ package d2datadict import ( "log" - "strings" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" - - dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) -type WeaponRecord struct { - Name string - - Type string // base type in ItemTypes.txt - Type2 string - Code string // identifies the item - AlternateGfx string // code of the DCC used when equipped - NameString string // seems to be identical to code? - Version int // 0 = classic, 100 = expansion - CompactSave bool // if true, doesn't store any stats upon saving - Rarity int // higher, the rarer - Spawnable bool // if 0, cannot spawn in shops - - MinDamage int - MaxDamage int - BarbOneOrTwoHanded bool // if true, barb can wield this in one or two hands - UsesTwoHands bool // if true, it's a 2handed weapon - Min2HandDamage int - Max2HandDamage int - MinMissileDamage int // ranged damage stats - MaxMissileDamage int - MissileSpeed int // unknown, affects movement speed of wielder during ranged attacks? - ExtraRange int // base range = 1, if this is non-zero add this to the range - Speed int // affects movement speed of wielder, >0 = you move slower, <0 = you move faster - StrengthBonus int - DexterityBonus int - // final mindam = min * str / strbonus + min * dex / dexbonus - // same for maxdam - RequiredStrength int - RequiredDexterity int - Durability int // base durability 0-255 - NoDurability bool // if true, item has no durability - - Level int // base item level (controls monster drops, for instance a lv20 monster cannot drop a lv30 item) - RequiredLevel int // required level to wield - Cost int // base cost - GambleCost int // for reference only, not used - MagicLevel int // additional magic level (for gambling?) - AutoPrefix int // prefix automatically assigned to this item on spawn, maps to group column of Automagic.txt - OpenBetaGfx string // unknown - NormalCode string - UberCode string - UltraCode string - - WeaponClass string // what kind of attack does this weapon have (i.e. determines attack animations) - WeaponClass2Hand string // what kind of attack when wielded with two hands - Component int // corresponds to Composit.txt, player animation layer used by this - HitClass string // determines sounds/graphic effects when attacking - InventoryWidth int - InventoryHeight int - Stackable bool // can be stacked in inventory - MinStack int // min size of stack when item is spawned, used if stackable - MaxStack int // max size of stack when item is spawned - SpawnStack int // unknown, something to do with stack size when spawned (sold maybe?) - - FlippyFile string // DC6 file animation to play when item drops on the ground - InventoryFile string // DC6 file used in your inventory - UniqueInventoryFile string // DC6 file used by the unique version of this item - SetInventoryFile string // DC6 file used by the set version of this item - - HasInventory bool // if true, item can store gems or runes - GemSockets int // number of gems to store - GemApplyType int // what kind of gem effect is applied - // 0 = weapon, 1= armor or helmet, 2 = shield - - SpecialFeature string // Just a comment - - Useable bool // can be used via right click if true - // game knows what to do if used by item code - DropSound string // sfx for dropping - DropSfxFrame int // what frame of drop animation the sfx triggers on - UseSound string // sfx for using - - Unique bool // if true, only spawns as unique - Transparent bool // unused - TransTable int // unknown, related to blending mode? - Quivered bool // if true, requires ammo to use - LightRadius int // apparently unused - Belt bool // seems to be unused? supposed to be whether this can go in your quick access belt - - Quest int // indicates that this item belongs to a given quest? - QuestDifficultyCheck bool // if true, item only works in the difficulty it was found in - - MissileType int // missile gfx for throwing - DurabilityWarning int // controls what warning icon appears when durability is low - QuantityWarning int // controls at what quantity the low quantity warning appears - GemOffset int // unknown - BitField1 int // 1 = leather item, 3 = metal - - Vendors map[string]*ItemVendorParams // controls vendor settings - - SourceArt string // unused? - GameArt string // unused? - ColorTransform int // colormap to use for player's gfx - InventoryColorTransform int // colormap to use for inventory's gfx - - SkipName bool // if true, don't include the base name in the item description - NightmareUpgrade string // upgraded in higher difficulties - HellUpgrade string - - Nameable bool // if true, item can be personalized - PermStoreItem bool // if true, vendor will always sell this -} - -type ItemVendorParams struct { - Min int // minimum of this item they can stock - Max int // max they can stock - MagicMin int - MagicMax int - MagicLevel uint8 -} - -func createWeaponRecord(line string) WeaponRecord { - r := strings.Split(line, "\t") - i := -1 - inc := func() int { - i++ - return i - } - result := WeaponRecord{ - Name: r[inc()], - - Type: r[inc()], - Type2: r[inc()], - Code: r[inc()], - AlternateGfx: r[inc()], - NameString: r[inc()], - Version: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - CompactSave: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - Rarity: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Spawnable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - - MinDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - MaxDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - BarbOneOrTwoHanded: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - UsesTwoHands: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - Min2HandDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Max2HandDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - MinMissileDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - MaxMissileDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - MissileSpeed: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - ExtraRange: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Speed: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - StrengthBonus: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - DexterityBonus: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - - RequiredStrength: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - RequiredDexterity: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Durability: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - NoDurability: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - - Level: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - RequiredLevel: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Cost: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - GambleCost: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - MagicLevel: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - AutoPrefix: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - OpenBetaGfx: r[inc()], - NormalCode: r[inc()], - UberCode: r[inc()], - UltraCode: r[inc()], - - WeaponClass: r[inc()], - WeaponClass2Hand: r[inc()], - Component: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - HitClass: r[inc()], - InventoryWidth: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - InventoryHeight: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Stackable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - MinStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - MaxStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - SpawnStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - - FlippyFile: r[inc()], - InventoryFile: r[inc()], - UniqueInventoryFile: r[inc()], - SetInventoryFile: r[inc()], - - HasInventory: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - GemSockets: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - GemApplyType: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - - SpecialFeature: r[inc()], - - Useable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - - DropSound: r[inc()], - DropSfxFrame: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - UseSound: r[inc()], - - Unique: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - Transparent: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - TransTable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Quivered: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - LightRadius: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - Belt: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - - Quest: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - QuestDifficultyCheck: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - - MissileType: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - DurabilityWarning: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - QuantityWarning: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - GemOffset: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - BitField1: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - - Vendors: createWeaponVendorParams(&r, inc), - - SourceArt: r[inc()], - GameArt: r[inc()], - ColorTransform: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - InventoryColorTransform: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - - SkipName: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - NightmareUpgrade: r[inc()], - HellUpgrade: r[inc()], - - Nameable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - PermStoreItem: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - } - return result -} - -func createWeaponVendorParams(r *[]string, inc func() int) map[string]*ItemVendorParams { - vs := make([]string, 17) - vs[0] = "Charsi" - vs[1] = "Gheed" - vs[2] = "Akara" - vs[3] = "Fara" - vs[4] = "Lysander" - vs[5] = "Drognan" - vs[6] = "Hralti" - vs[7] = "Alkor" - vs[8] = "Ormus" - vs[9] = "Elzix" - vs[10] = "Asheara" - vs[11] = "Cain" - vs[12] = "Halbu" - vs[13] = "Jamella" - vs[14] = "Larzuk" - vs[15] = "Drehya" - vs[16] = "Malah" - - return CreateItemVendorParams(r, inc, vs) -} - -func CreateItemVendorParams(r *[]string, inc func() int, vs []string) map[string]*ItemVendorParams { - result := make(map[string]*ItemVendorParams) - - for _, name := range vs { - wvp := ItemVendorParams{ - Min: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), - Max: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), - MagicMin: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), - MagicMax: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), - MagicLevel: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])), - } - result[name] = &wvp - } - return result -} - -var Weapons map[string]*WeaponRecord +var Weapons map[string]*ItemCommonRecord func LoadWeapons(fileProvider d2interface.FileProvider) { - Weapons = make(map[string]*WeaponRecord) - data := strings.Split(string(fileProvider.LoadFile(d2resource.Weapons)), "\r\n")[1:] - for _, line := range data { - if len(line) == 0 { - continue - } - rec := createWeaponRecord(line) - Weapons[rec.Code] = &rec - } + Weapons = *LoadCommonItems(fileProvider, d2resource.Weapons, d2enum.InventoryItemTypeWeapon) log.Printf("Loaded %d weapons", len(Weapons)) }