From 4a48acb8baa864eb2ab83df80a61861d78f41f42 Mon Sep 17 00:00:00 2001 From: AndrejMijic <44673317+AndrejMijic@users.noreply.github.com> Date: Tue, 4 Aug 2020 18:12:03 +0200 Subject: [PATCH] Add objgroup.txt loader (#677) --- d2app/app.go | 1 + d2common/d2data/d2datadict/object_group.go | 112 +++++++++++++++++++++ d2common/d2resource/resource_paths.go | 1 + 3 files changed, 114 insertions(+) create mode 100644 d2common/d2data/d2datadict/object_group.go diff --git a/d2app/app.go b/d2app/app.go index 6ace7a1f..def95dd3 100644 --- a/d2app/app.go +++ b/d2app/app.go @@ -277,6 +277,7 @@ func (a *App) loadDataDict() error { {d2resource.MonsterSequence, d2datadict.LoadMonsterSequences}, {d2resource.PlayerClass, d2datadict.LoadPlayerClasses}, {d2resource.MonsterPlacement, d2datadict.LoadMonsterPlacements}, + {d2resource.ObjectGroup, d2datadict.LoadObjectGroups}, {d2resource.CompCode, d2datadict.LoadComponentCodes}, {d2resource.MonsterAI, d2datadict.LoadMonsterAI}, } diff --git a/d2common/d2data/d2datadict/object_group.go b/d2common/d2data/d2datadict/object_group.go new file mode 100644 index 00000000..9125bb83 --- /dev/null +++ b/d2common/d2data/d2datadict/object_group.go @@ -0,0 +1,112 @@ +package d2datadict + +import ( + "fmt" + "log" + "strconv" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" +) + +const ( + objectsGroupSize = 7 + memberDensityMin = 0 + memberDensityMax = 125 + memberProbabilityMin = 0 + memberProbabilityMax = 100 + expansionDataMarker = "EXPANSION" +) + +// ObjectGroupRecord represents a single line in objgroup.txt. +// Information has been gathered from [https://d2mods.info/forum/kb/viewarticle?a=394]. +type ObjectGroupRecord struct { + // GroupName is the name of the group. + GroupName string + + // Offset is the ID of the group, referred to by Levels.txt. + Offset int + + // Members are the objects in the group. + Members *[objectsGroupSize]ObjectGroupMember + + // Shrines determines whether this is a group of shrines. + // Note: for shrine groups, densities must be set to 0. + Shrines bool + + // Wells determines whether this is a group of wells. + // Note: for wells groups, densities must be set to 0. + Wells bool +} + +// ObjectGroupMember represents a member of an object group. +type ObjectGroupMember struct { + // ID is the ID of the object. + ID int + + // Density is how densely the level is filled with the object. + // Must be below 125. + Density int + + // Probability is the probability of this particular object being spawned. + // The value is a percentage. + Probability int +} + +// ObjectGroups stores the ObjectGroupRecords. +var ObjectGroups map[int]*ObjectGroupRecord //nolint:gochecknoglobals // Currently global by design. + +// LoadObjectGroups loads the ObjectGroupRecords into ObjectGroups. +func LoadObjectGroups(file []byte) { + ObjectGroups = make(map[int]*ObjectGroupRecord) + d := d2common.LoadDataDictionary(file) + + for d.Next() { + groupName := d.String("GroupName") + if groupName == expansionDataMarker { + continue + } + + shrines, wells := d.Bool("Shrines"), d.Bool("Wells") + record := &ObjectGroupRecord{ + GroupName: groupName, + Offset: d.Number("Offset"), + Members: createMembers(d, shrines || wells), + Shrines: shrines, + Wells: wells, + } + ObjectGroups[record.Offset] = record + } + + if d.Err != nil { + panic(d.Err) + } + + log.Printf("Loaded %d ObjectGroup records", len(ObjectGroups)) +} + +func createMembers(d *d2common.DataDictionary, shrinesOrWells bool) *[objectsGroupSize]ObjectGroupMember { + var members [objectsGroupSize]ObjectGroupMember + + for i := 0; i < objectsGroupSize; i++ { + suffix := strconv.Itoa(i) + members[i].ID = d.Number("ID" + suffix) + + members[i].Density = d.Number("DENSITY" + suffix) + if members[i].Density < memberDensityMin || members[i].Density > memberDensityMax { + panic(fmt.Sprintf("Invalid object group member density: %v, in group: %v", + members[i].Density, d.String("GroupName"))) // Vanilla crashes when density is over 125. + } + + if shrinesOrWells && members[i].Density != 0 { + panic(fmt.Sprintf("Shrine and well object groups must have densities set to 0, in group: %v", d.String("GroupName"))) + } + + members[i].Probability = d.Number("PROB" + suffix) + if members[i].Probability < memberProbabilityMin || members[i].Probability > memberProbabilityMax { + panic(fmt.Sprintf("Invalid object group member probability: %v, in group: %v", + members[i].Probability, d.String("GroupName"))) + } + } + + return &members +} diff --git a/d2common/d2resource/resource_paths.go b/d2common/d2resource/resource_paths.go index 3d8295c9..56057dde 100644 --- a/d2common/d2resource/resource_paths.go +++ b/d2common/d2resource/resource_paths.go @@ -214,6 +214,7 @@ const ( MonsterSound = "/data/global/excel/monsounds.txt" MonsterSequence = "/data/global/excel/monseq.txt" PlayerClass = "/data/global/excel/PlayerClass.txt" + ObjectGroup = "/data/global/excel/objgroup.txt" CompCode = "/data/global/excel/compcode.txt" // --- Animations ---