adding the rest of the data dictionary loaders (#869)

This commit is contained in:
gravestench 2020-10-28 17:52:15 +00:00 committed by GitHub
parent f0890d83fa
commit 4a62101b96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 596 additions and 31 deletions

View File

@ -194,6 +194,7 @@ const (
ItemRatio = "/data/global/excel/itemratio.txt"
ItemTypes = "/data/global/excel/ItemTypes.txt"
QualityItems = "/data/global/excel/qualityitems.txt"
LowQualityItems = "/data/global/excel/lowqualityitems.txt"
Overlays = "/data/global/excel/Overlay.txt"
Runes = "/data/global/excel/runes.txt"
Sets = "/data/global/excel/Sets.txt"
@ -203,14 +204,18 @@ const (
Events = "/data/global/excel/events.txt"
Properties = "/data/global/excel/Properties.txt"
Hireling = "/data/global/excel/hireling.txt"
HirelingDescription = "/data/global/excel/HireDesc.txt"
DifficultyLevels = "/data/global/excel/difficultylevels.txt"
AutoMap = "/data/global/excel/AutoMap.txt"
CubeRecipes = "/data/global/excel/cubemain.txt"
CubeModifier = "/data/global/excel/CubeMod.txt"
CubeType = "/data/global/excel/CubeType.txt"
Skills = "/data/global/excel/skills.txt"
SkillDesc = "/data/global/excel/skilldesc.txt"
SkillCalc = "/data/global/excel/skillcalc.txt"
MissileCalc = "/data/global/excel/misscalc.txt"
TreasureClass = "/data/global/excel/TreasureClassEx.txt"
TreasureClass = "/data/global/excel/TreasureClass.txt"
TreasureClassEx = "/data/global/excel/TreasureClassEx.txt"
States = "/data/global/excel/states.txt"
SoundEnvirons = "/data/global/excel/soundenviron.txt"
Shrines = "/data/global/excel/shrines.txt"
@ -226,6 +231,9 @@ const (
MonsterSound = "/data/global/excel/monsounds.txt"
MonsterSequence = "/data/global/excel/monseq.txt"
PlayerClass = "/data/global/excel/PlayerClass.txt"
PlayerType = "/data/global/excel/PlrType.txt"
Composite = "/data/global/excel/Composit.txt"
HitClass = "/data/global/excel/HitClass.txt"
ObjectGroup = "/data/global/excel/objgroup.txt"
CompCode = "/data/global/excel/compcode.txt"
Belts = "/data/global/excel/belts.txt"
@ -246,6 +254,8 @@ const (
Inventory = "/data/global/excel/inventory.txt"
Weapons = "/data/global/excel/weapons.txt"
Armor = "/data/global/excel/armor.txt"
ArmorType = "/data/global/excel/ArmType.txt"
WeaponClass = "/data/global/excel/WeaponClass.txt"
Books = "/data/global/excel/books.txt"
Misc = "/data/global/excel/misc.txt"
UniqueItems = "/data/global/excel/UniqueItems.txt"

View File

@ -115,6 +115,7 @@ func (am *AssetManager) initDataDictionaries() error {
d2resource.SetItems,
d2resource.AutoMagic,
d2resource.TreasureClass,
d2resource.TreasureClassEx,
d2resource.States,
d2resource.SoundEnvirons,
d2resource.Shrines,
@ -137,6 +138,17 @@ func (am *AssetManager) initDataDictionaries() error {
d2resource.RareSuffix,
d2resource.Events,
d2resource.Colors,
d2resource.ArmorType,
d2resource.WeaponClass,
d2resource.PlayerType,
d2resource.Composite,
d2resource.HitClass,
d2resource.UniquePrefix,
d2resource.UniqueSuffix,
d2resource.CubeModifier,
d2resource.CubeType,
d2resource.HirelingDescription,
d2resource.LowQualityItems,
}
for _, path := range dictPaths {
@ -440,7 +452,7 @@ func (am *AssetManager) initAnimationData(path string) error {
animData := d2data.LoadAnimationData(animDataBytes)
am.Records.Animations = animData
am.Records.Animation.Data = animData
return nil
}

View File

@ -259,7 +259,7 @@ func (c *Composite) createMode(animationMode animationMode, weaponClass string)
animationKey := strings.ToLower(c.token + animationMode.String() + weaponClass)
animationData := c.Records.Animations[animationKey]
animationData := c.Records.Animation.Data[animationKey]
if len(animationData) == 0 {
return nil, errors.New("could not find Animation data")
}

View File

@ -260,7 +260,7 @@ func (f *ItemFactory) ItemsFromTreasureClass(tcr *d2records.TreasureClassRecord)
// case we will roll that treasure class, eventually getting a slice of items
for idx := range treasurePicks {
picked := treasurePicks[idx]
if record, found := f.asset.Records.Item.TreasureClass[picked.Code]; found {
if record, found := f.asset.Records.Item.Treasure.Normal[picked.Code]; found {
// the code is for a treasure class, we roll again using that TC
itemSlice := f.ItemsFromTreasureClass(record)
for itemIdx := range itemSlice {

View File

@ -0,0 +1,30 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func armorTypesLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(ArmorTypes)
for d.Next() {
record := &ArmorTypeRecord{
Name: d.String("Name"),
Token: d.String("Token"),
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
r.Animation.Token.Armor = records
log.Printf("Loaded %d ArmorType records", len(records))
return nil
}

View File

@ -0,0 +1,11 @@
package d2records
// ArmorTypes is a map of ArmorTypeRecords
type ArmorTypes map[string]*ArmorTypeRecord
// ArmorTypeRecord describes an armor type. It has a name and 3-character token.
// The token is used to change the character animation mode.
type ArmorTypeRecord struct {
Name string
Token string
}

View File

@ -0,0 +1,30 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func compositeTypeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(CompositeTypes)
for d.Next() {
record := &CompositeTypeRecord{
Name: d.String("Name"),
Token: d.String("Token"),
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
r.Animation.Token.Composite = records
log.Printf("Loaded %d Composite Type records", len(records))
return nil
}

View File

@ -0,0 +1,11 @@
package d2records
// CompositeTypes is a map of CompositeTypeRecords
type CompositeTypes map[string]*CompositeTypeRecord
// CompositeTypeRecord describes a layer for an animated composite (multi-sprite entities).
// The token is used for changing character animation modes.
type CompositeTypeRecord struct {
Name string
Token string
}

View File

@ -0,0 +1,30 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func cubeModifierLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(CubeModifiers)
for d.Next() {
record := &CubeModifierRecord{
Name: d.String("cube modifier type"),
Token: d.String("Code"),
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
r.Item.Cube.Modifiers = records
log.Printf("Loaded %d Cube Modifier records", len(records))
return nil
}

View File

@ -0,0 +1,10 @@
package d2records
// CubeModifiers is a map of CubeModifierRecords
type CubeModifiers map[string]*CubeModifierRecord
// CubeModifierRecord is a name and 3-character token for cube modifier codes and gem types
type CubeModifierRecord struct {
Name string
Token string
}

View File

@ -0,0 +1,30 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func cubeTypeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(CubeTypes)
for d.Next() {
record := &CubeTypeRecord{
Name: d.String("cube item class"),
Token: d.String("Code"),
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
r.Item.Cube.Types = records
log.Printf("Loaded %d Cube Type records", len(records))
return nil
}

View File

@ -0,0 +1,10 @@
package d2records
// CubeTypes is a map of CubeTypeRecords
type CubeTypes map[string]*CubeTypeRecord
// CubeTypeRecord is a name and 3-character token for cube item types
type CubeTypeRecord struct {
Name string
Token string
}

View File

@ -85,7 +85,7 @@ func cubeRecipeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
log.Printf("Loaded %d CubeMainRecord records", len(records))
r.Item.Recipes = records
r.Item.Cube.Recipes = records
return nil
}

View File

@ -0,0 +1,30 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func hirelingDescriptionLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(HirelingDescriptions)
for d.Next() {
record := &HirelingDescriptionRecord{
Name: d.String("Hireling Description"),
Token: d.String("Code"),
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
r.Hireling.Descriptions = records
log.Printf("Loaded %d Hireling Descriptions records", len(records))
return nil
}

View File

@ -0,0 +1,10 @@
package d2records
// HirelingDescriptions is a lookup table for hireling subtype codes
type HirelingDescriptions map[string]*HirelingDescriptionRecord
// HirelingDescriptionRecord represents is a hireling subtype
type HirelingDescriptionRecord struct {
Name string
Token string
}

View File

@ -94,7 +94,7 @@ func hirelingLoader(r *RecordManager, d *d2txt.DataDictionary) error {
log.Printf("Loaded %d Hireling records", len(records))
r.Hirelings = records
r.Hireling.Details = records
return nil
}

View File

@ -0,0 +1,30 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func hitClassLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(HitClasses)
for d.Next() {
record := &HitClassRecord{
Name: d.String("Hit Class"),
Token: d.String("Code"),
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
r.Animation.Token.HitClass = records
log.Printf("Loaded %d HitClass records", len(records))
return nil
}

View File

@ -0,0 +1,10 @@
package d2records
// HitClasses is a map of HitClassRecords
type HitClasses map[string]*HitClassRecord
// HitClassRecord is used for changing character animation modes.
type HitClassRecord struct {
Name string
Token string
}

View File

@ -0,0 +1,29 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func lowQualityLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(LowQualities, 0)
for d.Next() {
record := &LowQualityRecord{
Name: d.String("Hireling Description"),
}
records = append(records, record)
}
if d.Err != nil {
panic(d.Err)
}
r.Item.LowQualityPrefixes = records
log.Printf("Loaded %d Low Item Quality records", len(records))
return nil
}

View File

@ -0,0 +1,9 @@
package d2records
// LowQualities is a slice of LowQualityRecords
type LowQualities []*LowQualityRecord
// LowQualityRecord is a name prefix that can be used for low quality item names
type LowQualityRecord struct {
Name string
}

View File

@ -0,0 +1,99 @@
package d2records
import (
"fmt"
"log"
"github.com/gravestench/akara"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
// Name
// MonType1
// MonType2
// MonType3
// MonType4
// MonType5
// MonType6
// MonType7
// MonType8
// MonType9
// MonType10
// MonType11
// MonType12
// MonType13
// MonType14
// MonType15
// MonType16
// MonType17
// MonType18
// MonType19
// MonType20
// MonType21
// MonType22
// MonType23
// MonType24
// MonType25
// MonType26
// MonType27
// MonType28
// MonType29
// MonType30
// MonType31
// MonType32
// MonType33
// MonType34
// MonType35
// MonType36
const (
numMonsterTypes = 36
fmtMonsterTypeColumn = "MonType%d"
)
func uniqueMonsterPrefixLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records, err := uniqueMonsterAffixCommonLoader(d)
if err != nil {
return err
}
r.Monster.Name.Prefix = records
log.Printf("Loaded %d unique monster prefix records", len(records))
return nil
}
func uniqueMonsterSuffixLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records, err := uniqueMonsterAffixCommonLoader(d)
if err != nil {
return err
}
r.Monster.Name.Suffix = records
log.Printf("Loaded %d unique monster suffix records", len(records))
return nil
}
func uniqueMonsterAffixCommonLoader(d *d2txt.DataDictionary) (UniqueMonsterAffixes, error) {
records := make(UniqueMonsterAffixes)
for d.Next() {
record := &UniqueMonsterAffixRecord{
StringTableKey: d.String("Name"),
MonsterTypeFlags: akara.NewBitSet(),
}
for idx := 0; idx < numMonsterTypes; idx++ {
bit := d.Number(fmt.Sprintf(fmtMonsterTypeColumn, idx)) > 0
record.MonsterTypeFlags.Set(idx, bit)
}
records[record.StringTableKey] = record
}
return records, d.Err
}

View File

@ -0,0 +1,23 @@
package d2records
import (
"github.com/gravestench/akara"
)
// UniqueMonsterPrefix is a representation of a possible name prefix for a unique monster instance
// eg _Blood_ Wing the Quick
type UniqueMonsterPrefix = UniqueMonsterAffixRecord
// UniqueMonsterSuffix is a representation of a possible name suffix for a unique monster instance.
// eg. Blood Wing _the Quick_
type UniqueMonsterSuffix = UniqueMonsterAffixRecord
// UniqueMonsterAffixes is a map of UniqueMonsterAffixRecords. The key is the string table lookup key.
type UniqueMonsterAffixes map[string]*UniqueMonsterAffixRecord
// UniqueMonsterAffixRecord is a string table key and a bit vector for the possible monster types
// that the suffix can be used with.
type UniqueMonsterAffixRecord struct {
StringTableKey string
MonsterTypeFlags *akara.BitSet
}

View File

@ -0,0 +1,34 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func playerTypeLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(PlayerTypes)
for d.Next() {
record := &PlayerTypeRecord{
Name: d.String("Player Class"),
Token: d.String("Token"),
}
if record.Name == expansionString {
continue
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
log.Printf("Loaded %d PlayerType records", len(records))
r.Animation.Token.Player = records
return nil
}

View File

@ -0,0 +1,10 @@
package d2records
// PlayerTypes is a map of PlayerTypeRecords
type PlayerTypes map[string]*PlayerTypeRecord
// PlayerTypeRecord is used for changing character animation modes.
type PlayerTypeRecord struct {
Name string
Token string
}

View File

@ -28,7 +28,16 @@ func NewRecordManager() (*RecordManager, error) {
// RecordManager stores all of the records loaded from txt files
type RecordManager struct {
boundLoaders map[string][]recordLoader // there can be more than one loader bound for a file
Animations d2data.AnimationData
Animation struct {
Data d2data.AnimationData
Token struct {
Player PlayerTypes
Composite CompositeTypes
Armor ArmorTypes
Weapon WeaponClasses
HitClass HitClasses
}
}
BodyLocations
Calculation struct {
Skills Calculations
@ -47,7 +56,10 @@ type RecordManager struct {
DifficultyLevels
ElemTypes
Gamble
Hirelings
Hireling struct {
Details Hirelings
Descriptions HirelingDescriptions
}
Item struct {
All CommonItems // NOTE: populated when armor, weapons, and misc items are ALL loaded
@ -66,20 +78,28 @@ type RecordManager struct {
Prefix MagicPrefix
Suffix MagicSuffix
}
MagicPrefixGroups ItemAffixGroups
MagicSuffixGroups ItemAffixGroups
Quality ItemQualities
Rare struct {
MagicPrefixGroups ItemAffixGroups
MagicSuffixGroups ItemAffixGroups
Quality ItemQualities
LowQualityPrefixes LowQualities
Rare struct {
Prefix RarePrefixes
Suffix RareSuffixes
}
Ratios ItemRatios
Recipes CubeRecipes
Ratios ItemRatios
Cube struct {
Recipes CubeRecipes
Modifiers CubeModifiers
Types CubeTypes
}
Runewords
Sets
SetItems
Stats ItemStatCosts
TreasureClass
Stats ItemStatCosts
Treasure struct {
Normal TreasureClass
Expansion TreasureClass
}
Types ItemTypes
Unique UniqueItems
StorePages
@ -100,10 +120,14 @@ type RecordManager struct {
Missiles
missilesByName
Monster struct {
AI MonsterAI
Equipment MonsterEquipment
Levels MonsterLevels
Modes MonModes
AI MonsterAI
Equipment MonsterEquipment
Levels MonsterLevels
Modes MonModes
Name struct {
Prefix UniqueMonsterAffixes
Suffix UniqueMonsterAffixes
}
Placements MonsterPlacements
Presets MonPresets
Props MonsterProperties
@ -140,7 +164,7 @@ type RecordManager struct {
States
}
func (r *RecordManager) init() error {
func (r *RecordManager) init() error { // nolint:funlen // can't reduce
loaders := []struct {
path string
loader recordLoader
@ -198,6 +222,7 @@ func (r *RecordManager) init() error {
{d2resource.SetItems, setItemLoader},
{d2resource.AutoMagic, autoMagicLoader},
{d2resource.TreasureClass, treasureClassLoader},
{d2resource.TreasureClassEx, treasureClassExLoader},
{d2resource.States, statesLoader},
{d2resource.SoundEnvirons, soundEnvironmentLoader},
{d2resource.Shrines, shrineLoader},
@ -219,6 +244,17 @@ func (r *RecordManager) init() error {
{d2resource.RarePrefix, rareItemPrefixLoader},
{d2resource.RareSuffix, rareItemSuffixLoader},
{d2resource.Events, eventsLoader},
{d2resource.ArmorType, armorTypesLoader}, // anim mode tokens
{d2resource.WeaponClass, weaponClassesLoader}, // anim mode tokens
{d2resource.PlayerType, playerTypeLoader}, // anim mode tokens
{d2resource.Composite, compositeTypeLoader}, // anim mode tokens
{d2resource.HitClass, hitClassLoader}, // anim mode tokens
{d2resource.UniquePrefix, uniqueMonsterPrefixLoader},
{d2resource.UniqueSuffix, uniqueMonsterSuffixLoader},
{d2resource.CubeModifier, cubeModifierLoader},
{d2resource.CubeType, cubeTypeLoader},
{d2resource.HirelingDescription, hirelingDescriptionLoader},
{d2resource.LowQualityItems, lowQualityLoader},
}
for idx := range loaders {

View File

@ -13,8 +13,33 @@ const (
treasureProbFmt = "Prob%d"
)
//nolint:funlen // Makes no sense to split
func treasureClassLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records, err := treasureClassCommonLoader(d)
if err != nil {
return err
}
r.Item.Treasure.Normal = records
log.Printf("Loaded %d treasure class (normal) records", len(records))
return nil
}
func treasureClassExLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records, err := treasureClassCommonLoader(d)
if err != nil {
return err
}
r.Item.Treasure.Expansion = records
log.Printf("Loaded %d treasure class (expansion) records", len(records))
return nil
}
func treasureClassCommonLoader(d *d2txt.DataDictionary) (TreasureClass, error) {
records := make(TreasureClass)
for d.Next() {
@ -60,13 +85,5 @@ func treasureClassLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records[record.Name] = record
}
if d.Err != nil {
return d.Err
}
r.Item.TreasureClass = records
log.Printf("Loaded %d records records", len(records))
return nil
return records, d.Err
}

View File

@ -0,0 +1,30 @@
package d2records
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2txt"
)
func weaponClassesLoader(r *RecordManager, d *d2txt.DataDictionary) error {
records := make(WeaponClasses)
for d.Next() {
record := &WeaponClassRecord{
Name: d.String("Weapon Class"),
Token: d.String("Code"),
}
records[record.Name] = record
}
if d.Err != nil {
panic(d.Err)
}
r.Animation.Token.Weapon = records
log.Printf("Loaded %d WeaponClass records", len(records))
return nil
}

View File

@ -0,0 +1,11 @@
package d2records
// WeaponClasses is a map of WeaponClassRecords
type WeaponClasses map[string]*WeaponClassRecord
// WeaponClassRecord describes a weapon class. It has a name and 3-character token.
// The token is used to change the character animation mode.
type WeaponClassRecord struct {
Name string
Token string
}

1
go.mod
View File

@ -8,6 +8,7 @@ require (
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1
github.com/google/uuid v1.1.2
github.com/gravestench/akara v0.0.0-20201014060234-a64208a7fd3c
github.com/hajimehoshi/ebiten v1.11.4
github.com/pkg/profile v1.5.0
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff

2
go.sum
View File

@ -16,6 +16,8 @@ github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gravestench/akara v0.0.0-20201014060234-a64208a7fd3c h1:WopE590cKxkcKXcOee4gPXHqtzwbarLClCaWNCdLqgI=
github.com/gravestench/akara v0.0.0-20201014060234-a64208a7fd3c/go.mod h1:fTeda1SogMg5Lkd4lXMEd/Pk/a5/gQuLGaAI2rn1PBQ=
github.com/hajimehoshi/bitmapfont v1.2.0/go.mod h1:h9QrPk6Ktb2neObTlAbma6Ini1xgMjbJ3w7ysmD7IOU=
github.com/hajimehoshi/ebiten v1.11.4 h1:ngYF0NxKjFBsY/Bol6V0X/b0hoCCTi9nJRg7Dv8+ePc=
github.com/hajimehoshi/ebiten v1.11.4/go.mod h1:aDEhx0K9gSpXw3Cxf2hCXDxPSoF8vgjNqKxrZa/B4Dg=