OpenDiablo2/d2common/d2data/d2datadict/item_common.go

399 lines
16 KiB
Go

package d2datadict
import (
"strconv"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2calculation"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
)
// ItemCommonRecord is a representation of entries from armor.txt, weapons.txt, and misc.txt
type ItemCommonRecord struct {
UsageStats [3]ItemUsageStat // stat boosts applied upon usage
CureOverlayStates [2]string // name of the overlay states that are removed upon use of this item
OverlayState string // name of the overlay state to be applied upon use of this item
SpellDescriptionString string // points to a string containing the description
BetterGem string // 3 char code pointing to the gem this upgrades to (non if not applicable)
SpellDescriptionCalc d2calculation.CalcString // a calc string what value to display
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
SpecialFeature string // Just a comment
FlavorText string // unknown, probably just for reference
TransmogCode string // the 3 char code representing the item this becomes via transmog
NightmareUpgrade string // upgraded in higher difficulties
HellUpgrade string
SourceArt string // unused?
GameArt string // unused?
Vendors map[string]*ItemVendorParams // controls vendor settings
Type string // base type in ItemTypes.txt
Type2 string
DropSound string // sfx for dropping
UseSound string // sfx for using
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
Code string // identifies the item
NameString string // seems to be identical to code?
AlternateGfx string // code of the DCC used when equipped
OpenBetaGfx string // unknown
NormalCode string
UberCode string
UltraCode string
Name string
Source d2enum.InventoryItemType
Version int // 0 = classic, 100 = expansion
Rarity int // higher, the rarer
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
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
SpellOffset int // unknown
Component int // corresponds to Composit.txt, player animation layer used by this
InventoryWidth int
InventoryHeight int
GemSockets int // number of gems to store
GemApplyType int // what kind of gem effect is applied
// 0 = weapon, 1= armor or helmet, 2 = shield
// 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
MinStack int // min size of stack when item is spawned, used if stackable
MaxStack int // max size of stack when item is spawned
DropSfxFrame int // what frame of drop animation the sfx triggers on
TransTable int // unknown, related to blending mode?
LightRadius int // apparently unused
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
ColorTransform int // colormap to use for player's gfx
InventoryColorTransform int // colormap to use for inventory's gfx
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
SpawnStack int // unknown, something to do with stack size when spawned (sold maybe?)
TransmogMin int // min amount of the transmog item to create
TransmogMax int // max ''
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
EffectLength int // timer for timed usage effects
SpellDescriptionType int // specifies how to format the usage description
// 0 = none, 1 = use desc string, 2 = use desc string + calc value
AutoBelt bool // if true, item is put into your belt when picked up
HasInventory bool // if true, item can store gems or runes
CompactSave bool // if true, doesn't store any stats upon saving
Spawnable bool // if 0, cannot spawn in shops
NoDurability bool // if true, item has no durability
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
Unique bool // if true, only spawns as unique
Transparent bool // unused
Quivered bool // if true, requires ammo to use
Belt bool // tells what kind of belt this item is
SkipName bool // if true, don't include the base name in the item description
Nameable bool // if true, item can be personalized
BarbOneOrTwoHanded bool // if true, barb can wield this in one or two hands
UsesTwoHands bool // if true, it's a 2handed weapon
QuestDifficultyCheck bool // if true, item only works in the difficulty it was found in
PermStoreItem bool // if true, vendor will always sell this
Transmogrify bool // if true, can be turned into another item via right click
Multibuy bool // if true, when you buy via right click + shift it will fill your belt automatically
}
// ItemUsageStat the stat that gets applied when the item is used
type ItemUsageStat struct {
Stat string // name of the stat to add to
Calc d2calculation.CalcString // calc string representing the amount to add
}
// ItemVendorParams are parameters that vendors use
type ItemVendorParams struct {
Min int // minimum of this item they can stock
Max int // max they can stock
MagicMin int
MagicMax int
MagicLevel uint8
}
// CommonItems stores all ItemCommonRecords
var CommonItems map[string]*ItemCommonRecord //nolint:gochecknoglobals // Currently global by design
// LoadCommonItems loads armor/weapons/misc.txt ItemCommonRecords
func LoadCommonItems(file []byte, source d2enum.InventoryItemType) map[string]*ItemCommonRecord {
if CommonItems == nil {
CommonItems = make(map[string]*ItemCommonRecord)
}
items := make(map[string]*ItemCommonRecord)
data := strings.Split(string(file), "\r\n")
mapping := mapHeaders(data[0])
for lineno, line := range data {
if lineno == 0 {
continue
}
if line == "" {
continue
}
rec := createCommonItemRecord(line, mapping, source)
if rec.Name == expansion {
continue
}
items[rec.Code] = &rec
CommonItems[rec.Code] = &rec
}
return items
}
//nolint:funlen // Makes no sens to split
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: d2calculation.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 = d2calculation.CalcString(mapLoadString(r, mapping, "calc"+strconv.Itoa(i)))
}
return result
}