diff --git a/common/Cof.go b/common/Cof.go deleted file mode 100644 index abed4aa6..00000000 --- a/common/Cof.go +++ /dev/null @@ -1,185 +0,0 @@ -package common - -import "strings" - -// Tools used for go:generate. -// -// go get golang.org/x/tools/cmd/stringer -// go get github.com/mewspring/tools/cmd/string2enum - -//go:generate stringer -linecomment -type AnimationMode - -type AnimationMode int - -const ( - AnimationModePlayerDeath AnimationMode = 0 // DT - AnimationModePlayerNeutral AnimationMode = 1 // NU - AnimationModePlayerWalk AnimationMode = 2 // WL - AnimationModePlayerRun AnimationMode = 3 // RN - AnimationModePlayerGetHit AnimationMode = 4 // GH - AnimationModePlayerTownNeutral AnimationMode = 5 // TN - AnimationModePlayerTownWalk AnimationMode = 6 // TW - AnimationModePlayerAttack1 AnimationMode = 7 // A1 - AnimationModePlayerAttack2 AnimationMode = 8 // A2 - AnimationModePlayerBlock AnimationMode = 9 // BL - AnimationModePlayerCast AnimationMode = 10 // SC - AnimationModePlayerThrow AnimationMode = 11 // TH - AnimationModePlayerKick AnimationMode = 12 // KK - AnimationModePlayerSkill1 AnimationMode = 13 // S1 - AnimationModePlayerSkill2 AnimationMode = 14 // S2 - AnimationModePlayerSkill3 AnimationMode = 15 // S3 - AnimationModePlayerSkill4 AnimationMode = 16 // S4 - AnimationModePlayerDead AnimationMode = 17 // DD - AnimationModePlayerSequence AnimationMode = 18 // GH - AnimationModePlayerKnockBack AnimationMode = 19 // GH - AnimationModeMonsterDeath AnimationMode = 20 // DT - AnimationModeMonsterNeutral AnimationMode = 21 // NU - AnimationModeMonsterWalk AnimationMode = 22 // WL - AnimationModeMonsterGetHit AnimationMode = 23 // GH - AnimationModeMonsterAttack1 AnimationMode = 24 // A1 - AnimationModeMonsterAttack2 AnimationMode = 25 // A2 - AnimationModeMonsterBlock AnimationMode = 26 // BL - AnimationModeMonsterCast AnimationMode = 27 // SC - AnimationModeMonsterSkill1 AnimationMode = 28 // S1 - AnimationModeMonsterSkill2 AnimationMode = 29 // S2 - AnimationModeMonsterSkill3 AnimationMode = 30 // S3 - AnimationModeMonsterSkill4 AnimationMode = 31 // S4 - AnimationModeMonsterDead AnimationMode = 32 // DD - AnimationModeMonsterKnockback AnimationMode = 33 // GH - AnimationModeMonsterSequence AnimationMode = 34 // xx - AnimationModeMonsterRun AnimationMode = 35 // RN - AnimationModeObjectNeutral AnimationMode = 36 // NU - AnimationModeObjectOperating AnimationMode = 37 // OP - AnimationModeObjectOpened AnimationMode = 38 // ON - AnimationModeObjectSpecial1 AnimationMode = 39 // S1 - AnimationModeObjectSpecial2 AnimationMode = 40 // S2 - AnimationModeObjectSpecial3 AnimationMode = 41 // S3 - AnimationModeObjectSpecial4 AnimationMode = 42 // S4 - AnimationModeObjectSpecial5 AnimationMode = 43 // S5 -) - -type CompositeType int - -const ( - CompositeTypeHead CompositeType = 0 - CompositeTypeTorso CompositeType = 1 - CompositeTypeLegs CompositeType = 2 - CompositeTypeRightArm CompositeType = 3 - CompositeTypeLeftArm CompositeType = 4 - CompositeTypeRightHand CompositeType = 5 - CompositeTypeLeftHand CompositeType = 6 - CompositeTypeShield CompositeType = 7 - CompositeTypeSpecial1 CompositeType = 8 - CompositeTypeSpecial2 CompositeType = 9 - CompositeTypeSpecial3 CompositeType = 10 - CompositeTypeSpecial4 CompositeType = 11 - CompositeTypeSpecial5 CompositeType = 12 - CompositeTypeSpecial6 CompositeType = 13 - CompositeTypeSpecial7 CompositeType = 14 - CompositeTypeSpecial8 CompositeType = 15 - CompositeTypeMax CompositeType = 16 -) - -type DrawEffect int - -const ( - DrawEffectPctTransparency75 = 0 //75 % transparency (colormaps 561-816 in a .pl2) - DrawEffectPctTransparency50 = 1 //50 % transparency (colormaps 305-560 in a .pl2) - DrawEffectPctTransparency25 = 2 //25 % transparency (colormaps 49-304 in a .pl2) - DrawEffectScreen = 3 //Screen (colormaps 817-1072 in a .pl2) - DrawEffectLuminance = 4 //luminance (colormaps 1073-1328 in a .pl2) - DrawEffectBringAlphaBlending = 5 //bright alpha blending (colormaps 1457-1712 in a .pl2) -) - -//go:generate stringer -linecomment -type WeaponClass -//go:generate string2enum -samepkg -linecomment -type WeaponClass - -type WeaponClass int - -const ( - WeaponClassNone WeaponClass = 0 // - WeaponClassHandToHand WeaponClass = 1 // hth - WeaponClassBow WeaponClass = 2 // bow - WeaponClassOneHandSwing WeaponClass = 3 // 1hs - WeaponClassOneHandThrust WeaponClass = 4 // 1ht - WeaponClassStaff WeaponClass = 5 // stf - WeaponClassTwoHandSwing WeaponClass = 6 // 2hs - WeaponClassTwoHandThrust WeaponClass = 7 // 2ht - WeaponClassCrossbow WeaponClass = 8 // xbw - WeaponClassLeftJabRightSwing WeaponClass = 9 // 1js - WeaponClassLeftJabRightThrust WeaponClass = 10 // 1jt - WeaponClassLeftSwingRightSwing WeaponClass = 11 // 1ss - WeaponClassLeftSwingRightThrust WeaponClass = 12 // 1st - WeaponClassOneHandToHand WeaponClass = 13 // ht1 - WeaponClassTwoHandToHand WeaponClass = 14 // ht2 -) - -type AnimationFrame int - -const ( - AnimationFrameNoEvent AnimationFrame = 0 - AnimationFrameAttack AnimationFrame = 1 - AnimationFrameMissile AnimationFrame = 2 - AnimationFrameSound AnimationFrame = 3 - AnimationFrameSkill AnimationFrame = 4 -) - -type CofLayer struct { - Type CompositeType - Shadow byte - Transparent bool - DrawEffect DrawEffect - WeaponClass WeaponClass -} - -type Cof struct { - NumberOfDirections int - FramesPerDirection int - NumberOfLayers int - CofLayers []*CofLayer - CompositeLayers map[CompositeType]int - AnimationFrames []AnimationFrame - Priority [][][]CompositeType -} - -func LoadCof(fileName string, fileProvider FileProvider) *Cof { - result := &Cof{} - fileData := fileProvider.LoadFile(fileName) - streamReader := CreateStreamReader(fileData) - result.NumberOfLayers = int(streamReader.GetByte()) - result.FramesPerDirection = int(streamReader.GetByte()) - result.NumberOfDirections = int(streamReader.GetByte()) - streamReader.SkipBytes(25) // Skip 25 unknown bytes... - result.CofLayers = make([]*CofLayer, 0) - result.CompositeLayers = make(map[CompositeType]int, 0) - for i := 0; i < result.NumberOfLayers; i++ { - layer := &CofLayer{} - layer.Type = CompositeType(streamReader.GetByte()) - layer.Shadow = streamReader.GetByte() - streamReader.SkipBytes(1) // Unknown - layer.Transparent = streamReader.GetByte() != 0 - layer.DrawEffect = DrawEffect(streamReader.GetByte()) - weaponClassStr, _ := streamReader.ReadBytes(4) - layer.WeaponClass = WeaponClassFromString(strings.TrimSpace(strings.ReplaceAll(string(weaponClassStr), string(0), ""))) - result.CofLayers = append(result.CofLayers, layer) - result.CompositeLayers[layer.Type] = i - } - animationFrameBytes, _ := streamReader.ReadBytes(result.FramesPerDirection) - result.AnimationFrames = make([]AnimationFrame, result.FramesPerDirection) - for i := range animationFrameBytes { - result.AnimationFrames[i] = AnimationFrame(animationFrameBytes[i]) - } - priorityLen := result.FramesPerDirection * result.NumberOfDirections * result.NumberOfLayers - result.Priority = make([][][]CompositeType, result.NumberOfDirections) - priorityBytes, _ := streamReader.ReadBytes(priorityLen) - for direction := 0; direction < result.NumberOfDirections; direction++ { - result.Priority[direction] = make([][]CompositeType, result.FramesPerDirection) - for frame := 0; frame < result.FramesPerDirection; frame++ { - result.Priority[direction][frame] = make([]CompositeType, result.NumberOfLayers) - for i := 0; i < result.NumberOfLayers; i++ { - result.Priority[direction][frame][i] = CompositeType(priorityBytes[i]) - } - } - } - return result -} diff --git a/common/FileProvider.go b/common/FileProvider.go deleted file mode 100644 index 8e2f267f..00000000 --- a/common/FileProvider.go +++ /dev/null @@ -1,9 +0,0 @@ -package common - -import "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - -// FileProvider is an instance that can provide different types of files -type FileProvider interface { - LoadFile(fileName string) []byte - LoadSprite(fileName string, palette palettedefs.PaletteType) *Sprite -} diff --git a/common/MonStats.go b/common/MonStats.go deleted file mode 100644 index 537f799c..00000000 --- a/common/MonStats.go +++ /dev/null @@ -1,9 +0,0 @@ -package common - -import "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" - -var MonStatsDictionary *DataDictionary - -func LoadMonStats(fileProvider FileProvider) { - MonStatsDictionary = LoadDataDictionary(string(fileProvider.LoadFile(resourcepaths.MonStats))) -} diff --git a/common/NPC.go b/common/NPC.go deleted file mode 100644 index 42b061c4..00000000 --- a/common/NPC.go +++ /dev/null @@ -1,24 +0,0 @@ -package common - -import ( - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - "github.com/hajimehoshi/ebiten" -) - -type NPC struct { - AnimatedEntity *AnimatedEntity - Paths []Path -} - -func CreateNPC(object Object, fileProvider FileProvider) *NPC { - result := &NPC{ - AnimatedEntity: CreateAnimatedEntity(object, fileProvider, palettedefs.Units), - Paths: object.Paths, - } - result.AnimatedEntity.SetMode(object.Lookup.Mode, object.Lookup.Class, 1, fileProvider) - return result -} - -func (v *NPC) Render(target *ebiten.Image, offsetX, offsetY int) { - v.AnimatedEntity.Render(target, offsetX, offsetY) -} diff --git a/common/Object.go b/common/Object.go deleted file mode 100644 index 2d0f03de..00000000 --- a/common/Object.go +++ /dev/null @@ -1,12 +0,0 @@ -package common - -type Object struct { - Type int32 - Id int32 - X int32 - Y int32 - Flags int32 - Paths []Path - Lookup *ObjectLookupRecord - ObjectInfo *ObjectRecord -} diff --git a/common/Objects.go b/common/Objects.go deleted file mode 100644 index d0f5b8dc..00000000 --- a/common/Objects.go +++ /dev/null @@ -1,353 +0,0 @@ -package common - -import ( - "log" - "strings" - - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" -) - -// An ObjectRecord represents the settings for one type of object from objects.txt -type ObjectRecord struct { - Name string - Description string - Id int - Token string // refers to what graphics this object uses - - SpawnMax int // unused? - Selectable [8]bool // is this mode selectable - TrapProbability int // unused - - SizeX int - SizeY int - - NTgtFX int // unknown - NTgtFY int // unknown - NTgtBX int // unknown - NTgtBY int // unknown - - 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) - CycleAnimation [8]bool // probably whether animation loops - LightDiameter [8]int - BlocksLight [8]bool - HasCollision [8]bool - IsAttackable bool // do we kick it when interacting - StartFrame [8]int - - EnvEffect bool // unknown - IsDoor bool - BlockVisibility bool // only works with IsDoor - Orientation int // unknown (1=sw, 2=nw, 3=se, 4=ne) - Trans int // controls palette mapping - - OrderFlag [8]int // 0 = object, 1 = floor, 2 = wall - PreOperate bool // unknown - HasAnimationMode [8]bool // 'Mode' in source, true if this mode is used - - XOffset int // in pixels offset - YOffset int - Draw bool // if false, object isn't drawn (shadow is still drawn and player can still select though) - - LightRed byte // if lightdiameter is set, rgb of the light - LightGreen byte - LightBlue byte - - SelHD bool // whether these DCC components are selectable - SelTR bool - SelLG bool - SelRA bool - SelLA bool - SelRH bool - SelLH bool - SelSH bool - SelS [8]bool - - 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 - - MonsterOk bool // unknown - OperateRange int // distance object can be used from, might be unused - ShrineFunction int // unused - Restore bool // if true, object is stored in memory and will be retained if you leave and re-enter the area - - Parm [8]int // unknown - Act int // what acts this object can appear in (15 = all three) - Lockable bool - Gore bool // unknown, something with corpses - Sync bool // unknown - Flicker bool // light flickers if true - Damage int // amount of damage done by this (used depending on operatefn) - Beta bool // if true, appeared in the beta? - Overlay bool // unknown - CollisionSubst bool // unknown, controls some kind of special collision checking? - - 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 - // (todo: we should enumerate all the functions somewhere, but probably not here - // b/c it's a very long list) - PopulateFn int // what function is used to spawn this object? - // (see above todo) - InitFn int // what function is run when the object is initialized? - // (see above todo) - ClientFn int // controls special audio-visual functions - // (see above todo) - - 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 - // '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 -} - -// 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: StringToInt(props[inc()]), - Token: props[inc()], - - SpawnMax: StringToInt(props[inc()]), - Selectable: [8]bool{ - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - }, - TrapProbability: StringToInt(props[inc()]), - - SizeX: StringToInt(props[inc()]), - SizeY: StringToInt(props[inc()]), - - NTgtFX: StringToInt(props[inc()]), - NTgtFY: StringToInt(props[inc()]), - NTgtBX: StringToInt(props[inc()]), - NTgtBY: StringToInt(props[inc()]), - - FrameCount: [8]int{ - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - }, - FrameDelta: [8]int{ - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - }, - CycleAnimation: [8]bool{ - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - }, - LightDiameter: [8]int{ - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - }, - BlocksLight: [8]bool{ - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - }, - HasCollision: [8]bool{ - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - }, - IsAttackable: StringToUint8(props[inc()]) == 1, - StartFrame: [8]int{ - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - }, - - EnvEffect: StringToUint8(props[inc()]) == 1, - IsDoor: StringToUint8(props[inc()]) == 1, - BlockVisibility: StringToUint8(props[inc()]) == 1, - Orientation: StringToInt(props[inc()]), - Trans: StringToInt(props[inc()]), - - OrderFlag: [8]int{ - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - }, - PreOperate: StringToUint8(props[inc()]) == 1, - HasAnimationMode: [8]bool{ - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - }, - - XOffset: StringToInt(props[inc()]), - YOffset: StringToInt(props[inc()]), - Draw: StringToUint8(props[inc()]) == 1, - - LightRed: StringToUint8(props[inc()]), - LightGreen: StringToUint8(props[inc()]), - LightBlue: StringToUint8(props[inc()]), - - SelHD: StringToUint8(props[inc()]) == 1, - SelTR: StringToUint8(props[inc()]) == 1, - SelLG: StringToUint8(props[inc()]) == 1, - SelRA: StringToUint8(props[inc()]) == 1, - SelLA: StringToUint8(props[inc()]) == 1, - SelRH: StringToUint8(props[inc()]) == 1, - SelLH: StringToUint8(props[inc()]) == 1, - SelSH: StringToUint8(props[inc()]) == 1, - SelS: [8]bool{ - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - StringToUint8(props[inc()]) == 1, - }, - - TotalPieces: StringToInt(props[inc()]), - SubClass: StringToInt(props[inc()]), - - XSpace: StringToInt(props[inc()]), - YSpace: StringToInt(props[inc()]), - - NameOffset: StringToInt(props[inc()]), - - MonsterOk: StringToUint8(props[inc()]) == 1, - OperateRange: StringToInt(props[inc()]), - ShrineFunction: StringToInt(props[inc()]), - Restore: StringToUint8(props[inc()]) == 1, - - Parm: [8]int{ - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - StringToInt(props[inc()]), - }, - Act: StringToInt(props[inc()]), - Lockable: StringToUint8(props[inc()]) == 1, - Gore: StringToUint8(props[inc()]) == 1, - Sync: StringToUint8(props[inc()]) == 1, - Flicker: StringToUint8(props[inc()]) == 1, - Damage: StringToInt(props[inc()]), - Beta: StringToUint8(props[inc()]) == 1, - Overlay: StringToUint8(props[inc()]) == 1, - CollisionSubst: StringToUint8(props[inc()]) == 1, - - Left: StringToInt(props[inc()]), - Top: StringToInt(props[inc()]), - Width: StringToInt(props[inc()]), - Height: StringToInt(props[inc()]), - - OperateFn: StringToInt(props[inc()]), - PopulateFn: StringToInt(props[inc()]), - InitFn: StringToInt(props[inc()]), - ClientFn: StringToInt(props[inc()]), - - RestoreVirgins: StringToUint8(props[inc()]) == 1, - BlockMissile: StringToUint8(props[inc()]) == 1, - DrawUnder: StringToUint8(props[inc()]) == 1, - OpenWarp: StringToUint8(props[inc()]) == 1, - - AutoMap: StringToInt(props[inc()]), - } - return result -} - -var Objects map[int]*ObjectRecord - -func LoadObjects(fileProvider FileProvider) { - Objects = make(map[int]*ObjectRecord) - data := strings.Split(string(fileProvider.LoadFile(resourcepaths.ObjectDetails)), "\r\n")[1:] - for _, line := range data { - if len(line) == 0 { - continue - } - props := strings.Split(line, "\t") - if props[2] == "" { - continue // skip a line that doesn't have an id - } - rec := createObjectRecord(props) - Objects[rec.Id] = &rec - } - log.Printf("Loaded %d objects", len(Objects)) -} diff --git a/sound/AudioProvider.go b/d2audio/AudioProvider.go similarity index 90% rename from sound/AudioProvider.go rename to d2audio/AudioProvider.go index 8eb2cc59..b3edab3c 100644 --- a/sound/AudioProvider.go +++ b/d2audio/AudioProvider.go @@ -1,16 +1,17 @@ -package sound +package d2audio import ( "log" - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/hajimehoshi/ebiten/audio" "github.com/hajimehoshi/ebiten/audio/wav" ) // Manager provides sound type Manager struct { - fileProvider common.FileProvider + fileProvider d2interface.FileProvider audioContext *audio.Context // The Audio context bgmAudio *audio.Player // The audio player lastBgm string @@ -19,7 +20,7 @@ type Manager struct { } // CreateManager creates a sound provider -func CreateManager(fileProvider common.FileProvider) *Manager { +func CreateManager(fileProvider d2interface.FileProvider) *Manager { result := &Manager{ fileProvider: fileProvider, } diff --git a/sound/SoundEffect.go b/d2audio/SoundEffect.go similarity index 66% rename from sound/SoundEffect.go rename to d2audio/SoundEffect.go index 6df1970c..fab886e0 100644 --- a/sound/SoundEffect.go +++ b/d2audio/SoundEffect.go @@ -1,11 +1,13 @@ -package sound +package d2audio import ( "log" - "github.com/hajimehoshi/ebiten/audio/wav" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + + "github.com/hajimehoshi/ebiten/audio/wav" "github.com/hajimehoshi/ebiten/audio" ) @@ -14,11 +16,11 @@ type SoundEffect struct { player *audio.Player } -func CreateSoundEffect(sfx string, fileProvider common.FileProvider, context *audio.Context, volume float64) *SoundEffect { +func CreateSoundEffect(sfx string, fileProvider d2interface.FileProvider, context *audio.Context, volume float64) *SoundEffect { result := &SoundEffect{} var soundFile string - if _, exists := common.Sounds[sfx]; exists { - soundEntry := common.Sounds[sfx] + if _, exists := datadict.Sounds[sfx]; exists { + soundEntry := datadict.Sounds[sfx] soundFile = soundEntry.FileName } else { soundFile = sfx diff --git a/common/BitMuncher.go b/d2common/BitMuncher.go similarity index 99% rename from common/BitMuncher.go rename to d2common/BitMuncher.go index e7a38646..68ef9e69 100644 --- a/common/BitMuncher.go +++ b/d2common/BitMuncher.go @@ -1,4 +1,4 @@ -package common +package d2common type BitMuncher struct { data []byte diff --git a/common/BitStream.go b/d2common/BitStream.go similarity index 98% rename from common/BitStream.go rename to d2common/BitStream.go index 6a9f48cd..cb588bff 100644 --- a/common/BitStream.go +++ b/d2common/BitStream.go @@ -1,4 +1,4 @@ -package common +package d2common import "log" diff --git a/common/BitStream_test.go b/d2common/BitStream_test.go similarity index 97% rename from common/BitStream_test.go rename to d2common/BitStream_test.go index bd2076a0..d6878be1 100644 --- a/common/BitStream_test.go +++ b/d2common/BitStream_test.go @@ -1,4 +1,4 @@ -package common +package d2common import ( "testing" diff --git a/common/BuildInfo.go b/d2common/BuildInfo.go similarity index 92% rename from common/BuildInfo.go rename to d2common/BuildInfo.go index 7df25fcd..fe0b9e8a 100644 --- a/common/BuildInfo.go +++ b/d2common/BuildInfo.go @@ -1,4 +1,4 @@ -package common +package d2common type BuildInfoRecord struct { Branch string diff --git a/common/Configuration.go b/d2common/Configuration.go similarity index 98% rename from common/Configuration.go rename to d2common/Configuration.go index 1b58a7d1..8e6b7aed 100644 --- a/common/Configuration.go +++ b/d2common/Configuration.go @@ -1,4 +1,4 @@ -package common +package d2common import ( "encoding/json" diff --git a/common/DataDictionary.go b/d2common/DataDictionary.go similarity index 98% rename from common/DataDictionary.go rename to d2common/DataDictionary.go index 8f4125e5..b17b2be8 100644 --- a/common/DataDictionary.go +++ b/d2common/DataDictionary.go @@ -1,4 +1,4 @@ -package common +package d2common import ( "log" diff --git a/common/Path.go b/d2common/Path.go similarity index 79% rename from common/Path.go rename to d2common/Path.go index d6ccfe21..7e3a706e 100644 --- a/common/Path.go +++ b/d2common/Path.go @@ -1,4 +1,4 @@ -package common +package d2common type Path struct { X int32 diff --git a/common/Rectangle.go b/d2common/Rectangle.go similarity index 95% rename from common/Rectangle.go rename to d2common/Rectangle.go index a6de206d..347f7283 100644 --- a/common/Rectangle.go +++ b/d2common/Rectangle.go @@ -1,4 +1,4 @@ -package common +package d2common type Rectangle struct { Left int diff --git a/resourcepaths/ResourcePaths.go b/d2common/ResourcePaths.go similarity index 99% rename from resourcepaths/ResourcePaths.go rename to d2common/ResourcePaths.go index 83845a28..7866928f 100644 --- a/resourcepaths/ResourcePaths.go +++ b/d2common/ResourcePaths.go @@ -1,4 +1,4 @@ -package resourcepaths +package d2common var LanguageCode string diff --git a/common/StreamReader.go b/d2common/StreamReader.go similarity index 99% rename from common/StreamReader.go rename to d2common/StreamReader.go index 07a45b99..ddb81c7d 100644 --- a/common/StreamReader.go +++ b/d2common/StreamReader.go @@ -1,4 +1,4 @@ -package common +package d2common import ( "io" diff --git a/common/StreamReader_test.go b/d2common/StreamReader_test.go similarity index 99% rename from common/StreamReader_test.go rename to d2common/StreamReader_test.go index f7ff774a..6c4b4872 100644 --- a/common/StreamReader_test.go +++ b/d2common/StreamReader_test.go @@ -1,4 +1,4 @@ -package common +package d2common import ( "testing" diff --git a/common/StreamWriter.go b/d2common/StreamWriter.go similarity index 98% rename from common/StreamWriter.go rename to d2common/StreamWriter.go index 4645e843..8d2ffa97 100644 --- a/common/StreamWriter.go +++ b/d2common/StreamWriter.go @@ -1,4 +1,4 @@ -package common +package d2common // StreamWriter allows you to create a byte array by streaming in writes of various sizes type StreamWriter struct { diff --git a/common/StreamWriter_test.go b/d2common/StreamWriter_test.go similarity index 98% rename from common/StreamWriter_test.go rename to d2common/StreamWriter_test.go index bb127897..e73343b8 100644 --- a/common/StreamWriter_test.go +++ b/d2common/StreamWriter_test.go @@ -1,4 +1,4 @@ -package common +package d2common import ( "testing" diff --git a/common/TextDictionary.go b/d2common/TextDictionary.go similarity index 85% rename from common/TextDictionary.go rename to d2common/TextDictionary.go index 266e137c..c0be1b39 100644 --- a/common/TextDictionary.go +++ b/d2common/TextDictionary.go @@ -1,10 +1,10 @@ -package common +package d2common import ( "log" "strconv" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" ) type textDictionaryHashEntry struct { @@ -26,16 +26,16 @@ func TranslateString(key string) string { return result } -func LoadTextDictionary(fileProvider FileProvider) { +func LoadTextDictionary(fileProvider d2interface.FileProvider) { lookupTable = make(map[string]string) - loadDictionary(fileProvider, resourcepaths.PatchStringTable) - loadDictionary(fileProvider, resourcepaths.ExpansionStringTable) - loadDictionary(fileProvider, resourcepaths.StringTable) + loadDictionary(fileProvider, PatchStringTable) + loadDictionary(fileProvider, ExpansionStringTable) + loadDictionary(fileProvider, StringTable) log.Printf("Loaded %d entries from the string table", len(lookupTable)) } -func loadDictionary(fileProvider FileProvider, dictionaryName string) { +func loadDictionary(fileProvider d2interface.FileProvider, dictionaryName string) { dictionaryData := fileProvider.LoadFile(dictionaryName) br := CreateStreamReader(dictionaryData) br.ReadBytes(2) // CRC diff --git a/d2common/d2enum/AnimationFrame.go b/d2common/d2enum/AnimationFrame.go new file mode 100644 index 00000000..9c12f90f --- /dev/null +++ b/d2common/d2enum/AnimationFrame.go @@ -0,0 +1,11 @@ +package d2enum + +type AnimationFrame int + +const ( + AnimationFrameNoEvent AnimationFrame = 0 + AnimationFrameAttack AnimationFrame = 1 + AnimationFrameMissile AnimationFrame = 2 + AnimationFrameSound AnimationFrame = 3 + AnimationFrameSkill AnimationFrame = 4 +) diff --git a/d2common/d2enum/AnimationMode.go b/d2common/d2enum/AnimationMode.go new file mode 100644 index 00000000..0b236437 --- /dev/null +++ b/d2common/d2enum/AnimationMode.go @@ -0,0 +1,52 @@ +package d2enum + +type AnimationMode int + +const ( + AnimationModePlayerDeath AnimationMode = 0 // DT + AnimationModePlayerNeutral AnimationMode = 1 // NU + AnimationModePlayerWalk AnimationMode = 2 // WL + AnimationModePlayerRun AnimationMode = 3 // RN + AnimationModePlayerGetHit AnimationMode = 4 // GH + AnimationModePlayerTownNeutral AnimationMode = 5 // TN + AnimationModePlayerTownWalk AnimationMode = 6 // TW + AnimationModePlayerAttack1 AnimationMode = 7 // A1 + AnimationModePlayerAttack2 AnimationMode = 8 // A2 + AnimationModePlayerBlock AnimationMode = 9 // BL + AnimationModePlayerCast AnimationMode = 10 // SC + AnimationModePlayerThrow AnimationMode = 11 // TH + AnimationModePlayerKick AnimationMode = 12 // KK + AnimationModePlayerSkill1 AnimationMode = 13 // S1 + AnimationModePlayerSkill2 AnimationMode = 14 // S2 + AnimationModePlayerSkill3 AnimationMode = 15 // S3 + AnimationModePlayerSkill4 AnimationMode = 16 // S4 + AnimationModePlayerDead AnimationMode = 17 // DD + AnimationModePlayerSequence AnimationMode = 18 // GH + AnimationModePlayerKnockBack AnimationMode = 19 // GH + AnimationModeMonsterDeath AnimationMode = 20 // DT + AnimationModeMonsterNeutral AnimationMode = 21 // NU + AnimationModeMonsterWalk AnimationMode = 22 // WL + AnimationModeMonsterGetHit AnimationMode = 23 // GH + AnimationModeMonsterAttack1 AnimationMode = 24 // A1 + AnimationModeMonsterAttack2 AnimationMode = 25 // A2 + AnimationModeMonsterBlock AnimationMode = 26 // BL + AnimationModeMonsterCast AnimationMode = 27 // SC + AnimationModeMonsterSkill1 AnimationMode = 28 // S1 + AnimationModeMonsterSkill2 AnimationMode = 29 // S2 + AnimationModeMonsterSkill3 AnimationMode = 30 // S3 + AnimationModeMonsterSkill4 AnimationMode = 31 // S4 + AnimationModeMonsterDead AnimationMode = 32 // DD + AnimationModeMonsterKnockback AnimationMode = 33 // GH + AnimationModeMonsterSequence AnimationMode = 34 // xx + AnimationModeMonsterRun AnimationMode = 35 // RN + AnimationModeObjectNeutral AnimationMode = 36 // NU + AnimationModeObjectOperating AnimationMode = 37 // OP + AnimationModeObjectOpened AnimationMode = 38 // ON + AnimationModeObjectSpecial1 AnimationMode = 39 // S1 + AnimationModeObjectSpecial2 AnimationMode = 40 // S2 + AnimationModeObjectSpecial3 AnimationMode = 41 // S3 + AnimationModeObjectSpecial4 AnimationMode = 42 // S4 + AnimationModeObjectSpecial5 AnimationMode = 43 // S5 +) + +//go:generate stringer -linecomment -type AnimationMode diff --git a/common/animationmode_string.go b/d2common/d2enum/AnimationMode_string.go similarity index 99% rename from common/animationmode_string.go rename to d2common/d2enum/AnimationMode_string.go index 0c592f91..2b655afb 100644 --- a/common/animationmode_string.go +++ b/d2common/d2enum/AnimationMode_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -linecomment -type AnimationMode"; DO NOT EDIT. -package common +package d2enum import "strconv" diff --git a/d2common/d2enum/CompositeType.go b/d2common/d2enum/CompositeType.go new file mode 100644 index 00000000..9e43a93e --- /dev/null +++ b/d2common/d2enum/CompositeType.go @@ -0,0 +1,23 @@ +package d2enum + +type CompositeType int + +const ( + CompositeTypeHead CompositeType = 0 + CompositeTypeTorso CompositeType = 1 + CompositeTypeLegs CompositeType = 2 + CompositeTypeRightArm CompositeType = 3 + CompositeTypeLeftArm CompositeType = 4 + CompositeTypeRightHand CompositeType = 5 + CompositeTypeLeftHand CompositeType = 6 + CompositeTypeShield CompositeType = 7 + CompositeTypeSpecial1 CompositeType = 8 + CompositeTypeSpecial2 CompositeType = 9 + CompositeTypeSpecial3 CompositeType = 10 + CompositeTypeSpecial4 CompositeType = 11 + CompositeTypeSpecial5 CompositeType = 12 + CompositeTypeSpecial6 CompositeType = 13 + CompositeTypeSpecial7 CompositeType = 14 + CompositeTypeSpecial8 CompositeType = 15 + CompositeTypeMax CompositeType = 16 +) diff --git a/d2common/d2enum/DrawEffect.go b/d2common/d2enum/DrawEffect.go new file mode 100644 index 00000000..5e16c4fc --- /dev/null +++ b/d2common/d2enum/DrawEffect.go @@ -0,0 +1,12 @@ +package d2enum + +type DrawEffect int + +const ( + DrawEffectPctTransparency75 = 0 //75 % transparency (colormaps 561-816 in a .pl2) + DrawEffectPctTransparency50 = 1 //50 % transparency (colormaps 305-560 in a .pl2) + DrawEffectPctTransparency25 = 2 //25 % transparency (colormaps 49-304 in a .pl2) + DrawEffectScreen = 3 //Screen (colormaps 817-1072 in a .pl2) + DrawEffectLuminance = 4 //luminance (colormaps 1073-1328 in a .pl2) + DrawEffectBringAlphaBlending = 5 //bright alpha blending (colormaps 1457-1712 in a .pl2) +) diff --git a/common/Hero.go b/d2common/d2enum/Hero.go similarity index 93% rename from common/Hero.go rename to d2common/d2enum/Hero.go index a8280376..b45d5901 100644 --- a/common/Hero.go +++ b/d2common/d2enum/Hero.go @@ -1,4 +1,4 @@ -package common +package d2enum type Hero int diff --git a/d2common/d2enum/HeroStance.go b/d2common/d2enum/HeroStance.go new file mode 100644 index 00000000..d2c64385 --- /dev/null +++ b/d2common/d2enum/HeroStance.go @@ -0,0 +1,11 @@ +package d2enum + +type HeroStance int + +const ( + HeroStanceIdle HeroStance = 0 + HeroStanceIdleSelected HeroStance = 1 + HeroStanceApproaching HeroStance = 2 + HeroStanceSelected HeroStance = 3 + HeroStanceRetreating HeroStance = 4 +) diff --git a/map/Orientation.go b/d2common/d2enum/Orientation.go similarity index 98% rename from map/Orientation.go rename to d2common/d2enum/Orientation.go index bdbffd3d..79b777d4 100644 --- a/map/Orientation.go +++ b/d2common/d2enum/Orientation.go @@ -1,4 +1,4 @@ -package _map +package d2enum type Orientation int32 diff --git a/palettedefs/PaletteDefs.go b/d2common/d2enum/PaletteDefs.go similarity index 97% rename from palettedefs/PaletteDefs.go rename to d2common/d2enum/PaletteDefs.go index b3d7d1a7..805cf100 100644 --- a/palettedefs/PaletteDefs.go +++ b/d2common/d2enum/PaletteDefs.go @@ -1,4 +1,4 @@ -package palettedefs +package d2enum // PaletteType represents a named palette type PaletteType string diff --git a/d2common/d2enum/WeaponClass.go b/d2common/d2enum/WeaponClass.go new file mode 100644 index 00000000..4baa32d0 --- /dev/null +++ b/d2common/d2enum/WeaponClass.go @@ -0,0 +1,24 @@ +package d2enum + +type WeaponClass int + +const ( + WeaponClassNone WeaponClass = 0 // + WeaponClassHandToHand WeaponClass = 1 // hth + WeaponClassBow WeaponClass = 2 // bow + WeaponClassOneHandSwing WeaponClass = 3 // 1hs + WeaponClassOneHandThrust WeaponClass = 4 // 1ht + WeaponClassStaff WeaponClass = 5 // stf + WeaponClassTwoHandSwing WeaponClass = 6 // 2hs + WeaponClassTwoHandThrust WeaponClass = 7 // 2ht + WeaponClassCrossbow WeaponClass = 8 // xbw + WeaponClassLeftJabRightSwing WeaponClass = 9 // 1js + WeaponClassLeftJabRightThrust WeaponClass = 10 // 1jt + WeaponClassLeftSwingRightSwing WeaponClass = 11 // 1ss + WeaponClassLeftSwingRightThrust WeaponClass = 12 // 1st + WeaponClassOneHandToHand WeaponClass = 13 // ht1 + WeaponClassTwoHandToHand WeaponClass = 14 // ht2 +) + +//go:generate stringer -linecomment -type WeaponClass +//go:generate string2enum -samepkg -linecomment -type WeaponClass diff --git a/common/weaponclass_string.go b/d2common/d2enum/WeaponClass_string.go similarity index 98% rename from common/weaponclass_string.go rename to d2common/d2enum/WeaponClass_string.go index a697e681..84a331fd 100644 --- a/common/weaponclass_string.go +++ b/d2common/d2enum/WeaponClass_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -linecomment -type WeaponClass"; DO NOT EDIT. -package common +package d2enum import "strconv" diff --git a/common/weaponclass_string2enum.go b/d2common/d2enum/WeaponClass_string2enum.go similarity index 97% rename from common/weaponclass_string2enum.go rename to d2common/d2enum/WeaponClass_string2enum.go index f852d1d0..382e899d 100644 --- a/common/weaponclass_string2enum.go +++ b/d2common/d2enum/WeaponClass_string2enum.go @@ -1,6 +1,6 @@ // Code generated by "string2enum -samepkg -linecomment -type WeaponClass"; DO NOT EDIT. -package common +package d2enum import "fmt" diff --git a/d2common/d2enum/readme.md b/d2common/d2enum/readme.md new file mode 100644 index 00000000..fb53b5c5 --- /dev/null +++ b/d2common/d2enum/readme.md @@ -0,0 +1,17 @@ +# OpenDiablo2 Enums +Items in this folder are compiled with two programs. You can obtain them +by running the following: +``` +go get golang.org/x/tools/cmd/stringer +go get github.com/mewspring/tools/cmd/string2enum +``` +Once you have the tools installed, simply run the following command in this +folder to regenerate the support files: +``` +generate +``` +If you add any new files, make sure to add the following to the end of the +file: +```go +//go:generate stringer -linecomment -type AnimationMode +``` diff --git a/common/Drawable.go b/d2common/d2interface/Drawable.go similarity index 93% rename from common/Drawable.go rename to d2common/d2interface/Drawable.go index 1b6f1fb1..93946519 100644 --- a/common/Drawable.go +++ b/d2common/d2interface/Drawable.go @@ -1,4 +1,4 @@ -package common +package d2interface import "github.com/hajimehoshi/ebiten" diff --git a/d2common/d2interface/FileProvider.go b/d2common/d2interface/FileProvider.go new file mode 100644 index 00000000..08ff5f22 --- /dev/null +++ b/d2common/d2interface/FileProvider.go @@ -0,0 +1,7 @@ +package d2interface + +// FileProvider is an instance that can provide different types of files +type FileProvider interface { + LoadFile(fileName string) []byte + //LoadSprite(fileName string, palette enums.PaletteType) *d2render.Sprite +} diff --git a/scenes/Scene.go b/d2common/d2interface/Scene.go similarity index 91% rename from scenes/Scene.go rename to d2common/d2interface/Scene.go index 9b72ec73..187f67e7 100644 --- a/scenes/Scene.go +++ b/d2common/d2interface/Scene.go @@ -1,4 +1,4 @@ -package scenes +package d2interface import ( "github.com/hajimehoshi/ebiten" diff --git a/scenes/SceneProvider.go b/d2common/d2interface/SceneProvider.go similarity index 85% rename from scenes/SceneProvider.go rename to d2common/d2interface/SceneProvider.go index 8db8c464..926708f1 100644 --- a/scenes/SceneProvider.go +++ b/d2common/d2interface/SceneProvider.go @@ -1,4 +1,4 @@ -package scenes +package d2interface // SceneProvider provides the ability to change scenes type SceneProvider interface { diff --git a/core/Engine.go b/d2core/Engine.go similarity index 62% rename from core/Engine.go rename to d2core/Engine.go index ba28643d..4ecc7d1f 100644 --- a/core/Engine.go +++ b/d2core/Engine.go @@ -1,4 +1,4 @@ -package core +package d2core import ( "log" @@ -10,16 +10,24 @@ import ( "sync" "time" - "github.com/OpenDiablo2/OpenDiablo2/mpq" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" - "github.com/OpenDiablo2/OpenDiablo2/sound" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" - "github.com/OpenDiablo2/OpenDiablo2/scenes" - "github.com/OpenDiablo2/OpenDiablo2/ui" + "github.com/OpenDiablo2/OpenDiablo2/d2render" + + "github.com/OpenDiablo2/OpenDiablo2/d2data" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/mpq" + + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2render/ui" "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/ebitenutil" @@ -28,20 +36,20 @@ import ( // Engine is the core OpenDiablo2 engine type Engine struct { - Settings *common.Configuration // Engine configuration settings from json file - Files map[string]string // Map that defines which files are in which MPQs - CheckedPatch map[string]bool // First time we check a file, we'll check if it's in the patch. This notes that we've already checked that. - LoadingSprite *common.Sprite // The sprite shown when loading stuff - loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays. - loadingIndex int // Determines which load function is currently being called - thingsToLoad []func() // The load functions for the next scene - stepLoadingSize float64 // The size for each loading step - CurrentScene scenes.Scene // The current scene being rendered - UIManager *ui.Manager // The UI manager - SoundManager *sound.Manager // The sound manager - nextScene scenes.Scene // The next scene to be loaded at the end of the game loop - fullscreenKey bool // When true, the fullscreen toggle is still being pressed - lastTime float64 // Last time we updated the scene + Settings *d2common.Configuration // Engine configuration settings from json file + Files map[string]string // Map that defines which files are in which MPQs + CheckedPatch map[string]bool // First time we check a file, we'll check if it's in the patch. This notes that we've already checked that. + LoadingSprite *d2render.Sprite // The sprite shown when loading stuff + loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays. + loadingIndex int // Determines which load function is currently being called + thingsToLoad []func() // The load functions for the next scene + stepLoadingSize float64 // The size for each loading step + CurrentScene d2interface.Scene // The current scene being rendered + UIManager *ui.Manager // The UI manager + SoundManager *d2audio.Manager // The sound manager + nextScene d2interface.Scene // The next scene to be loaded at the end of the game loop + fullscreenKey bool // When true, the fullscreen toggle is still being pressed + lastTime float64 // Last time we updated the scene showFPS bool } @@ -52,36 +60,35 @@ func CreateEngine() *Engine { nextScene: nil, } result.loadConfigurationFile() - resourcepaths.LanguageCode = result.Settings.Language + d2common.LanguageCode = result.Settings.Language result.mapMpqFiles() - common.LoadPalettes(result.Files, result) - common.LoadTextDictionary(result) - common.LoadLevelTypes(result) - common.LoadLevelPresets(result) - common.LoadLevelWarps(result) - common.LoadObjectTypes(result) - common.LoadObjects(result) - common.LoadWeapons(result) - common.LoadArmors(result) - common.LoadUniqueItems(result) - common.LoadMissiles(result) - common.LoadSounds(result) - common.LoadAnimationData(result) - common.LoadMonStats(result) - result.SoundManager = sound.CreateManager(result) + datadict.LoadPalettes(result.Files, result) + d2common.LoadTextDictionary(result) + datadict.LoadLevelTypes(result) + datadict.LoadLevelPresets(result) + datadict.LoadLevelWarps(result) + datadict.LoadObjectTypes(result) + datadict.LoadObjects(result) + datadict.LoadWeapons(result) + datadict.LoadArmors(result) + datadict.LoadUniqueItems(result) + datadict.LoadMissiles(result) + datadict.LoadSounds(result) + d2data.LoadAnimationData(result) + datadict.LoadMonStats(result) + result.SoundManager = d2audio.CreateManager(result) result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume) result.UIManager = ui.CreateManager(result, *result.SoundManager) - result.LoadingSprite = result.LoadSprite(resourcepaths.LoadingScreen, palettedefs.Loading) + result.LoadingSprite = result.LoadSprite(d2common.LoadingScreen, d2enum.Loading) loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetSize() result.LoadingSprite.MoveTo(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2))) - result.SetNextScene(scenes.CreateMainMenu(result, result, result.UIManager, result.SoundManager)) //result.SetNextScene(Scenes.CreateBlizzardIntro(result, result)) return result } func (v *Engine) loadConfigurationFile() { log.Println("Loading configuration file") - v.Settings = common.LoadConfiguration() + v.Settings = d2common.LoadConfiguration() } func (v *Engine) mapMpqFiles() { @@ -91,7 +98,7 @@ func (v *Engine) mapMpqFiles() { var mutex sync.Mutex func (v *Engine) LoadFile(fileName string) []byte { - fileName = strings.ReplaceAll(fileName, "{LANG}", resourcepaths.LanguageCode) + fileName = strings.ReplaceAll(fileName, "{LANG}", d2common.LanguageCode) fileName = strings.ToLower(fileName) fileName = strings.ReplaceAll(fileName, `/`, "\\") if fileName[0] == '\\' { @@ -131,9 +138,9 @@ func (v *Engine) IsLoading() bool { } // LoadSprite loads a sprite from the game's data files -func (v *Engine) LoadSprite(fileName string, palette palettedefs.PaletteType) *common.Sprite { +func (v *Engine) LoadSprite(fileName string, palette d2enum.PaletteType) *d2render.Sprite { data := v.LoadFile(fileName) - sprite := common.CreateSprite(data, common.Palettes[palette]) + sprite := d2render.CreateSprite(data, datadict.Palettes[palette]) return sprite } @@ -208,7 +215,7 @@ func (v *Engine) Update() { // Draw draws the game func (v *Engine) Draw(screen *ebiten.Image) { if v.loadingProgress < 1.0 { - v.LoadingSprite.Frame = uint8(common.Max(0, common.Min(uint32(len(v.LoadingSprite.Frames)-1), uint32(float64(len(v.LoadingSprite.Frames)-1)*v.loadingProgress)))) + v.LoadingSprite.Frame = uint8(d2helper.Max(0, d2helper.Min(uint32(len(v.LoadingSprite.Frames)-1), uint32(float64(len(v.LoadingSprite.Frames)-1)*v.loadingProgress)))) v.LoadingSprite.Draw(screen) } else { if v.CurrentScene == nil { @@ -223,7 +230,7 @@ func (v *Engine) Draw(screen *ebiten.Image) { } // SetNextScene tells the engine what scene to load on the next update cycle -func (v *Engine) SetNextScene(nextScene scenes.Scene) { +func (v *Engine) SetNextScene(nextScene d2interface.Scene) { v.nextScene = nextScene } diff --git a/common/GameState.go b/d2core/GameState.go similarity index 94% rename from common/GameState.go rename to d2core/GameState.go index 9828294a..fa50229b 100644 --- a/common/GameState.go +++ b/d2core/GameState.go @@ -1,4 +1,4 @@ -package common +package d2core import ( "log" diff --git a/scenes/BlizzardIntro.go b/d2core/scenes/BlizzardIntro.go similarity index 66% rename from scenes/BlizzardIntro.go rename to d2core/scenes/BlizzardIntro.go index 5152cbd9..14d23400 100644 --- a/scenes/BlizzardIntro.go +++ b/d2core/scenes/BlizzardIntro.go @@ -1,18 +1,18 @@ package scenes import ( - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/video" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2data/video" "github.com/hajimehoshi/ebiten" ) type BlizzardIntro struct { - fileProvider common.FileProvider - sceneProvider SceneProvider + fileProvider d2interface.FileProvider + sceneProvider d2interface.SceneProvider videoDecoder *video.BinkDecoder } -func CreateBlizzardIntro(fileProvider common.FileProvider, sceneProvider SceneProvider) *BlizzardIntro { +func CreateBlizzardIntro(fileProvider d2interface.FileProvider, sceneProvider d2interface.SceneProvider) *BlizzardIntro { result := &BlizzardIntro{ fileProvider: fileProvider, sceneProvider: sceneProvider, diff --git a/scenes/CharacterSelect.go b/d2core/scenes/CharacterSelect.go similarity index 64% rename from scenes/CharacterSelect.go rename to d2core/scenes/CharacterSelect.go index 5750d65a..3ee72c78 100644 --- a/scenes/CharacterSelect.go +++ b/d2core/scenes/CharacterSelect.go @@ -1,20 +1,23 @@ package scenes import ( - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" - "github.com/OpenDiablo2/OpenDiablo2/sound" - "github.com/OpenDiablo2/OpenDiablo2/ui" + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" + "github.com/OpenDiablo2/OpenDiablo2/d2render" + "github.com/OpenDiablo2/OpenDiablo2/d2render/ui" "github.com/hajimehoshi/ebiten" ) type CharacterSelect struct { uiManager *ui.Manager - soundManager *sound.Manager - fileProvider common.FileProvider - sceneProvider SceneProvider - background *common.Sprite + soundManager *d2audio.Manager + fileProvider d2interface.FileProvider + sceneProvider d2interface.SceneProvider + background *d2render.Sprite newCharButton *ui.Button convertCharButton *ui.Button deleteCharButton *ui.Button @@ -23,10 +26,10 @@ type CharacterSelect struct { } func CreateCharacterSelect( - fileProvider common.FileProvider, - sceneProvider SceneProvider, + fileProvider d2interface.FileProvider, + sceneProvider d2interface.SceneProvider, uiManager *ui.Manager, - soundManager *sound.Manager, + soundManager *d2audio.Manager, ) *CharacterSelect { result := &CharacterSelect{ uiManager: uiManager, @@ -38,38 +41,38 @@ func CreateCharacterSelect( } func (v *CharacterSelect) Load() []func() { - v.soundManager.PlayBGM(resourcepaths.BGMTitle) + v.soundManager.PlayBGM(d2common.BGMTitle) return []func(){ func() { - v.background = v.fileProvider.LoadSprite(resourcepaths.CharacterSelectionBackground, palettedefs.Sky) + v.background = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.CharacterSelectionBackground), datadict.Palettes[d2enum.Sky]) v.background.MoveTo(0, 0) }, func() { - v.newCharButton = ui.CreateButton(ui.ButtonTypeTall, v.fileProvider, common.CombineStrings(common.SplitIntoLinesWithMaxWidth(common.TranslateString("#831"), 15))) + v.newCharButton = ui.CreateButton(ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#831"), 15))) v.newCharButton.MoveTo(33, 468) v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() }) v.uiManager.AddWidget(v.newCharButton) }, func() { - v.convertCharButton = ui.CreateButton(ui.ButtonTypeTall, v.fileProvider, common.CombineStrings(common.SplitIntoLinesWithMaxWidth(common.TranslateString("#825"), 15))) + v.convertCharButton = ui.CreateButton(ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#825"), 15))) v.convertCharButton.MoveTo(233, 468) v.convertCharButton.SetEnabled(false) v.uiManager.AddWidget(v.convertCharButton) }, func() { - v.deleteCharButton = ui.CreateButton(ui.ButtonTypeTall, v.fileProvider, common.CombineStrings(common.SplitIntoLinesWithMaxWidth(common.TranslateString("#832"), 15))) + v.deleteCharButton = ui.CreateButton(ui.ButtonTypeTall, v.fileProvider, dh.CombineStrings(dh.SplitIntoLinesWithMaxWidth(d2common.TranslateString("#832"), 15))) v.deleteCharButton.MoveTo(433, 468) v.deleteCharButton.SetEnabled(false) v.uiManager.AddWidget(v.deleteCharButton) }, func() { - v.exitButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, common.TranslateString("#970")) + v.exitButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970")) v.exitButton.MoveTo(33, 537) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) v.uiManager.AddWidget(v.exitButton) }, func() { - v.okButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, common.TranslateString("#971")) + v.okButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#971")) v.okButton.MoveTo(625, 537) v.okButton.SetEnabled(false) v.uiManager.AddWidget(v.okButton) diff --git a/scenes/Credits.go b/d2core/scenes/Credits.go similarity index 80% rename from scenes/Credits.go rename to d2core/scenes/Credits.go index 009fcb1b..02609c4b 100644 --- a/scenes/Credits.go +++ b/d2core/scenes/Credits.go @@ -4,11 +4,18 @@ import ( "image/color" "strings" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" - "github.com/OpenDiablo2/OpenDiablo2/sound" - "github.com/OpenDiablo2/OpenDiablo2/ui" + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2render" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" + "github.com/OpenDiablo2/OpenDiablo2/d2render/ui" "github.com/hajimehoshi/ebiten" ) @@ -21,10 +28,10 @@ type labelItem struct { // Credits represents the credits scene type Credits struct { uiManager *ui.Manager - soundManager *sound.Manager - fileProvider common.FileProvider - sceneProvider SceneProvider - creditsBackground *common.Sprite + soundManager *d2audio.Manager + fileProvider d2interface.FileProvider + sceneProvider d2interface.SceneProvider + creditsBackground *d2render.Sprite exitButton *ui.Button creditsText []string labels []*labelItem @@ -34,7 +41,7 @@ type Credits struct { } // CreateCredits creates an instance of the credits scene -func CreateCredits(fileProvider common.FileProvider, sceneProvider SceneProvider, uiManager *ui.Manager, soundManager *sound.Manager) *Credits { +func CreateCredits(fileProvider d2interface.FileProvider, sceneProvider d2interface.SceneProvider, uiManager *ui.Manager, soundManager *d2audio.Manager) *Credits { result := &Credits{ fileProvider: fileProvider, uiManager: uiManager, @@ -52,17 +59,17 @@ func CreateCredits(fileProvider common.FileProvider, sceneProvider SceneProvider func (v *Credits) Load() []func() { return []func(){ func() { - v.creditsBackground = v.fileProvider.LoadSprite(resourcepaths.CreditsBackground, palettedefs.Sky) + v.creditsBackground = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.CreditsBackground), datadict.Palettes[d2enum.Sky]) v.creditsBackground.MoveTo(0, 0) }, func() { - v.exitButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, common.TranslateString("#970")) + v.exitButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970")) v.exitButton.MoveTo(30, 550) v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) v.uiManager.AddWidget(v.exitButton) }, func() { - fileData, _ := common.Utf16BytesToString(v.fileProvider.LoadFile(resourcepaths.CreditsText)[2:]) + fileData, _ := dh.Utf16BytesToString(v.fileProvider.LoadFile(d2common.CreditsText)[2:]) v.creditsText = strings.Split(fileData, "\r\n") for i := range v.creditsText { v.creditsText[i] = strings.Trim(v.creditsText[i], " ") @@ -190,7 +197,7 @@ func (v *Credits) getNewFontLabel(isHeading bool) *ui.Label { newLabelItem := &labelItem{ Available: false, IsHeading: isHeading, - Label: ui.CreateLabel(v.fileProvider, resourcepaths.FontFormal10, palettedefs.Sky), + Label: ui.CreateLabel(v.fileProvider, d2common.FontFormal10, d2enum.Sky), } if isHeading { diff --git a/scenes/MainMenu.go b/d2core/scenes/MainMenu.go similarity index 71% rename from scenes/MainMenu.go rename to d2core/scenes/MainMenu.go index dcd6dcab..c16a8b91 100644 --- a/scenes/MainMenu.go +++ b/d2core/scenes/MainMenu.go @@ -8,27 +8,33 @@ import ( "os/exec" "runtime" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - "github.com/OpenDiablo2/OpenDiablo2/sound" - "github.com/OpenDiablo2/OpenDiablo2/ui" + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2render" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2render/ui" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/hajimehoshi/ebiten" ) // MainMenu represents the main menu type MainMenu struct { uiManager *ui.Manager - soundManager *sound.Manager - fileProvider common.FileProvider - sceneProvider SceneProvider - trademarkBackground *common.Sprite - background *common.Sprite - diabloLogoLeft *common.Sprite - diabloLogoRight *common.Sprite - diabloLogoLeftBack *common.Sprite - diabloLogoRightBack *common.Sprite + soundManager *d2audio.Manager + fileProvider d2interface.FileProvider + sceneProvider d2interface.SceneProvider + trademarkBackground *d2render.Sprite + background *d2render.Sprite + diabloLogoLeft *d2render.Sprite + diabloLogoRight *d2render.Sprite + diabloLogoLeftBack *d2render.Sprite + diabloLogoRightBack *d2render.Sprite singlePlayerButton *ui.Button githubButton *ui.Button exitDiabloButton *ui.Button @@ -46,7 +52,7 @@ type MainMenu struct { } // CreateMainMenu creates an instance of MainMenu -func CreateMainMenu(fileProvider common.FileProvider, sceneProvider SceneProvider, uiManager *ui.Manager, soundManager *sound.Manager) *MainMenu { +func CreateMainMenu(fileProvider d2interface.FileProvider, sceneProvider d2interface.SceneProvider, uiManager *ui.Manager, soundManager *d2audio.Manager) *MainMenu { result := &MainMenu{ fileProvider: fileProvider, uiManager: uiManager, @@ -60,93 +66,93 @@ func CreateMainMenu(fileProvider common.FileProvider, sceneProvider SceneProvide // Load is called to load the resources for the main menu func (v *MainMenu) Load() []func() { - v.soundManager.PlayBGM(resourcepaths.BGMTitle) + v.soundManager.PlayBGM(d2common.BGMTitle) return []func(){ func() { - v.versionLabel = ui.CreateLabel(v.fileProvider, resourcepaths.FontFormal12, palettedefs.Static) + v.versionLabel = ui.CreateLabel(v.fileProvider, d2common.FontFormal12, d2enum.Static) v.versionLabel.Alignment = ui.LabelAlignRight - v.versionLabel.SetText("OpenDiablo2 - " + common.BuildInfo.Branch) + v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch) v.versionLabel.Color = color.RGBA{255, 255, 255, 255} v.versionLabel.MoveTo(795, -10) }, func() { - v.commitLabel = ui.CreateLabel(v.fileProvider, resourcepaths.FontFormal10, palettedefs.Static) + v.commitLabel = ui.CreateLabel(v.fileProvider, d2common.FontFormal10, d2enum.Static) v.commitLabel.Alignment = ui.LabelAlignLeft - v.commitLabel.SetText(common.BuildInfo.Commit) + v.commitLabel.SetText(d2common.BuildInfo.Commit) v.commitLabel.Color = color.RGBA{255, 255, 255, 255} v.commitLabel.MoveTo(2, 2) }, func() { - v.copyrightLabel = ui.CreateLabel(v.fileProvider, resourcepaths.FontFormal12, palettedefs.Static) + v.copyrightLabel = ui.CreateLabel(v.fileProvider, d2common.FontFormal12, d2enum.Static) v.copyrightLabel.Alignment = ui.LabelAlignCenter v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment") v.copyrightLabel.Color = color.RGBA{188, 168, 140, 255} v.copyrightLabel.MoveTo(400, 500) }, func() { - v.copyrightLabel2 = ui.CreateLabel(v.fileProvider, resourcepaths.FontFormal12, palettedefs.Static) + v.copyrightLabel2 = ui.CreateLabel(v.fileProvider, d2common.FontFormal12, d2enum.Static) v.copyrightLabel2.Alignment = ui.LabelAlignCenter - v.copyrightLabel2.SetText(common.TranslateString("#1614")) + v.copyrightLabel2.SetText(d2common.TranslateString("#1614")) v.copyrightLabel2.Color = color.RGBA{188, 168, 140, 255} v.copyrightLabel2.MoveTo(400, 525) }, func() { - v.openDiabloLabel = ui.CreateLabel(v.fileProvider, resourcepaths.FontFormal10, palettedefs.Static) + v.openDiabloLabel = ui.CreateLabel(v.fileProvider, d2common.FontFormal10, d2enum.Static) v.openDiabloLabel.Alignment = ui.LabelAlignCenter v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision") v.openDiabloLabel.Color = color.RGBA{255, 255, 140, 255} v.openDiabloLabel.MoveTo(400, 580) }, func() { - v.background = v.fileProvider.LoadSprite(resourcepaths.GameSelectScreen, palettedefs.Sky) + v.background = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.GameSelectScreen), datadict.Palettes[d2enum.Sky]) v.background.MoveTo(0, 0) }, func() { - v.trademarkBackground = v.fileProvider.LoadSprite(resourcepaths.TrademarkScreen, palettedefs.Sky) + v.trademarkBackground = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.TrademarkScreen), datadict.Palettes[d2enum.Sky]) v.trademarkBackground.MoveTo(0, 0) }, func() { - v.diabloLogoLeft = v.fileProvider.LoadSprite(resourcepaths.Diablo2LogoFireLeft, palettedefs.Units) + v.diabloLogoLeft = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.Diablo2LogoFireLeft), datadict.Palettes[d2enum.Units]) v.diabloLogoLeft.Blend = true v.diabloLogoLeft.Animate = true v.diabloLogoLeft.MoveTo(400, 120) }, func() { - v.diabloLogoRight = v.fileProvider.LoadSprite(resourcepaths.Diablo2LogoFireRight, palettedefs.Units) + v.diabloLogoRight = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.Diablo2LogoFireRight), datadict.Palettes[d2enum.Units]) v.diabloLogoRight.Blend = true v.diabloLogoRight.Animate = true v.diabloLogoRight.MoveTo(400, 120) }, func() { - v.diabloLogoLeftBack = v.fileProvider.LoadSprite(resourcepaths.Diablo2LogoBlackLeft, palettedefs.Units) + v.diabloLogoLeftBack = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.Diablo2LogoBlackLeft), datadict.Palettes[d2enum.Units]) v.diabloLogoLeftBack.MoveTo(400, 120) }, func() { - v.diabloLogoRightBack = v.fileProvider.LoadSprite(resourcepaths.Diablo2LogoBlackRight, palettedefs.Units) + v.diabloLogoRightBack = d2render.CreateSprite(v.fileProvider.LoadFile(d2common.Diablo2LogoBlackRight), datadict.Palettes[d2enum.Units]) v.diabloLogoRightBack.MoveTo(400, 120) }, func() { - v.exitDiabloButton = ui.CreateButton(ui.ButtonTypeWide, v.fileProvider, common.TranslateString("#1625")) + v.exitDiabloButton = ui.CreateButton(ui.ButtonTypeWide, v.fileProvider, d2common.TranslateString("#1625")) v.exitDiabloButton.MoveTo(264, 535) v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen) v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() }) v.uiManager.AddWidget(v.exitDiabloButton) }, func() { - v.creditsButton = ui.CreateButton(ui.ButtonTypeShort, v.fileProvider, common.TranslateString("#1627")) + v.creditsButton = ui.CreateButton(ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1627")) v.creditsButton.MoveTo(264, 505) v.creditsButton.SetVisible(!v.ShowTrademarkScreen) v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() }) v.uiManager.AddWidget(v.creditsButton) }, func() { - v.cinematicsButton = ui.CreateButton(ui.ButtonTypeShort, v.fileProvider, common.TranslateString("#1639")) + v.cinematicsButton = ui.CreateButton(ui.ButtonTypeShort, v.fileProvider, d2common.TranslateString("#1639")) v.cinematicsButton.MoveTo(401, 505) v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen) v.uiManager.AddWidget(v.cinematicsButton) }, func() { - v.singlePlayerButton = ui.CreateButton(ui.ButtonTypeWide, v.fileProvider, common.TranslateString("#1620")) + v.singlePlayerButton = ui.CreateButton(ui.ButtonTypeWide, v.fileProvider, d2common.TranslateString("#1620")) v.singlePlayerButton.MoveTo(264, 290) v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen) v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() }) @@ -194,7 +200,6 @@ func openbrowser(url string) { func (v *MainMenu) onSinglePlayerClicked() { // Go here only if existing characters are available to select - //v.sceneProvider.SetNextScene(CreateCharacterSelect(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)) v.sceneProvider.SetNextScene(CreateSelectHeroClass(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)) } diff --git a/scenes/MapEngineTest.go b/d2core/scenes/MapEngineTest.go similarity index 80% rename from scenes/MapEngineTest.go rename to d2core/scenes/MapEngineTest.go index 5c851f05..47d042c3 100644 --- a/scenes/MapEngineTest.go +++ b/d2core/scenes/MapEngineTest.go @@ -4,35 +4,40 @@ import ( "fmt" "math" - "github.com/OpenDiablo2/OpenDiablo2/common" - _map "github.com/OpenDiablo2/OpenDiablo2/map" - "github.com/OpenDiablo2/OpenDiablo2/sound" - "github.com/OpenDiablo2/OpenDiablo2/ui" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2core" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + _map "github.com/OpenDiablo2/OpenDiablo2/d2render/mapengine" + "github.com/OpenDiablo2/OpenDiablo2/d2render/ui" "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/ebitenutil" ) type MapEngineTest struct { uiManager *ui.Manager - soundManager *sound.Manager - fileProvider common.FileProvider - sceneProvider SceneProvider - gameState *common.GameState + soundManager *d2audio.Manager + fileProvider d2interface.FileProvider + sceneProvider d2interface.SceneProvider + gameState *d2core.GameState mapEngine *_map.Engine } func CreateMapEngineTest( - fileProvider common.FileProvider, - sceneProvider SceneProvider, + fileProvider d2interface.FileProvider, + sceneProvider d2interface.SceneProvider, uiManager *ui.Manager, - soundManager *sound.Manager) *MapEngineTest { + soundManager *d2audio.Manager) *MapEngineTest { result := &MapEngineTest{ fileProvider: fileProvider, uiManager: uiManager, soundManager: soundManager, sceneProvider: sceneProvider, } - result.gameState = common.CreateGameState() + result.gameState = d2core.CreateGameState() return result } @@ -70,7 +75,7 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) { v.mapEngine.Render(screen) actualX := float64(v.uiManager.CursorX) - v.mapEngine.OffsetX actualY := float64(v.uiManager.CursorY) - v.mapEngine.OffsetY - tileX, tileY := common.ScreenToIso(actualX, actualY) + tileX, tileY := d2helper.ScreenToIso(actualX, actualY) subtileX := int(math.Ceil(math.Mod((tileX*10), 10))) / 2 subtileY := int(math.Ceil(math.Mod((tileY*10), 10))) / 2 curRegion := v.mapEngine.GetRegionAt(int(tileX), int(tileY)) diff --git a/d2core/scenes/SelectHeroClass.go b/d2core/scenes/SelectHeroClass.go new file mode 100644 index 00000000..2b3342e4 --- /dev/null +++ b/d2core/scenes/SelectHeroClass.go @@ -0,0 +1,568 @@ +package scenes + +import ( + "image" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + + "github.com/OpenDiablo2/OpenDiablo2/d2render" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" + "github.com/OpenDiablo2/OpenDiablo2/d2render/ui" + "github.com/hajimehoshi/ebiten" +) + +type HeroRenderInfo struct { + Stance d2enum.HeroStance + IdleSprite *d2render.Sprite + IdleSelectedSprite *d2render.Sprite + ForwardWalkSprite *d2render.Sprite + ForwardWalkSpriteOverlay *d2render.Sprite + SelectedSprite *d2render.Sprite + SelectedSpriteOverlay *d2render.Sprite + BackWalkSprite *d2render.Sprite + BackWalkSpriteOverlay *d2render.Sprite + SelectionBounds image.Rectangle + SelectSfx *d2audio.SoundEffect + DeselectSfx *d2audio.SoundEffect +} + +type SelectHeroClass struct { + uiManager *ui.Manager + soundManager *d2audio.Manager + fileProvider d2interface.FileProvider + sceneProvider d2interface.SceneProvider + bgImage *d2render.Sprite + campfire *d2render.Sprite + headingLabel *ui.Label + heroClassLabel *ui.Label + heroDesc1Label *ui.Label + heroDesc2Label *ui.Label + heroDesc3Label *ui.Label + heroRenderInfo map[d2enum.Hero]*HeroRenderInfo + selectedHero d2enum.Hero + exitButton *ui.Button +} + +func CreateSelectHeroClass( + fileProvider d2interface.FileProvider, + sceneProvider d2interface.SceneProvider, + uiManager *ui.Manager, soundManager *d2audio.Manager, +) *SelectHeroClass { + result := &SelectHeroClass{ + uiManager: uiManager, + sceneProvider: sceneProvider, + fileProvider: fileProvider, + soundManager: soundManager, + heroRenderInfo: make(map[d2enum.Hero]*HeroRenderInfo), + selectedHero: d2enum.HeroNone, + } + return result +} + +func (v *SelectHeroClass) loadSprite(path string, palette d2enum.PaletteType) *d2render.Sprite { + return d2render.CreateSprite(v.fileProvider.LoadFile(path), datadict.Palettes[palette]) +} + +func (v *SelectHeroClass) Load() []func() { + v.soundManager.PlayBGM(d2common.BGMTitle) + return []func(){ + func() { + v.bgImage = v.loadSprite(d2common.CharacterSelectBackground, d2enum.Fechar) + v.bgImage.MoveTo(0, 0) + }, + func() { + v.headingLabel = ui.CreateLabel(v.fileProvider, d2common.Font30, d2enum.Units) + fontWidth, _ := v.headingLabel.GetSize() + v.headingLabel.MoveTo(400-int(fontWidth/2), 17) + v.headingLabel.SetText("Select Hero Class") + v.headingLabel.Alignment = ui.LabelAlignCenter + }, + func() { + v.heroClassLabel = ui.CreateLabel(v.fileProvider, d2common.Font30, d2enum.Units) + v.heroClassLabel.Alignment = ui.LabelAlignCenter + v.heroClassLabel.MoveTo(400, 65) + }, + func() { + v.heroDesc1Label = ui.CreateLabel(v.fileProvider, d2common.Font16, d2enum.Units) + v.heroDesc1Label.Alignment = ui.LabelAlignCenter + v.heroDesc1Label.MoveTo(400, 100) + }, + func() { + v.heroDesc2Label = ui.CreateLabel(v.fileProvider, d2common.Font16, d2enum.Units) + v.heroDesc2Label.Alignment = ui.LabelAlignCenter + v.heroDesc2Label.MoveTo(400, 115) + }, + func() { + v.heroDesc3Label = ui.CreateLabel(v.fileProvider, d2common.Font16, d2enum.Units) + v.heroDesc3Label.Alignment = ui.LabelAlignCenter + v.heroDesc3Label.MoveTo(400, 130) + }, + func() { + v.campfire = v.loadSprite(d2common.CharacterSelectCampfire, d2enum.Fechar) + v.campfire.MoveTo(380, 335) + v.campfire.Animate = true + v.campfire.Blend = true + }, + func() { + v.exitButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, d2common.TranslateString("#970")) + v.exitButton.MoveTo(33, 537) + v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) + v.uiManager.AddWidget(v.exitButton) + }, + func() { + v.heroRenderInfo[d2enum.HeroBarbarian] = &HeroRenderInfo{ + d2enum.HeroStanceIdle, + v.loadSprite(d2common.CharacterSelectBarbarianUnselected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectBarbarianUnselectedH, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectBarbarianForwardWalk, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectBarbarianForwardWalkOverlay, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectBarbarianSelected, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelectBarbarianBackWalk, d2enum.Fechar), + nil, + image.Rectangle{Min: image.Point{364, 201}, Max: image.Point{90, 170}}, + v.soundManager.LoadSoundEffect(d2common.SFXBarbarianSelect), + v.soundManager.LoadSoundEffect(d2common.SFXBarbarianDeselect), + } + v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.MoveTo(400, 330) + v.heroRenderInfo[d2enum.HeroBarbarian].IdleSprite.Animate = true + v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.MoveTo(400, 330) + v.heroRenderInfo[d2enum.HeroBarbarian].IdleSelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.MoveTo(400, 330) + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.SpecialFrameTime = 2500 + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.MoveTo(400, 330) + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.SpecialFrameTime = 2500 + v.heroRenderInfo[d2enum.HeroBarbarian].ForwardWalkSpriteOverlay.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.MoveTo(400, 330) + v.heroRenderInfo[d2enum.HeroBarbarian].SelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.MoveTo(400, 330) + v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.SpecialFrameTime = 1000 + v.heroRenderInfo[d2enum.HeroBarbarian].BackWalkSprite.StopOnLastFrame = true + }, + func() { + v.heroRenderInfo[d2enum.HeroSorceress] = &HeroRenderInfo{ + d2enum.HeroStanceIdle, + v.loadSprite(d2common.CharacterSelecSorceressUnselected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecSorceressUnselectedH, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecSorceressForwardWalk, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecSorceressForwardWalkOverlay, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecSorceressSelected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecSorceressSelectedOverlay, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecSorceressBackWalk, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecSorceressBackWalkOverlay, d2enum.Fechar), + image.Rectangle{Min: image.Point{580, 240}, Max: image.Point{65, 160}}, + v.soundManager.LoadSoundEffect(d2common.SFXSorceressSelect), + v.soundManager.LoadSoundEffect(d2common.SFXSorceressDeselect), + } + v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].IdleSprite.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].IdleSelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.SpecialFrameTime = 2300 + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.Blend = true + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.SpecialFrameTime = 2300 + v.heroRenderInfo[d2enum.HeroSorceress].ForwardWalkSpriteOverlay.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].SelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.Blend = true + v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].SelectedSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.SpecialFrameTime = 1200 + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.Blend = true + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.MoveTo(626, 352) + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.SpecialFrameTime = 1200 + v.heroRenderInfo[d2enum.HeroSorceress].BackWalkSpriteOverlay.StopOnLastFrame = true + }, + func() { + v.heroRenderInfo[d2enum.HeroNecromancer] = &HeroRenderInfo{ + d2enum.HeroStanceIdle, + v.loadSprite(d2common.CharacterSelectNecromancerUnselected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectNecromancerUnselectedH, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecNecromancerForwardWalk, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecNecromancerForwardWalkOverlay, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecNecromancerSelected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecNecromancerSelectedOverlay, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecNecromancerBackWalk, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecNecromancerBackWalkOverlay, d2enum.Fechar), + image.Rectangle{Min: image.Point{265, 220}, Max: image.Point{55, 175}}, + v.soundManager.LoadSoundEffect(d2common.SFXNecromancerSelect), + v.soundManager.LoadSoundEffect(d2common.SFXNecromancerDeselect), + } + v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].IdleSprite.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].IdleSelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.SpecialFrameTime = 2000 + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.Blend = true + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.SpecialFrameTime = 2000 + v.heroRenderInfo[d2enum.HeroNecromancer].ForwardWalkSpriteOverlay.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.Blend = true + v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].SelectedSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.SpecialFrameTime = 1500 + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.Blend = true + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.MoveTo(300, 335) + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.SpecialFrameTime = 1500 + v.heroRenderInfo[d2enum.HeroNecromancer].BackWalkSpriteOverlay.StopOnLastFrame = true + }, + func() { + v.heroRenderInfo[d2enum.HeroPaladin] = &HeroRenderInfo{ + d2enum.HeroStanceIdle, + v.loadSprite(d2common.CharacterSelectPaladinUnselected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectPaladinUnselectedH, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecPaladinForwardWalk, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecPaladinForwardWalkOverlay, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecPaladinSelected, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelecPaladinBackWalk, d2enum.Fechar), + nil, + image.Rectangle{Min: image.Point{490, 210}, Max: image.Point{65, 180}}, + v.soundManager.LoadSoundEffect(d2common.SFXPaladinSelect), + v.soundManager.LoadSoundEffect(d2common.SFXPaladinDeselect), + } + v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.MoveTo(521, 338) + v.heroRenderInfo[d2enum.HeroPaladin].IdleSprite.Animate = true + v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.MoveTo(521, 338) + v.heroRenderInfo[d2enum.HeroPaladin].IdleSelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.MoveTo(521, 338) + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.SpecialFrameTime = 3400 + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.MoveTo(521, 338) + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.Animate = true + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.SpecialFrameTime = 3400 + v.heroRenderInfo[d2enum.HeroPaladin].ForwardWalkSpriteOverlay.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.MoveTo(521, 338) + v.heroRenderInfo[d2enum.HeroPaladin].SelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.MoveTo(521, 338) + v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.SpecialFrameTime = 1300 + v.heroRenderInfo[d2enum.HeroPaladin].BackWalkSprite.StopOnLastFrame = true + }, + func() { + v.heroRenderInfo[d2enum.HeroAmazon] = &HeroRenderInfo{ + d2enum.HeroStanceIdle, + v.loadSprite(d2common.CharacterSelectAmazonUnselected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectAmazonUnselectedH, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelecAmazonForwardWalk, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelecAmazonSelected, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelecAmazonBackWalk, d2enum.Fechar), + nil, + image.Rectangle{Min: image.Point{70, 220}, Max: image.Point{55, 200}}, + v.soundManager.LoadSoundEffect(d2common.SFXAmazonSelect), + v.soundManager.LoadSoundEffect(d2common.SFXAmazonDeselect), + } + v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.MoveTo(100, 339) + v.heroRenderInfo[d2enum.HeroAmazon].IdleSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.MoveTo(100, 339) + v.heroRenderInfo[d2enum.HeroAmazon].IdleSelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.MoveTo(100, 339) + v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.SpecialFrameTime = 2200 + v.heroRenderInfo[d2enum.HeroAmazon].ForwardWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.MoveTo(100, 339) + v.heroRenderInfo[d2enum.HeroAmazon].SelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.MoveTo(100, 339) + v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.SpecialFrameTime = 1500 + v.heroRenderInfo[d2enum.HeroAmazon].BackWalkSprite.StopOnLastFrame = true + }, + func() { + v.heroRenderInfo[d2enum.HeroAssassin] = &HeroRenderInfo{ + d2enum.HeroStanceIdle, + v.loadSprite(d2common.CharacterSelectAssassinUnselected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectAssassinUnselectedH, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectAssassinForwardWalk, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelectAssassinSelected, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelectAssassinBackWalk, d2enum.Fechar), + nil, + image.Rectangle{Min: image.Point{175, 235}, Max: image.Point{50, 180}}, + v.soundManager.LoadSoundEffect(d2common.SFXAssassinSelect), + v.soundManager.LoadSoundEffect(d2common.SFXAssassinDeselect), + } + v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.MoveTo(231, 365) + v.heroRenderInfo[d2enum.HeroAssassin].IdleSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.MoveTo(231, 365) + v.heroRenderInfo[d2enum.HeroAssassin].IdleSelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.MoveTo(231, 365) + v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.SpecialFrameTime = 3800 + v.heroRenderInfo[d2enum.HeroAssassin].ForwardWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.MoveTo(231, 365) + v.heroRenderInfo[d2enum.HeroAssassin].SelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.MoveTo(231, 365) + v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.SpecialFrameTime = 1500 + v.heroRenderInfo[d2enum.HeroAssassin].BackWalkSprite.StopOnLastFrame = true + }, + func() { + v.heroRenderInfo[d2enum.HeroDruid] = &HeroRenderInfo{ + d2enum.HeroStanceIdle, + v.loadSprite(d2common.CharacterSelectDruidUnselected, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectDruidUnselectedH, d2enum.Fechar), + v.loadSprite(d2common.CharacterSelectDruidForwardWalk, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelectDruidSelected, d2enum.Fechar), + nil, + v.loadSprite(d2common.CharacterSelectDruidBackWalk, d2enum.Fechar), + nil, + image.Rectangle{Min: image.Point{680, 220}, Max: image.Point{70, 195}}, + v.soundManager.LoadSoundEffect(d2common.SFXDruidSelect), + v.soundManager.LoadSoundEffect(d2common.SFXDruidDeselect), + } + v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.MoveTo(720, 370) + v.heroRenderInfo[d2enum.HeroDruid].IdleSprite.Animate = true + v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.MoveTo(720, 370) + v.heroRenderInfo[d2enum.HeroDruid].IdleSelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.MoveTo(720, 370) + v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.SpecialFrameTime = 4800 + v.heroRenderInfo[d2enum.HeroDruid].ForwardWalkSprite.StopOnLastFrame = true + v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.MoveTo(720, 370) + v.heroRenderInfo[d2enum.HeroDruid].SelectedSprite.Animate = true + v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.MoveTo(720, 370) + v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.Animate = true + v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.SpecialFrameTime = 1500 + v.heroRenderInfo[d2enum.HeroDruid].BackWalkSprite.StopOnLastFrame = true + }, + } +} + +func (v *SelectHeroClass) Unload() { + v.heroRenderInfo = nil +} + +func (v *SelectHeroClass) onExitButtonClicked() { + v.sceneProvider.SetNextScene(CreateCharacterSelect(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)) +} + +func (v *SelectHeroClass) Render(screen *ebiten.Image) { + v.bgImage.DrawSegments(screen, 4, 3, 0) + v.headingLabel.Draw(screen) + if v.selectedHero != d2enum.HeroNone { + v.heroClassLabel.Draw(screen) + v.heroDesc1Label.Draw(screen) + v.heroDesc2Label.Draw(screen) + v.heroDesc3Label.Draw(screen) + } + for heroClass, heroInfo := range v.heroRenderInfo { + if heroInfo.Stance == d2enum.HeroStanceIdle || heroInfo.Stance == d2enum.HeroStanceIdleSelected { + v.renderHero(screen, heroClass) + } + } + for heroClass, heroInfo := range v.heroRenderInfo { + if heroInfo.Stance != d2enum.HeroStanceIdle && heroInfo.Stance != d2enum.HeroStanceIdleSelected { + v.renderHero(screen, heroClass) + } + } + v.campfire.Draw(screen) +} + +func (v *SelectHeroClass) Update(tickTime float64) { + canSelect := true + for _, info := range v.heroRenderInfo { + if info.Stance != d2enum.HeroStanceIdle && info.Stance != d2enum.HeroStanceIdleSelected && info.Stance != d2enum.HeroStanceSelected { + canSelect = false + break + } + } + allIdle := true + for heroType, data := range v.heroRenderInfo { + if allIdle && data.Stance != d2enum.HeroStanceIdle { + allIdle = false + } + v.updateHeroSelectionHover(heroType, canSelect) + } + if v.selectedHero != d2enum.HeroNone && allIdle { + v.selectedHero = d2enum.HeroNone + } +} + +func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect bool) { + renderInfo := v.heroRenderInfo[hero] + switch renderInfo.Stance { + case d2enum.HeroStanceApproaching: + if renderInfo.ForwardWalkSprite.OnLastFrame() { + renderInfo.Stance = d2enum.HeroStanceSelected + renderInfo.SelectedSprite.ResetAnimation() + if renderInfo.SelectedSpriteOverlay != nil { + renderInfo.SelectedSpriteOverlay.ResetAnimation() + } + } + return + case d2enum.HeroStanceRetreating: + if renderInfo.BackWalkSprite.OnLastFrame() { + renderInfo.Stance = d2enum.HeroStanceIdle + renderInfo.IdleSprite.ResetAnimation() + } + return + } + if !canSelect { + return + } + if renderInfo.Stance == d2enum.HeroStanceSelected { + return + } + mouseX := v.uiManager.CursorX + mouseY := v.uiManager.CursorY + b := renderInfo.SelectionBounds + mouseHover := (mouseX >= b.Min.X) && (mouseX <= b.Min.X+b.Max.X) && (mouseY >= b.Min.Y) && (mouseY <= b.Min.Y+b.Max.Y) + if mouseHover && v.uiManager.CursorButtonPressed(ui.CursorButtonLeft) { + // showEntryUi = true; + renderInfo.Stance = d2enum.HeroStanceApproaching + renderInfo.ForwardWalkSprite.ResetAnimation() + if renderInfo.ForwardWalkSpriteOverlay != nil { + renderInfo.ForwardWalkSpriteOverlay.ResetAnimation() + } + for _, heroInfo := range v.heroRenderInfo { + if heroInfo.Stance != d2enum.HeroStanceSelected { + continue + } + heroInfo.SelectSfx.Stop() + heroInfo.DeselectSfx.Play() + heroInfo.Stance = d2enum.HeroStanceRetreating + heroInfo.BackWalkSprite.ResetAnimation() + if heroInfo.BackWalkSpriteOverlay != nil { + heroInfo.BackWalkSpriteOverlay.ResetAnimation() + } + } + v.selectedHero = hero + v.updateHeroText() + renderInfo.SelectSfx.Play() + + return + } + + if mouseHover { + renderInfo.Stance = d2enum.HeroStanceIdleSelected + } else { + renderInfo.Stance = d2enum.HeroStanceIdle + } + + if v.selectedHero == d2enum.HeroNone && mouseHover { + v.selectedHero = hero + v.updateHeroText() + } + +} + +func (v *SelectHeroClass) renderHero(screen *ebiten.Image, hero d2enum.Hero) { + renderInfo := v.heroRenderInfo[hero] + switch renderInfo.Stance { + case d2enum.HeroStanceIdle: + renderInfo.IdleSprite.Draw(screen) + case d2enum.HeroStanceIdleSelected: + renderInfo.IdleSelectedSprite.Draw(screen) + case d2enum.HeroStanceApproaching: + renderInfo.ForwardWalkSprite.Draw(screen) + if renderInfo.ForwardWalkSpriteOverlay != nil { + renderInfo.ForwardWalkSpriteOverlay.Draw(screen) + } + case d2enum.HeroStanceSelected: + renderInfo.SelectedSprite.Draw(screen) + if renderInfo.SelectedSpriteOverlay != nil { + renderInfo.SelectedSpriteOverlay.Draw(screen) + } + case d2enum.HeroStanceRetreating: + renderInfo.BackWalkSprite.Draw(screen) + if renderInfo.BackWalkSpriteOverlay != nil { + renderInfo.BackWalkSpriteOverlay.Draw(screen) + } + } +} + +func (v *SelectHeroClass) updateHeroText() { + switch v.selectedHero { + case d2enum.HeroNone: + return + case d2enum.HeroBarbarian: + v.heroClassLabel.SetText(d2common.TranslateString("partycharbar")) + v.setDescLabels("#1709") + case d2enum.HeroNecromancer: + v.heroClassLabel.SetText(d2common.TranslateString("partycharnec")) + v.setDescLabels("#1704") + case d2enum.HeroPaladin: + v.heroClassLabel.SetText(d2common.TranslateString("partycharpal")) + v.setDescLabels("#1711") + case d2enum.HeroAssassin: + v.heroClassLabel.SetText(d2common.TranslateString("partycharass")) + v.setDescLabels("#305") + case d2enum.HeroSorceress: + v.heroClassLabel.SetText(d2common.TranslateString("partycharsor")) + v.setDescLabels("#1710") + case d2enum.HeroAmazon: + v.heroClassLabel.SetText(d2common.TranslateString("partycharama")) + v.setDescLabels("#1698") + case d2enum.HeroDruid: + v.heroClassLabel.SetText(d2common.TranslateString("partychardru")) + v.setDescLabels("#304") + } + /* + if (selectedHero == null) + return; + + switch (selectedHero.Value) + { + + } + + heroClassLabel.Location = new Point(400 - (heroClassLabel.TextArea.Width / 2), 65); + heroDesc1Label.Location = new Point(400 - (heroDesc1Label.TextArea.Width / 2), 100); + heroDesc2Label.Location = new Point(400 - (heroDesc2Label.TextArea.Width / 2), 115); + heroDesc3Label.Location = new Point(400 - (heroDesc3Label.TextArea.Width / 2), 130); + */ +} + +func (v *SelectHeroClass) setDescLabels(descKey string) { + heroDesc := d2common.TranslateString(descKey) + parts := dh.SplitIntoLinesWithMaxWidth(heroDesc, 37) + if len(parts) > 1 { + v.heroDesc1Label.SetText(parts[0]) + } else { + v.heroDesc1Label.SetText("") + } + if len(parts) > 1 { + v.heroDesc2Label.SetText(parts[1]) + } else { + v.heroDesc2Label.SetText("") + } + if len(parts) > 2 { + v.heroDesc3Label.SetText(parts[2]) + } else { + v.heroDesc3Label.SetText("") + } +} diff --git a/common/AnimationData.go b/d2data/AnimationData.go similarity index 83% rename from common/AnimationData.go rename to d2data/AnimationData.go index 5427bd29..b3d61aeb 100644 --- a/common/AnimationData.go +++ b/d2data/AnimationData.go @@ -1,10 +1,12 @@ -package common +package d2data import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) // AnimationDataRecord represents a single entry in the animation data dictionary file @@ -23,10 +25,10 @@ type AnimationDataRecord struct { var AnimationData map[string][]*AnimationDataRecord // LoadAnimationData loads the animation data table into the global AnimationData dictionary -func LoadAnimationData(fileProvider FileProvider) { +func LoadAnimationData(fileProvider d2interface.FileProvider) { AnimationData = make(map[string][]*AnimationDataRecord) - rawData := fileProvider.LoadFile(resourcepaths.AnimationData) - streamReader := CreateStreamReader(rawData) + rawData := fileProvider.LoadFile(d2common.AnimationData) + streamReader := d2common.CreateStreamReader(rawData) for !streamReader.Eof() { dataCount := int(streamReader.GetInt32()) for i := 0; i < dataCount; i++ { diff --git a/d2data/COF.go b/d2data/COF.go new file mode 100644 index 00000000..f303eb32 --- /dev/null +++ b/d2data/COF.go @@ -0,0 +1,71 @@ +package d2data + +import ( + "strings" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" +) + +type CofLayer struct { + Type d2enum.CompositeType + Shadow byte + Transparent bool + DrawEffect d2enum.DrawEffect + WeaponClass d2enum.WeaponClass +} + +type Cof struct { + NumberOfDirections int + FramesPerDirection int + NumberOfLayers int + CofLayers []*CofLayer + CompositeLayers map[d2enum.CompositeType]int + AnimationFrames []d2enum.AnimationFrame + Priority [][][]d2enum.CompositeType +} + +func LoadCof(fileName string, fileProvider d2interface.FileProvider) *Cof { + result := &Cof{} + fileData := fileProvider.LoadFile(fileName) + streamReader := d2common.CreateStreamReader(fileData) + result.NumberOfLayers = int(streamReader.GetByte()) + result.FramesPerDirection = int(streamReader.GetByte()) + result.NumberOfDirections = int(streamReader.GetByte()) + streamReader.SkipBytes(25) // Skip 25 unknown bytes... + result.CofLayers = make([]*CofLayer, 0) + result.CompositeLayers = make(map[d2enum.CompositeType]int, 0) + for i := 0; i < result.NumberOfLayers; i++ { + layer := &CofLayer{} + layer.Type = d2enum.CompositeType(streamReader.GetByte()) + layer.Shadow = streamReader.GetByte() + streamReader.SkipBytes(1) // Unknown + layer.Transparent = streamReader.GetByte() != 0 + layer.DrawEffect = d2enum.DrawEffect(streamReader.GetByte()) + weaponClassStr, _ := streamReader.ReadBytes(4) + layer.WeaponClass = d2enum.WeaponClassFromString(strings.TrimSpace(strings.ReplaceAll(string(weaponClassStr), string(0), ""))) + result.CofLayers = append(result.CofLayers, layer) + result.CompositeLayers[layer.Type] = i + } + animationFrameBytes, _ := streamReader.ReadBytes(result.FramesPerDirection) + result.AnimationFrames = make([]d2enum.AnimationFrame, result.FramesPerDirection) + for i := range animationFrameBytes { + result.AnimationFrames[i] = d2enum.AnimationFrame(animationFrameBytes[i]) + } + priorityLen := result.FramesPerDirection * result.NumberOfDirections * result.NumberOfLayers + result.Priority = make([][][]d2enum.CompositeType, result.NumberOfDirections) + priorityBytes, _ := streamReader.ReadBytes(priorityLen) + for direction := 0; direction < result.NumberOfDirections; direction++ { + result.Priority[direction] = make([][]d2enum.CompositeType, result.FramesPerDirection) + for frame := 0; frame < result.FramesPerDirection; frame++ { + result.Priority[direction][frame] = make([]d2enum.CompositeType, result.NumberOfLayers) + for i := 0; i < result.NumberOfLayers; i++ { + result.Priority[direction][frame][i] = d2enum.CompositeType(priorityBytes[i]) + } + } + } + return result +} diff --git a/common/Dcc.go b/d2data/DCC.go similarity index 91% rename from common/Dcc.go rename to d2data/DCC.go index f538969e..87352992 100644 --- a/common/Dcc.go +++ b/d2data/DCC.go @@ -1,7 +1,13 @@ -package common +package d2data import ( "log" + + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) type DCCPixelBufferEntry struct { @@ -29,7 +35,7 @@ type DCCDirectionFrame struct { NumberOfOptionalBytes int NumberOfCodedBytes int FrameIsBottomUp bool - Box Rectangle + Box d2common.Rectangle Cells []DCCCell PixelData []byte HorizontalCellCount int @@ -52,7 +58,7 @@ type DCCDirection struct { RawPixelCodesBitstreamSize int Frames []*DCCDirectionFrame PaletteEntries [256]byte - Box Rectangle + Box d2common.Rectangle Cells []*DCCCell PixelData []byte HorizontalCellCount int @@ -76,7 +82,7 @@ var dccDir16 = []byte{4, 8, 0, 9, 5, 10, 1, 11, 6, 12, 2, 13, 7, 14, 3, 15} var dccDir32 = []byte{4, 16, 8, 17, 0, 18, 9, 19, 5, 20, 10, 21, 1, 22, 11, 23, 6, 24, 12, 25, 2, 26, 13, 27, 7, 28, 14, 29, 3, 30, 15, 31} -func CreateDCCDirectionFrame(bits *BitMuncher, direction *DCCDirection) *DCCDirectionFrame { +func CreateDCCDirectionFrame(bits *d2common.BitMuncher, direction *DCCDirection) *DCCDirectionFrame { result := &DCCDirectionFrame{} bits.GetBits(direction.Variable0Bits) // Variable0 result.Width = int(bits.GetBits(direction.WidthBits)) @@ -89,7 +95,7 @@ func CreateDCCDirectionFrame(bits *BitMuncher, direction *DCCDirection) *DCCDire if result.FrameIsBottomUp { log.Panic("Bottom up frames are not implemented.") } else { - result.Box = Rectangle{ + result.Box = d2common.Rectangle{ result.XOffset, result.YOffset - result.Height + 1, result.Width, @@ -160,7 +166,7 @@ func (v *DCCDirectionFrame) CalculateCells(direction *DCCDirection) { } } -func CreateDCCDirection(bm *BitMuncher, file *DCC) *DCCDirection { +func CreateDCCDirection(bm *d2common.BitMuncher, file *DCC) *DCCDirection { result := &DCCDirection{} result.OutSizeCoded = int(bm.GetUInt32()) result.CompressionFlags = int(bm.GetBits(2)) @@ -179,12 +185,12 @@ func CreateDCCDirection(bm *BitMuncher, file *DCC) *DCCDirection { // Load the frame headers for frameIdx := 0; frameIdx < file.FramesPerDirection; frameIdx++ { result.Frames[frameIdx] = CreateDCCDirectionFrame(bm, result) - minx = int(MinInt32(int32(result.Frames[frameIdx].Box.Left), int32(minx))) - miny = int(MinInt32(int32(result.Frames[frameIdx].Box.Top), int32(miny))) - maxx = int(MaxInt32(int32(result.Frames[frameIdx].Box.Right()), int32(maxx))) - maxy = int(MaxInt32(int32(result.Frames[frameIdx].Box.Bottom()), int32(maxy))) + minx = int(d2helper.MinInt32(int32(result.Frames[frameIdx].Box.Left), int32(minx))) + miny = int(d2helper.MinInt32(int32(result.Frames[frameIdx].Box.Top), int32(miny))) + maxx = int(d2helper.MaxInt32(int32(result.Frames[frameIdx].Box.Right()), int32(maxx))) + maxy = int(d2helper.MaxInt32(int32(result.Frames[frameIdx].Box.Bottom()), int32(maxy))) } - result.Box = Rectangle{minx, miny, (maxx - minx), (maxy - miny)} + result.Box = d2common.Rectangle{minx, miny, (maxx - minx), (maxy - miny)} if result.OptionalDataBits > 0 { log.Panic("Optional bits in DCC data is not currently supported.") } @@ -210,15 +216,15 @@ func CreateDCCDirection(bm *BitMuncher, file *DCC) *DCCDirection { // here. For example, if you are on byte offset 3, bit offset 6, and // the EqualCellsBitstreamSize is 20 bytes, then the next bit stream // will be located at byte 23, bit offset 6! - equalCellsBitstream := CopyBitMuncher(bm) + equalCellsBitstream := d2common.CopyBitMuncher(bm) bm.SkipBits(result.EqualCellsBitstreamSize) - pixelMaskBitstream := CopyBitMuncher(bm) + pixelMaskBitstream := d2common.CopyBitMuncher(bm) bm.SkipBits(result.PixelMaskBitstreamSize) - encodingTypeBitsream := CopyBitMuncher(bm) + encodingTypeBitsream := d2common.CopyBitMuncher(bm) bm.SkipBits(result.EncodingTypeBitsreamSize) - rawPixelCodesBitstream := CopyBitMuncher(bm) + rawPixelCodesBitstream := d2common.CopyBitMuncher(bm) bm.SkipBits(result.RawPixelCodesBitstreamSize) - pixelCodeandDisplacement := CopyBitMuncher(bm) + pixelCodeandDisplacement := d2common.CopyBitMuncher(bm) // Calculate the cells for the direction result.CalculateCells() // Calculate the cells for each of the frames @@ -247,7 +253,7 @@ func CreateDCCDirection(bm *BitMuncher, file *DCC) *DCCDirection { return result } -func (v *DCCDirection) GenerateFrames(pcd *BitMuncher) { +func (v *DCCDirection) GenerateFrames(pcd *d2common.BitMuncher) { pbIdx := 0 for _, cell := range v.Cells { cell.LastWidth = -1 @@ -339,7 +345,7 @@ func (v *DCCDirection) GenerateFrames(pcd *BitMuncher) { v.PixelBuffer = nil } -func (v *DCCDirection) FillPixelBuffer(pcd, ec, pm, et, rp *BitMuncher) { +func (v *DCCDirection) FillPixelBuffer(pcd, ec, pm, et, rp *d2common.BitMuncher) { lastPixel := uint32(0) maxCellX := 0 maxCellY := 0 @@ -493,10 +499,10 @@ func (v *DCCDirection) CalculateCells() { } } -func LoadDCC(path string, fileProvider FileProvider) *DCC { +func LoadDCC(path string, fileProvider d2interface.FileProvider) *DCC { result := &DCC{} fileData := fileProvider.LoadFile(path) - var bm = CreateBitMuncher(fileData, 0) + var bm = d2common.CreateBitMuncher(fileData, 0) result.Signature = int(bm.GetByte()) if result.Signature != 0x74 { log.Fatal("Signature expected to be 0x74 but it is not.") @@ -527,7 +533,7 @@ func LoadDCC(path string, fileProvider FileProvider) *DCC { case 32: dir = dccDir32[i] } - result.Directions[dir] = CreateDCCDirection(CreateBitMuncher(fileData, directionOffsets[i]*8), result) + result.Directions[dir] = CreateDCCDirection(d2common.CreateBitMuncher(fileData, directionOffsets[i]*8), result) } return result diff --git a/map/DS1.go b/d2data/DS1.go similarity index 82% rename from map/DS1.go rename to d2data/DS1.go index 0262b3be..e98416e0 100644 --- a/map/DS1.go +++ b/d2data/DS1.go @@ -1,7 +1,10 @@ -package _map +package d2data import ( - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) var dirLookup = []int32{ @@ -67,23 +70,23 @@ type SubstitutionGroup struct { } type DS1 struct { - Version int32 // The version of the DS1 - Width int32 // Width of map, in # of tiles - Height int32 // Height of map, in # of tiles - Act int32 // Act, from 1 to 5. This tells which act table to use for the Objects list - SubstitutionType int32 // SubstitutionType (layer type): 0 if no layer, else type 1 or type 2 - Files []string // FilePtr table of file string pointers - NumberOfWalls int32 // WallNum number of wall & orientation layers used - NumberOfFloors int32 // number of floor layers used - NumberOfShadowLayers int32 // ShadowNum number of shadow layer used - NumberOfSubstitutionLayers int32 // SubstitutionNum number of substitution layer used - SubstitutionGroupsNum int32 // SubstitutionGroupsNum number of substitution groups, datas between objects & NPC paths - Objects []common.Object // Objects + Version int32 // The version of the DS1 + Width int32 // Width of map, in # of tiles + Height int32 // Height of map, in # of tiles + Act int32 // Act, from 1 to 5. This tells which act table to use for the Objects list + SubstitutionType int32 // SubstitutionType (layer type): 0 if no layer, else type 1 or type 2 + Files []string // FilePtr table of file string pointers + NumberOfWalls int32 // WallNum number of wall & orientation layers used + NumberOfFloors int32 // number of floor layers used + NumberOfShadowLayers int32 // ShadowNum number of shadow layer used + NumberOfSubstitutionLayers int32 // SubstitutionNum number of substitution layer used + SubstitutionGroupsNum int32 // SubstitutionGroupsNum number of substitution groups, datas between objects & NPC paths + Objects []Object // Objects Tiles [][]TileRecord SubstitutionGroups []SubstitutionGroup } -func LoadDS1(path string, fileProvider common.FileProvider) *DS1 { +func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 { ds1 := &DS1{ NumberOfFloors: 1, NumberOfWalls: 1, @@ -91,12 +94,12 @@ func LoadDS1(path string, fileProvider common.FileProvider) *DS1 { NumberOfSubstitutionLayers: 0, } fileData := fileProvider.LoadFile(path) - br := common.CreateStreamReader(fileData) + br := d2common.CreateStreamReader(fileData) ds1.Version = br.GetInt32() ds1.Width = br.GetInt32() + 1 ds1.Height = br.GetInt32() + 1 if ds1.Version >= 8 { - ds1.Act = common.MinInt32(5, br.GetInt32()+1) + ds1.Act = d2helper.MinInt32(5, br.GetInt32()+1) } if ds1.Version >= 10 { ds1.SubstitutionType = br.GetInt32() @@ -224,19 +227,19 @@ func LoadDS1(path string, fileProvider common.FileProvider) *DS1 { } } } - ds1.Objects = make([]common.Object, 0) + ds1.Objects = make([]Object, 0) if ds1.Version >= 2 { numberOfObjects := br.GetInt32() for objIdx := 0; objIdx < int(numberOfObjects); objIdx++ { - newObject := common.Object{} + newObject := Object{} newObject.Type = br.GetInt32() newObject.Id = br.GetInt32() newObject.X = br.GetInt32() newObject.Y = br.GetInt32() newObject.Flags = br.GetInt32() - newObject.Lookup = common.LookupObject(int(ds1.Act), int(newObject.Type), int(newObject.Id)) + newObject.Lookup = datadict.LookupObject(int(ds1.Act), int(newObject.Type), int(newObject.Id)) if newObject.Lookup != nil && newObject.Lookup.ObjectsTxtId != -1 { - newObject.ObjectInfo = common.Objects[newObject.Lookup.ObjectsTxtId] + newObject.ObjectInfo = datadict.Objects[newObject.Lookup.ObjectsTxtId] } ds1.Objects = append(ds1.Objects, newObject) } @@ -273,10 +276,10 @@ func LoadDS1(path string, fileProvider common.FileProvider) *DS1 { } if objIdx > -1 { if ds1.Objects[objIdx].Paths == nil { - ds1.Objects[objIdx].Paths = make([]common.Path, numPaths) + ds1.Objects[objIdx].Paths = make([]d2common.Path, numPaths) } for pathIdx := 0; pathIdx < int(numPaths); pathIdx++ { - newPath := common.Path{} + newPath := d2common.Path{} newPath.X = br.GetInt32() newPath.Y = br.GetInt32() if ds1.Version >= 15 { diff --git a/map/DT1.go b/d2data/DT1.go similarity index 92% rename from map/DT1.go rename to d2data/DT1.go index 9cf7caca..c9babc4b 100644 --- a/map/DT1.go +++ b/d2data/DT1.go @@ -1,9 +1,11 @@ -package _map +package d2data import ( "log" - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) // https://d2mods.info/forum/viewtopic.php?t=65163 @@ -47,10 +49,10 @@ const ( BlockFormatIsometric BlockDataFormat = 1 ) -func LoadDT1(path string, fileProvider common.FileProvider) *DT1 { +func LoadDT1(path string, fileProvider d2interface.FileProvider) *DT1 { result := &DT1{} fileData := fileProvider.LoadFile(path) - br := common.CreateStreamReader(fileData) + br := d2common.CreateStreamReader(fileData) ver1 := br.GetInt32() ver2 := br.GetInt32() if ver1 != 7 || ver2 != 6 { diff --git a/d2data/Object.go b/d2data/Object.go new file mode 100644 index 00000000..d524afd2 --- /dev/null +++ b/d2data/Object.go @@ -0,0 +1,17 @@ +package d2data + +import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" +) + +type Object struct { + Type int32 + Id int32 + X int32 + Y int32 + Flags int32 + Paths []d2common.Path + Lookup *datadict.ObjectLookupRecord + ObjectInfo *datadict.ObjectRecord +} diff --git a/compression/Huffman.go b/d2data/compression/Huffman.go similarity index 98% rename from compression/Huffman.go rename to d2data/compression/Huffman.go index 0a86be91..8b97ca9e 100644 --- a/compression/Huffman.go +++ b/d2data/compression/Huffman.go @@ -32,7 +32,7 @@ package compression import ( "log" - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) // linkedNode is a node which is both hierachcical (parent/child) and doubly linked (next/prev) @@ -182,7 +182,7 @@ var sPrime = [][]byte{ }, } -func decode(input *common.BitStream, head *linkedNode) *linkedNode { +func decode(input *d2common.BitStream, head *linkedNode) *linkedNode { node := head for node.Child0 != nil { @@ -344,8 +344,8 @@ func HuffmanDecompress(data []byte) []byte { tail := buildList(sPrime[comptype]) head := buildTree(tail) - outputstream := common.CreateStreamWriter() - bitstream := common.CreateBitStream(data[1:]) + outputstream := d2common.CreateStreamWriter() + bitstream := d2common.CreateBitStream(data[1:]) var decoded int for true { node := decode(bitstream, head) diff --git a/compression/Wav.go b/d2data/compression/Wav.go similarity index 95% rename from compression/Wav.go rename to d2data/compression/Wav.go index 66d15b82..b05f2afe 100644 --- a/compression/Wav.go +++ b/d2data/compression/Wav.go @@ -1,7 +1,7 @@ package compression import ( - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) var sLookup = []int{ @@ -30,8 +30,8 @@ func WavDecompress(data []byte, channelCount int) []byte { Array1 := []int{0x2c, 0x2c} Array2 := make([]int, channelCount) - input := common.CreateStreamReader(data) - output := common.CreateStreamWriter() + input := d2common.CreateStreamReader(data) + output := d2common.CreateStreamWriter() input.GetByte() shift := input.GetByte() diff --git a/common/Armor.go b/d2data/datadict/Armor.go similarity index 60% rename from common/Armor.go rename to d2data/datadict/Armor.go index eff0d5d6..42ff8e87 100644 --- a/common/Armor.go +++ b/d2data/datadict/Armor.go @@ -1,10 +1,14 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) type ArmorRecord struct { @@ -135,28 +139,28 @@ func createArmorRecord(line string) ArmorRecord { result := ArmorRecord{ Name: r[inc()], - Version: StringToInt(EmptyToZero(r[inc()])), - CompactSave: StringToInt(EmptyToZero(r[inc()])) == 1, - Rarity: StringToInt(EmptyToZero(r[inc()])), - Spawnable: StringToInt(EmptyToZero(r[inc()])) == 1, + Version: dh.StringToInt(dh.EmptyToZero(r[inc()])), + CompactSave: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + Rarity: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Spawnable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - MinAC: StringToInt(EmptyToZero(r[inc()])), - MaxAC: StringToInt(EmptyToZero(r[inc()])), - Absorbs: StringToInt(EmptyToZero(r[inc()])), - Speed: StringToInt(EmptyToZero(r[inc()])), - RequiredStrength: StringToInt(EmptyToZero(r[inc()])), - Block: StringToInt(EmptyToZero(r[inc()])), - Durability: StringToInt(EmptyToZero(r[inc()])), - NoDurability: StringToInt(EmptyToZero(r[inc()])) == 1, + MinAC: dh.StringToInt(dh.EmptyToZero(r[inc()])), + MaxAC: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Absorbs: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Speed: dh.StringToInt(dh.EmptyToZero(r[inc()])), + RequiredStrength: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Block: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Durability: dh.StringToInt(dh.EmptyToZero(r[inc()])), + NoDurability: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Level: StringToInt(EmptyToZero(r[inc()])), - RequiredLevel: StringToInt(EmptyToZero(r[inc()])), - Cost: StringToInt(EmptyToZero(r[inc()])), - GambleCost: StringToInt(EmptyToZero(r[inc()])), + Level: dh.StringToInt(dh.EmptyToZero(r[inc()])), + RequiredLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Cost: dh.StringToInt(dh.EmptyToZero(r[inc()])), + GambleCost: dh.StringToInt(dh.EmptyToZero(r[inc()])), Code: r[inc()], NameString: r[inc()], - MagicLevel: StringToInt(EmptyToZero(r[inc()])), - AutoPrefix: StringToInt(EmptyToZero(r[inc()])), + MagicLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])), + AutoPrefix: dh.StringToInt(dh.EmptyToZero(r[inc()])), AlternateGfx: r[inc()], OpenBetaGfx: r[inc()], @@ -164,77 +168,77 @@ func createArmorRecord(line string) ArmorRecord { UberCode: r[inc()], UltraCode: r[inc()], - SpellOffset: StringToInt(EmptyToZero(r[inc()])), + SpellOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Component: StringToInt(EmptyToZero(r[inc()])), - InventoryWidth: StringToInt(EmptyToZero(r[inc()])), - InventoryHeight: StringToInt(EmptyToZero(r[inc()])), - HasInventory: StringToInt(EmptyToZero(r[inc()])) == 1, - GemSockets: StringToInt(EmptyToZero(r[inc()])), - GemApplyType: StringToInt(EmptyToZero(r[inc()])), + Component: dh.StringToInt(dh.EmptyToZero(r[inc()])), + InventoryWidth: dh.StringToInt(dh.EmptyToZero(r[inc()])), + InventoryHeight: dh.StringToInt(dh.EmptyToZero(r[inc()])), + HasInventory: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + GemSockets: dh.StringToInt(dh.EmptyToZero(r[inc()])), + GemApplyType: dh.StringToInt(dh.EmptyToZero(r[inc()])), FlippyFile: r[inc()], InventoryFile: r[inc()], UniqueInventoryFile: r[inc()], SetInventoryFile: r[inc()], - AnimRightArm: StringToInt(EmptyToZero(r[inc()])), - AnimLeftArm: StringToInt(EmptyToZero(r[inc()])), - AnimTorso: StringToInt(EmptyToZero(r[inc()])), - AnimLegs: StringToInt(EmptyToZero(r[inc()])), - AnimRightShoulderPad: StringToInt(EmptyToZero(r[inc()])), - AnimLeftShoulderPad: StringToInt(EmptyToZero(r[inc()])), + AnimRightArm: dh.StringToInt(dh.EmptyToZero(r[inc()])), + AnimLeftArm: dh.StringToInt(dh.EmptyToZero(r[inc()])), + AnimTorso: dh.StringToInt(dh.EmptyToZero(r[inc()])), + AnimLegs: dh.StringToInt(dh.EmptyToZero(r[inc()])), + AnimRightShoulderPad: dh.StringToInt(dh.EmptyToZero(r[inc()])), + AnimLeftShoulderPad: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Useable: StringToInt(EmptyToZero(r[inc()])) == 1, + Useable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Throwable: StringToInt(EmptyToZero(r[inc()])) == 1, - Stackable: StringToInt(EmptyToZero(r[inc()])) == 1, - MinStack: StringToInt(EmptyToZero(r[inc()])), - MaxStack: StringToInt(EmptyToZero(r[inc()])), + Throwable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + Stackable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + MinStack: dh.StringToInt(dh.EmptyToZero(r[inc()])), + MaxStack: dh.StringToInt(dh.EmptyToZero(r[inc()])), Type: r[inc()], Type2: r[inc()], DropSound: r[inc()], - DropSfxFrame: StringToInt(EmptyToZero(r[inc()])), + DropSfxFrame: dh.StringToInt(dh.EmptyToZero(r[inc()])), UseSound: r[inc()], - Unique: StringToInt(EmptyToZero(r[inc()])) == 1, - Transparent: StringToInt(EmptyToZero(r[inc()])) == 1, - TransTable: StringToInt(EmptyToZero(r[inc()])), - Quivered: StringToInt(EmptyToZero(r[inc()])) == 1, - LightRadius: StringToInt(EmptyToZero(r[inc()])), - Belt: StringToInt(EmptyToZero(r[inc()])) == 1, + Unique: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + Transparent: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + TransTable: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Quivered: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + LightRadius: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Belt: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Quest: StringToInt(EmptyToZero(r[inc()])), + Quest: dh.StringToInt(dh.EmptyToZero(r[inc()])), - MissileType: StringToInt(EmptyToZero(r[inc()])), - DurabilityWarning: StringToInt(EmptyToZero(r[inc()])), - QuantityWarning: StringToInt(EmptyToZero(r[inc()])), + MissileType: dh.StringToInt(dh.EmptyToZero(r[inc()])), + DurabilityWarning: dh.StringToInt(dh.EmptyToZero(r[inc()])), + QuantityWarning: dh.StringToInt(dh.EmptyToZero(r[inc()])), - MinDamage: StringToInt(EmptyToZero(r[inc()])), - MaxDamage: StringToInt(EmptyToZero(r[inc()])), - StrengthBonus: StringToInt(EmptyToZero(r[inc()])), - DexterityBonus: StringToInt(EmptyToZero(r[inc()])), + MinDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), + MaxDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), + StrengthBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])), + DexterityBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])), - GemOffset: StringToInt(EmptyToZero(r[inc()])), - BitField1: StringToInt(EmptyToZero(r[inc()])), + GemOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])), + BitField1: dh.StringToInt(dh.EmptyToZero(r[inc()])), Vendors: createArmorVendorParams(&r, inc), SourceArt: r[inc()], GameArt: r[inc()], - ColorTransform: StringToInt(EmptyToZero(r[inc()])), - InventoryColorTransform: StringToInt(EmptyToZero(r[inc()])), + ColorTransform: dh.StringToInt(dh.EmptyToZero(r[inc()])), + InventoryColorTransform: dh.StringToInt(dh.EmptyToZero(r[inc()])), - SkipName: StringToInt(EmptyToZero(r[inc()])) == 1, + SkipName: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, NightmareUpgrade: r[inc()], HellUpgrade: r[inc()], - UnusedMinDamage: StringToInt(EmptyToZero(r[inc()])), - UnusedMaxDamage: StringToInt(EmptyToZero(r[inc()])), + UnusedMinDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), + UnusedMaxDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), - Nameable: StringToInt(EmptyToZero(r[inc()])) == 1, + Nameable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, } return result } @@ -264,9 +268,9 @@ func createArmorVendorParams(r *[]string, inc func() int) map[string]*ItemVendor var Armors map[string]*ArmorRecord -func LoadArmors(fileProvider FileProvider) { +func LoadArmors(fileProvider d2interface.FileProvider) { Armors = make(map[string]*ArmorRecord) - data := strings.Split(string(fileProvider.LoadFile(resourcepaths.Armor)), "\r\n")[1:] + data := strings.Split(string(fileProvider.LoadFile(d2common.Armor)), "\r\n")[1:] for _, line := range data { if len(line) == 0 { continue diff --git a/common/LevelPresets.go b/d2data/datadict/LevelPresets.go similarity index 51% rename from common/LevelPresets.go rename to d2data/datadict/LevelPresets.go index 1914d77c..f7af5782 100644 --- a/common/LevelPresets.go +++ b/d2data/datadict/LevelPresets.go @@ -1,10 +1,14 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) type LevelPresetRecord struct { @@ -39,21 +43,21 @@ func createLevelPresetRecord(props []string) LevelPresetRecord { } result := LevelPresetRecord{ Name: props[inc()], - DefinitionId: StringToInt(props[inc()]), - LevelId: StringToInt(props[inc()]), - Populate: StringToUint8(props[inc()]) == 1, - Logicals: StringToUint8(props[inc()]) == 1, - Outdoors: StringToUint8(props[inc()]) == 1, - Animate: StringToUint8(props[inc()]) == 1, - KillEdge: StringToUint8(props[inc()]) == 1, - FillBlanks: StringToUint8(props[inc()]) == 1, - SizeX: StringToInt(props[inc()]), - SizeY: StringToInt(props[inc()]), - AutoMap: StringToUint8(props[inc()]) == 1, - Scan: StringToUint8(props[inc()]) == 1, - Pops: StringToInt(props[inc()]), - PopPad: StringToInt(props[inc()]), - FileCount: StringToInt(props[inc()]), + DefinitionId: dh.StringToInt(props[inc()]), + LevelId: dh.StringToInt(props[inc()]), + Populate: dh.StringToUint8(props[inc()]) == 1, + Logicals: dh.StringToUint8(props[inc()]) == 1, + Outdoors: dh.StringToUint8(props[inc()]) == 1, + Animate: dh.StringToUint8(props[inc()]) == 1, + KillEdge: dh.StringToUint8(props[inc()]) == 1, + FillBlanks: dh.StringToUint8(props[inc()]) == 1, + SizeX: dh.StringToInt(props[inc()]), + SizeY: dh.StringToInt(props[inc()]), + AutoMap: dh.StringToUint8(props[inc()]) == 1, + Scan: dh.StringToUint8(props[inc()]) == 1, + Pops: dh.StringToInt(props[inc()]), + PopPad: dh.StringToInt(props[inc()]), + FileCount: dh.StringToInt(props[inc()]), Files: [6]string{ props[inc()], props[inc()], @@ -62,18 +66,18 @@ func createLevelPresetRecord(props []string) LevelPresetRecord { props[inc()], props[inc()], }, - Dt1Mask: StringToUint(props[inc()]), - Beta: StringToUint8(props[inc()]) == 1, - Expansion: StringToUint8(props[inc()]) == 1, + Dt1Mask: dh.StringToUint(props[inc()]), + Beta: dh.StringToUint8(props[inc()]) == 1, + Expansion: dh.StringToUint8(props[inc()]) == 1, } return result } var LevelPresets map[int]*LevelPresetRecord -func LoadLevelPresets(fileProvider FileProvider) { +func LoadLevelPresets(fileProvider d2interface.FileProvider) { LevelPresets = make(map[int]*LevelPresetRecord) - data := strings.Split(string(fileProvider.LoadFile(resourcepaths.LevelPreset)), "\r\n")[1:] + data := strings.Split(string(fileProvider.LoadFile(d2common.LevelPreset)), "\r\n")[1:] for _, line := range data { if len(line) == 0 { continue diff --git a/common/LevelTypes.go b/d2data/datadict/LevelTypes.go similarity index 66% rename from common/LevelTypes.go rename to d2data/datadict/LevelTypes.go index e2204070..bfc2cb59 100644 --- a/common/LevelTypes.go +++ b/d2data/datadict/LevelTypes.go @@ -1,10 +1,14 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) type LevelTypeRecord struct { @@ -18,8 +22,8 @@ type LevelTypeRecord struct { var LevelTypes []LevelTypeRecord -func LoadLevelTypes(fileProvider FileProvider) { - data := strings.Split(string(fileProvider.LoadFile(resourcepaths.LevelType)), "\r\n")[1:] +func LoadLevelTypes(fileProvider d2interface.FileProvider) { + data := strings.Split(string(fileProvider.LoadFile(d2common.LevelType)), "\r\n")[1:] LevelTypes = make([]LevelTypeRecord, len(data)) for i, line := range data { idx := -1 @@ -35,7 +39,7 @@ func LoadLevelTypes(fileProvider FileProvider) { continue } LevelTypes[i].Name = parts[inc()] - LevelTypes[i].Id = StringToInt(parts[inc()]) + LevelTypes[i].Id = dh.StringToInt(parts[inc()]) for fileIdx := range LevelTypes[i].Files { LevelTypes[i].Files[fileIdx] = parts[inc()] if LevelTypes[i].Files[fileIdx] == "0" { @@ -44,7 +48,7 @@ func LoadLevelTypes(fileProvider FileProvider) { } LevelTypes[i].Beta = parts[inc()] != "1" - LevelTypes[i].Act = StringToInt(parts[inc()]) + LevelTypes[i].Act = dh.StringToInt(parts[inc()]) LevelTypes[i].Expansion = parts[inc()] != "1" } log.Printf("Loaded %d LevelType records", len(LevelTypes)) diff --git a/common/LevelWarp.go b/d2data/datadict/LevelWarp.go similarity index 79% rename from common/LevelWarp.go rename to d2data/datadict/LevelWarp.go index c00f8a51..c1aaab97 100644 --- a/common/LevelWarp.go +++ b/d2data/datadict/LevelWarp.go @@ -1,9 +1,11 @@ -package common +package datadict import ( "log" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) type LevelWarpRecord struct { @@ -23,10 +25,10 @@ type LevelWarpRecord struct { var LevelWarps map[int]*LevelWarpRecord -func LoadLevelWarps(fileProvider FileProvider) { +func LoadLevelWarps(fileProvider d2interface.FileProvider) { LevelWarps = make(map[int]*LevelWarpRecord) - levelWarpData := fileProvider.LoadFile(resourcepaths.LevelWarp) - streamReader := CreateStreamReader(levelWarpData) + levelWarpData := fileProvider.LoadFile(d2common.LevelWarp) + streamReader := d2common.CreateStreamReader(levelWarpData) numRecords := int(streamReader.GetInt32()) for i := 0; i < numRecords; i++ { id := int(streamReader.GetInt32()) diff --git a/common/Missiles.go b/d2data/datadict/Missiles.go similarity index 62% rename from common/Missiles.go rename to d2data/datadict/Missiles.go index fe38f301..a59b2997 100644 --- a/common/Missiles.go +++ b/d2data/datadict/Missiles.go @@ -1,10 +1,14 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) type MissileCalcParam struct { @@ -196,16 +200,16 @@ func createMissileRecord(line string) MissileRecord { return i } // note: in this file, empties are equivalent to zero, so all numerical conversions should - // be wrapped in an EmptyToZero transform + // be wrapped in an dh.EmptyToZero transform result := MissileRecord{ Name: r[inc()], - Id: StringToInt(EmptyToZero(r[inc()])), + Id: dh.StringToInt(dh.EmptyToZero(r[inc()])), - ClientMovementFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - ClientCollisionFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - ServerMovementFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - ServerCollisionFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - ServerDamageFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + ClientMovementFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + ClientCollisionFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + ServerMovementFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + ServerCollisionFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + ServerDamageFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), ServerMovementCalc: loadMissileCalc(&r, inc, 5), ClientMovementCalc: loadMissileCalc(&r, inc, 5), @@ -213,12 +217,12 @@ func createMissileRecord(line string) MissileRecord { ClientCollisionCalc: loadMissileCalc(&r, inc, 3), ServerDamageCalc: loadMissileCalc(&r, inc, 2), - Velocity: StringToInt(EmptyToZero(r[inc()])), - MaxVelocity: StringToInt(EmptyToZero(r[inc()])), - LevelVelocityBonus: StringToInt(EmptyToZero(r[inc()])), - Accel: StringToInt(EmptyToZero(r[inc()])), - Range: StringToInt(EmptyToZero(r[inc()])), - LevelRangeBonus: StringToInt(EmptyToZero(r[inc()])), + Velocity: dh.StringToInt(dh.EmptyToZero(r[inc()])), + MaxVelocity: dh.StringToInt(dh.EmptyToZero(r[inc()])), + LevelVelocityBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Accel: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Range: dh.StringToInt(dh.EmptyToZero(r[inc()])), + LevelRangeBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])), Light: loadMissileLight(&r, inc), @@ -226,54 +230,54 @@ func createMissileRecord(line string) MissileRecord { Collision: loadMissileCollision(&r, inc), - XOffset: StringToInt(EmptyToZero(r[inc()])), - YOffset: StringToInt(EmptyToZero(r[inc()])), - ZOffset: StringToInt(EmptyToZero(r[inc()])), - Size: StringToInt(EmptyToZero(r[inc()])), + XOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])), + YOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])), + ZOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Size: dh.StringToInt(dh.EmptyToZero(r[inc()])), - DestroyedByTP: StringToInt(EmptyToZero(r[inc()])) == 1, - DestroyedByTPFrame: StringToInt(EmptyToZero(r[inc()])), - CanDestroy: StringToInt(EmptyToZero(r[inc()])) == 1, + DestroyedByTP: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + DestroyedByTPFrame: dh.StringToInt(dh.EmptyToZero(r[inc()])), + CanDestroy: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - UseAttackRating: StringToInt(EmptyToZero(r[inc()])) == 1, - AlwaysExplode: StringToInt(EmptyToZero(r[inc()])) == 1, + UseAttackRating: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + AlwaysExplode: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - ClientExplosion: StringToInt(EmptyToZero(r[inc()])) == 1, - TownSafe: StringToInt(EmptyToZero(r[inc()])) == 1, - IgnoreBossModifiers: StringToInt(EmptyToZero(r[inc()])) == 1, - IgnoreMultishot: StringToInt(EmptyToZero(r[inc()])) == 1, - HolyFilterType: StringToInt(EmptyToZero(r[inc()])), - CanBeSlowed: StringToInt(EmptyToZero(r[inc()])) == 1, - TriggersHitEvents: StringToInt(EmptyToZero(r[inc()])) == 1, - TriggersGetHit: StringToInt(EmptyToZero(r[inc()])) == 1, - SoftHit: StringToInt(EmptyToZero(r[inc()])) == 1, - KnockbackPercent: StringToInt(EmptyToZero(r[inc()])), + ClientExplosion: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + TownSafe: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + IgnoreBossModifiers: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + IgnoreMultishot: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + HolyFilterType: dh.StringToInt(dh.EmptyToZero(r[inc()])), + CanBeSlowed: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + TriggersHitEvents: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + TriggersGetHit: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + SoftHit: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + KnockbackPercent: dh.StringToInt(dh.EmptyToZero(r[inc()])), - TransparencyMode: StringToInt(EmptyToZero(r[inc()])), + TransparencyMode: dh.StringToInt(dh.EmptyToZero(r[inc()])), - UseQuantity: StringToInt(EmptyToZero(r[inc()])) == 1, - AffectedByPierce: StringToInt(EmptyToZero(r[inc()])) == 1, - SpecialSetup: StringToInt(EmptyToZero(r[inc()])) == 1, + UseQuantity: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + AffectedByPierce: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + SpecialSetup: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - MissileSkill: StringToInt(EmptyToZero(r[inc()])) == 1, + MissileSkill: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, SkillName: r[inc()], - ResultFlags: StringToInt(EmptyToZero(r[inc()])), - HitFlags: StringToInt(EmptyToZero(r[inc()])), + ResultFlags: dh.StringToInt(dh.EmptyToZero(r[inc()])), + HitFlags: dh.StringToInt(dh.EmptyToZero(r[inc()])), - HitShift: StringToInt(EmptyToZero(r[inc()])), - ApplyMastery: StringToInt(EmptyToZero(r[inc()])) == 1, - SourceDamage: StringToInt(EmptyToZero(r[inc()])), - HalfDamageForTwoHander: StringToInt(EmptyToZero(r[inc()])) == 1, - SourceMissDamage: StringToInt(EmptyToZero(r[inc()])), + HitShift: dh.StringToInt(dh.EmptyToZero(r[inc()])), + ApplyMastery: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + SourceDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), + HalfDamageForTwoHander: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + SourceMissDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])), Damage: loadMissileDamage(&r, inc), ElementalDamage: loadMissileElementalDamage(&r, inc), - HitClass: StringToInt(EmptyToZero(r[inc()])), - NumDirections: StringToInt(EmptyToZero(r[inc()])), - LocalBlood: StringToInt(EmptyToZero(r[inc()])), - DamageReductionRate: StringToInt(EmptyToZero(r[inc()])), + HitClass: dh.StringToInt(dh.EmptyToZero(r[inc()])), + NumDirections: dh.StringToInt(dh.EmptyToZero(r[inc()])), + LocalBlood: dh.StringToInt(dh.EmptyToZero(r[inc()])), + DamageReductionRate: dh.StringToInt(dh.EmptyToZero(r[inc()])), TravelSound: r[inc()], HitSound: r[inc()], @@ -291,9 +295,9 @@ func createMissileRecord(line string) MissileRecord { var Missiles map[int]*MissileRecord -func LoadMissiles(fileProvider FileProvider) { +func LoadMissiles(fileProvider d2interface.FileProvider) { Missiles = make(map[int]*MissileRecord) - data := strings.Split(string(fileProvider.LoadFile(resourcepaths.Missiles)), "\r\n")[1:] + data := strings.Split(string(fileProvider.LoadFile(d2common.Missiles)), "\r\n")[1:] for _, line := range data { if len(line) == 0 { continue @@ -306,7 +310,7 @@ func LoadMissiles(fileProvider FileProvider) { func loadMissileCalcParam(r *[]string, inc func() int) MissileCalcParam { result := MissileCalcParam{ - Param: StringToInt(EmptyToZero((*r)[inc()])), + Param: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), Desc: (*r)[inc()], } return result @@ -326,64 +330,64 @@ func loadMissileCalc(r *[]string, inc func() int, params int) MissileCalc { func loadMissileLight(r *[]string, inc func() int) MissileLight { result := MissileLight{ - Diameter: StringToInt(EmptyToZero((*r)[inc()])), - Flicker: StringToInt(EmptyToZero((*r)[inc()])), - Red: StringToUint8(EmptyToZero((*r)[inc()])), - Green: StringToUint8(EmptyToZero((*r)[inc()])), - Blue: StringToUint8(EmptyToZero((*r)[inc()])), + Diameter: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + Flicker: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + Red: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])), + Green: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])), + Blue: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])), } return result } func loadMissileAnimation(r *[]string, inc func() int) MissileAnimation { result := MissileAnimation{ - StepsBeforeVisible: StringToInt(EmptyToZero((*r)[inc()])), - StepsBeforeActive: StringToInt(EmptyToZero((*r)[inc()])), - LoopAnimation: StringToInt(EmptyToZero((*r)[inc()])) == 1, + StepsBeforeVisible: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + StepsBeforeActive: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + LoopAnimation: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, CelFileName: (*r)[inc()], - AnimationRate: StringToInt(EmptyToZero((*r)[inc()])), - AnimationLength: StringToInt(EmptyToZero((*r)[inc()])), - AnimationSpeed: StringToInt(EmptyToZero((*r)[inc()])), - StartingFrame: StringToInt(EmptyToZero((*r)[inc()])), - HasSubLoop: StringToInt(EmptyToZero((*r)[inc()])) == 1, - SubStartingFrame: StringToInt(EmptyToZero((*r)[inc()])), - SubEndingFrame: StringToInt(EmptyToZero((*r)[inc()])), + AnimationRate: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + AnimationLength: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + AnimationSpeed: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + StartingFrame: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + HasSubLoop: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + SubStartingFrame: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + SubEndingFrame: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), } return result } func loadMissileCollision(r *[]string, inc func() int) MissileCollision { result := MissileCollision{ - CollisionType: StringToInt(EmptyToZero((*r)[inc()])), - DestroyedUponCollision: StringToInt(EmptyToZero((*r)[inc()])) == 1, - FriendlyFire: StringToInt(EmptyToZero((*r)[inc()])) == 1, - LastCollide: StringToInt(EmptyToZero((*r)[inc()])) == 1, - Collision: StringToInt(EmptyToZero((*r)[inc()])) == 1, - ClientCollision: StringToInt(EmptyToZero((*r)[inc()])) == 1, - ClientSend: StringToInt(EmptyToZero((*r)[inc()])) == 1, - UseCollisionTimer: StringToInt(EmptyToZero((*r)[inc()])) == 1, - TimerFrames: StringToInt(EmptyToZero((*r)[inc()])), + CollisionType: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + DestroyedUponCollision: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + FriendlyFire: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + LastCollide: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + Collision: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + ClientCollision: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + ClientSend: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + UseCollisionTimer: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1, + TimerFrames: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), } return result } func loadMissileDamage(r *[]string, inc func() int) MissileDamage { result := MissileDamage{ - MinDamage: StringToInt(EmptyToZero((*r)[inc()])), + MinDamage: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), MinLevelDamage: [5]int{ - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), }, - MaxDamage: StringToInt(EmptyToZero((*r)[inc()])), + MaxDamage: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), MaxLevelDamage: [5]int{ - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), }, DamageSynergyPerCalc: (*r)[inc()], } @@ -394,11 +398,11 @@ func loadMissileElementalDamage(r *[]string, inc func() int) MissileElementalDam result := MissileElementalDamage{ ElementType: (*r)[inc()], Damage: loadMissileDamage(r, inc), - Duration: StringToInt(EmptyToZero((*r)[inc()])), + Duration: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), LevelDuration: [3]int{ - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), - StringToInt(EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + dh.StringToInt(dh.EmptyToZero((*r)[inc()])), }, } return result diff --git a/d2data/datadict/MonStats.go b/d2data/datadict/MonStats.go new file mode 100644 index 00000000..cac4e967 --- /dev/null +++ b/d2data/datadict/MonStats.go @@ -0,0 +1,12 @@ +package datadict + +import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" +) + +var MonStatsDictionary *d2common.DataDictionary + +func LoadMonStats(fileProvider d2interface.FileProvider) { + MonStatsDictionary = d2common.LoadDataDictionary(string(fileProvider.LoadFile(d2common.MonStats))) +} diff --git a/common/ObjectLookup.go b/d2data/datadict/ObjectLookup.go similarity index 99% rename from common/ObjectLookup.go rename to d2data/datadict/ObjectLookup.go index 35d8b6e2..8a161a9f 100644 --- a/common/ObjectLookup.go +++ b/d2data/datadict/ObjectLookup.go @@ -1,4 +1,4 @@ -package common +package datadict import ( "log" diff --git a/common/ObjectTypes.go b/d2data/datadict/ObjectTypes.go similarity index 66% rename from common/ObjectTypes.go rename to d2data/datadict/ObjectTypes.go index 53686c32..205b8f64 100644 --- a/common/ObjectTypes.go +++ b/d2data/datadict/ObjectTypes.go @@ -1,10 +1,12 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) type ObjectTypeRecord struct { @@ -14,9 +16,9 @@ type ObjectTypeRecord struct { var ObjectTypes []ObjectTypeRecord -func LoadObjectTypes(fileProvider FileProvider) { - objectTypeData := fileProvider.LoadFile(resourcepaths.ObjectType) - streamReader := CreateStreamReader(objectTypeData) +func LoadObjectTypes(fileProvider d2interface.FileProvider) { + objectTypeData := fileProvider.LoadFile(d2common.ObjectType) + streamReader := d2common.CreateStreamReader(objectTypeData) count := streamReader.GetInt32() ObjectTypes = make([]ObjectTypeRecord, count) for i := range ObjectTypes { diff --git a/d2data/datadict/Objects.go b/d2data/datadict/Objects.go new file mode 100644 index 00000000..de8db1d1 --- /dev/null +++ b/d2data/datadict/Objects.go @@ -0,0 +1,357 @@ +package datadict + +import ( + "log" + "strings" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" +) + +// An ObjectRecord represents the settings for one type of object from objects.txt +type ObjectRecord struct { + Name string + Description string + Id int + Token string // refers to what graphics this object uses + + SpawnMax int // unused? + Selectable [8]bool // is this mode selectable + TrapProbability int // unused + + SizeX int + SizeY int + + NTgtFX int // unknown + NTgtFY int // unknown + NTgtBX int // unknown + NTgtBY int // unknown + + 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) + CycleAnimation [8]bool // probably whether animation loops + LightDiameter [8]int + BlocksLight [8]bool + HasCollision [8]bool + IsAttackable bool // do we kick it when interacting + StartFrame [8]int + + EnvEffect bool // unknown + IsDoor bool + BlockVisibility bool // only works with IsDoor + Orientation int // unknown (1=sw, 2=nw, 3=se, 4=ne) + Trans int // controls palette mapping + + OrderFlag [8]int // 0 = object, 1 = floor, 2 = wall + PreOperate bool // unknown + HasAnimationMode [8]bool // 'Mode' in source, true if this mode is used + + XOffset int // in pixels offset + YOffset int + Draw bool // if false, object isn't drawn (shadow is still drawn and player can still select though) + + LightRed byte // if lightdiameter is set, rgb of the light + LightGreen byte + LightBlue byte + + SelHD bool // whether these DCC components are selectable + SelTR bool + SelLG bool + SelRA bool + SelLA bool + SelRH bool + SelLH bool + SelSH bool + SelS [8]bool + + 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 + + MonsterOk bool // unknown + OperateRange int // distance object can be used from, might be unused + ShrineFunction int // unused + Restore bool // if true, object is stored in memory and will be retained if you leave and re-enter the area + + Parm [8]int // unknown + Act int // what acts this object can appear in (15 = all three) + Lockable bool + Gore bool // unknown, something with corpses + Sync bool // unknown + Flicker bool // light flickers if true + Damage int // amount of damage done by this (used depending on operatefn) + Beta bool // if true, appeared in the beta? + Overlay bool // unknown + CollisionSubst bool // unknown, controls some kind of special collision checking? + + 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 + // (todo: we should enumerate all the functions somewhere, but probably not here + // b/c it's a very long list) + PopulateFn int // what function is used to spawn this object? + // (see above todo) + InitFn int // what function is run when the object is initialized? + // (see above todo) + ClientFn int // controls special audio-visual functions + // (see above todo) + + 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 + // '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 +} + +// 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: dh.StringToInt(props[inc()]), + Token: props[inc()], + + SpawnMax: dh.StringToInt(props[inc()]), + Selectable: [8]bool{ + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + }, + TrapProbability: dh.StringToInt(props[inc()]), + + SizeX: dh.StringToInt(props[inc()]), + SizeY: dh.StringToInt(props[inc()]), + + NTgtFX: dh.StringToInt(props[inc()]), + NTgtFY: dh.StringToInt(props[inc()]), + NTgtBX: dh.StringToInt(props[inc()]), + NTgtBY: dh.StringToInt(props[inc()]), + + FrameCount: [8]int{ + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + }, + FrameDelta: [8]int{ + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + }, + CycleAnimation: [8]bool{ + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + }, + LightDiameter: [8]int{ + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + }, + BlocksLight: [8]bool{ + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + }, + HasCollision: [8]bool{ + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + }, + IsAttackable: dh.StringToUint8(props[inc()]) == 1, + StartFrame: [8]int{ + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + }, + + EnvEffect: dh.StringToUint8(props[inc()]) == 1, + IsDoor: dh.StringToUint8(props[inc()]) == 1, + BlockVisibility: dh.StringToUint8(props[inc()]) == 1, + Orientation: dh.StringToInt(props[inc()]), + Trans: dh.StringToInt(props[inc()]), + + OrderFlag: [8]int{ + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + }, + PreOperate: dh.StringToUint8(props[inc()]) == 1, + HasAnimationMode: [8]bool{ + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + }, + + XOffset: dh.StringToInt(props[inc()]), + YOffset: dh.StringToInt(props[inc()]), + Draw: dh.StringToUint8(props[inc()]) == 1, + + LightRed: dh.StringToUint8(props[inc()]), + LightGreen: dh.StringToUint8(props[inc()]), + LightBlue: dh.StringToUint8(props[inc()]), + + SelHD: dh.StringToUint8(props[inc()]) == 1, + SelTR: dh.StringToUint8(props[inc()]) == 1, + SelLG: dh.StringToUint8(props[inc()]) == 1, + SelRA: dh.StringToUint8(props[inc()]) == 1, + SelLA: dh.StringToUint8(props[inc()]) == 1, + SelRH: dh.StringToUint8(props[inc()]) == 1, + SelLH: dh.StringToUint8(props[inc()]) == 1, + SelSH: dh.StringToUint8(props[inc()]) == 1, + SelS: [8]bool{ + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + dh.StringToUint8(props[inc()]) == 1, + }, + + TotalPieces: dh.StringToInt(props[inc()]), + SubClass: dh.StringToInt(props[inc()]), + + XSpace: dh.StringToInt(props[inc()]), + YSpace: dh.StringToInt(props[inc()]), + + NameOffset: dh.StringToInt(props[inc()]), + + MonsterOk: dh.StringToUint8(props[inc()]) == 1, + OperateRange: dh.StringToInt(props[inc()]), + ShrineFunction: dh.StringToInt(props[inc()]), + Restore: dh.StringToUint8(props[inc()]) == 1, + + Parm: [8]int{ + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + dh.StringToInt(props[inc()]), + }, + Act: dh.StringToInt(props[inc()]), + Lockable: dh.StringToUint8(props[inc()]) == 1, + Gore: dh.StringToUint8(props[inc()]) == 1, + Sync: dh.StringToUint8(props[inc()]) == 1, + Flicker: dh.StringToUint8(props[inc()]) == 1, + Damage: dh.StringToInt(props[inc()]), + Beta: dh.StringToUint8(props[inc()]) == 1, + Overlay: dh.StringToUint8(props[inc()]) == 1, + CollisionSubst: dh.StringToUint8(props[inc()]) == 1, + + Left: dh.StringToInt(props[inc()]), + Top: dh.StringToInt(props[inc()]), + Width: dh.StringToInt(props[inc()]), + Height: dh.StringToInt(props[inc()]), + + OperateFn: dh.StringToInt(props[inc()]), + PopulateFn: dh.StringToInt(props[inc()]), + InitFn: dh.StringToInt(props[inc()]), + ClientFn: dh.StringToInt(props[inc()]), + + RestoreVirgins: dh.StringToUint8(props[inc()]) == 1, + BlockMissile: dh.StringToUint8(props[inc()]) == 1, + DrawUnder: dh.StringToUint8(props[inc()]) == 1, + OpenWarp: dh.StringToUint8(props[inc()]) == 1, + + AutoMap: dh.StringToInt(props[inc()]), + } + return result +} + +var Objects map[int]*ObjectRecord + +func LoadObjects(fileProvider d2interface.FileProvider) { + Objects = make(map[int]*ObjectRecord) + data := strings.Split(string(fileProvider.LoadFile(d2common.ObjectDetails)), "\r\n")[1:] + for _, line := range data { + if len(line) == 0 { + continue + } + props := strings.Split(line, "\t") + if props[2] == "" { + continue // skip a line that doesn't have an id + } + rec := createObjectRecord(props) + Objects[rec.Id] = &rec + } + log.Printf("Loaded %d objects", len(Objects)) +} diff --git a/common/Palette.go b/d2data/datadict/Palette.go similarity index 64% rename from common/Palette.go rename to d2data/datadict/Palette.go index 330b9fee..8a19dc01 100644 --- a/common/Palette.go +++ b/d2data/datadict/Palette.go @@ -1,9 +1,11 @@ -package common +package datadict import ( "log" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" ) // PaletteRGB represents a color in a palette @@ -13,14 +15,14 @@ type PaletteRGB struct { // PaletteType represents a palette type PaletteRec struct { - Name palettedefs.PaletteType + Name d2enum.PaletteType Colors [256]PaletteRGB } -var Palettes map[palettedefs.PaletteType]PaletteRec +var Palettes map[d2enum.PaletteType]PaletteRec // CreatePalette creates a palette -func CreatePalette(name palettedefs.PaletteType, data []byte) PaletteRec { +func CreatePalette(name d2enum.PaletteType, data []byte) PaletteRec { result := PaletteRec{Name: name} for i := 0; i <= 255; i++ { @@ -33,14 +35,14 @@ func CreatePalette(name palettedefs.PaletteType, data []byte) PaletteRec { return result } -func LoadPalettes(mpqFiles map[string]string, fileProvider FileProvider) { - Palettes = make(map[palettedefs.PaletteType]PaletteRec) +func LoadPalettes(mpqFiles map[string]string, fileProvider d2interface.FileProvider) { + Palettes = make(map[d2enum.PaletteType]PaletteRec) for _, pal := range []string{ "act1", "act2", "act3", "act4", "act5", "endgame", "endgame2", "fechar", "loading", "menu0", "menu1", "menu2", "menu3", "menu4", "sky", "static", "trademark", "units", } { filePath := `data\global\palette\` + pal + `\pal.dat` - paletteName := palettedefs.PaletteType(pal) + paletteName := d2enum.PaletteType(pal) palette := CreatePalette(paletteName, fileProvider.LoadFile(filePath)) Palettes[paletteName] = palette } diff --git a/common/Sounds.go b/d2data/datadict/Sounds.go similarity index 53% rename from common/Sounds.go rename to d2data/datadict/Sounds.go index 627e07a8..194e3545 100644 --- a/common/Sounds.go +++ b/d2data/datadict/Sounds.go @@ -1,10 +1,14 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) // SoundEntry represents a sound entry @@ -46,39 +50,39 @@ func createSoundEntry(soundLine string) SoundEntry { } result := SoundEntry{ Handle: props[inc()], - Index: StringToInt(props[inc()]), + Index: dh.StringToInt(props[inc()]), FileName: props[inc()], - Volume: StringToUint8(props[inc()]), - GroupSize: StringToUint8(props[inc()]), - Loop: StringToUint8(props[inc()]) == 1, - FadeIn: StringToUint8(props[inc()]), - FadeOut: StringToUint8(props[inc()]), - DeferInst: StringToUint8(props[inc()]), - StopInst: StringToUint8(props[inc()]), - Duration: StringToUint8(props[inc()]), - Compound: StringToInt8(props[inc()]), - Reverb: StringToUint8(props[inc()]) == 1, - Falloff: StringToUint8(props[inc()]), - Cache: StringToUint8(props[inc()]), - AsyncOnly: StringToUint8(props[inc()]) == 1, - Priority: StringToUint8(props[inc()]), - Stream: StringToUint8(props[inc()]), - Stereo: StringToUint8(props[inc()]), - Tracking: StringToUint8(props[inc()]), - Solo: StringToUint8(props[inc()]), - MusicVol: StringToUint8(props[inc()]), - Block1: StringToInt(props[inc()]), - Block2: StringToInt(props[inc()]), - Block3: StringToInt(props[inc()]), + Volume: dh.StringToUint8(props[inc()]), + GroupSize: dh.StringToUint8(props[inc()]), + Loop: dh.StringToUint8(props[inc()]) == 1, + FadeIn: dh.StringToUint8(props[inc()]), + FadeOut: dh.StringToUint8(props[inc()]), + DeferInst: dh.StringToUint8(props[inc()]), + StopInst: dh.StringToUint8(props[inc()]), + Duration: dh.StringToUint8(props[inc()]), + Compound: dh.StringToInt8(props[inc()]), + Reverb: dh.StringToUint8(props[inc()]) == 1, + Falloff: dh.StringToUint8(props[inc()]), + Cache: dh.StringToUint8(props[inc()]), + AsyncOnly: dh.StringToUint8(props[inc()]) == 1, + Priority: dh.StringToUint8(props[inc()]), + Stream: dh.StringToUint8(props[inc()]), + Stereo: dh.StringToUint8(props[inc()]), + Tracking: dh.StringToUint8(props[inc()]), + Solo: dh.StringToUint8(props[inc()]), + MusicVol: dh.StringToUint8(props[inc()]), + Block1: dh.StringToInt(props[inc()]), + Block2: dh.StringToInt(props[inc()]), + Block3: dh.StringToInt(props[inc()]), } return result } var Sounds map[string]SoundEntry -func LoadSounds(fileProvider FileProvider) { +func LoadSounds(fileProvider d2interface.FileProvider) { Sounds = make(map[string]SoundEntry) - soundData := strings.Split(string(fileProvider.LoadFile(resourcepaths.SoundSettings)), "\r\n")[1:] + soundData := strings.Split(string(fileProvider.LoadFile(d2common.SoundSettings)), "\r\n")[1:] for _, line := range soundData { if len(line) == 0 { continue diff --git a/common/UniqueItems.go b/d2data/datadict/UniqueItems.go similarity index 77% rename from common/UniqueItems.go rename to d2data/datadict/UniqueItems.go index 91f9883f..0a772394 100644 --- a/common/UniqueItems.go +++ b/d2data/datadict/UniqueItems.go @@ -1,10 +1,14 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) type UniqueItemRecord struct { @@ -56,22 +60,22 @@ func createUniqueItemRecord(r []string) UniqueItemRecord { } result := UniqueItemRecord{ Name: r[inc()], - Version: StringToInt(EmptyToZero(r[inc()])), - Enabled: StringToInt(EmptyToZero(r[inc()])) == 1, + Version: dh.StringToInt(dh.EmptyToZero(r[inc()])), + Enabled: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Ladder: StringToInt(EmptyToZero(r[inc()])) == 1, - Rarity: StringToInt(EmptyToZero(r[inc()])), - NoLimit: StringToInt(EmptyToZero(r[inc()])) == 1, + Ladder: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + Rarity: dh.StringToInt(dh.EmptyToZero(r[inc()])), + NoLimit: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, - Level: StringToInt(EmptyToZero(r[inc()])), - RequiredLevel: StringToInt(EmptyToZero(r[inc()])), + Level: dh.StringToInt(dh.EmptyToZero(r[inc()])), + RequiredLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])), Code: r[inc()], TypeDescription: r[inc()], UberDescription: r[inc()], - SingleCopy: StringToInt(EmptyToZero(r[inc()])) == 1, - CostMultiplier: StringToInt(EmptyToZero(r[inc()])), - CostAdd: StringToInt(EmptyToZero(r[inc()])), + SingleCopy: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1, + CostMultiplier: dh.StringToInt(dh.EmptyToZero(r[inc()])), + CostAdd: dh.StringToInt(dh.EmptyToZero(r[inc()])), CharacterGfxTransform: r[inc()], InventoryGfxTransform: r[inc()], @@ -79,7 +83,7 @@ func createUniqueItemRecord(r []string) UniqueItemRecord { InventoryFile: r[inc()], DropSound: r[inc()], - DropSfxFrame: StringToInt(EmptyToZero(r[inc()])), + DropSfxFrame: dh.StringToInt(dh.EmptyToZero(r[inc()])), UseSound: r[inc()], Properties: [12]UniqueItemProperty{ @@ -106,17 +110,17 @@ func createUniqueItemProperty(r *[]string, inc func() int) UniqueItemProperty { result := UniqueItemProperty{ Property: (*r)[inc()], Parameter: (*r)[inc()], - Min: StringToInt(EmptyToZero((*r)[inc()])), - Max: StringToInt(EmptyToZero((*r)[inc()])), + Min: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + Max: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), } return result } var UniqueItems map[string]*UniqueItemRecord -func LoadUniqueItems(fileProvider FileProvider) { +func LoadUniqueItems(fileProvider d2interface.FileProvider) { UniqueItems = make(map[string]*UniqueItemRecord) - data := strings.Split(string(fileProvider.LoadFile(resourcepaths.UniqueItems)), "\r\n")[1:] + data := strings.Split(string(fileProvider.LoadFile(d2common.UniqueItems)), "\r\n")[1:] for _, line := range data { if len(line) == 0 { continue diff --git a/common/Weapons.go b/d2data/datadict/Weapons.go similarity index 57% rename from common/Weapons.go rename to d2data/datadict/Weapons.go index 364c9b15..12014145 100644 --- a/common/Weapons.go +++ b/d2data/datadict/Weapons.go @@ -1,10 +1,14 @@ -package common +package datadict import ( "log" "strings" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + dh "github.com/OpenDiablo2/OpenDiablo2/d2helper" ) type WeaponRecord struct { @@ -134,36 +138,36 @@ func createWeaponRecord(line string) WeaponRecord { Code: r[inc()], AlternateGfx: r[inc()], NameString: r[inc()], - Version: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - CompactSave: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - Rarity: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Spawnable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, + Version: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + CompactSave: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + Rarity: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Spawnable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - MinDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - MaxDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - BarbOneOrTwoHanded: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - UsesTwoHands: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - Min2HandDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Max2HandDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - MinMissileDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - MaxMissileDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - MissileSpeed: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - ExtraRange: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Speed: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - StrengthBonus: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - DexterityBonus: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + MinDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + MaxDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + BarbOneOrTwoHanded: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + UsesTwoHands: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + Min2HandDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Max2HandDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + MinMissileDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + MaxMissileDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + MissileSpeed: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + ExtraRange: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Speed: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + StrengthBonus: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + DexterityBonus: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - RequiredStrength: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - RequiredDexterity: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Durability: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - NoDurability: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, + RequiredStrength: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + RequiredDexterity: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Durability: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + NoDurability: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - Level: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - RequiredLevel: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Cost: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - GambleCost: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - MagicLevel: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - AutoPrefix: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + Level: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + RequiredLevel: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Cost: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + GambleCost: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + MagicLevel: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + AutoPrefix: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), OpenBetaGfx: r[inc()], NormalCode: r[inc()], UberCode: r[inc()], @@ -171,61 +175,61 @@ func createWeaponRecord(line string) WeaponRecord { WeaponClass: r[inc()], WeaponClass2Hand: r[inc()], - Component: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + Component: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), HitClass: r[inc()], - InventoryWidth: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - InventoryHeight: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Stackable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - MinStack: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - MaxStack: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - SpawnStack: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + InventoryWidth: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + InventoryHeight: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Stackable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + MinStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + MaxStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + SpawnStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), FlippyFile: r[inc()], InventoryFile: r[inc()], UniqueInventoryFile: r[inc()], SetInventoryFile: r[inc()], - HasInventory: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - GemSockets: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - GemApplyType: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + HasInventory: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + GemSockets: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + GemApplyType: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), SpecialFeature: r[inc()], - Useable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, + Useable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, DropSound: r[inc()], - DropSfxFrame: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + DropSfxFrame: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), UseSound: r[inc()], - Unique: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - Transparent: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - TransTable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Quivered: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - LightRadius: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - Belt: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, + Unique: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + Transparent: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + TransTable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Quivered: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + LightRadius: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + Belt: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - Quest: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - QuestDifficultyCheck: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, + Quest: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + QuestDifficultyCheck: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, - MissileType: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - DurabilityWarning: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - QuantityWarning: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - GemOffset: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - BitField1: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + MissileType: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + DurabilityWarning: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + QuantityWarning: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + GemOffset: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + BitField1: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), Vendors: createWeaponVendorParams(&r, inc), SourceArt: r[inc()], GameArt: r[inc()], - ColorTransform: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), - InventoryColorTransform: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), + ColorTransform: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), + InventoryColorTransform: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))), - SkipName: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, + SkipName: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, NightmareUpgrade: r[inc()], HellUpgrade: r[inc()], - Nameable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, - PermStoreItem: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, + Nameable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, + PermStoreItem: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1, } return result } @@ -258,11 +262,11 @@ func CreateItemVendorParams(r *[]string, inc func() int, vs []string) map[string for _, name := range vs { wvp := ItemVendorParams{ - Min: StringToInt(EmptyToZero((*r)[inc()])), - Max: StringToInt(EmptyToZero((*r)[inc()])), - MagicMin: StringToInt(EmptyToZero((*r)[inc()])), - MagicMax: StringToInt(EmptyToZero((*r)[inc()])), - MagicLevel: StringToUint8(EmptyToZero((*r)[inc()])), + Min: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + Max: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + MagicMin: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + MagicMax: dh.StringToInt(dh.EmptyToZero((*r)[inc()])), + MagicLevel: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])), } result[name] = &wvp } @@ -271,9 +275,9 @@ func CreateItemVendorParams(r *[]string, inc func() int, vs []string) map[string var Weapons map[string]*WeaponRecord -func LoadWeapons(fileProvider FileProvider) { +func LoadWeapons(fileProvider d2interface.FileProvider) { Weapons = make(map[string]*WeaponRecord) - data := strings.Split(string(fileProvider.LoadFile(resourcepaths.Weapons)), "\r\n")[1:] + data := strings.Split(string(fileProvider.LoadFile(d2common.Weapons)), "\r\n")[1:] for _, line := range data { if len(line) == 0 { continue diff --git a/mpq/CryptoBuff.go b/d2data/mpq/CryptoBuff.go similarity index 100% rename from mpq/CryptoBuff.go rename to d2data/mpq/CryptoBuff.go diff --git a/mpq/MPQ.go b/d2data/mpq/MPQ.go similarity index 98% rename from mpq/MPQ.go rename to d2data/mpq/MPQ.go index 69678d79..c4a07d51 100644 --- a/mpq/MPQ.go +++ b/d2data/mpq/MPQ.go @@ -10,7 +10,7 @@ import ( "strings" "sync" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) // MPQ represents an MPQ archive @@ -260,7 +260,7 @@ func (v MPQ) FileExists(fileName string) bool { // ReadFile reads a file from the MPQ and returns a memory stream func (v MPQ) ReadFile(fileName string) ([]byte, error) { - fileName = strings.ReplaceAll(fileName, "{LANG}", resourcepaths.LanguageCode) + fileName = strings.ReplaceAll(fileName, "{LANG}", d2common.LanguageCode) fileName = strings.ToLower(fileName) fileName = strings.ReplaceAll(fileName, `/`, "\\") cached := v.fileCache[fileName] diff --git a/mpq/MPQStream.go b/d2data/mpq/MPQStream.go similarity index 95% rename from mpq/MPQStream.go rename to d2data/mpq/MPQStream.go index 11547f2c..0b0a9079 100644 --- a/mpq/MPQStream.go +++ b/d2data/mpq/MPQStream.go @@ -9,9 +9,10 @@ import ( "log" "strings" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + "github.com/JoshVarga/blast" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/compression" + "github.com/OpenDiablo2/OpenDiablo2/d2data/compression" ) // Stream represents a stream of data in an MPQ archive @@ -98,7 +99,7 @@ func (v *Stream) readInternalSingleUnit(buffer []byte, offset, count uint32) uin v.loadSingleUnit() } - bytesToCopy := common.Min(uint32(len(v.CurrentData))-v.CurrentPosition, count) + bytesToCopy := d2helper.Min(uint32(len(v.CurrentData))-v.CurrentPosition, count) copy(buffer[offset:offset+bytesToCopy], v.CurrentData[v.CurrentPosition:v.CurrentPosition+bytesToCopy]) v.CurrentPosition += bytesToCopy return bytesToCopy @@ -107,7 +108,7 @@ func (v *Stream) readInternalSingleUnit(buffer []byte, offset, count uint32) uin func (v *Stream) readInternal(buffer []byte, offset, count uint32) uint32 { v.bufferData() localPosition := v.CurrentPosition % v.BlockSize - bytesToCopy := common.MinInt32(int32(len(v.CurrentData))-int32(localPosition), int32(count)) + bytesToCopy := d2helper.MinInt32(int32(len(v.CurrentData))-int32(localPosition), int32(count)) if bytesToCopy <= 0 { return 0 } @@ -121,7 +122,7 @@ func (v *Stream) bufferData() { if requiredBlock == v.CurrentBlockIndex { return } - expectedLength := common.Min(v.BlockTableEntry.UncompressedFileSize-(requiredBlock*v.BlockSize), v.BlockSize) + expectedLength := d2helper.Min(v.BlockTableEntry.UncompressedFileSize-(requiredBlock*v.BlockSize), v.BlockSize) v.CurrentData = v.loadBlock(requiredBlock, expectedLength) v.CurrentBlockIndex = requiredBlock } diff --git a/common/MpqFileRecord.go b/d2data/mpq/MpqFileRecord.go similarity index 87% rename from common/MpqFileRecord.go rename to d2data/mpq/MpqFileRecord.go index 4fe633c9..b0c61c66 100644 --- a/common/MpqFileRecord.go +++ b/d2data/mpq/MpqFileRecord.go @@ -1,4 +1,4 @@ -package common +package mpq type MpqFileRecord struct { MpqFile string diff --git a/video/BinkDecoder.go b/d2data/video/BinkDecoder.go similarity index 95% rename from video/BinkDecoder.go rename to d2data/video/BinkDecoder.go index 2ae912ef..bbaaad5a 100644 --- a/video/BinkDecoder.go +++ b/d2data/video/BinkDecoder.go @@ -3,7 +3,7 @@ package video import ( "log" - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) type BinkVideoMode uint32 @@ -41,7 +41,7 @@ type BinkDecoder struct { VideoHeight uint32 FPS uint32 FrameTimeMS uint32 - streamReader *common.StreamReader + streamReader *d2common.StreamReader VideoMode BinkVideoMode HasAlphaPlane bool Grayscale bool @@ -52,7 +52,7 @@ type BinkDecoder struct { func CreateBinkDecoder(source []byte) *BinkDecoder { result := &BinkDecoder{ - streamReader: common.CreateStreamReader(source), + streamReader: d2common.CreateStreamReader(source), } result.loadHeaderInformation() return result diff --git a/common/ColorConvert.go b/d2helper/ColorConvert.go similarity index 98% rename from common/ColorConvert.go rename to d2helper/ColorConvert.go index d5fe11f8..b5d792dc 100644 --- a/common/ColorConvert.go +++ b/d2helper/ColorConvert.go @@ -1,4 +1,4 @@ -package common +package d2helper import ( "image/color" diff --git a/common/Math.go b/d2helper/Math.go similarity index 98% rename from common/Math.go rename to d2helper/Math.go index 39f4c2e0..506d8138 100644 --- a/common/Math.go +++ b/d2helper/Math.go @@ -1,4 +1,4 @@ -package common +package d2helper // Min returns the lower of two values func Min(a, b uint32) uint32 { diff --git a/common/StringUtils.go b/d2helper/StringUtils.go similarity index 99% rename from common/StringUtils.go rename to d2helper/StringUtils.go index 1e6908ed..94c6b203 100644 --- a/common/StringUtils.go +++ b/d2helper/StringUtils.go @@ -1,4 +1,4 @@ -package common +package d2helper import ( "bytes" diff --git a/common/AnimatedEntity.go b/d2render/AnimatedEntity.go similarity index 78% rename from common/AnimatedEntity.go rename to d2render/AnimatedEntity.go index 13a69eb3..8322c324 100644 --- a/common/AnimatedEntity.go +++ b/d2render/AnimatedEntity.go @@ -1,4 +1,4 @@ -package common +package d2render import ( "fmt" @@ -6,7 +6,17 @@ import ( "strings" "time" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" + + "github.com/OpenDiablo2/OpenDiablo2/d2data" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" "github.com/hajimehoshi/ebiten" ) @@ -19,9 +29,9 @@ type AnimatedEntity struct { LocationX float64 // LocationY represents the tile Y position of the entity LocationY float64 - dccLayers map[string]*DCC - Cof *Cof - palette palettedefs.PaletteType + dccLayers map[string]*d2data.DCC + Cof *d2data.Cof + palette d2enum.PaletteType base string token string animationMode string @@ -32,19 +42,19 @@ type AnimatedEntity struct { direction int currentFrame int frames map[string][]*ebiten.Image - frameLocations map[string][]Rectangle - object Object + frameLocations map[string][]d2common.Rectangle + object d2data.Object } // CreateAnimatedEntity creates an instance of AnimatedEntity -func CreateAnimatedEntity(object Object, fileProvider FileProvider, palette palettedefs.PaletteType) *AnimatedEntity { +func CreateAnimatedEntity(object d2data.Object, fileProvider d2interface.FileProvider, palette d2enum.PaletteType) *AnimatedEntity { result := &AnimatedEntity{ base: object.Lookup.Base, token: object.Lookup.Token, object: object, palette: palette, } - result.dccLayers = make(map[string]*DCC) + result.dccLayers = make(map[string]*d2data.DCC) result.LocationX = float64(object.X) / 5 result.LocationY = float64(object.Y) / 5 return result @@ -54,9 +64,9 @@ func CreateAnimatedEntity(object Object, fileProvider FileProvider, palette pale var DirectionLookup = []int{3, 15, 4, 8, 0, 9, 5, 10, 1, 11, 6, 12, 2, 13, 7, 14} // SetMode changes the graphical mode of this animated entity -func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction int, provider FileProvider) { +func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction int, provider d2interface.FileProvider) { cofPath := fmt.Sprintf("%s/%s/Cof/%s%s%s.Cof", v.base, v.token, v.token, animationMode, weaponClass) - v.Cof = LoadCof(cofPath, provider) + v.Cof = d2data.LoadCof(cofPath, provider) v.animationMode = animationMode v.weaponClass = weaponClass v.direction = direction @@ -64,8 +74,8 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in v.direction = v.Cof.NumberOfDirections - 1 } v.frames = make(map[string][]*ebiten.Image) - v.frameLocations = make(map[string][]Rectangle) - v.dccLayers = make(map[string]*DCC) + v.frameLocations = make(map[string][]d2common.Rectangle) + v.dccLayers = make(map[string]*d2data.DCC) for _, cofLayer := range v.Cof.CofLayers { layerName := DccLayerNames[cofLayer.Type] v.dccLayers[layerName] = v.LoadLayer(layerName, provider) @@ -77,7 +87,7 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in } -func (v *AnimatedEntity) LoadLayer(layer string, fileProvider FileProvider) *DCC { +func (v *AnimatedEntity) LoadLayer(layer string, fileProvider d2interface.FileProvider) *d2data.DCC { layerName := "tr" switch strings.ToUpper(layer) { case "HD": // Head @@ -117,7 +127,7 @@ func (v *AnimatedEntity) LoadLayer(layer string, fileProvider FileProvider) *DCC return nil } dccPath := fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dcc", v.base, v.token, layer, v.token, layer, layerName, v.animationMode, v.weaponClass) - return LoadDCC(dccPath, fileProvider) + return d2data.LoadDCC(dccPath, fileProvider) } // Render draws this animated entity onto the target @@ -149,7 +159,7 @@ func (v *AnimatedEntity) Render(target *ebiten.Image, offsetX, offsetY int) { func (v *AnimatedEntity) cacheFrames(layerName string) { dcc := v.dccLayers[layerName] v.currentFrame = 0 - animationData := AnimationData[strings.ToLower(v.token+v.animationMode+v.weaponClass)][0] + animationData := d2data.AnimationData[strings.ToLower(v.token+v.animationMode+v.weaponClass)][0] v.animationSpeed = int(1000.0 / ((float64(animationData.AnimationSpeed) * 25.0) / 256.0)) v.framesToAnimate = animationData.FramesPerDirection v.lastFrameTime = time.Now() @@ -158,15 +168,15 @@ func (v *AnimatedEntity) cacheFrames(layerName string) { maxX := int32(-10000) maxY := int32(-10000) for _, layer := range dcc.Directions { - minX = MinInt32(minX, int32(layer.Box.Left)) - minY = MinInt32(minY, int32(layer.Box.Top)) - maxX = MaxInt32(maxX, int32(layer.Box.Right())) - maxY = MaxInt32(maxY, int32(layer.Box.Bottom())) + minX = d2helper.MinInt32(minX, int32(layer.Box.Left)) + minY = d2helper.MinInt32(minY, int32(layer.Box.Top)) + maxX = d2helper.MaxInt32(maxX, int32(layer.Box.Right())) + maxY = d2helper.MaxInt32(maxY, int32(layer.Box.Bottom())) } frameW := maxX - minX frameH := maxY - minY v.frames[layerName] = make([]*ebiten.Image, v.framesToAnimate) - v.frameLocations[layerName] = make([]Rectangle, v.framesToAnimate) + v.frameLocations[layerName] = make([]d2common.Rectangle, v.framesToAnimate) for frameIndex := range v.frames[layerName] { v.frames[layerName][frameIndex], _ = ebiten.NewImage(int(frameW), int(frameH), ebiten.FilterNearest) for layerIdx := 0; layerIdx < v.Cof.NumberOfLayers; layerIdx++ { @@ -185,7 +195,7 @@ func (v *AnimatedEntity) cacheFrames(layerName string) { if paletteIndex == 0 { continue } - color := Palettes[v.palette].Colors[paletteIndex] + color := datadict.Palettes[v.palette].Colors[paletteIndex] actualX := x + direction.Box.Left - int(minX) actualY := y + direction.Box.Top - int(minY) img.Pix[(actualX*4)+(actualY*int(frameW)*4)] = color.R @@ -197,7 +207,7 @@ func (v *AnimatedEntity) cacheFrames(layerName string) { newImage, _ := ebiten.NewImageFromImage(img, ebiten.FilterNearest) img = nil v.frames[layerName][frameIndex] = newImage - v.frameLocations[layerName][frameIndex] = Rectangle{ + v.frameLocations[layerName][frameIndex] = d2common.Rectangle{ Left: int(minX), Top: int(minY), Width: int(frameW), diff --git a/d2render/NPC.go b/d2render/NPC.go new file mode 100644 index 00000000..485de300 --- /dev/null +++ b/d2render/NPC.go @@ -0,0 +1,27 @@ +package d2render + +import ( + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2data" + "github.com/hajimehoshi/ebiten" +) + +type NPC struct { + AnimatedEntity *AnimatedEntity + Paths []d2common.Path +} + +func CreateNPC(object d2data.Object, fileProvider d2interface.FileProvider) *NPC { + result := &NPC{ + AnimatedEntity: CreateAnimatedEntity(object, fileProvider, d2enum.Units), + Paths: object.Paths, + } + result.AnimatedEntity.SetMode(object.Lookup.Mode, object.Lookup.Class, 1, fileProvider) + return result +} + +func (v *NPC) Render(target *ebiten.Image, offsetX, offsetY int) { + v.AnimatedEntity.Render(target, offsetX, offsetY) +} diff --git a/common/Sprite.go b/d2render/Sprite.go similarity index 92% rename from common/Sprite.go rename to d2render/Sprite.go index 05578cb2..115af1f2 100644 --- a/common/Sprite.go +++ b/d2render/Sprite.go @@ -1,4 +1,4 @@ -package common +package d2render import ( "encoding/binary" @@ -7,6 +7,10 @@ import ( "sync" "time" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + "github.com/hajimehoshi/ebiten" ) @@ -45,7 +49,7 @@ type SpriteFrame struct { } // CreateSprite creates an instance of a sprite -func CreateSprite(data []byte, palette PaletteRec) *Sprite { +func CreateSprite(data []byte, palette datadict.PaletteRec) *Sprite { result := &Sprite{ X: 50, Y: 50, @@ -81,9 +85,9 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite { dataPointer += 4 result.Frames[i].Height = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4]) dataPointer += 4 - result.Frames[i].OffsetX = BytesToInt32(data[dataPointer : dataPointer+4]) + result.Frames[i].OffsetX = d2helper.BytesToInt32(data[dataPointer : dataPointer+4]) dataPointer += 4 - result.Frames[i].OffsetY = BytesToInt32(data[dataPointer : dataPointer+4]) + result.Frames[i].OffsetY = d2helper.BytesToInt32(data[dataPointer : dataPointer+4]) dataPointer += 4 result.Frames[i].Unknown = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4]) dataPointer += 4 @@ -143,7 +147,7 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite { for d := 0; d < int(result.Directions); d++ { curMaxWidth := 0 for f := 0; f < int(result.FramesPerDirection); f++ { - curMaxWidth = int(Max(uint32(curMaxWidth), result.Frames[frame].Width)) + curMaxWidth = int(d2helper.Max(uint32(curMaxWidth), result.Frames[frame].Width)) totalHeight += int(result.Frames[frame].Height) frame++ } @@ -157,7 +161,7 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite { for d := 0; d < int(result.Directions); d++ { curMaxWidth := 0 for f := 0; f < int(result.FramesPerDirection); f++ { - curMaxWidth = int(Max(uint32(curMaxWidth), result.Frames[frame].Width)) + curMaxWidth = int(d2helper.Max(uint32(curMaxWidth), result.Frames[frame].Width)) result.Frames[frame].Image = result.atlas.SubImage(image.Rect(curX, curY, curX+int(result.Frames[frame].Width), curY+int(result.Frames[frame].Height))).(*ebiten.Image) curY += int(result.Frames[frame].Height) frame++ @@ -260,7 +264,7 @@ func (v *Sprite) Draw(target *ebiten.Image) { opts.CompositeMode = ebiten.CompositeModeSourceOver } if v.ColorMod != nil { - opts.ColorM = ColorToColorM(v.ColorMod) + opts.ColorM = d2helper.ColorToColorM(v.ColorMod) } target.DrawImage(frame.Image, opts) } @@ -288,11 +292,11 @@ func (v *Sprite) DrawSegments(target *ebiten.Image, xSegments, ySegments, offset opts.CompositeMode = ebiten.CompositeModeSourceOver } if v.ColorMod != nil { - opts.ColorM = ColorToColorM(v.ColorMod) + opts.ColorM = d2helper.ColorToColorM(v.ColorMod) } target.DrawImage(frame.Image, opts) xOffset += int32(frame.Width) - biggestYOffset = MaxInt32(biggestYOffset, int32(frame.Height)) + biggestYOffset = d2helper.MaxInt32(biggestYOffset, int32(frame.Height)) } yOffset += biggestYOffset } diff --git a/map/Engine.go b/d2render/mapengine/Engine.go similarity index 77% rename from map/Engine.go rename to d2render/mapengine/Engine.go index 066019ff..08249922 100644 --- a/map/Engine.go +++ b/d2render/mapengine/Engine.go @@ -1,30 +1,36 @@ -package _map +package mapengine import ( "math" "math/rand" "strings" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/sound" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2core" + + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + "github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/hajimehoshi/ebiten" ) type EngineRegion struct { - Rect common.Rectangle + Rect d2common.Rectangle Region *Region } type Engine struct { - soundManager *sound.Manager - gameState *common.GameState - fileProvider common.FileProvider + soundManager *d2audio.Manager + gameState *d2core.GameState + fileProvider d2interface.FileProvider regions []EngineRegion OffsetX float64 OffsetY float64 } -func CreateMapEngine(gameState *common.GameState, soundManager *sound.Manager, fileProvider common.FileProvider) *Engine { +func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager, fileProvider d2interface.FileProvider) *Engine { result := &Engine{ gameState: gameState, soundManager: soundManager, @@ -38,7 +44,7 @@ func (v *Engine) GenerateMap(regionType RegionIdType, levelPreset int) { randomSource := rand.NewSource(v.gameState.Seed) region := LoadRegion(randomSource, regionType, levelPreset, v.fileProvider) v.regions = append(v.regions, EngineRegion{ - Rect: common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)}, + Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)}, Region: region, }) } @@ -48,24 +54,24 @@ func (v *Engine) GenerateAct1Overworld() { randomSource := rand.NewSource(v.gameState.Seed) region := LoadRegion(randomSource, RegionAct1Town, 1, v.fileProvider) v.regions = append(v.regions, EngineRegion{ - Rect: common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)}, + Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)}, Region: region, }) if strings.Contains(region.RegionPath, "E1") { region2 := LoadRegion(randomSource, RegionAct1Town, 2, v.fileProvider) v.regions = append(v.regions, EngineRegion{ - Rect: common.Rectangle{int(region.TileWidth - 1), 0, int(region2.TileWidth), int(region2.TileHeight)}, + Rect: d2common.Rectangle{int(region.TileWidth - 1), 0, int(region2.TileWidth), int(region2.TileHeight)}, Region: region2, }) } else if strings.Contains(region.RegionPath, "S1") { region2 := LoadRegion(randomSource, RegionAct1Town, 3, v.fileProvider) v.regions = append(v.regions, EngineRegion{ - Rect: common.Rectangle{0, int(region.TileHeight - 1), int(region2.TileWidth), int(region2.TileHeight)}, + Rect: d2common.Rectangle{0, int(region.TileHeight - 1), int(region2.TileWidth), int(region2.TileHeight)}, Region: region2, }) } - sx, sy := common.IsoToScreen(int(region.StartX), int(region.StartY), 0, 0) + sx, sy := d2helper.IsoToScreen(int(region.StartX), int(region.StartY), 0, 0) v.OffsetX = float64(sx) - 400 v.OffsetY = float64(sy) - 300 } @@ -94,7 +100,7 @@ func (v *Engine) RenderRegion(region EngineRegion, target *ebiten.Image) { offX := -((y + region.Rect.Top) * 80) + (region.Rect.Left * 80) offY := ((y + region.Rect.Top) * 40) + (region.Rect.Left * 40) for x := 0; x < int(region.Region.TileWidth); x++ { - sx, sy := common.IsoToScreen(x+region.Rect.Left, y+region.Rect.Top, int(v.OffsetX), int(v.OffsetY)) + sx, sy := d2helper.IsoToScreen(x+region.Rect.Left, y+region.Rect.Top, int(v.OffsetX), int(v.OffsetY)) if sx > -160 && sy > -160 && sx <= 880 && sy <= 1000 { v.RenderTile(region.Region, offX, offY, x, y, target) } diff --git a/map/Region.go b/d2render/mapengine/Region.go similarity index 78% rename from map/Region.go rename to d2render/mapengine/Region.go index f70d1356..8ccac7dd 100644 --- a/map/Region.go +++ b/d2render/mapengine/Region.go @@ -1,4 +1,4 @@ -package _map +package mapengine import ( "image/color" @@ -8,11 +8,19 @@ import ( "strconv" "sync" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2render" + + "github.com/OpenDiablo2/OpenDiablo2/d2data" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" "github.com/hajimehoshi/ebiten" - - "github.com/OpenDiablo2/OpenDiablo2/common" ) type TileCacheRecord struct { @@ -23,18 +31,18 @@ type TileCacheRecord struct { type Region struct { RegionPath string - LevelType common.LevelTypeRecord - levelPreset *common.LevelPresetRecord + LevelType datadict.LevelTypeRecord + levelPreset *datadict.LevelPresetRecord TileWidth int32 TileHeight int32 - Tiles []Tile - DS1 *DS1 - Palette common.PaletteRec + Tiles []d2data.Tile + DS1 *d2data.DS1 + Palette datadict.PaletteRec FloorCache map[uint32]*TileCacheRecord ShadowCache map[uint32]*TileCacheRecord WallCache map[uint32]*TileCacheRecord - AnimationEntities []*common.AnimatedEntity - NPCs []*common.NPC + AnimationEntities []*d2render.AnimatedEntity + NPCs []*d2render.NPC StartX float64 StartY float64 } @@ -87,16 +95,16 @@ const ( RegionAct5Lava RegionIdType = 35 ) -func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileProvider common.FileProvider) *Region { +func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileProvider d2interface.FileProvider) *Region { result := &Region{ - LevelType: common.LevelTypes[levelType], - levelPreset: common.LevelPresets[levelPreset], - Tiles: make([]Tile, 0), + LevelType: datadict.LevelTypes[levelType], + levelPreset: datadict.LevelPresets[levelPreset], + Tiles: make([]d2data.Tile, 0), FloorCache: make(map[uint32]*TileCacheRecord), ShadowCache: make(map[uint32]*TileCacheRecord), WallCache: make(map[uint32]*TileCacheRecord), } - result.Palette = common.Palettes[palettedefs.PaletteType("act"+strconv.Itoa(int(result.LevelType.Act)))] + result.Palette = datadict.Palettes[d2enum.PaletteType("act"+strconv.Itoa(int(result.LevelType.Act)))] //\bm := result.levelPreset.Dt1Mask for _, levelTypeDt1 := range result.LevelType.Files { /* @@ -109,7 +117,7 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP if len(levelTypeDt1) == 0 || levelTypeDt1 == "" || levelTypeDt1 == "0" { continue } - dt1 := LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider) + dt1 := d2data.LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider) result.Tiles = append(result.Tiles, dt1.Tiles...) } levelFilesToPick := make([]string, 0) @@ -123,34 +131,34 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * random.Float64())) levelFile := levelFilesToPick[levelIndex] result.RegionPath = levelFile - result.DS1 = LoadDS1("/data/global/tiles/"+levelFile, fileProvider) + result.DS1 = d2data.LoadDS1("/data/global/tiles/"+levelFile, fileProvider) result.TileWidth = result.DS1.Width result.TileHeight = result.DS1.Height result.loadObjects(fileProvider) return result } -func (v *Region) loadObjects(fileProvider common.FileProvider) { +func (v *Region) loadObjects(fileProvider d2interface.FileProvider) { var wg sync.WaitGroup wg.Add(len(v.DS1.Objects)) - v.AnimationEntities = make([]*common.AnimatedEntity, 0) - v.NPCs = make([]*common.NPC, 0) + v.AnimationEntities = make([]*d2render.AnimatedEntity, 0) + v.NPCs = make([]*d2render.NPC, 0) for _, object := range v.DS1.Objects { - go func(object common.Object) { + go func(object d2data.Object) { defer wg.Done() switch object.Lookup.Type { - case common.ObjectTypeCharacter: + case datadict.ObjectTypeCharacter: // Temp code, maybe.. if object.Lookup.Base == "" || object.Lookup.Token == "" || object.Lookup.TR == "" { return } - npc := common.CreateNPC(object, fileProvider) + npc := d2render.CreateNPC(object, fileProvider) v.NPCs = append(v.NPCs, npc) - case common.ObjectTypeItem: + case datadict.ObjectTypeItem: if object.ObjectInfo == nil || !object.ObjectInfo.Draw || object.Lookup.Base == "" || object.Lookup.Token == "" { return } - entity := common.CreateAnimatedEntity(object, fileProvider, palettedefs.Units) + entity := d2render.CreateAnimatedEntity(object, fileProvider, d2enum.Units) entity.SetMode(object.Lookup.Mode, object.Lookup.Class, 0, fileProvider) v.AnimationEntities = append(v.AnimationEntities, entity) } @@ -171,7 +179,7 @@ func (v *Region) RenderTile(offsetX, offsetY, tileX, tileY int, layerType Region } } -func (v *Region) getTile(mainIndex, subIndex, orientation int32) *Tile { +func (v *Region) getTile(mainIndex, subIndex, orientation int32) *d2data.Tile { // TODO: Need to support randomly grabbing tile based on x/y as there can be multiple matches for same main/sub index for _, tile := range v.Tiles { if tile.MainIndex != mainIndex || tile.SubIndex != subIndex || tile.Orientation != orientation { @@ -183,7 +191,7 @@ func (v *Region) getTile(mainIndex, subIndex, orientation int32) *Tile { return nil } -func (v *Region) renderFloor(tile FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) { +func (v *Region) renderFloor(tile d2data.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) { tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8) tileCache, exists := v.FloorCache[tileCacheIndex] if !exists { @@ -198,7 +206,7 @@ func (v *Region) renderFloor(tile FloorShadowRecord, offsetX, offsetY int, targe target.DrawImage(tileCache.Image, opts) } -func (v *Region) renderWall(tile WallRecord, offsetX, offsetY int, target *ebiten.Image) { +func (v *Region) renderWall(tile d2data.WallRecord, offsetX, offsetY int, target *ebiten.Image) { tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8) | (uint32(tile.Orientation)) tileCache, exists := v.WallCache[tileCacheIndex] if !exists { @@ -213,7 +221,7 @@ func (v *Region) renderWall(tile WallRecord, offsetX, offsetY int, target *ebite target.DrawImage(tileCache.Image, opts) } -func (v *Region) renderShadow(tile FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) { +func (v *Region) renderShadow(tile d2data.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) { tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + 0 tileCache, exists := v.ShadowCache[tileCacheIndex] if !exists { @@ -225,13 +233,13 @@ func (v *Region) renderShadow(tile FloorShadowRecord, offsetX, offsetY int, targ } opts := &ebiten.DrawImageOptions{} opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset)) - opts.ColorM = common.ColorToColorM(color.RGBA{255, 255, 255, 160}) + opts.ColorM = d2helper.ColorToColorM(color.RGBA{255, 255, 255, 160}) target.DrawImage(tileCache.Image, opts) } -func (v *Region) decodeTileGfxData(blocks []Block, pixels []byte, tileYOffset int32, tileWidth int32) { +func (v *Region) decodeTileGfxData(blocks []d2data.Block, pixels []byte, tileYOffset int32, tileWidth int32) { for _, block := range blocks { - if block.Format == BlockFormatIsometric { + if block.Format == d2data.BlockFormatIsometric { // 3D isometric decoding xjump := []int32{14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14} nbpix := []int32{4, 8, 12, 16, 20, 24, 28, 32, 28, 24, 20, 16, 12, 8, 4} @@ -301,17 +309,17 @@ func (v *Region) decodeTileGfxData(blocks []Block, pixels []byte, tileYOffset in } } -func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { +func (v *Region) generateFloorCache(tile d2data.FloorShadowRecord) *TileCacheRecord { tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 0) if tileData == nil { log.Fatalf("Could not locate tile Idx:%d, Sub: %d, Ori: %d", tile.MainIndex, tile.SubIndex, 0) } tileYMinimum := int32(0) for _, block := range tileData.Blocks { - tileYMinimum = common.MinInt32(tileYMinimum, int32(block.Y)) + tileYMinimum = d2helper.MinInt32(tileYMinimum, int32(block.Y)) } - tileYOffset := common.AbsInt32(tileYMinimum) - tileHeight := common.AbsInt32(tileData.Height) + tileYOffset := d2helper.AbsInt32(tileYMinimum) + tileHeight := d2helper.AbsInt32(tileData.Height) image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest) pixels := make([]byte, 4*tileData.Width*tileHeight) v.decodeTileGfxData(tileData.Blocks, pixels, tileYOffset, tileData.Width) @@ -319,7 +327,7 @@ func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { return &TileCacheRecord{image, 0, 0} } -func (v *Region) generateShadowCache(tile FloorShadowRecord) *TileCacheRecord { +func (v *Region) generateShadowCache(tile d2data.FloorShadowRecord) *TileCacheRecord { tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 13) if tileData == nil { return nil @@ -327,8 +335,8 @@ func (v *Region) generateShadowCache(tile FloorShadowRecord) *TileCacheRecord { tileMinY := int32(0) tileMaxY := int32(0) for _, block := range tileData.Blocks { - tileMinY = common.MinInt32(tileMinY, int32(block.Y)) - tileMaxY = common.MaxInt32(tileMaxY, int32(block.Y+32)) + tileMinY = d2helper.MinInt32(tileMinY, int32(block.Y)) + tileMaxY = d2helper.MaxInt32(tileMaxY, int32(block.Y+32)) } tileYOffset := -tileMinY tileHeight := int(tileMaxY - tileMinY) @@ -339,12 +347,12 @@ func (v *Region) generateShadowCache(tile FloorShadowRecord) *TileCacheRecord { return &TileCacheRecord{image, 0, int(tileMinY) + 80} } -func (v *Region) generateWallCache(tile WallRecord) *TileCacheRecord { +func (v *Region) generateWallCache(tile d2data.WallRecord) *TileCacheRecord { tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(tile.Orientation)) if tileData == nil { return nil } - var newTileData *Tile = nil + var newTileData *d2data.Tile = nil if tile.Orientation == 3 { newTileData = v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(4)) } @@ -356,10 +364,10 @@ func (v *Region) generateWallCache(tile WallRecord) *TileCacheRecord { target = newTileData } for _, block := range target.Blocks { - tileMinY = common.MinInt32(tileMinY, int32(block.Y)) - tileMaxY = common.MaxInt32(tileMaxY, int32(block.Y+32)) + tileMinY = d2helper.MinInt32(tileMinY, int32(block.Y)) + tileMaxY = d2helper.MaxInt32(tileMaxY, int32(block.Y+32)) } - realHeight := common.MaxInt32(common.AbsInt32(tileData.Height), tileMaxY-tileMinY) + realHeight := d2helper.MaxInt32(d2helper.AbsInt32(tileData.Height), tileMaxY-tileMinY) tileYOffset := -tileMinY //tileHeight := int(tileMaxY - tileMinY) image, _ := ebiten.NewImage(160, int(realHeight), ebiten.FilterNearest) diff --git a/ui/Button.go b/d2render/ui/Button.go similarity index 82% rename from ui/Button.go rename to d2render/ui/Button.go index d49cc09b..81626e2e 100644 --- a/ui/Button.go +++ b/d2render/ui/Button.go @@ -4,9 +4,16 @@ import ( "image" "image/color" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2render" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/hajimehoshi/ebiten" ) @@ -40,25 +47,25 @@ const ( // ButtonLayout defines the type of buttons type ButtonLayout struct { - XSegments int //1 - YSegments int // 1 - ResourceName string // Font Name - PaletteName palettedefs.PaletteType // PaletteType - Toggleable bool // false - BaseFrame int // 0 - DisabledFrame int // -1 - FontPath string // ResourcePaths.FontExocet10 - ClickableRect *image.Rectangle // nil - AllowFrameChange bool // true - TextOffset int // 0 + XSegments int //1 + YSegments int // 1 + ResourceName string // Font Name + PaletteName d2enum.PaletteType // PaletteType + Toggleable bool // false + BaseFrame int // 0 + DisabledFrame int // -1 + FontPath string // ResourcePaths.FontExocet10 + ClickableRect *image.Rectangle // nil + AllowFrameChange bool // true + TextOffset int // 0 } // ButtonLayouts define the type of buttons you can have var ButtonLayouts = map[ButtonType]ButtonLayout{ - ButtonTypeWide: {2, 1, resourcepaths.WideButtonBlank, palettedefs.Units, false, 0, -1, resourcepaths.FontExocet10, nil, true, 1}, - ButtonTypeShort: {1, 1, resourcepaths.ShortButtonBlank, palettedefs.Units, false, 0, -1, resourcepaths.FontRediculous, nil, true, -1}, - ButtonTypeMedium: {1, 1, resourcepaths.MediumButtonBlank, palettedefs.Units, false, 0, 0, resourcepaths.FontExocet10, nil, true, 0}, - ButtonTypeTall: {1, 1, resourcepaths.TallButtonBlank, palettedefs.Units, false, 0, 0, resourcepaths.FontExocet10, nil, true, 5}, + ButtonTypeWide: {2, 1, d2common.WideButtonBlank, d2enum.Units, false, 0, -1, d2common.FontExocet10, nil, true, 1}, + ButtonTypeShort: {1, 1, d2common.ShortButtonBlank, d2enum.Units, false, 0, -1, d2common.FontRediculous, nil, true, -1}, + ButtonTypeMedium: {1, 1, d2common.MediumButtonBlank, d2enum.Units, false, 0, 0, d2common.FontExocet10, nil, true, 0}, + ButtonTypeTall: {1, 1, d2common.TallButtonBlank, d2enum.Units, false, 0, 0, d2common.FontExocet10, nil, true, 5}, /* {eButtonType.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = PaletteDefs.Units } }, {eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = PaletteDefs.Units } }, @@ -89,7 +96,7 @@ type Button struct { visible bool pressed bool toggled bool - fileProvider common.FileProvider + fileProvider d2interface.FileProvider normalImage *ebiten.Image pressedImage *ebiten.Image toggledImage *ebiten.Image @@ -100,7 +107,7 @@ type Button struct { } // CreateButton creates an instance of Button -func CreateButton(buttonType ButtonType, fileProvider common.FileProvider, text string) *Button { +func CreateButton(buttonType ButtonType, fileProvider d2interface.FileProvider, text string) *Button { result := &Button{ fileProvider: fileProvider, width: 0, @@ -111,8 +118,9 @@ func CreateButton(buttonType ButtonType, fileProvider common.FileProvider, text } buttonLayout := ButtonLayouts[buttonType] result.buttonLayout = buttonLayout - font := GetFont(buttonLayout.FontPath, palettedefs.Units, fileProvider) - buttonSprite := fileProvider.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName) + font := GetFont(buttonLayout.FontPath, d2enum.Units, fileProvider) + + buttonSprite := d2render.CreateSprite(fileProvider.LoadFile(buttonLayout.ResourceName), datadict.Palettes[buttonLayout.PaletteName]) totalButtonTypes := buttonSprite.GetTotalFrames() / (buttonLayout.XSegments * buttonLayout.YSegments) for i := 0; i < buttonLayout.XSegments; i++ { w, _ := buttonSprite.GetFrameSize(i) @@ -179,7 +187,7 @@ func (v *Button) Draw(target *ebiten.Image) { if !v.enabled { //opts.CompositeMode = ebiten.CompositeModeLighter - opts.ColorM = common.ColorToColorM(color.RGBA{128, 128, 128, 195}) + opts.ColorM = d2helper.ColorToColorM(color.RGBA{128, 128, 128, 195}) target.DrawImage(v.disabledImage, opts) } else if v.toggled && v.pressed { target.DrawImage(v.pressedToggledImage, opts) diff --git a/ui/Font.go b/d2render/ui/Font.go similarity index 73% rename from ui/Font.go rename to d2render/ui/Font.go index 9fc38b28..7274ff7f 100644 --- a/ui/Font.go +++ b/d2render/ui/Font.go @@ -4,8 +4,16 @@ import ( "image/color" "strings" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" + "github.com/OpenDiablo2/OpenDiablo2/d2helper" + + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + + "github.com/OpenDiablo2/OpenDiablo2/d2render" + "github.com/hajimehoshi/ebiten" ) @@ -19,12 +27,12 @@ type FontSize struct { // Font represents a font type Font struct { - fontSprite *common.Sprite + fontSprite *d2render.Sprite metrics map[uint8]FontSize } // GetFont creates or loads an existing font -func GetFont(font string, palette palettedefs.PaletteType, fileProvider common.FileProvider) *Font { +func GetFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font { cacheItem, exists := fontCache[font+"_"+string(palette)] if exists { return cacheItem @@ -35,11 +43,11 @@ func GetFont(font string, palette palettedefs.PaletteType, fileProvider common.F } // CreateFont creates an instance of a MPQ Font -func CreateFont(font string, palette palettedefs.PaletteType, fileProvider common.FileProvider) *Font { +func CreateFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font { result := &Font{ metrics: make(map[uint8]FontSize), } - result.fontSprite = fileProvider.LoadSprite(font+".dc6", palette) + result.fontSprite = d2render.CreateSprite(fileProvider.LoadFile(font+".dc6"), datadict.Palettes[palette]) woo := "Woo!\x01" fontData := fileProvider.LoadFile(font + ".tbl") if string(fontData[0:5]) != woo { @@ -62,12 +70,12 @@ func (v *Font) GetTextMetrics(text string) (width, height uint32) { height = uint32(0) maxCharHeight := uint32(0) for _, m := range v.fontSprite.Frames { - maxCharHeight = common.Max(maxCharHeight, uint32(m.Height)) + maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height)) } for i := 0; i < len(text); i++ { ch := text[i] if ch == '\n' { - width = common.Max(width, curWidth) + width = d2helper.Max(width, curWidth) curWidth = 0 height += maxCharHeight + 6 continue @@ -75,7 +83,7 @@ func (v *Font) GetTextMetrics(text string) (width, height uint32) { metric := v.metrics[uint8(ch)] curWidth += uint32(metric.Width) } - width = common.Max(width, curWidth) + width = d2helper.Max(width, curWidth) height += maxCharHeight return } @@ -87,7 +95,7 @@ func (v *Font) Draw(x, y int, text string, color color.Color, target *ebiten.Ima maxCharHeight := uint32(0) for _, m := range v.metrics { - maxCharHeight = common.Max(maxCharHeight, uint32(m.Height)) + maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height)) } targetWidth, _ := target.Size() diff --git a/ui/Label.go b/d2render/ui/Label.go similarity index 90% rename from ui/Label.go rename to d2render/ui/Label.go index 3025a5a5..1e6d4761 100644 --- a/ui/Label.go +++ b/d2render/ui/Label.go @@ -3,8 +3,10 @@ package ui import ( "image/color" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/hajimehoshi/ebiten" ) @@ -34,7 +36,7 @@ type Label struct { } // CreateLabel creates a new instance of a UI label -func CreateLabel(provider common.FileProvider, font string, palette palettedefs.PaletteType) *Label { +func CreateLabel(provider d2interface.FileProvider, font string, palette d2enum.PaletteType) *Label { result := &Label{ Alignment: LabelAlignLeft, Color: color.White, diff --git a/ui/Manager.go b/d2render/ui/Manager.go similarity index 83% rename from ui/Manager.go rename to d2render/ui/Manager.go index 6530b423..a590ea04 100644 --- a/ui/Manager.go +++ b/d2render/ui/Manager.go @@ -1,10 +1,12 @@ package ui import ( - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" - "github.com/OpenDiablo2/OpenDiablo2/sound" + "github.com/OpenDiablo2/OpenDiablo2/d2audio" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" + "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2render" "github.com/hajimehoshi/ebiten" ) @@ -21,22 +23,22 @@ const ( // Manager represents the UI manager type Manager struct { widgets []Widget - cursorSprite *common.Sprite + cursorSprite *d2render.Sprite cursorButtons CursorButton pressedIndex int CursorX int CursorY int - clickSfx *sound.SoundEffect + clickSfx *d2audio.SoundEffect waitForLeftMouseUp bool } // CreateManager creates a new instance of a UI manager -func CreateManager(fileProvider common.FileProvider, soundManager sound.Manager) *Manager { +func CreateManager(fileProvider d2interface.FileProvider, soundManager d2audio.Manager) *Manager { result := &Manager{ pressedIndex: -1, widgets: make([]Widget, 0), - cursorSprite: fileProvider.LoadSprite(resourcepaths.CursorDefault, palettedefs.Units), - clickSfx: soundManager.LoadSoundEffect(resourcepaths.SFXButtonClick), + cursorSprite: d2render.CreateSprite(fileProvider.LoadFile(d2common.CursorDefault), datadict.Palettes[d2enum.Units]), + clickSfx: soundManager.LoadSoundEffect(d2common.SFXButtonClick), waitForLeftMouseUp: false, } return result diff --git a/ui/Widget.go b/d2render/ui/Widget.go similarity index 73% rename from ui/Widget.go rename to d2render/ui/Widget.go index 17f4a15d..f2c62243 100644 --- a/ui/Widget.go +++ b/d2render/ui/Widget.go @@ -1,12 +1,12 @@ package ui import ( - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" ) // Widget defines an object that is a UI widget type Widget interface { - common.Drawable + d2interface.Drawable GetEnabled() bool SetEnabled(enabled bool) SetPressed(pressed bool) diff --git a/go.mod b/go.mod index 2ac27ca7..efdcde2a 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,12 @@ require ( github.com/gopherjs/gopherwasm v1.1.0 // indirect github.com/hajimehoshi/ebiten v1.10.1-0.20191108205544-35436ea50457 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect + github.com/mewspring/tools v0.0.0-20191031203036-122e7c80ae0a // indirect github.com/mitchellh/go-homedir v1.1.0 github.com/pkg/profile v1.3.0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect golang.org/x/mobile v0.0.0-20191031020345-0945064e013a // indirect golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd // indirect - golang.org/x/tools v0.0.0-20191107010934-f79515f33823 // indirect + golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101 // indirect ) diff --git a/go.sum b/go.sum index 5d64d0f5..55279fe7 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,8 @@ github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2Q github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mewspring/tools v0.0.0-20191031203036-122e7c80ae0a h1:Bgb7myjG5GA2qL+rXzV1pc3lbKXVEc4NhUfciOvWp+E= +github.com/mewspring/tools v0.0.0-20191031203036-122e7c80ae0a/go.mod h1:QEmU0TSELL2hDAiUxfPAjLuC10uK0CkvFULzHIUZ1us= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= @@ -103,8 +105,11 @@ golang.org/x/tools v0.0.0-20190909214602-067311248421/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d h1:QFO0Wgcqcp8nI9hbisKDTBsmfwrvLswk2T73QDZZgVo= golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191031220737-6d8f1af9ccc0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191107010934-f79515f33823 h1:akkRBeitX2EZP59KdtKw310CI4WGPCNPyrLbE7WZA8Y= golang.org/x/tools v0.0.0-20191107010934-f79515f33823/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101 h1:LCmXVkvpQCDj724eX6irUTPCJP5GelFHxqGSWL2D1R0= +golang.org/x/tools v0.0.0-20191109212701-97ad0ed33101/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/main.go b/main.go index 0313b400..1dcc94e2 100644 --- a/main.go +++ b/main.go @@ -4,12 +4,14 @@ import ( "image" "log" + "github.com/OpenDiablo2/OpenDiablo2/d2core/scenes" + "github.com/hajimehoshi/ebiten/ebitenutil" - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2common" - "github.com/OpenDiablo2/OpenDiablo2/core" - "github.com/OpenDiablo2/OpenDiablo2/mpq" + "github.com/OpenDiablo2/OpenDiablo2/d2core" + "github.com/OpenDiablo2/OpenDiablo2/d2data/mpq" "github.com/hajimehoshi/ebiten" ) @@ -18,16 +20,17 @@ var GitBranch string // GitCommit is set by the CI build process to the commit hash var GitCommit string -var d2Engine *core.Engine +var d2Engine *d2core.Engine func main() { + //defer profile.Start(profile.CPUProfile).Stop() //runtime.LockOSThread() //defer runtime.UnlockOSThread() if len(GitBranch) == 0 { GitBranch = "Local Build" GitCommit = "" } - common.SetBuildInfo(GitBranch, GitCommit) + d2common.SetBuildInfo(GitBranch, GitCommit) log.SetFlags(log.Ldate | log.LUTC | log.Lmicroseconds | log.Llongfile) log.Println("OpenDiablo2 - Open source Diablo 2 engine") _, iconImage, err := ebitenutil.NewImageFromFile("d2logo.png", ebiten.FilterLinear) @@ -35,7 +38,8 @@ func main() { ebiten.SetWindowIcon([]image.Image{iconImage}) } mpq.InitializeCryptoBuffer() - d2Engine = core.CreateEngine() + d2Engine = d2core.CreateEngine() + d2Engine.SetNextScene(scenes.CreateMainMenu(d2Engine, d2Engine, d2Engine.UIManager, d2Engine.SoundManager)) ebiten.SetCursorVisible(false) ebiten.SetFullscreen(d2Engine.Settings.FullScreen) ebiten.SetRunnableInBackground(d2Engine.Settings.RunInBackground) diff --git a/scenes/SelectHeroClass.go b/scenes/SelectHeroClass.go deleted file mode 100644 index 95a54cf8..00000000 --- a/scenes/SelectHeroClass.go +++ /dev/null @@ -1,568 +0,0 @@ -package scenes - -import ( - "image" - - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/palettedefs" - "github.com/OpenDiablo2/OpenDiablo2/resourcepaths" - "github.com/OpenDiablo2/OpenDiablo2/sound" - "github.com/OpenDiablo2/OpenDiablo2/ui" - "github.com/hajimehoshi/ebiten" -) - -type HeroStance int - -const ( - HeroStanceIdle HeroStance = 0 - HeroStanceIdleSelected HeroStance = 1 - HeroStanceApproaching HeroStance = 2 - HeroStanceSelected HeroStance = 3 - HeroStanceRetreating HeroStance = 4 -) - -type HeroRenderInfo struct { - Stance HeroStance - IdleSprite *common.Sprite - IdleSelectedSprite *common.Sprite - ForwardWalkSprite *common.Sprite - ForwardWalkSpriteOverlay *common.Sprite - SelectedSprite *common.Sprite - SelectedSpriteOverlay *common.Sprite - BackWalkSprite *common.Sprite - BackWalkSpriteOverlay *common.Sprite - SelectionBounds image.Rectangle - SelectSfx *sound.SoundEffect - DeselectSfx *sound.SoundEffect -} - -type SelectHeroClass struct { - uiManager *ui.Manager - soundManager *sound.Manager - fileProvider common.FileProvider - sceneProvider SceneProvider - bgImage *common.Sprite - campfire *common.Sprite - headingLabel *ui.Label - heroClassLabel *ui.Label - heroDesc1Label *ui.Label - heroDesc2Label *ui.Label - heroDesc3Label *ui.Label - heroRenderInfo map[common.Hero]*HeroRenderInfo - selectedHero common.Hero - exitButton *ui.Button -} - -func CreateSelectHeroClass( - fileProvider common.FileProvider, - sceneProvider SceneProvider, - uiManager *ui.Manager, soundManager *sound.Manager, -) *SelectHeroClass { - result := &SelectHeroClass{ - uiManager: uiManager, - sceneProvider: sceneProvider, - fileProvider: fileProvider, - soundManager: soundManager, - heroRenderInfo: make(map[common.Hero]*HeroRenderInfo), - selectedHero: common.HeroNone, - } - return result -} - -func (v *SelectHeroClass) Load() []func() { - v.soundManager.PlayBGM(resourcepaths.BGMTitle) - return []func(){ - func() { - v.bgImage = v.fileProvider.LoadSprite(resourcepaths.CharacterSelectBackground, palettedefs.Fechar) - v.bgImage.MoveTo(0, 0) - }, - func() { - v.headingLabel = ui.CreateLabel(v.fileProvider, resourcepaths.Font30, palettedefs.Units) - fontWidth, _ := v.headingLabel.GetSize() - v.headingLabel.MoveTo(400-int(fontWidth/2), 17) - v.headingLabel.SetText("Select Hero Class") - v.headingLabel.Alignment = ui.LabelAlignCenter - }, - func() { - v.heroClassLabel = ui.CreateLabel(v.fileProvider, resourcepaths.Font30, palettedefs.Units) - v.heroClassLabel.Alignment = ui.LabelAlignCenter - v.heroClassLabel.MoveTo(400, 65) - }, - func() { - v.heroDesc1Label = ui.CreateLabel(v.fileProvider, resourcepaths.Font16, palettedefs.Units) - v.heroDesc1Label.Alignment = ui.LabelAlignCenter - v.heroDesc1Label.MoveTo(400, 100) - }, - func() { - v.heroDesc2Label = ui.CreateLabel(v.fileProvider, resourcepaths.Font16, palettedefs.Units) - v.heroDesc2Label.Alignment = ui.LabelAlignCenter - v.heroDesc2Label.MoveTo(400, 115) - }, - func() { - v.heroDesc3Label = ui.CreateLabel(v.fileProvider, resourcepaths.Font16, palettedefs.Units) - v.heroDesc3Label.Alignment = ui.LabelAlignCenter - v.heroDesc3Label.MoveTo(400, 130) - }, - func() { - v.campfire = v.fileProvider.LoadSprite(resourcepaths.CharacterSelectCampfire, palettedefs.Fechar) - v.campfire.MoveTo(380, 335) - v.campfire.Animate = true - v.campfire.Blend = true - }, - func() { - v.exitButton = ui.CreateButton(ui.ButtonTypeMedium, v.fileProvider, common.TranslateString("#970")) - v.exitButton.MoveTo(33, 537) - v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) - v.uiManager.AddWidget(v.exitButton) - }, - func() { - v.heroRenderInfo[common.HeroBarbarian] = &HeroRenderInfo{ - HeroStanceIdle, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectBarbarianUnselected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectBarbarianUnselectedH, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectBarbarianForwardWalk, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectBarbarianForwardWalkOverlay, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectBarbarianSelected, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectBarbarianBackWalk, palettedefs.Fechar), - nil, - image.Rectangle{Min: image.Point{364, 201}, Max: image.Point{90, 170}}, - v.soundManager.LoadSoundEffect(resourcepaths.SFXBarbarianSelect), - v.soundManager.LoadSoundEffect(resourcepaths.SFXBarbarianDeselect), - } - v.heroRenderInfo[common.HeroBarbarian].IdleSprite.MoveTo(400, 330) - v.heroRenderInfo[common.HeroBarbarian].IdleSprite.Animate = true - v.heroRenderInfo[common.HeroBarbarian].IdleSelectedSprite.MoveTo(400, 330) - v.heroRenderInfo[common.HeroBarbarian].IdleSelectedSprite.Animate = true - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSprite.MoveTo(400, 330) - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSprite.Animate = true - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSprite.SpecialFrameTime = 2500 - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSpriteOverlay.MoveTo(400, 330) - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSpriteOverlay.SpecialFrameTime = 2500 - v.heroRenderInfo[common.HeroBarbarian].ForwardWalkSpriteOverlay.StopOnLastFrame = true - v.heroRenderInfo[common.HeroBarbarian].SelectedSprite.MoveTo(400, 330) - v.heroRenderInfo[common.HeroBarbarian].SelectedSprite.Animate = true - v.heroRenderInfo[common.HeroBarbarian].BackWalkSprite.MoveTo(400, 330) - v.heroRenderInfo[common.HeroBarbarian].BackWalkSprite.Animate = true - v.heroRenderInfo[common.HeroBarbarian].BackWalkSprite.SpecialFrameTime = 1000 - v.heroRenderInfo[common.HeroBarbarian].BackWalkSprite.StopOnLastFrame = true - }, - func() { - v.heroRenderInfo[common.HeroSorceress] = &HeroRenderInfo{ - HeroStanceIdle, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressUnselected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressUnselectedH, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressForwardWalk, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressForwardWalkOverlay, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressSelected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressSelectedOverlay, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressBackWalk, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecSorceressBackWalkOverlay, palettedefs.Fechar), - image.Rectangle{Min: image.Point{580, 240}, Max: image.Point{65, 160}}, - v.soundManager.LoadSoundEffect(resourcepaths.SFXSorceressSelect), - v.soundManager.LoadSoundEffect(resourcepaths.SFXSorceressDeselect), - } - v.heroRenderInfo[common.HeroSorceress].IdleSprite.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].IdleSprite.Animate = true - v.heroRenderInfo[common.HeroSorceress].IdleSelectedSprite.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].IdleSelectedSprite.Animate = true - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSprite.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSprite.Animate = true - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSprite.SpecialFrameTime = 2300 - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSpriteOverlay.Blend = true - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSpriteOverlay.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSpriteOverlay.SpecialFrameTime = 2300 - v.heroRenderInfo[common.HeroSorceress].ForwardWalkSpriteOverlay.StopOnLastFrame = true - v.heroRenderInfo[common.HeroSorceress].SelectedSprite.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].SelectedSprite.Animate = true - v.heroRenderInfo[common.HeroSorceress].SelectedSpriteOverlay.Blend = true - v.heroRenderInfo[common.HeroSorceress].SelectedSpriteOverlay.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].SelectedSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroSorceress].BackWalkSprite.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].BackWalkSprite.Animate = true - v.heroRenderInfo[common.HeroSorceress].BackWalkSprite.SpecialFrameTime = 1200 - v.heroRenderInfo[common.HeroSorceress].BackWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroSorceress].BackWalkSpriteOverlay.Blend = true - v.heroRenderInfo[common.HeroSorceress].BackWalkSpriteOverlay.MoveTo(626, 352) - v.heroRenderInfo[common.HeroSorceress].BackWalkSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroSorceress].BackWalkSpriteOverlay.SpecialFrameTime = 1200 - v.heroRenderInfo[common.HeroSorceress].BackWalkSpriteOverlay.StopOnLastFrame = true - }, - func() { - v.heroRenderInfo[common.HeroNecromancer] = &HeroRenderInfo{ - HeroStanceIdle, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectNecromancerUnselected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectNecromancerUnselectedH, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecNecromancerForwardWalk, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecNecromancerForwardWalkOverlay, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecNecromancerSelected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecNecromancerSelectedOverlay, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecNecromancerBackWalk, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecNecromancerBackWalkOverlay, palettedefs.Fechar), - image.Rectangle{Min: image.Point{265, 220}, Max: image.Point{55, 175}}, - v.soundManager.LoadSoundEffect(resourcepaths.SFXNecromancerSelect), - v.soundManager.LoadSoundEffect(resourcepaths.SFXNecromancerDeselect), - } - v.heroRenderInfo[common.HeroNecromancer].IdleSprite.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].IdleSprite.Animate = true - v.heroRenderInfo[common.HeroNecromancer].IdleSelectedSprite.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].IdleSelectedSprite.Animate = true - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSprite.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSprite.Animate = true - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSprite.SpecialFrameTime = 2000 - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSpriteOverlay.Blend = true - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSpriteOverlay.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSpriteOverlay.SpecialFrameTime = 2000 - v.heroRenderInfo[common.HeroNecromancer].ForwardWalkSpriteOverlay.StopOnLastFrame = true - v.heroRenderInfo[common.HeroNecromancer].SelectedSprite.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].SelectedSprite.Animate = true - v.heroRenderInfo[common.HeroNecromancer].SelectedSpriteOverlay.Blend = true - v.heroRenderInfo[common.HeroNecromancer].SelectedSpriteOverlay.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].SelectedSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroNecromancer].BackWalkSprite.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].BackWalkSprite.Animate = true - v.heroRenderInfo[common.HeroNecromancer].BackWalkSprite.SpecialFrameTime = 1500 - v.heroRenderInfo[common.HeroNecromancer].BackWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroNecromancer].BackWalkSpriteOverlay.Blend = true - v.heroRenderInfo[common.HeroNecromancer].BackWalkSpriteOverlay.MoveTo(300, 335) - v.heroRenderInfo[common.HeroNecromancer].BackWalkSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroNecromancer].BackWalkSpriteOverlay.SpecialFrameTime = 1500 - v.heroRenderInfo[common.HeroNecromancer].BackWalkSpriteOverlay.StopOnLastFrame = true - }, - func() { - v.heroRenderInfo[common.HeroPaladin] = &HeroRenderInfo{ - HeroStanceIdle, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectPaladinUnselected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectPaladinUnselectedH, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecPaladinForwardWalk, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecPaladinForwardWalkOverlay, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecPaladinSelected, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecPaladinBackWalk, palettedefs.Fechar), - nil, - image.Rectangle{Min: image.Point{490, 210}, Max: image.Point{65, 180}}, - v.soundManager.LoadSoundEffect(resourcepaths.SFXPaladinSelect), - v.soundManager.LoadSoundEffect(resourcepaths.SFXPaladinDeselect), - } - v.heroRenderInfo[common.HeroPaladin].IdleSprite.MoveTo(521, 338) - v.heroRenderInfo[common.HeroPaladin].IdleSprite.Animate = true - v.heroRenderInfo[common.HeroPaladin].IdleSelectedSprite.MoveTo(521, 338) - v.heroRenderInfo[common.HeroPaladin].IdleSelectedSprite.Animate = true - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSprite.MoveTo(521, 338) - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSprite.Animate = true - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSprite.SpecialFrameTime = 3400 - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSpriteOverlay.MoveTo(521, 338) - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSpriteOverlay.Animate = true - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSpriteOverlay.SpecialFrameTime = 3400 - v.heroRenderInfo[common.HeroPaladin].ForwardWalkSpriteOverlay.StopOnLastFrame = true - v.heroRenderInfo[common.HeroPaladin].SelectedSprite.MoveTo(521, 338) - v.heroRenderInfo[common.HeroPaladin].SelectedSprite.Animate = true - v.heroRenderInfo[common.HeroPaladin].BackWalkSprite.MoveTo(521, 338) - v.heroRenderInfo[common.HeroPaladin].BackWalkSprite.Animate = true - v.heroRenderInfo[common.HeroPaladin].BackWalkSprite.SpecialFrameTime = 1300 - v.heroRenderInfo[common.HeroPaladin].BackWalkSprite.StopOnLastFrame = true - }, - func() { - v.heroRenderInfo[common.HeroAmazon] = &HeroRenderInfo{ - HeroStanceIdle, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectAmazonUnselected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectAmazonUnselectedH, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecAmazonForwardWalk, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecAmazonSelected, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelecAmazonBackWalk, palettedefs.Fechar), - nil, - image.Rectangle{Min: image.Point{70, 220}, Max: image.Point{55, 200}}, - v.soundManager.LoadSoundEffect(resourcepaths.SFXAmazonSelect), - v.soundManager.LoadSoundEffect(resourcepaths.SFXAmazonDeselect), - } - v.heroRenderInfo[common.HeroAmazon].IdleSprite.MoveTo(100, 339) - v.heroRenderInfo[common.HeroAmazon].IdleSprite.Animate = true - v.heroRenderInfo[common.HeroAmazon].IdleSelectedSprite.MoveTo(100, 339) - v.heroRenderInfo[common.HeroAmazon].IdleSelectedSprite.Animate = true - v.heroRenderInfo[common.HeroAmazon].ForwardWalkSprite.MoveTo(100, 339) - v.heroRenderInfo[common.HeroAmazon].ForwardWalkSprite.Animate = true - v.heroRenderInfo[common.HeroAmazon].ForwardWalkSprite.SpecialFrameTime = 2200 - v.heroRenderInfo[common.HeroAmazon].ForwardWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroAmazon].SelectedSprite.MoveTo(100, 339) - v.heroRenderInfo[common.HeroAmazon].SelectedSprite.Animate = true - v.heroRenderInfo[common.HeroAmazon].BackWalkSprite.MoveTo(100, 339) - v.heroRenderInfo[common.HeroAmazon].BackWalkSprite.Animate = true - v.heroRenderInfo[common.HeroAmazon].BackWalkSprite.SpecialFrameTime = 1500 - v.heroRenderInfo[common.HeroAmazon].BackWalkSprite.StopOnLastFrame = true - }, - func() { - v.heroRenderInfo[common.HeroAssassin] = &HeroRenderInfo{ - HeroStanceIdle, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectAssassinUnselected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectAssassinUnselectedH, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectAssassinForwardWalk, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectAssassinSelected, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectAssassinBackWalk, palettedefs.Fechar), - nil, - image.Rectangle{Min: image.Point{175, 235}, Max: image.Point{50, 180}}, - v.soundManager.LoadSoundEffect(resourcepaths.SFXAssassinSelect), - v.soundManager.LoadSoundEffect(resourcepaths.SFXAssassinDeselect), - } - v.heroRenderInfo[common.HeroAssassin].IdleSprite.MoveTo(231, 365) - v.heroRenderInfo[common.HeroAssassin].IdleSprite.Animate = true - v.heroRenderInfo[common.HeroAssassin].IdleSelectedSprite.MoveTo(231, 365) - v.heroRenderInfo[common.HeroAssassin].IdleSelectedSprite.Animate = true - v.heroRenderInfo[common.HeroAssassin].ForwardWalkSprite.MoveTo(231, 365) - v.heroRenderInfo[common.HeroAssassin].ForwardWalkSprite.Animate = true - v.heroRenderInfo[common.HeroAssassin].ForwardWalkSprite.SpecialFrameTime = 3800 - v.heroRenderInfo[common.HeroAssassin].ForwardWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroAssassin].SelectedSprite.MoveTo(231, 365) - v.heroRenderInfo[common.HeroAssassin].SelectedSprite.Animate = true - v.heroRenderInfo[common.HeroAssassin].BackWalkSprite.MoveTo(231, 365) - v.heroRenderInfo[common.HeroAssassin].BackWalkSprite.Animate = true - v.heroRenderInfo[common.HeroAssassin].BackWalkSprite.SpecialFrameTime = 1500 - v.heroRenderInfo[common.HeroAssassin].BackWalkSprite.StopOnLastFrame = true - }, - func() { - v.heroRenderInfo[common.HeroDruid] = &HeroRenderInfo{ - HeroStanceIdle, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectDruidUnselected, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectDruidUnselectedH, palettedefs.Fechar), - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectDruidForwardWalk, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectDruidSelected, palettedefs.Fechar), - nil, - v.fileProvider.LoadSprite(resourcepaths.CharacterSelectDruidBackWalk, palettedefs.Fechar), - nil, - image.Rectangle{Min: image.Point{680, 220}, Max: image.Point{70, 195}}, - v.soundManager.LoadSoundEffect(resourcepaths.SFXDruidSelect), - v.soundManager.LoadSoundEffect(resourcepaths.SFXDruidDeselect), - } - v.heroRenderInfo[common.HeroDruid].IdleSprite.MoveTo(720, 370) - v.heroRenderInfo[common.HeroDruid].IdleSprite.Animate = true - v.heroRenderInfo[common.HeroDruid].IdleSelectedSprite.MoveTo(720, 370) - v.heroRenderInfo[common.HeroDruid].IdleSelectedSprite.Animate = true - v.heroRenderInfo[common.HeroDruid].ForwardWalkSprite.MoveTo(720, 370) - v.heroRenderInfo[common.HeroDruid].ForwardWalkSprite.Animate = true - v.heroRenderInfo[common.HeroDruid].ForwardWalkSprite.SpecialFrameTime = 4800 - v.heroRenderInfo[common.HeroDruid].ForwardWalkSprite.StopOnLastFrame = true - v.heroRenderInfo[common.HeroDruid].SelectedSprite.MoveTo(720, 370) - v.heroRenderInfo[common.HeroDruid].SelectedSprite.Animate = true - v.heroRenderInfo[common.HeroDruid].BackWalkSprite.MoveTo(720, 370) - v.heroRenderInfo[common.HeroDruid].BackWalkSprite.Animate = true - v.heroRenderInfo[common.HeroDruid].BackWalkSprite.SpecialFrameTime = 1500 - v.heroRenderInfo[common.HeroDruid].BackWalkSprite.StopOnLastFrame = true - }, - } -} - -func (v *SelectHeroClass) Unload() { - v.heroRenderInfo = nil -} - -func (v *SelectHeroClass) onExitButtonClicked() { - v.sceneProvider.SetNextScene(CreateCharacterSelect(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager)) -} - -func (v *SelectHeroClass) Render(screen *ebiten.Image) { - v.bgImage.DrawSegments(screen, 4, 3, 0) - v.headingLabel.Draw(screen) - if v.selectedHero != common.HeroNone { - v.heroClassLabel.Draw(screen) - v.heroDesc1Label.Draw(screen) - v.heroDesc2Label.Draw(screen) - v.heroDesc3Label.Draw(screen) - } - for heroClass, heroInfo := range v.heroRenderInfo { - if heroInfo.Stance == HeroStanceIdle || heroInfo.Stance == HeroStanceIdleSelected { - v.renderHero(screen, heroClass) - } - } - for heroClass, heroInfo := range v.heroRenderInfo { - if heroInfo.Stance != HeroStanceIdle && heroInfo.Stance != HeroStanceIdleSelected { - v.renderHero(screen, heroClass) - } - } - v.campfire.Draw(screen) -} - -func (v *SelectHeroClass) Update(tickTime float64) { - canSelect := true - for _, info := range v.heroRenderInfo { - if info.Stance != HeroStanceIdle && info.Stance != HeroStanceIdleSelected && info.Stance != HeroStanceSelected { - canSelect = false - break - } - } - allIdle := true - for heroType, data := range v.heroRenderInfo { - if allIdle && data.Stance != HeroStanceIdle { - allIdle = false - } - v.updateHeroSelectionHover(heroType, canSelect) - } - if v.selectedHero != common.HeroNone && allIdle { - v.selectedHero = common.HeroNone - } -} - -func (v *SelectHeroClass) updateHeroSelectionHover(hero common.Hero, canSelect bool) { - renderInfo := v.heroRenderInfo[hero] - switch renderInfo.Stance { - case HeroStanceApproaching: - if renderInfo.ForwardWalkSprite.OnLastFrame() { - renderInfo.Stance = HeroStanceSelected - renderInfo.SelectedSprite.ResetAnimation() - if renderInfo.SelectedSpriteOverlay != nil { - renderInfo.SelectedSpriteOverlay.ResetAnimation() - } - } - return - case HeroStanceRetreating: - if renderInfo.BackWalkSprite.OnLastFrame() { - renderInfo.Stance = HeroStanceIdle - renderInfo.IdleSprite.ResetAnimation() - } - return - } - if !canSelect { - return - } - if renderInfo.Stance == HeroStanceSelected { - return - } - mouseX := v.uiManager.CursorX - mouseY := v.uiManager.CursorY - b := renderInfo.SelectionBounds - mouseHover := (mouseX >= b.Min.X) && (mouseX <= b.Min.X+b.Max.X) && (mouseY >= b.Min.Y) && (mouseY <= b.Min.Y+b.Max.Y) - if mouseHover && v.uiManager.CursorButtonPressed(ui.CursorButtonLeft) { - // showEntryUi = true; - renderInfo.Stance = HeroStanceApproaching - renderInfo.ForwardWalkSprite.ResetAnimation() - if renderInfo.ForwardWalkSpriteOverlay != nil { - renderInfo.ForwardWalkSpriteOverlay.ResetAnimation() - } - for _, heroInfo := range v.heroRenderInfo { - if heroInfo.Stance != HeroStanceSelected { - continue - } - heroInfo.SelectSfx.Stop() - heroInfo.DeselectSfx.Play() - heroInfo.Stance = HeroStanceRetreating - heroInfo.BackWalkSprite.ResetAnimation() - if heroInfo.BackWalkSpriteOverlay != nil { - heroInfo.BackWalkSpriteOverlay.ResetAnimation() - } - } - v.selectedHero = hero - v.updateHeroText() - renderInfo.SelectSfx.Play() - - return - } - - if mouseHover { - renderInfo.Stance = HeroStanceIdleSelected - } else { - renderInfo.Stance = HeroStanceIdle - } - - if v.selectedHero == common.HeroNone && mouseHover { - v.selectedHero = hero - v.updateHeroText() - } - -} - -func (v *SelectHeroClass) renderHero(screen *ebiten.Image, hero common.Hero) { - renderInfo := v.heroRenderInfo[hero] - switch renderInfo.Stance { - case HeroStanceIdle: - renderInfo.IdleSprite.Draw(screen) - case HeroStanceIdleSelected: - renderInfo.IdleSelectedSprite.Draw(screen) - case HeroStanceApproaching: - renderInfo.ForwardWalkSprite.Draw(screen) - if renderInfo.ForwardWalkSpriteOverlay != nil { - renderInfo.ForwardWalkSpriteOverlay.Draw(screen) - } - case HeroStanceSelected: - renderInfo.SelectedSprite.Draw(screen) - if renderInfo.SelectedSpriteOverlay != nil { - renderInfo.SelectedSpriteOverlay.Draw(screen) - } - case HeroStanceRetreating: - renderInfo.BackWalkSprite.Draw(screen) - if renderInfo.BackWalkSpriteOverlay != nil { - renderInfo.BackWalkSpriteOverlay.Draw(screen) - } - } -} - -func (v *SelectHeroClass) updateHeroText() { - switch v.selectedHero { - case common.HeroNone: - return - case common.HeroBarbarian: - v.heroClassLabel.SetText(common.TranslateString("partycharbar")) - v.setDescLabels("#1709") - case common.HeroNecromancer: - v.heroClassLabel.SetText(common.TranslateString("partycharnec")) - v.setDescLabels("#1704") - case common.HeroPaladin: - v.heroClassLabel.SetText(common.TranslateString("partycharpal")) - v.setDescLabels("#1711") - case common.HeroAssassin: - v.heroClassLabel.SetText(common.TranslateString("partycharass")) - v.setDescLabels("#305") - case common.HeroSorceress: - v.heroClassLabel.SetText(common.TranslateString("partycharsor")) - v.setDescLabels("#1710") - case common.HeroAmazon: - v.heroClassLabel.SetText(common.TranslateString("partycharama")) - v.setDescLabels("#1698") - case common.HeroDruid: - v.heroClassLabel.SetText(common.TranslateString("partychardru")) - v.setDescLabels("#304") - } - /* - if (selectedHero == null) - return; - - switch (selectedHero.Value) - { - - } - - heroClassLabel.Location = new Point(400 - (heroClassLabel.TextArea.Width / 2), 65); - heroDesc1Label.Location = new Point(400 - (heroDesc1Label.TextArea.Width / 2), 100); - heroDesc2Label.Location = new Point(400 - (heroDesc2Label.TextArea.Width / 2), 115); - heroDesc3Label.Location = new Point(400 - (heroDesc3Label.TextArea.Width / 2), 130); - */ -} - -func (v *SelectHeroClass) setDescLabels(descKey string) { - heroDesc := common.TranslateString(descKey) - parts := common.SplitIntoLinesWithMaxWidth(heroDesc, 37) - if len(parts) > 1 { - v.heroDesc1Label.SetText(parts[0]) - } else { - v.heroDesc1Label.SetText("") - } - if len(parts) > 1 { - v.heroDesc2Label.SetText(parts[1]) - } else { - v.heroDesc2Label.SetText("") - } - if len(parts) > 2 { - v.heroDesc3Label.SetText(parts[2]) - } else { - v.heroDesc3Label.SetText("") - } -} diff --git a/tests/MPQ_test.go b/tests/MPQ_test.go index 38a9c8ed..c37a6d18 100644 --- a/tests/MPQ_test.go +++ b/tests/MPQ_test.go @@ -6,19 +6,21 @@ import ( "strings" "testing" - "github.com/OpenDiablo2/OpenDiablo2/core" + "github.com/OpenDiablo2/OpenDiablo2/d2data" - "github.com/OpenDiablo2/OpenDiablo2/mpq" + "github.com/OpenDiablo2/OpenDiablo2/d2core" - "github.com/OpenDiablo2/OpenDiablo2/common" + "github.com/OpenDiablo2/OpenDiablo2/d2data/mpq" + + "github.com/OpenDiablo2/OpenDiablo2/d2common" ) func TestMPQScanPerformance(t *testing.T) { log.SetFlags(log.Ldate | log.LUTC | log.Lmicroseconds | log.Llongfile) mpq.InitializeCryptoBuffer() - common.ConfigBasePath = "../" - config := common.LoadConfiguration() - engine := core.CreateEngine() + d2common.ConfigBasePath = "../" + config := d2common.LoadConfiguration() + engine := d2core.CreateEngine() for _, fileName := range config.MpqLoadOrder { mpqFile := path.Join(config.MpqPath, fileName) archive, _ := mpq.Load(mpqFile) @@ -34,12 +36,12 @@ func TestMPQScanPerformance(t *testing.T) { parts := strings.Split(archiveFile, ".") switch strings.ToLower(parts[len(parts)-1]) { case "coff": - _ = common.LoadCof(archiveFile, engine) + _ = d2data.LoadCof(archiveFile, engine) case "dcc": if strings.ContainsAny(archiveFile, "common") { continue } - _ = common.LoadDCC(archiveFile, engine) + _ = d2data.LoadDCC(archiveFile, engine) } _, _ = archive.ReadFile(archiveFile) diff --git a/tests/MapLoad_test.go b/tests/MapLoad_test.go index afe4ff1e..159a4066 100644 --- a/tests/MapLoad_test.go +++ b/tests/MapLoad_test.go @@ -5,19 +5,19 @@ import ( "github.com/hajimehoshi/ebiten" - _map "github.com/OpenDiablo2/OpenDiablo2/map" + _map "github.com/OpenDiablo2/OpenDiablo2/d2render/mapengine" - "github.com/OpenDiablo2/OpenDiablo2/common" - "github.com/OpenDiablo2/OpenDiablo2/core" - "github.com/OpenDiablo2/OpenDiablo2/mpq" + "github.com/OpenDiablo2/OpenDiablo2/d2common" + "github.com/OpenDiablo2/OpenDiablo2/d2core" + "github.com/OpenDiablo2/OpenDiablo2/d2data/mpq" ) func TestMapGenerationPerformance(t *testing.T) { mpq.InitializeCryptoBuffer() - common.ConfigBasePath = "../" + d2common.ConfigBasePath = "../" - engine := core.CreateEngine() - gameState := common.CreateGameState() + engine := d2core.CreateEngine() + gameState := d2core.CreateGameState() mapEngine := _map.CreateMapEngine(gameState, engine.SoundManager, engine) mapEngine.GenerateAct1Overworld() surface, _ := ebiten.NewImage(800, 600, ebiten.FilterNearest)