1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-04 15:00:42 +00:00

d2data item related loaders (#619)

* added loader for ItemTypes.txt

* added loader for bodylocs.txt

* lint fix for item_types loader

* adding loader for sets.txt

* minor edit

* adding loader for SetItems.txt

* added loader for automagic.txt
This commit is contained in:
lord 2020-07-24 18:56:19 -07:00 committed by GitHub
parent 1ce81f1aec
commit b13175b070
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 975 additions and 0 deletions

View File

@ -239,6 +239,11 @@ func (a *App) loadDataDict() error {
{d2resource.Skills, d2datadict.LoadSkills},
{d2resource.Properties, d2datadict.LoadProperties},
{d2resource.SkillDesc, d2datadict.LoadSkillDescriptions},
{d2resource.ItemTypes, d2datadict.LoadItemTypes},
{d2resource.BodyLocations, d2datadict.LoadBodyLocations},
{d2resource.Sets, d2datadict.LoadSets},
{d2resource.SetItems, d2datadict.LoadSetItems},
{d2resource.AutoMagic, d2datadict.LoadAutoMagicRecords},
}
d2datadict.InitObjectRecords()

View File

@ -0,0 +1,206 @@
package d2datadict
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
)
// AutoMagicRecord describes rules for automatically generating magic properties when spawning
// items
type AutoMagicRecord struct {
// Name
// String Comment Blizzard lists the equivalent prefix/affix here.
// You can use what ever you wish here though. Handy for keeping track of groups.
Name string
// Version
// it needs to be set to 0 if the prefix\affix you want to create or edit is going to be a
// classic-only item ( with "classic" we mean "non-expansion" mode,
// which you can toggle on and off when creating a character) or set to 100 if it's going to be
// available in Expansion. This field is important,
// as Items with " version" set to 100 will NOT be generated in Classic Diablo II.
Version int
// Spawnable
// It is a boolean type field, and states if this autoprefix can actually spawn in the game.
// You can disable this row by setting it to 0 , or enable it by setting it to 1
Spawnable bool
// SpawnOnRare
// It decides whether this autoprefix spawns on rare quality items or not.
// You can prevent that from happening by setting it to 0 , or you can allow it by setting it to 1
SpawnOnRare bool // rare
// MinSpawnLevel
// this field accepts numeric values and specifies the minimum level from which this autoprefix
// can spawn. The column in question can be combined with the following maxlevel: to effectively
// control groups of automods,
// because you can use this field to combine multiple rows so that the autoprefixes are assigned
// based on the level of the treasure drop [see below].
MinSpawnLevel int // level
// MaxSpawnLevel
// this field accepts numeric values and specifies the maximum level beyond which the automod
// stop spawning.
MaxSpawnLevel int // maxlevel
// LevelRequirement
// It is the level requirement for this autoprefix.
// This value is added to the Level Requirement of the item generated with this mod.
LevelRequirement int
// Class
// the class type
Class d2enum.Hero
// ClassLevelRequirement
// If class is set, this should allow a separate level requirement for this class.
// This is a polite thing to do,
// as other classes gain no advantage from class specific modifiers.
// I am uncertain that this actually works.
ClassLevelRequirement int // classlevelreq
// Frequency
// For autoprefix groups, it states the chance to spawn this specific group member vs others.
// Higher numbers means the automod will be more common. The 1.
// 09 version file guide has some formuae relateing to this.
Frequency int
// Group
// This field accepts numeric values and groups all the lines with the same values,
// which are treated as a group. Only one autoprefix per group can be chosen,
// and groups are influenced by levelreq, classlevelreq and frequency The 1.
// 09 version file guide has a very nice tutorial about how to set up groups.
// NOTE: The group number must also be entered in the 'auto prefix' column of each entry in
// Weapons.txt or Armor.txt in order for the property to appear.
Group int
// ModCode
// They're the Property codes from Properties.txt.
// These determine the actual properties which make up this autoprefix.
// Each autoprefix can include up to three modifiers.
ModCode [3]string
// ModParam, min, max
// Parameter, min, and max values for the property
ModParam [3]int
ModMin [3]int
ModMax [3]int
// transform
// It is a boolean value whichallows the colorization of the items.
Transform bool
// PaletteTransform
// If transform is set to 1 then the item will be colored with the chosen color code,
// taken from Colors.txt
PaletteTransform int // transformcolor
// IncludeItemCodes
// itype 1 to itype7
// "Include Type" fields. You need to place item codes in any of these columns to allow that item
// to receive mods from this row. See the note below.
IncludeItemCodes [7]string
// ExcludeItemCodes
// etype 1 to etype3
// 'Exclude type' . This field prevents certain mods from spawning on specific item codes.
ExcludeItemCodes [3]string
// CostDivide
// Numeric value that acts as divisor for the item price.
CostDivide int // divide
// CostMultiply
// Numeric value that acts as multiplier for the item price.
CostMultiply int // multiply
// CostAdd
// Numeric value that acts as a flat sum added to the item price.
CostAdd int // add
}
// AutoMagic has all of the AutoMagicRecords, used for generating magic properties for spawned items
var AutoMagic []*AutoMagicRecord //nolint:gochecknoglobals // Currently global by design, only written once
// LoadAutoMagicRecords loads AutoMagic records from automagic.txt
func LoadAutoMagicRecords(file []byte) {
AutoMagic = make([]*AutoMagicRecord, 0)
charCodeMap := map[string]d2enum.Hero{
"ama": d2enum.HeroAmazon,
"ass": d2enum.HeroAssassin,
"bar": d2enum.HeroBarbarian,
"dru": d2enum.HeroDruid,
"nec": d2enum.HeroNecromancer,
"pal": d2enum.HeroPaladin,
"sor": d2enum.HeroSorceress,
}
d := d2common.LoadDataDictionary(file)
for d.Next() {
record := &AutoMagicRecord{
Name: d.String("Name"),
Version: d.Number("version"),
Spawnable: d.Number("spawnable") > 0,
SpawnOnRare: d.Number("rare") > 0,
MinSpawnLevel: d.Number("level"),
MaxSpawnLevel: d.Number("maxlevel"),
LevelRequirement: d.Number("levelreq"),
Class: charCodeMap[d.String("class")],
ClassLevelRequirement: d.Number("classlevelreq"),
Frequency: d.Number("frequency"),
Group: d.Number("group"),
ModCode: [3]string{
d.String("mod1code"),
d.String("mod2code"),
d.String("mod3code"),
},
ModParam: [3]int{
d.Number("mod1param"),
d.Number("mod2param"),
d.Number("mod3param"),
},
ModMin: [3]int{
d.Number("mod1min"),
d.Number("mod2min"),
d.Number("mod3min"),
},
ModMax: [3]int{
d.Number("mod1max"),
d.Number("mod2max"),
d.Number("mod3max"),
},
Transform: d.Number("transform") > 0,
PaletteTransform: d.Number("transformcolor"),
IncludeItemCodes: [7]string{
d.String("itype1"),
d.String("itype2"),
d.String("itype3"),
d.String("itype4"),
d.String("itype5"),
d.String("itype6"),
d.String("itype7"),
},
ExcludeItemCodes: [3]string{
d.String("etype1"),
d.String("etype2"),
d.String("etype3"),
},
CostDivide: d.Number("divide"),
CostMultiply: d.Number("multiply"),
CostAdd: d.Number("add"),
}
AutoMagic = append(AutoMagic, record)
}
if d.Err != nil {
panic(d.Err)
}
log.Printf("Loaded %d AutoMagic records", len(AutoMagic))
}

View File

@ -0,0 +1,37 @@
package d2datadict
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
)
// BodyLocationRecord describes a body location that items can be equipped to
type BodyLocationRecord struct {
Name string
Code string
}
// BodyLocations contains the body location records
//nolint:gochecknoglobals // Currently global by design, only written once
var BodyLocations map[string]*BodyLocationRecord
// LoadBodyLocations loads body locations from
func LoadBodyLocations(file []byte) {
BodyLocations = make(map[string]*BodyLocationRecord)
d := d2common.LoadDataDictionary(file)
for d.Next() {
location := &BodyLocationRecord{
Name: d.String("Name"),
Code: d.String("Code"),
}
BodyLocations[location.Code] = location
}
if d.Err != nil {
panic(d.Err)
}
log.Printf("Loaded %d Body Location records", len(BodyLocations))
}

View File

@ -0,0 +1,257 @@
package d2datadict
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
)
// ItemTypeRecord describes the types for items
type ItemTypeRecord struct {
// Name (ItemType)
// A comment field that contains the “internal name” of this iType,
// you can basically enter anything you wish here,
// but since you can add as many comment columns as you wish,
// there is no reason to use it for another purpose .
Name string
// Code
// The ID pointer of this ItemType, this pointer is used in many txt files (armor.txt,
// cubemain.txt, misc.txt, skills.txt, treasureclassex.txt, weapons.txt),
// never use the same ID pointer twice,
// the game will only use the first instance and ignore all other occurrences.
// ID pointers are case sensitive, 3-4 chars long and can contain numbers, letters and symbols.
Code string
// Equiv1-2
// This is used to define the parent iType, note that an iType can have multiple parents (
// as will be shown in the cladogram link below),
// the only thing you must avoid at all cost is creating infinite loops.
// I haven't ever tested what happens when you create an iType loop,
// but infinite loops are something you should always avoid.
Equiv1 string
Equiv2 string
// Repair
// Boolean, 1=Merchants can repair this item type, 0=Merchants cannot repair this iType (note,
// this also refers to charges being rechargeable).
Repair bool
// Body
// Boolean, 1=The character can wear this iType,
// 0=This iType can only be carried in the inventory,
// cube or stash (and belt if it is set as “beltable” in the other item related txt files)
Body bool
// BodyLoc1-2
// If you have set the previous column to 1,
// you need to specify the inventory slots in which the item has to be equipped. (
// the codes used by this field are read from BodyLocs.txt)
BodyLoc1 int
BodyLoc2 int
// Shoots
// This column specifies which type of quiver (“ammo”) this iType (
// in case it is a weapon) requires in order to shoot (
// you use the ID pointer of the quiver iType here).
// Caution: The place it checks which missile to pick (either arrow, bolt,
// explosive arrow or magic arrow) is buried deep within D2Common.dll,
// the section can be modified, there is an extensive post discussing this in Code Editing.
// - Thanks go to Kingpin for spotting a silly little mistake in here.
Shoots string
// Quiver
// The equivalent to the previous column,
// in here you specify which weapon this quiver is linked to. Make sure the two columns match. (
// this also uses the ID pointer of course).
Quiver string
// Throwable
// Can this iType be thrown (determines whenever it uses the quantity and throwing damage columns
// in Weapons.txt for example).
Throwable bool
// Reload
// Can the this item be re-stacked via drag and drop. 1=Yes, 0=No.
Reload bool
// ReEquip
// If the ammo runs out the game will automatically pick the next item of the same iType to
// be equipped in it's place.
// 1=Yes, 0=No. (more clearly, when you use up all the arrows in a quiver, the next quiver,
// if available, will be equipped in its place).
ReEquip bool
// AutoStack
// Are identical stacks automatically combined when you pick the up? 1=Yes, 0=No. (for example,
// which you pick up throwing potions or normal javelins,
// they are automatically combined with those you already have)
AutoStack bool
// Magic
// Is this iType always Magic? 1=Yes, 0=No.
Magic bool
// Rare
// Can this iType spawn as a rare item?
// 1=Yes, 0=No.
// Note: If you want an item that spawns only as magic or rare,
// you need to set the previous column to 1 as well.
Rare bool
// Normal
// Is this iType always Normal? 1=Yes, 0=No.
Normal bool
// Charm
// Does this iType function as a charm? 1=Yes, 0=No. Note: This effect is hardcoded,
// if you need a new charm type, you must use the char iType in one of the equivs.
Charm bool
// Gem
// Can this iType be inserted into sockets? 1=Yes,
// 0=No (Link your item to the sock iType instead to achieve this).
Gem bool
// Beltable
// Can this iType be placed in your characters belt slots? 1=Yes,
// 0=No. (This requires further tweaking in other txt files).
Beltable bool
// MaxSock1, MaxSock25, MaxSock40
// Maximum sockets for iLvl 1-25,
// 26-40 and 40+. The range is hardcoded but the location is known,
// so you can alter around the range to your liking. On normal,
// items dropped from monsters are limited to 3, on nightmare to 4 and on hell to 6 sockets,
// irregardless of this columns content.
MaxSock1 int
MaxSock25 int
MaxSock40 int
// TreasureClass
// Can this iType ID Pointer be used as an auto TC in TreasureClassEx.txt. 1=Yes,
// 0=No. *Such as armo3-99 and weap3-99 etc.
TreasureClass int
// Rarity
// Dunno what it does, may have to do with the chance that an armor or weapon rack will pick
// items of this iType. If it works like other rarity fields,
// the chance is rarity / total_rarity * 100.
Rarity int
// StaffMods
// Contains the class code for the character class that should get +skills from this iType (
// such as wands that can spawn with +Necromancer skills). Note,
// this only works if the item is not low quality, set or unique. Note,
// that this uses the vanilla min/max skill IDs for each class as the range for the skill pool,
// so if you add new class skills to the end of the file, you should use automagic.txt instead
StaffMods d2enum.Hero
// CostFormula
// Does the game generate the sell/repair/buy prices of this iType based on its modifiers or does
// it use only the cost specific in the respective item txt files. 2=Organ (
// probably higher price based on unit that dropped the organ), 1=Yes, 0=No.
// Note: Only applies to items that are not unique or set, for those the price is solely controlled
// by the base item file and by the bonus to price given in SetItems and UniqueItems txt files.
// The exact functionality remains unknown, as for example charms, have this disabled.
CostFormula int
// Class
// Contains the class code for the class that should be able to use this iType (
// for class specific items).
Class d2enum.Hero
// VarInvGfx
// This column contains the sum of randomly picked inventory graphics this iType can have.
VarInvGfx int
// InvGfx1-6
// This column contains the file names of the inventory graphics that are randomly picked for
// this iType, so if you use columns 1-3, you will set VarInvGfx to 3 (duh).
InvGfx1 string
InvGfx2 string
InvGfx3 string
InvGfx4 string
InvGfx5 string
InvGfx6 string
// StorePage
// The page code for the page a vendor should place this iType in when sold,
// if you enable the magic tab in D2Client.dll,
// you need to use the proper code here to put items in that tab.
// Right now the ones used are weap = weapons1 and 2, armo = armor and misc = miscellaneous.
StorePage string
}
// ItemTypes stores all of the ItemTypeRecords
var ItemTypes map[string]*ItemTypeRecord //nolint:gochecknoglobals // Currently global by design, only written once
// LoadItemTypes loads ItemType records
func LoadItemTypes(file []byte) {
ItemTypes = make(map[string]*ItemTypeRecord)
charCodeMap := map[string]d2enum.Hero{
"ama": d2enum.HeroAmazon,
"ass": d2enum.HeroAssassin,
"bar": d2enum.HeroBarbarian,
"dru": d2enum.HeroDruid,
"nec": d2enum.HeroNecromancer,
"pal": d2enum.HeroPaladin,
"sor": d2enum.HeroSorceress,
}
d := d2common.LoadDataDictionary(file)
for d.Next() {
if d.String("*eol") == "" {
continue
}
itemType := &ItemTypeRecord{
Name: d.String("ItemType"),
Code: d.String("Code"),
Equiv1: d.String("Equiv1"),
Equiv2: d.String("Equiv2"),
Repair: d.Number("Repair") > 0,
Body: d.Number("Body") > 0,
BodyLoc1: d.Number("BodyLoc1"),
BodyLoc2: d.Number("BodyLoc2"),
Shoots: d.String("Shoots"),
Quiver: d.String("Quiver"),
Throwable: d.Number("Throwable") > 0,
Reload: d.Number("Reload") > 0,
ReEquip: d.Number("ReEquip") > 0,
AutoStack: d.Number("AutoStack") > 0,
Magic: d.Number("Magic") > 0,
Rare: d.Number("Rare") > 0,
Normal: d.Number("Normal") > 0,
Charm: d.Number("Charm") > 0,
Gem: d.Number("Gem") > 0,
Beltable: d.Number("Beltable") > 0,
MaxSock1: d.Number("MaxSock1"),
MaxSock25: d.Number("MaxSock25"),
MaxSock40: d.Number("MaxSock40"),
TreasureClass: d.Number("TreasureClass"),
Rarity: d.Number("Rarity"),
StaffMods: charCodeMap[d.String("StaffMods")],
CostFormula: d.Number("CostFormula"),
Class: charCodeMap[d.String("Class")],
VarInvGfx: d.Number("VarInvGfx"),
InvGfx1: d.String("InvGfx1"),
InvGfx2: d.String("InvGfx2"),
InvGfx3: d.String("InvGfx3"),
InvGfx4: d.String("InvGfx4"),
InvGfx5: d.String("InvGfx5"),
InvGfx6: d.String("InvGfx6"),
StorePage: d.String("StorePage"),
}
ItemTypes[itemType.Name] = itemType
}
if d.Err != nil {
panic(d.Err)
}
log.Printf("Loaded %d ItemType records", len(ItemTypes))
}

View File

@ -0,0 +1,275 @@
package d2datadict
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"log"
)
// SetItemRecord represents a set item
type SetItemRecord struct {
// StringTableKey (index)
// string key to item's name in a .tbl file
StringTableKey string
// SetKey (set)
// string key to the index field in Sets.txt - the set the item is a part of.
SetKey string
// ItemCode (item)
// base item code of this set item (matches code field in Weapons.txt, Armor.txt or Misc.txt files).
ItemCode string
// Rarity
// Chance to pick this set item if more then one set item of the same base item exist,
// this uses the common rarity/total_rarity formula, so if you have two set rings,
// one with a rarity of 100 the other with a rarity of 1,
// then the first will drop 100/101 percent of the time (
// 99%) and the other will drop 1/101 percent of the time (1%),
// rarity can be anything between 0 and 255.
Rarity int
// QualityLevel (lvl)
// The quality level of this set item, monsters, cube recipes, vendors,
// objects and the like most be at least this level or higher to be able to drop this item,
// otherwise they would drop a magical item with twice normal durability.
QualityLevel int
// RequiredLevel ("lvl req")
// The character level required to use this set item.
RequiredLevel int
// CharacterPaletteTransform (chrtransform)
// Palette shift to apply to the the DCC component-file and the DC6 flippy-file (
// whenever or not the color shift will apply is determined by Weapons.txt,
// Armor.txt or Misc.txt). This is an ID pointer from Colors.txt.
CharacterPaletteTransform int
// InventoryPaletteTransform (invtransform)
// Palette shift to apply to the the DC6 inventory-file (
// whenever or not the color shift will apply is determined by Weapons.txt,
// Armor.txt or Misc.txt). This is an ID pointer from Colors.txt.
InventoryPaletteTransform int
// InvFile
// Overrides the invfile and setinvfile specified in Weapons.txt,
// Armor.txt or Misc.txt for the base item.
// This field contains the file name of the DC6 inventory graphic (without the .dc6 extension).
InvFile string
// FlippyFile
// Overrides the flippyfile specified in Weapons.txt, Armor.txt or Misc.txt for the base item.
// This field contains the file name of the DC6 flippy animation (without the .dc6 extension).
FlippyFile string
// DropSound
// Overrides the dropsound (the sound played when the item hits the ground) specified in Weapons.
// txt, Armor.txt or Misc.txt for the base item. This field contains an ID pointer from Sounds.txt.
DropSound string
// DropSfxFrame
// How many frames after the flippy animation starts playing will the associated drop sound start
// to play. This overrides the values in Weapons.txt, Armor.txt or Misc.txt.
DropSfxFrame int
// UseSound
// Overrides the usesound (the sound played when the item is consumed by the player) specified in
// Weapons.txt, Armor.txt or Misc.txt for the base item.
// This field contains an ID pointer from Sounds.txt.
UseSound string
// CostMult ("cost mult")
// The base item's price is multiplied by this value when sold, repaired or bought from a vendor.
CostMult int
// CostAdd ("cost add")
// After the price has been multiplied, this amount of gold is added to the price on top.
CostAdd int
// AddFn ("add func")
// a property mode field that controls how the variable attributes will appear and be functional
// on a set item. See the appendix for further details about this field's effects.
AddFn int
// Prop (prop1 to prop9)
// An ID pointer of a property from Properties.txt,
// these columns control each of the nine different fixed (
// blue) modifiers a set item can grant you at most.
Prop [9]string
// Par (par1 to par9)
// The parameter passed on to the associated property, this is used to pass skill IDs, state IDs,
// monster IDs, montype IDs and the like on to the properties that require them,
// these fields support calculations.
Par [9]int
// Min, Max (min1 to min9, max1 to max9)
// Minimum value to assign to the associated (blue) property.
// Certain properties have special interpretations based on stat encoding (e.g.
// chance-to-cast and charged skills). See the File Guide for Properties.txt and ItemStatCost.
// txt for further details.
Min [9]int
Max [9]int
// APropA, APropB (aprop1a,aprop1b to aprop5a,aprop5b)
// An ID pointer of a property from Properties.txt,
// these columns control each of the five pairs of different variable (
// green) modifiers a set item can grant you at most.
APropA [5]string
APropB [5]string
// AParA, AParB (apar1a,apar1b to apar5a,apar5b)
// The parameter passed on to the associated property, this is used to pass skill IDs, state IDs,
// monster IDs, montype IDs and the like on to the properties that require them,
// these fields support calculations.
AParA [5]int
AParB [5]int
// AMinA, AMinB, AMaxA, AMaxB (amin1a,amin1b to amin5a,amin5b)
// Minimum value to assign to the associated property.
// Certain properties have special interpretations based on stat encoding (e.g.
// chance-to-cast and charged skills). See the File Guide for Properties.txt and ItemStatCost.
// txt for further details.
AMinA [5]int
AMinB [5]int
AMaxA [5]int
AMaxB [5]int
}
// SetItems holds all of the SetItemRecords
var SetItems []*SetItemRecord //nolint:gochecknoglobals // Currently global by design, only written once
// LoadSetItems loads all of the SetItemRecords from SetItems.txt
func LoadSetItems(file []byte) {
SetItems = make([]*SetItemRecord, 0)
d := d2common.LoadDataDictionary(file)
for d.Next() {
record := &SetItemRecord{
StringTableKey: d.String("index"),
SetKey: d.String("set"),
ItemCode: d.String("item"),
Rarity: d.Number("rarity"),
QualityLevel: d.Number("lvl"),
RequiredLevel: d.Number("lvl req"),
CharacterPaletteTransform: d.Number("chrtransform"),
InventoryPaletteTransform: d.Number("invtransform"),
InvFile: d.String("invfile"),
FlippyFile: d.String("flippyfile"),
DropSound: d.String("dropsound"),
DropSfxFrame: d.Number("dropsfxframe"),
UseSound: d.String("usesound"),
CostMult: d.Number("cost mult"),
CostAdd: d.Number("cost add"),
AddFn: d.Number("add func"),
Prop: [9]string{
d.String("prop1"),
d.String("prop2"),
d.String("prop3"),
d.String("prop4"),
d.String("prop5"),
d.String("prop6"),
d.String("prop7"),
d.String("prop8"),
d.String("prop9"),
},
Par: [9]int{
d.Number("par1"),
d.Number("par2"),
d.Number("par3"),
d.Number("par4"),
d.Number("par5"),
d.Number("par6"),
d.Number("par7"),
d.Number("par8"),
d.Number("par9"),
},
Min: [9]int{
d.Number("min1"),
d.Number("min2"),
d.Number("min3"),
d.Number("min4"),
d.Number("min5"),
d.Number("min6"),
d.Number("min7"),
d.Number("min8"),
d.Number("min9"),
},
Max: [9]int{
d.Number("max1"),
d.Number("max2"),
d.Number("max3"),
d.Number("max4"),
d.Number("max5"),
d.Number("max6"),
d.Number("max7"),
d.Number("max8"),
d.Number("max9"),
},
APropA: [5]string{
d.String("aprop1a"),
d.String("aprop2a"),
d.String("aprop3a"),
d.String("aprop4a"),
d.String("aprop5a"),
},
APropB: [5]string{
d.String("aprop1b"),
d.String("aprop2b"),
d.String("aprop3b"),
d.String("aprop4b"),
d.String("aprop5b"),
},
AParA: [5]int{
d.Number("apar1a"),
d.Number("apar2a"),
d.Number("apar3a"),
d.Number("apar4a"),
d.Number("apar5a"),
},
AParB: [5]int{
d.Number("apar1b"),
d.Number("apar2b"),
d.Number("apar3b"),
d.Number("apar4b"),
d.Number("apar5b"),
},
AMinA: [5]int{
d.Number("amin1a"),
d.Number("amin2a"),
d.Number("amin3a"),
d.Number("amin4a"),
d.Number("amin5a"),
},
AMinB: [5]int{
d.Number("amin1b"),
d.Number("amin2b"),
d.Number("amin3b"),
d.Number("amin4b"),
d.Number("amin5b"),
},
AMaxA: [5]int{
d.Number("amax1a"),
d.Number("amax2a"),
d.Number("amax3a"),
d.Number("amax4a"),
d.Number("amax5a"),
},
AMaxB: [5]int{
d.Number("amax1b"),
d.Number("amax2b"),
d.Number("amax3b"),
d.Number("amax4b"),
d.Number("amax5b"),
},
}
SetItems = append(SetItems, record)
}
if d.Err != nil {
panic(d.Err)
}
log.Printf("Loaded %d SetItem records", len(SetItems))
}

View File

@ -0,0 +1,190 @@
package d2datadict
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
)
type SetRecord struct {
// index
// String key linked to by the set field in SetItems.
// txt - used to tie all of the set's items to the same set.
Key string
// name
// String key to item's name in a .tbl file.
StringTableKey string
// Version 0 for vanilla, 100 for LoD expansion
Version int
// Level
// set level, perhaps intended as a minimum level for partial or full attributes to appear
// (reference only, not loaded into game).
Level int
// PCodeA, PCodeB -- PCode2a,PCode2b to PCode5a,PCode5b
// An ID pointer of a property from Properties.txt,
// these columns control each of the five pairs of different partial set modifiers a set item can
// grant you at most.
PCodeA [4]string
PCodeB [4]string
// PParamA, PParamB -- PParam2[a|b] to PParam5[a|b]
// The parameter passed on to the associated property, this is used to pass skill IDs, state IDs,
// monster IDs, montype IDs and the like on to the properties that require them,
// these fields support calculations.
PParamA [4]int
PParamB [4]int
// PMinA, PMaxA, PMinB, PMaxB -- P[Min|Max]2[a|b] to P[Min|Max]5[a|b]
// Minimum value to assign to the associated property.
// Certain properties have special interpretations based on stat encoding (e.g.
// chance-to-cast and charged skills). See the File Guides for Properties.txt and ItemStatCost.
// txt for further details.
PMinA [4]int
PMaxA [4]int
PMinB [4]int
PMaxB [4]int
// FCode -- FCode1 to FCode8
// An ID pointer of a property from Properties.txt,
// these columns control each of the eight different full set modifiers a set item can grant you
// at most.
FCode [8]string
// FParam -- FParam1 to FParam8
// The parameter passed on to the associated property, this is used to pass skill IDs, state IDs,
// monster IDs, montype IDs and the like on to the properties that require them,
// these fields support calculations.
FParam [8]int
// FMin -- FMin1 to FMin8
// Minimum value to assign to the associated property.
// Certain properties have special interpretations based on stat encoding (e.g.
// chance-to-cast and charged skills). See the File Guides for Properties.txt and ItemStatCost.
// txt for further details.
FMin [8]int
// FMax -- FMax1 to FMax8
// Maximum value to assign to the associated property.
// Certain properties have special interpretations based on stat encoding (e.g.
// chance-to-cast and charged skills). See the File Guides for Properties.txt and ItemStatCost.
// txt for further details.
FMax [8]int
}
// SetRecords contain the set records from sets.txt
var SetRecords map[string]*SetRecord
// LoadSetRecords loads set records from sets.txt
func LoadSets(file []byte) {
SetRecords = make(map[string]*SetRecord)
d := d2common.LoadDataDictionary(file)
for d.Next() {
record := &SetRecord{
Key: d.String("index"),
StringTableKey: d.String("name"),
Version: d.Number("version"),
Level: d.Number("level"),
PCodeA: [4]string{
d.String("PCode2a"),
d.String("PCode3a"),
d.String("PCode4a"),
d.String("PCode5a"),
},
PCodeB: [4]string{
d.String("PCode2b"),
d.String("PCode3b"),
d.String("PCode4b"),
d.String("PCode5b"),
},
PParamA: [4]int{
d.Number("PParam2a"),
d.Number("PParam3a"),
d.Number("PParam4a"),
d.Number("PParam5a"),
},
PParamB: [4]int{
d.Number("PParam2b"),
d.Number("PParam3b"),
d.Number("PParam4b"),
d.Number("PParam5b"),
},
PMinA: [4]int{
d.Number("PMin2a"),
d.Number("PMin3a"),
d.Number("PMin4a"),
d.Number("PMin5a"),
},
PMinB: [4]int{
d.Number("PMin2b"),
d.Number("PMin3b"),
d.Number("PMin4b"),
d.Number("PMin5b"),
},
PMaxA: [4]int{
d.Number("PMax2a"),
d.Number("PMax3a"),
d.Number("PMax4a"),
d.Number("PMax5a"),
},
PMaxB: [4]int{
d.Number("PMax2b"),
d.Number("PMax3b"),
d.Number("PMax4b"),
d.Number("PMax5b"),
},
FCode: [8]string{
d.String("FCode1"),
d.String("FCode2"),
d.String("FCode3"),
d.String("FCode4"),
d.String("FCode5"),
d.String("FCode6"),
d.String("FCode7"),
d.String("FCode9"),
},
FParam: [8]int{
d.Number("FParam1"),
d.Number("FParam2"),
d.Number("FParam3"),
d.Number("FParam4"),
d.Number("FParam5"),
d.Number("FParam6"),
d.Number("FParam7"),
d.Number("FParam9"),
},
FMin: [8]int{
d.Number("FMin1"),
d.Number("FMin2"),
d.Number("FMin3"),
d.Number("FMin4"),
d.Number("FMin5"),
d.Number("FMin6"),
d.Number("FMin7"),
d.Number("FMin9"),
},
FMax: [8]int{
d.Number("FMax1"),
d.Number("FMax2"),
d.Number("FMax3"),
d.Number("FMax4"),
d.Number("FMax5"),
d.Number("FMax6"),
d.Number("FMax7"),
d.Number("FMax9"),
},
}
SetRecords[record.Key] = record
}
if d.Err != nil {
panic(d.Err)
}
log.Printf("Loaded %d Sets records", len(SetRecords))
}

View File

@ -180,6 +180,11 @@ const (
ObjectDetails = "/data/global/excel/Objects.txt"
SoundSettings = "/data/global/excel/Sounds.txt"
ItemStatCost = "/data/global/excel/ItemStatCost.txt"
ItemTypes = "/data/global/excel/ItemTypes.txt"
Sets = "/data/global/excel/Sets.txt"
SetItems = "/data/global/excel/SetItems.txt"
AutoMagic = "/data/global/excel/automagic.txt"
BodyLocations = "/data/global/excel/bodylocs.txt"
Properties = "/data/global/excel/Properties.txt"
Hireling = "/data/global/excel/hireling.txt"
DifficultyLevels = "/data/global/excel/difficultylevels.txt"