diff --git a/d2common/d2data/d2datadict/item_affix.go b/d2common/d2data/d2datadict/item_affix.go new file mode 100644 index 00000000..e4d9c248 --- /dev/null +++ b/d2common/d2data/d2datadict/item_affix.go @@ -0,0 +1,255 @@ +package d2datadict + +import ( + "fmt" + "log" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" +) + +var MagicPrefixDictionary *d2common.DataDictionary +var MagicSuffixDictionary *d2common.DataDictionary + +var MagicPrefixRecords []*ItemAffixCommonRecord +var MagicSuffixRecords []*ItemAffixCommonRecord + +var AffixMagicGroups []*ItemAffixCommonGroup + +var superType d2enum.ItemAffixSuperType +var subType d2enum.ItemAffixSubType + +func LoadMagicPrefix(file []byte) { + superType = d2enum.ItemAffixPrefix + subType = d2enum.ItemAffixMagic + loadDictionary(file, MagicPrefixDictionary, superType, subType) +} + +func LoadMagicSuffix(file []byte) { + superType = d2enum.ItemAffixSuffix + subType = d2enum.ItemAffixMagic + loadDictionary(file, MagicSuffixDictionary, superType, subType) +} + +func getAffixString(t1 d2enum.ItemAffixSuperType, t2 d2enum.ItemAffixSubType) string { + var name string = "" + + switch t2 { + case d2enum.ItemAffixMagic: + name = "Magic" + } + + switch t1 { + case d2enum.ItemAffixPrefix: + name += "Prefix" + case d2enum.ItemAffixSuffix: + name += "Suffix" + } + + return name + +} + +func loadDictionary( + file []byte, + dict *d2common.DataDictionary, + superType d2enum.ItemAffixSuperType, + subType d2enum.ItemAffixSubType, +) { + dict = d2common.LoadDataDictionary(string(file)) + records := make([]*ItemAffixCommonRecord, 0) + + createItemAffixRecords(dict, records, superType, subType) + name := getAffixString(superType, subType) + log.Printf("Loaded %d %s records", len(dict.Data), name) +} + +// --- column names from d2exp.mpq:/data/globa/excel/MagicPrefix.txt +// Name +// version +// spawnable +// rare +// level +// maxlevel +// levelreq +// classspecific +// class +// classlevelreq +// frequency +// group +// mod1code +// mod1param +// mod1min +// mod1max +// mod2code +// mod2param +// mod2min +// mod2max +// mod3code +// mod3param +// mod3min +// mod3max +// transform +// transformcolor +// itype1 +// itype2 +// itype3 +// itype4 +// itype5 +// itype6 +// itype7 +// etype1 +// etype2 +// etype3 +// etype4 +// etype5 +// divide +// multiply +// add + +func createItemAffixRecords( + d *d2common.DataDictionary, + r []*ItemAffixCommonRecord, + superType d2enum.ItemAffixSuperType, + subType d2enum.ItemAffixSubType, +) { + for index, _ := range d.Data { + + affix := &ItemAffixCommonRecord{ + Name: d.GetString("Name", index), + Version: d.GetNumber("version", index), + Type: subType, + IsPrefix: superType == d2enum.ItemAffixPrefix, + IsSuffix: superType == d2enum.ItemAffixSuffix, + Spawnable: d.GetNumber("spawnable", index) == 1, + Rare: d.GetNumber("rare", index) == 1, + Level: d.GetNumber("level", index), + MaxLevel: d.GetNumber("maxlevel", index), + LevelReq: d.GetNumber("levelreq", index), + Class: d.GetString("classspecific", index), + ClassLevelReq: d.GetNumber("classlevelreq", index), + Frequency: d.GetNumber("frequency", index), + GroupID: d.GetNumber("group", index), + Transform: d.GetNumber("transform", index) == 1, + TransformColor: d.GetString("transformcolor", index), + PriceAdd: d.GetNumber("add", index), + PriceScale: d.GetNumber("multiply", index), + } + + // modifiers (Property references with parameters to be eval'd) + for i := 1; i <= 3; i++ { + codeKey := fmt.Sprintf("mod%dcode", i) + paramKey := fmt.Sprintf("mod%dparam", i) + minKey := fmt.Sprintf("mod%dmin", i) + maxKey := fmt.Sprintf("mod%dmax", i) + modifier := &ItemAffixCommonModifier{ + Code: d.GetString(codeKey, index), + Parameter: d.GetNumber(paramKey, index), + Min: d.GetNumber(minKey, index), + Max: d.GetNumber(maxKey, index), + } + affix.Modifiers = append(affix.Modifiers, modifier) + } + + // items to include for spawning + for i := 1; i <= 7; i++ { + itemKey := fmt.Sprintf("itype%d", i) + itemToken := d.GetString(itemKey, index) + affix.ItemInclude = append(affix.ItemInclude, itemToken) + } + + // items to exclude for spawning + for i := 1; i <= 7; i++ { + itemKey := fmt.Sprintf("etype%d", i) + itemToken := d.GetString(itemKey, index) + affix.ItemExclude = append(affix.ItemExclude, itemToken) + } + + // affix groupis + if ItemAffixGroups == nil { + ItemAffixGroups = make(map[int]*ItemAffixCommonGroup) + } + + if _, found := ItemAffixGroups[affix.GroupID]; !found { + ItemAffixGroup := &ItemAffixCommonGroup{} + ItemAffixGroup.ID = affix.GroupID + ItemAffixGroups[affix.GroupID] = ItemAffixGroup + } + + group := ItemAffixGroups[affix.GroupID] + group.AddMember(affix) + + r = append(r, affix) + } +} + +var ItemAffixGroups map[int]*ItemAffixCommonGroup + +type ItemAffixCommonGroup struct { + ID int + Members map[string]*ItemAffixCommonRecord +} + +func (g *ItemAffixCommonGroup) AddMember(a *ItemAffixCommonRecord) { + if g.Members == nil { + g.Members = make(map[string]*ItemAffixCommonRecord) + } + g.Members[a.Name] = a +} + +func (g *ItemAffixCommonGroup) GetTotalFrequency() int { + total := 0 + for _, affix := range g.Members { + total += affix.Frequency + } + return total +} + +type ItemAffixCommonModifier struct { + Code string + Parameter int + Min int + Max int +} + +type ItemAffixCommonRecord struct { + Name string + Version int + Type d2enum.ItemAffixSubType + + IsPrefix bool + IsSuffix bool + + Spawnable bool + Rare bool + + Level int + MaxLevel int + + LevelReq int + Class string + ClassLevelReq int + + Frequency int + GroupID int + Group *ItemAffixCommonGroup + + Modifiers []*ItemAffixCommonModifier + + Transform bool + TransformColor string + + ItemInclude []string + ItemExclude []string + + PriceAdd int + PriceScale int +} + +func (a *ItemAffixCommonRecord) ProbabilityToSpawn(qlvl int) float64 { + if (qlvl > a.MaxLevel) || (qlvl < a.Level) { + return 0.0 + } + p := (float64)(a.Frequency) / (float64)(a.Group.GetTotalFrequency()) + return p +} diff --git a/d2common/d2enum/item_affix_type.go b/d2common/d2enum/item_affix_type.go new file mode 100644 index 00000000..917b3e22 --- /dev/null +++ b/d2common/d2enum/item_affix_type.go @@ -0,0 +1,14 @@ +package d2enum + +type ItemAffixSuperType int +type ItemAffixSubType int + +const ( + ItemAffixPrefix ItemAffixSuperType = iota + ItemAffixSuffix +) + +const ( + ItemAffixCommon ItemAffixSubType = iota + ItemAffixMagic +) diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index 99341d90..0066d84d 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -189,6 +189,17 @@ const ( Misc = "/data/global/excel/misc.txt" UniqueItems = "/data/global/excel/UniqueItems.txt" + // --- Affixes --- + + MagicPrefix = "/data/global/excel/MagicPrefix.txt" + MagicSuffix = "/data/global/excel/MagicSuffix.txt" + + // --- Monster Prefix/Suffixes (?) --- + RarePrefix = "/data/global/excel/RarePrefix.txt" + RareSuffix = "/data/global/excel/RareSuffix.txt" + UniquePrefix = "/data/global/excel/UniquePrefix.txt" + UniqueSuffix = "/data/global/excel/UniqueSuffix.txt" + // --- Character Data --- Experience = "/data/global/excel/experience.txt" diff --git a/d2common/data_dictionary.go b/d2common/data_dictionary.go index 01a7b766..2c5d2b51 100644 --- a/d2common/data_dictionary.go +++ b/d2common/data_dictionary.go @@ -20,7 +20,7 @@ func LoadDataDictionary(text string) *DataDictionary { for i, fieldName := range fileNames { result.FieldNameLookup[fieldName] = i } - result.Data = make([][]string, len(lines)-1) + result.Data = make([][]string, len(lines)-2) for i, line := range lines[1:] { if len(strings.TrimSpace(line)) == 0 { continue @@ -39,7 +39,9 @@ func (v *DataDictionary) GetString(fieldName string, index int) string { } func (v *DataDictionary) GetNumber(fieldName string, index int) int { - result, err := strconv.Atoi(v.GetString(fieldName, index)) + str := v.GetString(fieldName, index) + str = EmptyToZero(AsterToEmpty(str)) + result, err := strconv.Atoi(str) if err != nil { log.Panic(err) } diff --git a/main.go b/main.go index 36c485e7..fd404927 100644 --- a/main.go +++ b/main.go @@ -383,6 +383,8 @@ func loadDataDict() error { {d2resource.SoundSettings, d2datadict.LoadSounds}, {d2resource.AnimationData, d2data.LoadAnimationData}, {d2resource.MonStats, d2datadict.LoadMonStats}, + {d2resource.MagicPrefix, d2datadict.LoadMagicPrefix}, + {d2resource.MagicSuffix, d2datadict.LoadMagicSuffix}, } for _, entry := range entries {