OpenDiablo2/d2common/d2data/d2datadict/objects.go

367 lines
12 KiB
Go

package d2datadict
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"log"
"strings"
)
// An ObjectRecord represents the settings for one type of object from objects.txt
type ObjectRecord struct {
Index int // Line number in file, this is the actual index used for objects
FrameCount [8]int // how many frames does this mode have, 0 = skip
FrameDelta [8]int // what rate is the animation played at (256 = 100% speed)
LightDiameter [8]int
StartFrame [8]int
OrderFlag [8]int // 0 = object, 1 = floor, 2 = wall
Parm [8]int // unknown
Name string
Description string
// Don't use, get token from objtypes
token string // refers to what graphics this object uses
// Don't use, index by line number
id int //nolint:golint,stylecheck // unused, indexed by line number instead
SpawnMax int // unused?
TrapProbability int // unused
SizeX int
SizeY int
NTgtFX int // unknown
NTgtFY int // unknown
NTgtBX int // unknown
NTgtBY int // unknown
Orientation int // unknown (1=sw, 2=nw, 3=se, 4=ne)
Trans int // controls palette mapping
XOffset int // in pixels offset
YOffset int
TotalPieces int // selectable DCC components count
SubClass int // subclass of object:
// 1 = shrine
// 2 = obelisk
// 4 = portal
// 8 = container
// 16 = arcane sanctuary gateway
// 32 = well
// 64 = waypoint
// 128 = secret jails door
XSpace int // unknown
YSpace int
NameOffset int // pixels to offset the name from the animation pivot
OperateRange int // distance object can be used from, might be unused
ShrineFunction int // unused
Act int // what acts this object can appear in (15 = all three)
Damage int // amount of damage done by this (used depending on operatefn)
Left int // unknown, clickable bounding box?
Top int
Width int
Height int
OperateFn int // what function is called when the player clicks on the object
PopulateFn int // what function is used to spawn this object?
InitFn int // what function is run when the object is initialized?
ClientFn int // controls special audio-visual functions
// 'To ...' or 'trap door' when highlighting, not sure which is T/F
AutoMap int // controls how this object appears on the map
// 0 = it doesn't, rest of modes need to be analyzed
CycleAnimation [8]bool // probably whether animation loops
Selectable [8]bool // is this mode selectable
BlocksLight [8]bool
HasCollision [8]bool
HasAnimationMode [8]bool // 'Mode' in source, true if this mode is used
SelS [8]bool
IsAttackable bool // do we kick it when interacting
EnvEffect bool // unknown
IsDoor bool
BlockVisibility bool // only works with IsDoor
PreOperate bool // unknown
Draw bool // if false, object isn't drawn (shadow is still drawn and player can still select though)
SelHD bool // whether these DCC components are selectable
SelTR bool
SelLG bool
SelRA bool
SelLA bool
SelRH bool
SelLH bool
SelSH bool
MonsterOk bool // unknown
Restore bool // if true, object is stored in memory and will be retained if you leave and re-enter the area
Lockable bool
Gore bool // unknown, something with corpses
Sync bool // unknown
Flicker bool // light flickers if true
Beta bool // if true, appeared in the beta?
Overlay bool // unknown
CollisionSubst bool // unknown, controls some kind of special collision checking?
RestoreVirgins bool // if true, only restores unused objects (see Restore)
BlockMissile bool // if true, missiles collide with this
DrawUnder bool // if true, drawn as a floor tile is
OpenWarp bool // needs clarification, controls whether highlighting shows
LightRed byte // if lightdiameter is set, rgb of the light
LightGreen byte
LightBlue byte
}
//nolint:funlen // Makes no sense to split
// CreateObjectRecord parses a row from objects.txt into an object record
func createObjectRecord(props []string) ObjectRecord {
i := -1
inc := func() int {
i++
return i
}
result := ObjectRecord{
Name: props[inc()],
Description: props[inc()],
id: d2util.StringToInt(props[inc()]),
token: props[inc()],
SpawnMax: d2util.StringToInt(props[inc()]),
Selectable: [8]bool{
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
},
TrapProbability: d2util.StringToInt(props[inc()]),
SizeX: d2util.StringToInt(props[inc()]),
SizeY: d2util.StringToInt(props[inc()]),
NTgtFX: d2util.StringToInt(props[inc()]),
NTgtFY: d2util.StringToInt(props[inc()]),
NTgtBX: d2util.StringToInt(props[inc()]),
NTgtBY: d2util.StringToInt(props[inc()]),
FrameCount: [8]int{
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
},
FrameDelta: [8]int{
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
},
CycleAnimation: [8]bool{
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
},
LightDiameter: [8]int{
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
},
BlocksLight: [8]bool{
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
},
HasCollision: [8]bool{
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
},
IsAttackable: d2util.StringToUint8(props[inc()]) == 1,
StartFrame: [8]int{
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
},
EnvEffect: d2util.StringToUint8(props[inc()]) == 1,
IsDoor: d2util.StringToUint8(props[inc()]) == 1,
BlockVisibility: d2util.StringToUint8(props[inc()]) == 1,
Orientation: d2util.StringToInt(props[inc()]),
Trans: d2util.StringToInt(props[inc()]),
OrderFlag: [8]int{
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
},
PreOperate: d2util.StringToUint8(props[inc()]) == 1,
HasAnimationMode: [8]bool{
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
},
XOffset: d2util.StringToInt(props[inc()]),
YOffset: d2util.StringToInt(props[inc()]),
Draw: d2util.StringToUint8(props[inc()]) == 1,
LightRed: d2util.StringToUint8(props[inc()]),
LightGreen: d2util.StringToUint8(props[inc()]),
LightBlue: d2util.StringToUint8(props[inc()]),
SelHD: d2util.StringToUint8(props[inc()]) == 1,
SelTR: d2util.StringToUint8(props[inc()]) == 1,
SelLG: d2util.StringToUint8(props[inc()]) == 1,
SelRA: d2util.StringToUint8(props[inc()]) == 1,
SelLA: d2util.StringToUint8(props[inc()]) == 1,
SelRH: d2util.StringToUint8(props[inc()]) == 1,
SelLH: d2util.StringToUint8(props[inc()]) == 1,
SelSH: d2util.StringToUint8(props[inc()]) == 1,
SelS: [8]bool{
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
d2util.StringToUint8(props[inc()]) == 1,
},
TotalPieces: d2util.StringToInt(props[inc()]),
SubClass: d2util.StringToInt(props[inc()]),
XSpace: d2util.StringToInt(props[inc()]),
YSpace: d2util.StringToInt(props[inc()]),
NameOffset: d2util.StringToInt(props[inc()]),
MonsterOk: d2util.StringToUint8(props[inc()]) == 1,
OperateRange: d2util.StringToInt(props[inc()]),
ShrineFunction: d2util.StringToInt(props[inc()]),
Restore: d2util.StringToUint8(props[inc()]) == 1,
Parm: [8]int{
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
d2util.StringToInt(props[inc()]),
},
Act: d2util.StringToInt(props[inc()]),
Lockable: d2util.StringToUint8(props[inc()]) == 1,
Gore: d2util.StringToUint8(props[inc()]) == 1,
Sync: d2util.StringToUint8(props[inc()]) == 1,
Flicker: d2util.StringToUint8(props[inc()]) == 1,
Damage: d2util.StringToInt(props[inc()]),
Beta: d2util.StringToUint8(props[inc()]) == 1,
Overlay: d2util.StringToUint8(props[inc()]) == 1,
CollisionSubst: d2util.StringToUint8(props[inc()]) == 1,
Left: d2util.StringToInt(props[inc()]),
Top: d2util.StringToInt(props[inc()]),
Width: d2util.StringToInt(props[inc()]),
Height: d2util.StringToInt(props[inc()]),
OperateFn: d2util.StringToInt(props[inc()]),
PopulateFn: d2util.StringToInt(props[inc()]),
InitFn: d2util.StringToInt(props[inc()]),
ClientFn: d2util.StringToInt(props[inc()]),
RestoreVirgins: d2util.StringToUint8(props[inc()]) == 1,
BlockMissile: d2util.StringToUint8(props[inc()]) == 1,
DrawUnder: d2util.StringToUint8(props[inc()]) == 1,
OpenWarp: d2util.StringToUint8(props[inc()]) == 1,
AutoMap: d2util.StringToInt(props[inc()]),
}
return result
}
// Objects stores all of the ObjectRecords
//nolint:gochecknoglobals // Currently global by design, only written once
var Objects map[int]*ObjectRecord
// LoadObjects loads all objects from objects.txt
func LoadObjects(file []byte) {
Objects = make(map[int]*ObjectRecord)
data := strings.Split(string(file), "\r\n")[1:]
lineNumber := 0
for _, line := range data {
if line == "" {
continue
}
props := strings.Split(line, "\t")
if props[2] == "" {
continue // skip a line that doesn't have an id
}
rec := createObjectRecord(props)
rec.Index = lineNumber
Objects[lineNumber] = &rec
lineNumber++
}
log.Printf("Loaded %d objects", len(Objects))
}