1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-10 18:00:42 +00:00

Restructured everything. (#128)

This commit is contained in:
Tim Sarbin 2019-11-10 03:36:53 -05:00 committed by GitHub
parent 46e163bc38
commit b41f7f4dab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
92 changed files with 2066 additions and 1879 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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)))
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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))
}

View File

@ -1,16 +1,17 @@
package sound package d2audio
import ( import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/hajimehoshi/ebiten/audio" "github.com/hajimehoshi/ebiten/audio"
"github.com/hajimehoshi/ebiten/audio/wav" "github.com/hajimehoshi/ebiten/audio/wav"
) )
// Manager provides sound // Manager provides sound
type Manager struct { type Manager struct {
fileProvider common.FileProvider fileProvider d2interface.FileProvider
audioContext *audio.Context // The Audio context audioContext *audio.Context // The Audio context
bgmAudio *audio.Player // The audio player bgmAudio *audio.Player // The audio player
lastBgm string lastBgm string
@ -19,7 +20,7 @@ type Manager struct {
} }
// CreateManager creates a sound provider // CreateManager creates a sound provider
func CreateManager(fileProvider common.FileProvider) *Manager { func CreateManager(fileProvider d2interface.FileProvider) *Manager {
result := &Manager{ result := &Manager{
fileProvider: fileProvider, fileProvider: fileProvider,
} }

View File

@ -1,11 +1,13 @@
package sound package d2audio
import ( import (
"log" "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" "github.com/hajimehoshi/ebiten/audio"
) )
@ -14,11 +16,11 @@ type SoundEffect struct {
player *audio.Player 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{} result := &SoundEffect{}
var soundFile string var soundFile string
if _, exists := common.Sounds[sfx]; exists { if _, exists := datadict.Sounds[sfx]; exists {
soundEntry := common.Sounds[sfx] soundEntry := datadict.Sounds[sfx]
soundFile = soundEntry.FileName soundFile = soundEntry.FileName
} else { } else {
soundFile = sfx soundFile = sfx

View File

@ -1,4 +1,4 @@
package common package d2common
type BitMuncher struct { type BitMuncher struct {
data []byte data []byte

View File

@ -1,4 +1,4 @@
package common package d2common
import "log" import "log"

View File

@ -1,4 +1,4 @@
package common package d2common
import ( import (
"testing" "testing"

View File

@ -1,4 +1,4 @@
package common package d2common
type BuildInfoRecord struct { type BuildInfoRecord struct {
Branch string Branch string

View File

@ -1,4 +1,4 @@
package common package d2common
import ( import (
"encoding/json" "encoding/json"

View File

@ -1,4 +1,4 @@
package common package d2common
import ( import (
"log" "log"

View File

@ -1,4 +1,4 @@
package common package d2common
type Path struct { type Path struct {
X int32 X int32

View File

@ -1,4 +1,4 @@
package common package d2common
type Rectangle struct { type Rectangle struct {
Left int Left int

View File

@ -1,4 +1,4 @@
package resourcepaths package d2common
var LanguageCode string var LanguageCode string

View File

@ -1,4 +1,4 @@
package common package d2common
import ( import (
"io" "io"

View File

@ -1,4 +1,4 @@
package common package d2common
import ( import (
"testing" "testing"

View File

@ -1,4 +1,4 @@
package common package d2common
// StreamWriter allows you to create a byte array by streaming in writes of various sizes // StreamWriter allows you to create a byte array by streaming in writes of various sizes
type StreamWriter struct { type StreamWriter struct {

View File

@ -1,4 +1,4 @@
package common package d2common
import ( import (
"testing" "testing"

View File

@ -1,10 +1,10 @@
package common package d2common
import ( import (
"log" "log"
"strconv" "strconv"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
type textDictionaryHashEntry struct { type textDictionaryHashEntry struct {
@ -26,16 +26,16 @@ func TranslateString(key string) string {
return result return result
} }
func LoadTextDictionary(fileProvider FileProvider) { func LoadTextDictionary(fileProvider d2interface.FileProvider) {
lookupTable = make(map[string]string) lookupTable = make(map[string]string)
loadDictionary(fileProvider, resourcepaths.PatchStringTable) loadDictionary(fileProvider, PatchStringTable)
loadDictionary(fileProvider, resourcepaths.ExpansionStringTable) loadDictionary(fileProvider, ExpansionStringTable)
loadDictionary(fileProvider, resourcepaths.StringTable) loadDictionary(fileProvider, StringTable)
log.Printf("Loaded %d entries from the string table", len(lookupTable)) 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) dictionaryData := fileProvider.LoadFile(dictionaryName)
br := CreateStreamReader(dictionaryData) br := CreateStreamReader(dictionaryData)
br.ReadBytes(2) // CRC br.ReadBytes(2) // CRC

View File

@ -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
)

View File

@ -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

View File

@ -1,6 +1,6 @@
// Code generated by "stringer -linecomment -type AnimationMode"; DO NOT EDIT. // Code generated by "stringer -linecomment -type AnimationMode"; DO NOT EDIT.
package common package d2enum
import "strconv" import "strconv"

View File

@ -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
)

View File

@ -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)
)

View File

@ -1,4 +1,4 @@
package common package d2enum
type Hero int type Hero int

View File

@ -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
)

View File

@ -1,4 +1,4 @@
package _map package d2enum
type Orientation int32 type Orientation int32

View File

@ -1,4 +1,4 @@
package palettedefs package d2enum
// PaletteType represents a named palette // PaletteType represents a named palette
type PaletteType string type PaletteType string

View File

@ -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

View File

@ -1,6 +1,6 @@
// Code generated by "stringer -linecomment -type WeaponClass"; DO NOT EDIT. // Code generated by "stringer -linecomment -type WeaponClass"; DO NOT EDIT.
package common package d2enum
import "strconv" import "strconv"

View File

@ -1,6 +1,6 @@
// Code generated by "string2enum -samepkg -linecomment -type WeaponClass"; DO NOT EDIT. // Code generated by "string2enum -samepkg -linecomment -type WeaponClass"; DO NOT EDIT.
package common package d2enum
import "fmt" import "fmt"

17
d2common/d2enum/readme.md Normal file
View File

@ -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
```

View File

@ -1,4 +1,4 @@
package common package d2interface
import "github.com/hajimehoshi/ebiten" import "github.com/hajimehoshi/ebiten"

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package scenes package d2interface
import ( import (
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"

View File

@ -1,4 +1,4 @@
package scenes package d2interface
// SceneProvider provides the ability to change scenes // SceneProvider provides the ability to change scenes
type SceneProvider interface { type SceneProvider interface {

View File

@ -1,4 +1,4 @@
package core package d2core
import ( import (
"log" "log"
@ -10,16 +10,24 @@ import (
"sync" "sync"
"time" "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/d2render"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths"
"github.com/OpenDiablo2/OpenDiablo2/scenes" "github.com/OpenDiablo2/OpenDiablo2/d2data"
"github.com/OpenDiablo2/OpenDiablo2/ui"
"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"
"github.com/hajimehoshi/ebiten/ebitenutil" "github.com/hajimehoshi/ebiten/ebitenutil"
@ -28,20 +36,20 @@ import (
// Engine is the core OpenDiablo2 engine // Engine is the core OpenDiablo2 engine
type Engine struct { type Engine struct {
Settings *common.Configuration // Engine configuration settings from json file Settings *d2common.Configuration // Engine configuration settings from json file
Files map[string]string // Map that defines which files are in which MPQs 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. 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 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. 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 loadingIndex int // Determines which load function is currently being called
thingsToLoad []func() // The load functions for the next scene thingsToLoad []func() // The load functions for the next scene
stepLoadingSize float64 // The size for each loading step stepLoadingSize float64 // The size for each loading step
CurrentScene scenes.Scene // The current scene being rendered CurrentScene d2interface.Scene // The current scene being rendered
UIManager *ui.Manager // The UI manager UIManager *ui.Manager // The UI manager
SoundManager *sound.Manager // The sound manager SoundManager *d2audio.Manager // The sound manager
nextScene scenes.Scene // The next scene to be loaded at the end of the game loop 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 fullscreenKey bool // When true, the fullscreen toggle is still being pressed
lastTime float64 // Last time we updated the scene lastTime float64 // Last time we updated the scene
showFPS bool showFPS bool
} }
@ -52,36 +60,35 @@ func CreateEngine() *Engine {
nextScene: nil, nextScene: nil,
} }
result.loadConfigurationFile() result.loadConfigurationFile()
resourcepaths.LanguageCode = result.Settings.Language d2common.LanguageCode = result.Settings.Language
result.mapMpqFiles() result.mapMpqFiles()
common.LoadPalettes(result.Files, result) datadict.LoadPalettes(result.Files, result)
common.LoadTextDictionary(result) d2common.LoadTextDictionary(result)
common.LoadLevelTypes(result) datadict.LoadLevelTypes(result)
common.LoadLevelPresets(result) datadict.LoadLevelPresets(result)
common.LoadLevelWarps(result) datadict.LoadLevelWarps(result)
common.LoadObjectTypes(result) datadict.LoadObjectTypes(result)
common.LoadObjects(result) datadict.LoadObjects(result)
common.LoadWeapons(result) datadict.LoadWeapons(result)
common.LoadArmors(result) datadict.LoadArmors(result)
common.LoadUniqueItems(result) datadict.LoadUniqueItems(result)
common.LoadMissiles(result) datadict.LoadMissiles(result)
common.LoadSounds(result) datadict.LoadSounds(result)
common.LoadAnimationData(result) d2data.LoadAnimationData(result)
common.LoadMonStats(result) datadict.LoadMonStats(result)
result.SoundManager = sound.CreateManager(result) result.SoundManager = d2audio.CreateManager(result)
result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume) result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume)
result.UIManager = ui.CreateManager(result, *result.SoundManager) 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() loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetSize()
result.LoadingSprite.MoveTo(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2))) 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)) //result.SetNextScene(Scenes.CreateBlizzardIntro(result, result))
return result return result
} }
func (v *Engine) loadConfigurationFile() { func (v *Engine) loadConfigurationFile() {
log.Println("Loading configuration file") log.Println("Loading configuration file")
v.Settings = common.LoadConfiguration() v.Settings = d2common.LoadConfiguration()
} }
func (v *Engine) mapMpqFiles() { func (v *Engine) mapMpqFiles() {
@ -91,7 +98,7 @@ func (v *Engine) mapMpqFiles() {
var mutex sync.Mutex var mutex sync.Mutex
func (v *Engine) LoadFile(fileName string) []byte { 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.ToLower(fileName)
fileName = strings.ReplaceAll(fileName, `/`, "\\") fileName = strings.ReplaceAll(fileName, `/`, "\\")
if fileName[0] == '\\' { if fileName[0] == '\\' {
@ -131,9 +138,9 @@ func (v *Engine) IsLoading() bool {
} }
// LoadSprite loads a sprite from the game's data files // 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) data := v.LoadFile(fileName)
sprite := common.CreateSprite(data, common.Palettes[palette]) sprite := d2render.CreateSprite(data, datadict.Palettes[palette])
return sprite return sprite
} }
@ -208,7 +215,7 @@ func (v *Engine) Update() {
// Draw draws the game // Draw draws the game
func (v *Engine) Draw(screen *ebiten.Image) { func (v *Engine) Draw(screen *ebiten.Image) {
if v.loadingProgress < 1.0 { 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) v.LoadingSprite.Draw(screen)
} else { } else {
if v.CurrentScene == nil { 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 // 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 v.nextScene = nextScene
} }

View File

@ -1,4 +1,4 @@
package common package d2core
import ( import (
"log" "log"

View File

@ -1,18 +1,18 @@
package scenes package scenes
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/video" "github.com/OpenDiablo2/OpenDiablo2/d2data/video"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
) )
type BlizzardIntro struct { type BlizzardIntro struct {
fileProvider common.FileProvider fileProvider d2interface.FileProvider
sceneProvider SceneProvider sceneProvider d2interface.SceneProvider
videoDecoder *video.BinkDecoder videoDecoder *video.BinkDecoder
} }
func CreateBlizzardIntro(fileProvider common.FileProvider, sceneProvider SceneProvider) *BlizzardIntro { func CreateBlizzardIntro(fileProvider d2interface.FileProvider, sceneProvider d2interface.SceneProvider) *BlizzardIntro {
result := &BlizzardIntro{ result := &BlizzardIntro{
fileProvider: fileProvider, fileProvider: fileProvider,
sceneProvider: sceneProvider, sceneProvider: sceneProvider,

View File

@ -1,20 +1,23 @@
package scenes package scenes
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/palettedefs" "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/sound" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/ui" "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" "github.com/hajimehoshi/ebiten"
) )
type CharacterSelect struct { type CharacterSelect struct {
uiManager *ui.Manager uiManager *ui.Manager
soundManager *sound.Manager soundManager *d2audio.Manager
fileProvider common.FileProvider fileProvider d2interface.FileProvider
sceneProvider SceneProvider sceneProvider d2interface.SceneProvider
background *common.Sprite background *d2render.Sprite
newCharButton *ui.Button newCharButton *ui.Button
convertCharButton *ui.Button convertCharButton *ui.Button
deleteCharButton *ui.Button deleteCharButton *ui.Button
@ -23,10 +26,10 @@ type CharacterSelect struct {
} }
func CreateCharacterSelect( func CreateCharacterSelect(
fileProvider common.FileProvider, fileProvider d2interface.FileProvider,
sceneProvider SceneProvider, sceneProvider d2interface.SceneProvider,
uiManager *ui.Manager, uiManager *ui.Manager,
soundManager *sound.Manager, soundManager *d2audio.Manager,
) *CharacterSelect { ) *CharacterSelect {
result := &CharacterSelect{ result := &CharacterSelect{
uiManager: uiManager, uiManager: uiManager,
@ -38,38 +41,38 @@ func CreateCharacterSelect(
} }
func (v *CharacterSelect) Load() []func() { func (v *CharacterSelect) Load() []func() {
v.soundManager.PlayBGM(resourcepaths.BGMTitle) v.soundManager.PlayBGM(d2common.BGMTitle)
return []func(){ return []func(){
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) v.background.MoveTo(0, 0)
}, },
func() { 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.MoveTo(33, 468)
v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() }) v.newCharButton.OnActivated(func() { v.onNewCharButtonClicked() })
v.uiManager.AddWidget(v.newCharButton) v.uiManager.AddWidget(v.newCharButton)
}, },
func() { 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.MoveTo(233, 468)
v.convertCharButton.SetEnabled(false) v.convertCharButton.SetEnabled(false)
v.uiManager.AddWidget(v.convertCharButton) v.uiManager.AddWidget(v.convertCharButton)
}, },
func() { 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.MoveTo(433, 468)
v.deleteCharButton.SetEnabled(false) v.deleteCharButton.SetEnabled(false)
v.uiManager.AddWidget(v.deleteCharButton) v.uiManager.AddWidget(v.deleteCharButton)
}, },
func() { 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.MoveTo(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
v.uiManager.AddWidget(v.exitButton) v.uiManager.AddWidget(v.exitButton)
}, },
func() { 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.MoveTo(625, 537)
v.okButton.SetEnabled(false) v.okButton.SetEnabled(false)
v.uiManager.AddWidget(v.okButton) v.uiManager.AddWidget(v.okButton)

View File

@ -4,11 +4,18 @@ import (
"image/color" "image/color"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict"
"github.com/OpenDiablo2/OpenDiablo2/palettedefs"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/sound"
"github.com/OpenDiablo2/OpenDiablo2/ui" "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" "github.com/hajimehoshi/ebiten"
) )
@ -21,10 +28,10 @@ type labelItem struct {
// Credits represents the credits scene // Credits represents the credits scene
type Credits struct { type Credits struct {
uiManager *ui.Manager uiManager *ui.Manager
soundManager *sound.Manager soundManager *d2audio.Manager
fileProvider common.FileProvider fileProvider d2interface.FileProvider
sceneProvider SceneProvider sceneProvider d2interface.SceneProvider
creditsBackground *common.Sprite creditsBackground *d2render.Sprite
exitButton *ui.Button exitButton *ui.Button
creditsText []string creditsText []string
labels []*labelItem labels []*labelItem
@ -34,7 +41,7 @@ type Credits struct {
} }
// CreateCredits creates an instance of the credits scene // 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{ result := &Credits{
fileProvider: fileProvider, fileProvider: fileProvider,
uiManager: uiManager, uiManager: uiManager,
@ -52,17 +59,17 @@ func CreateCredits(fileProvider common.FileProvider, sceneProvider SceneProvider
func (v *Credits) Load() []func() { func (v *Credits) Load() []func() {
return []func(){ return []func(){
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) v.creditsBackground.MoveTo(0, 0)
}, },
func() { 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.MoveTo(30, 550)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() }) v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
v.uiManager.AddWidget(v.exitButton) v.uiManager.AddWidget(v.exitButton)
}, },
func() { 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") v.creditsText = strings.Split(fileData, "\r\n")
for i := range v.creditsText { for i := range v.creditsText {
v.creditsText[i] = strings.Trim(v.creditsText[i], " ") v.creditsText[i] = strings.Trim(v.creditsText[i], " ")
@ -190,7 +197,7 @@ func (v *Credits) getNewFontLabel(isHeading bool) *ui.Label {
newLabelItem := &labelItem{ newLabelItem := &labelItem{
Available: false, Available: false,
IsHeading: isHeading, IsHeading: isHeading,
Label: ui.CreateLabel(v.fileProvider, resourcepaths.FontFormal10, palettedefs.Sky), Label: ui.CreateLabel(v.fileProvider, d2common.FontFormal10, d2enum.Sky),
} }
if isHeading { if isHeading {

View File

@ -8,27 +8,33 @@ import (
"os/exec" "os/exec"
"runtime" "runtime"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2data/datadict"
"github.com/OpenDiablo2/OpenDiablo2/palettedefs"
"github.com/OpenDiablo2/OpenDiablo2/sound" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/ui"
"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" "github.com/hajimehoshi/ebiten"
) )
// MainMenu represents the main menu // MainMenu represents the main menu
type MainMenu struct { type MainMenu struct {
uiManager *ui.Manager uiManager *ui.Manager
soundManager *sound.Manager soundManager *d2audio.Manager
fileProvider common.FileProvider fileProvider d2interface.FileProvider
sceneProvider SceneProvider sceneProvider d2interface.SceneProvider
trademarkBackground *common.Sprite trademarkBackground *d2render.Sprite
background *common.Sprite background *d2render.Sprite
diabloLogoLeft *common.Sprite diabloLogoLeft *d2render.Sprite
diabloLogoRight *common.Sprite diabloLogoRight *d2render.Sprite
diabloLogoLeftBack *common.Sprite diabloLogoLeftBack *d2render.Sprite
diabloLogoRightBack *common.Sprite diabloLogoRightBack *d2render.Sprite
singlePlayerButton *ui.Button singlePlayerButton *ui.Button
githubButton *ui.Button githubButton *ui.Button
exitDiabloButton *ui.Button exitDiabloButton *ui.Button
@ -46,7 +52,7 @@ type MainMenu struct {
} }
// CreateMainMenu creates an instance of MainMenu // 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{ result := &MainMenu{
fileProvider: fileProvider, fileProvider: fileProvider,
uiManager: uiManager, uiManager: uiManager,
@ -60,93 +66,93 @@ func CreateMainMenu(fileProvider common.FileProvider, sceneProvider SceneProvide
// Load is called to load the resources for the main menu // Load is called to load the resources for the main menu
func (v *MainMenu) Load() []func() { func (v *MainMenu) Load() []func() {
v.soundManager.PlayBGM(resourcepaths.BGMTitle) v.soundManager.PlayBGM(d2common.BGMTitle)
return []func(){ return []func(){
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.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.Color = color.RGBA{255, 255, 255, 255}
v.versionLabel.MoveTo(795, -10) v.versionLabel.MoveTo(795, -10)
}, },
func() { 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.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.Color = color.RGBA{255, 255, 255, 255}
v.commitLabel.MoveTo(2, 2) v.commitLabel.MoveTo(2, 2)
}, },
func() { 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.Alignment = ui.LabelAlignCenter
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment") v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
v.copyrightLabel.Color = color.RGBA{188, 168, 140, 255} v.copyrightLabel.Color = color.RGBA{188, 168, 140, 255}
v.copyrightLabel.MoveTo(400, 500) v.copyrightLabel.MoveTo(400, 500)
}, },
func() { 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.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.Color = color.RGBA{188, 168, 140, 255}
v.copyrightLabel2.MoveTo(400, 525) v.copyrightLabel2.MoveTo(400, 525)
}, },
func() { 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.Alignment = ui.LabelAlignCenter
v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision") 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.Color = color.RGBA{255, 255, 140, 255}
v.openDiabloLabel.MoveTo(400, 580) v.openDiabloLabel.MoveTo(400, 580)
}, },
func() { 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) v.background.MoveTo(0, 0)
}, },
func() { 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) v.trademarkBackground.MoveTo(0, 0)
}, },
func() { 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.Blend = true
v.diabloLogoLeft.Animate = true v.diabloLogoLeft.Animate = true
v.diabloLogoLeft.MoveTo(400, 120) v.diabloLogoLeft.MoveTo(400, 120)
}, },
func() { 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.Blend = true
v.diabloLogoRight.Animate = true v.diabloLogoRight.Animate = true
v.diabloLogoRight.MoveTo(400, 120) v.diabloLogoRight.MoveTo(400, 120)
}, },
func() { 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) v.diabloLogoLeftBack.MoveTo(400, 120)
}, },
func() { 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) v.diabloLogoRightBack.MoveTo(400, 120)
}, },
func() { 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.MoveTo(264, 535)
v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen) v.exitDiabloButton.SetVisible(!v.ShowTrademarkScreen)
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() }) v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
v.uiManager.AddWidget(v.exitDiabloButton) v.uiManager.AddWidget(v.exitDiabloButton)
}, },
func() { 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.MoveTo(264, 505)
v.creditsButton.SetVisible(!v.ShowTrademarkScreen) v.creditsButton.SetVisible(!v.ShowTrademarkScreen)
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() }) v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
v.uiManager.AddWidget(v.creditsButton) v.uiManager.AddWidget(v.creditsButton)
}, },
func() { 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.MoveTo(401, 505)
v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen) v.cinematicsButton.SetVisible(!v.ShowTrademarkScreen)
v.uiManager.AddWidget(v.cinematicsButton) v.uiManager.AddWidget(v.cinematicsButton)
}, },
func() { 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.MoveTo(264, 290)
v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen) v.singlePlayerButton.SetVisible(!v.ShowTrademarkScreen)
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() }) v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
@ -194,7 +200,6 @@ func openbrowser(url string) {
func (v *MainMenu) onSinglePlayerClicked() { func (v *MainMenu) onSinglePlayerClicked() {
// Go here only if existing characters are available to select // 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)) v.sceneProvider.SetNextScene(CreateSelectHeroClass(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager))
} }

View File

@ -4,35 +4,40 @@ import (
"fmt" "fmt"
"math" "math"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2helper"
_map "github.com/OpenDiablo2/OpenDiablo2/map"
"github.com/OpenDiablo2/OpenDiablo2/sound" "github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/OpenDiablo2/ui"
"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"
"github.com/hajimehoshi/ebiten/ebitenutil" "github.com/hajimehoshi/ebiten/ebitenutil"
) )
type MapEngineTest struct { type MapEngineTest struct {
uiManager *ui.Manager uiManager *ui.Manager
soundManager *sound.Manager soundManager *d2audio.Manager
fileProvider common.FileProvider fileProvider d2interface.FileProvider
sceneProvider SceneProvider sceneProvider d2interface.SceneProvider
gameState *common.GameState gameState *d2core.GameState
mapEngine *_map.Engine mapEngine *_map.Engine
} }
func CreateMapEngineTest( func CreateMapEngineTest(
fileProvider common.FileProvider, fileProvider d2interface.FileProvider,
sceneProvider SceneProvider, sceneProvider d2interface.SceneProvider,
uiManager *ui.Manager, uiManager *ui.Manager,
soundManager *sound.Manager) *MapEngineTest { soundManager *d2audio.Manager) *MapEngineTest {
result := &MapEngineTest{ result := &MapEngineTest{
fileProvider: fileProvider, fileProvider: fileProvider,
uiManager: uiManager, uiManager: uiManager,
soundManager: soundManager, soundManager: soundManager,
sceneProvider: sceneProvider, sceneProvider: sceneProvider,
} }
result.gameState = common.CreateGameState() result.gameState = d2core.CreateGameState()
return result return result
} }
@ -70,7 +75,7 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) {
v.mapEngine.Render(screen) v.mapEngine.Render(screen)
actualX := float64(v.uiManager.CursorX) - v.mapEngine.OffsetX actualX := float64(v.uiManager.CursorX) - v.mapEngine.OffsetX
actualY := float64(v.uiManager.CursorY) - v.mapEngine.OffsetY 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 subtileX := int(math.Ceil(math.Mod((tileX*10), 10))) / 2
subtileY := int(math.Ceil(math.Mod((tileY*10), 10))) / 2 subtileY := int(math.Ceil(math.Mod((tileY*10), 10))) / 2
curRegion := v.mapEngine.GetRegionAt(int(tileX), int(tileY)) curRegion := v.mapEngine.GetRegionAt(int(tileX), int(tileY))

View File

@ -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("")
}
}

View File

@ -1,10 +1,12 @@
package common package d2data
import ( import (
"log" "log"
"strings" "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 // AnimationDataRecord represents a single entry in the animation data dictionary file
@ -23,10 +25,10 @@ type AnimationDataRecord struct {
var AnimationData map[string][]*AnimationDataRecord var AnimationData map[string][]*AnimationDataRecord
// LoadAnimationData loads the animation data table into the global AnimationData dictionary // 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) AnimationData = make(map[string][]*AnimationDataRecord)
rawData := fileProvider.LoadFile(resourcepaths.AnimationData) rawData := fileProvider.LoadFile(d2common.AnimationData)
streamReader := CreateStreamReader(rawData) streamReader := d2common.CreateStreamReader(rawData)
for !streamReader.Eof() { for !streamReader.Eof() {
dataCount := int(streamReader.GetInt32()) dataCount := int(streamReader.GetInt32())
for i := 0; i < dataCount; i++ { for i := 0; i < dataCount; i++ {

71
d2data/COF.go Normal file
View File

@ -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
}

View File

@ -1,7 +1,13 @@
package common package d2data
import ( import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
) )
type DCCPixelBufferEntry struct { type DCCPixelBufferEntry struct {
@ -29,7 +35,7 @@ type DCCDirectionFrame struct {
NumberOfOptionalBytes int NumberOfOptionalBytes int
NumberOfCodedBytes int NumberOfCodedBytes int
FrameIsBottomUp bool FrameIsBottomUp bool
Box Rectangle Box d2common.Rectangle
Cells []DCCCell Cells []DCCCell
PixelData []byte PixelData []byte
HorizontalCellCount int HorizontalCellCount int
@ -52,7 +58,7 @@ type DCCDirection struct {
RawPixelCodesBitstreamSize int RawPixelCodesBitstreamSize int
Frames []*DCCDirectionFrame Frames []*DCCDirectionFrame
PaletteEntries [256]byte PaletteEntries [256]byte
Box Rectangle Box d2common.Rectangle
Cells []*DCCCell Cells []*DCCCell
PixelData []byte PixelData []byte
HorizontalCellCount int 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, 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} 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{} result := &DCCDirectionFrame{}
bits.GetBits(direction.Variable0Bits) // Variable0 bits.GetBits(direction.Variable0Bits) // Variable0
result.Width = int(bits.GetBits(direction.WidthBits)) result.Width = int(bits.GetBits(direction.WidthBits))
@ -89,7 +95,7 @@ func CreateDCCDirectionFrame(bits *BitMuncher, direction *DCCDirection) *DCCDire
if result.FrameIsBottomUp { if result.FrameIsBottomUp {
log.Panic("Bottom up frames are not implemented.") log.Panic("Bottom up frames are not implemented.")
} else { } else {
result.Box = Rectangle{ result.Box = d2common.Rectangle{
result.XOffset, result.XOffset,
result.YOffset - result.Height + 1, result.YOffset - result.Height + 1,
result.Width, 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 := &DCCDirection{}
result.OutSizeCoded = int(bm.GetUInt32()) result.OutSizeCoded = int(bm.GetUInt32())
result.CompressionFlags = int(bm.GetBits(2)) result.CompressionFlags = int(bm.GetBits(2))
@ -179,12 +185,12 @@ func CreateDCCDirection(bm *BitMuncher, file *DCC) *DCCDirection {
// Load the frame headers // Load the frame headers
for frameIdx := 0; frameIdx < file.FramesPerDirection; frameIdx++ { for frameIdx := 0; frameIdx < file.FramesPerDirection; frameIdx++ {
result.Frames[frameIdx] = CreateDCCDirectionFrame(bm, result) result.Frames[frameIdx] = CreateDCCDirectionFrame(bm, result)
minx = int(MinInt32(int32(result.Frames[frameIdx].Box.Left), int32(minx))) minx = int(d2helper.MinInt32(int32(result.Frames[frameIdx].Box.Left), int32(minx)))
miny = int(MinInt32(int32(result.Frames[frameIdx].Box.Top), int32(miny))) miny = int(d2helper.MinInt32(int32(result.Frames[frameIdx].Box.Top), int32(miny)))
maxx = int(MaxInt32(int32(result.Frames[frameIdx].Box.Right()), int32(maxx))) maxx = int(d2helper.MaxInt32(int32(result.Frames[frameIdx].Box.Right()), int32(maxx)))
maxy = int(MaxInt32(int32(result.Frames[frameIdx].Box.Bottom()), int32(maxy))) 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 { if result.OptionalDataBits > 0 {
log.Panic("Optional bits in DCC data is not currently supported.") 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 // here. For example, if you are on byte offset 3, bit offset 6, and
// the EqualCellsBitstreamSize is 20 bytes, then the next bit stream // the EqualCellsBitstreamSize is 20 bytes, then the next bit stream
// will be located at byte 23, bit offset 6! // will be located at byte 23, bit offset 6!
equalCellsBitstream := CopyBitMuncher(bm) equalCellsBitstream := d2common.CopyBitMuncher(bm)
bm.SkipBits(result.EqualCellsBitstreamSize) bm.SkipBits(result.EqualCellsBitstreamSize)
pixelMaskBitstream := CopyBitMuncher(bm) pixelMaskBitstream := d2common.CopyBitMuncher(bm)
bm.SkipBits(result.PixelMaskBitstreamSize) bm.SkipBits(result.PixelMaskBitstreamSize)
encodingTypeBitsream := CopyBitMuncher(bm) encodingTypeBitsream := d2common.CopyBitMuncher(bm)
bm.SkipBits(result.EncodingTypeBitsreamSize) bm.SkipBits(result.EncodingTypeBitsreamSize)
rawPixelCodesBitstream := CopyBitMuncher(bm) rawPixelCodesBitstream := d2common.CopyBitMuncher(bm)
bm.SkipBits(result.RawPixelCodesBitstreamSize) bm.SkipBits(result.RawPixelCodesBitstreamSize)
pixelCodeandDisplacement := CopyBitMuncher(bm) pixelCodeandDisplacement := d2common.CopyBitMuncher(bm)
// Calculate the cells for the direction // Calculate the cells for the direction
result.CalculateCells() result.CalculateCells()
// Calculate the cells for each of the frames // Calculate the cells for each of the frames
@ -247,7 +253,7 @@ func CreateDCCDirection(bm *BitMuncher, file *DCC) *DCCDirection {
return result return result
} }
func (v *DCCDirection) GenerateFrames(pcd *BitMuncher) { func (v *DCCDirection) GenerateFrames(pcd *d2common.BitMuncher) {
pbIdx := 0 pbIdx := 0
for _, cell := range v.Cells { for _, cell := range v.Cells {
cell.LastWidth = -1 cell.LastWidth = -1
@ -339,7 +345,7 @@ func (v *DCCDirection) GenerateFrames(pcd *BitMuncher) {
v.PixelBuffer = nil 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) lastPixel := uint32(0)
maxCellX := 0 maxCellX := 0
maxCellY := 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{} result := &DCC{}
fileData := fileProvider.LoadFile(path) fileData := fileProvider.LoadFile(path)
var bm = CreateBitMuncher(fileData, 0) var bm = d2common.CreateBitMuncher(fileData, 0)
result.Signature = int(bm.GetByte()) result.Signature = int(bm.GetByte())
if result.Signature != 0x74 { if result.Signature != 0x74 {
log.Fatal("Signature expected to be 0x74 but it is not.") log.Fatal("Signature expected to be 0x74 but it is not.")
@ -527,7 +533,7 @@ func LoadDCC(path string, fileProvider FileProvider) *DCC {
case 32: case 32:
dir = dccDir32[i] 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 return result

View File

@ -1,7 +1,10 @@
package _map package d2data
import ( 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{ var dirLookup = []int32{
@ -67,23 +70,23 @@ type SubstitutionGroup struct {
} }
type DS1 struct { type DS1 struct {
Version int32 // The version of the DS1 Version int32 // The version of the DS1
Width int32 // Width of map, in # of tiles Width int32 // Width of map, in # of tiles
Height int32 // Height 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 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 SubstitutionType int32 // SubstitutionType (layer type): 0 if no layer, else type 1 or type 2
Files []string // FilePtr table of file string pointers Files []string // FilePtr table of file string pointers
NumberOfWalls int32 // WallNum number of wall & orientation layers used NumberOfWalls int32 // WallNum number of wall & orientation layers used
NumberOfFloors int32 // number of floor layers used NumberOfFloors int32 // number of floor layers used
NumberOfShadowLayers int32 // ShadowNum number of shadow layer used NumberOfShadowLayers int32 // ShadowNum number of shadow layer used
NumberOfSubstitutionLayers int32 // SubstitutionNum number of substitution layer used NumberOfSubstitutionLayers int32 // SubstitutionNum number of substitution layer used
SubstitutionGroupsNum int32 // SubstitutionGroupsNum number of substitution groups, datas between objects & NPC paths SubstitutionGroupsNum int32 // SubstitutionGroupsNum number of substitution groups, datas between objects & NPC paths
Objects []common.Object // Objects Objects []Object // Objects
Tiles [][]TileRecord Tiles [][]TileRecord
SubstitutionGroups []SubstitutionGroup SubstitutionGroups []SubstitutionGroup
} }
func LoadDS1(path string, fileProvider common.FileProvider) *DS1 { func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 {
ds1 := &DS1{ ds1 := &DS1{
NumberOfFloors: 1, NumberOfFloors: 1,
NumberOfWalls: 1, NumberOfWalls: 1,
@ -91,12 +94,12 @@ func LoadDS1(path string, fileProvider common.FileProvider) *DS1 {
NumberOfSubstitutionLayers: 0, NumberOfSubstitutionLayers: 0,
} }
fileData := fileProvider.LoadFile(path) fileData := fileProvider.LoadFile(path)
br := common.CreateStreamReader(fileData) br := d2common.CreateStreamReader(fileData)
ds1.Version = br.GetInt32() ds1.Version = br.GetInt32()
ds1.Width = br.GetInt32() + 1 ds1.Width = br.GetInt32() + 1
ds1.Height = br.GetInt32() + 1 ds1.Height = br.GetInt32() + 1
if ds1.Version >= 8 { if ds1.Version >= 8 {
ds1.Act = common.MinInt32(5, br.GetInt32()+1) ds1.Act = d2helper.MinInt32(5, br.GetInt32()+1)
} }
if ds1.Version >= 10 { if ds1.Version >= 10 {
ds1.SubstitutionType = br.GetInt32() 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 { if ds1.Version >= 2 {
numberOfObjects := br.GetInt32() numberOfObjects := br.GetInt32()
for objIdx := 0; objIdx < int(numberOfObjects); objIdx++ { for objIdx := 0; objIdx < int(numberOfObjects); objIdx++ {
newObject := common.Object{} newObject := Object{}
newObject.Type = br.GetInt32() newObject.Type = br.GetInt32()
newObject.Id = br.GetInt32() newObject.Id = br.GetInt32()
newObject.X = br.GetInt32() newObject.X = br.GetInt32()
newObject.Y = br.GetInt32() newObject.Y = br.GetInt32()
newObject.Flags = 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 { 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) ds1.Objects = append(ds1.Objects, newObject)
} }
@ -273,10 +276,10 @@ func LoadDS1(path string, fileProvider common.FileProvider) *DS1 {
} }
if objIdx > -1 { if objIdx > -1 {
if ds1.Objects[objIdx].Paths == nil { 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++ { for pathIdx := 0; pathIdx < int(numPaths); pathIdx++ {
newPath := common.Path{} newPath := d2common.Path{}
newPath.X = br.GetInt32() newPath.X = br.GetInt32()
newPath.Y = br.GetInt32() newPath.Y = br.GetInt32()
if ds1.Version >= 15 { if ds1.Version >= 15 {

View File

@ -1,9 +1,11 @@
package _map package d2data
import ( import (
"log" "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 // https://d2mods.info/forum/viewtopic.php?t=65163
@ -47,10 +49,10 @@ const (
BlockFormatIsometric BlockDataFormat = 1 BlockFormatIsometric BlockDataFormat = 1
) )
func LoadDT1(path string, fileProvider common.FileProvider) *DT1 { func LoadDT1(path string, fileProvider d2interface.FileProvider) *DT1 {
result := &DT1{} result := &DT1{}
fileData := fileProvider.LoadFile(path) fileData := fileProvider.LoadFile(path)
br := common.CreateStreamReader(fileData) br := d2common.CreateStreamReader(fileData)
ver1 := br.GetInt32() ver1 := br.GetInt32()
ver2 := br.GetInt32() ver2 := br.GetInt32()
if ver1 != 7 || ver2 != 6 { if ver1 != 7 || ver2 != 6 {

17
d2data/Object.go Normal file
View File

@ -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
}

View File

@ -32,7 +32,7 @@ package compression
import ( import (
"log" "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) // 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 node := head
for node.Child0 != nil { for node.Child0 != nil {
@ -344,8 +344,8 @@ func HuffmanDecompress(data []byte) []byte {
tail := buildList(sPrime[comptype]) tail := buildList(sPrime[comptype])
head := buildTree(tail) head := buildTree(tail)
outputstream := common.CreateStreamWriter() outputstream := d2common.CreateStreamWriter()
bitstream := common.CreateBitStream(data[1:]) bitstream := d2common.CreateBitStream(data[1:])
var decoded int var decoded int
for true { for true {
node := decode(bitstream, head) node := decode(bitstream, head)

View File

@ -1,7 +1,7 @@
package compression package compression
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
) )
var sLookup = []int{ var sLookup = []int{
@ -30,8 +30,8 @@ func WavDecompress(data []byte, channelCount int) []byte {
Array1 := []int{0x2c, 0x2c} Array1 := []int{0x2c, 0x2c}
Array2 := make([]int, channelCount) Array2 := make([]int, channelCount)
input := common.CreateStreamReader(data) input := d2common.CreateStreamReader(data)
output := common.CreateStreamWriter() output := d2common.CreateStreamWriter()
input.GetByte() input.GetByte()
shift := input.GetByte() shift := input.GetByte()

View File

@ -1,10 +1,14 @@
package common package datadict
import ( import (
"log" "log"
"strings" "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 { type ArmorRecord struct {
@ -135,28 +139,28 @@ func createArmorRecord(line string) ArmorRecord {
result := ArmorRecord{ result := ArmorRecord{
Name: r[inc()], Name: r[inc()],
Version: StringToInt(EmptyToZero(r[inc()])), Version: dh.StringToInt(dh.EmptyToZero(r[inc()])),
CompactSave: StringToInt(EmptyToZero(r[inc()])) == 1, CompactSave: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
Rarity: StringToInt(EmptyToZero(r[inc()])), Rarity: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Spawnable: StringToInt(EmptyToZero(r[inc()])) == 1, Spawnable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
MinAC: StringToInt(EmptyToZero(r[inc()])), MinAC: dh.StringToInt(dh.EmptyToZero(r[inc()])),
MaxAC: StringToInt(EmptyToZero(r[inc()])), MaxAC: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Absorbs: StringToInt(EmptyToZero(r[inc()])), Absorbs: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Speed: StringToInt(EmptyToZero(r[inc()])), Speed: dh.StringToInt(dh.EmptyToZero(r[inc()])),
RequiredStrength: StringToInt(EmptyToZero(r[inc()])), RequiredStrength: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Block: StringToInt(EmptyToZero(r[inc()])), Block: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Durability: StringToInt(EmptyToZero(r[inc()])), Durability: dh.StringToInt(dh.EmptyToZero(r[inc()])),
NoDurability: StringToInt(EmptyToZero(r[inc()])) == 1, NoDurability: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
Level: StringToInt(EmptyToZero(r[inc()])), Level: dh.StringToInt(dh.EmptyToZero(r[inc()])),
RequiredLevel: StringToInt(EmptyToZero(r[inc()])), RequiredLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Cost: StringToInt(EmptyToZero(r[inc()])), Cost: dh.StringToInt(dh.EmptyToZero(r[inc()])),
GambleCost: StringToInt(EmptyToZero(r[inc()])), GambleCost: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Code: r[inc()], Code: r[inc()],
NameString: r[inc()], NameString: r[inc()],
MagicLevel: StringToInt(EmptyToZero(r[inc()])), MagicLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])),
AutoPrefix: StringToInt(EmptyToZero(r[inc()])), AutoPrefix: dh.StringToInt(dh.EmptyToZero(r[inc()])),
AlternateGfx: r[inc()], AlternateGfx: r[inc()],
OpenBetaGfx: r[inc()], OpenBetaGfx: r[inc()],
@ -164,77 +168,77 @@ func createArmorRecord(line string) ArmorRecord {
UberCode: r[inc()], UberCode: r[inc()],
UltraCode: r[inc()], UltraCode: r[inc()],
SpellOffset: StringToInt(EmptyToZero(r[inc()])), SpellOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Component: StringToInt(EmptyToZero(r[inc()])), Component: dh.StringToInt(dh.EmptyToZero(r[inc()])),
InventoryWidth: StringToInt(EmptyToZero(r[inc()])), InventoryWidth: dh.StringToInt(dh.EmptyToZero(r[inc()])),
InventoryHeight: StringToInt(EmptyToZero(r[inc()])), InventoryHeight: dh.StringToInt(dh.EmptyToZero(r[inc()])),
HasInventory: StringToInt(EmptyToZero(r[inc()])) == 1, HasInventory: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
GemSockets: StringToInt(EmptyToZero(r[inc()])), GemSockets: dh.StringToInt(dh.EmptyToZero(r[inc()])),
GemApplyType: StringToInt(EmptyToZero(r[inc()])), GemApplyType: dh.StringToInt(dh.EmptyToZero(r[inc()])),
FlippyFile: r[inc()], FlippyFile: r[inc()],
InventoryFile: r[inc()], InventoryFile: r[inc()],
UniqueInventoryFile: r[inc()], UniqueInventoryFile: r[inc()],
SetInventoryFile: r[inc()], SetInventoryFile: r[inc()],
AnimRightArm: StringToInt(EmptyToZero(r[inc()])), AnimRightArm: dh.StringToInt(dh.EmptyToZero(r[inc()])),
AnimLeftArm: StringToInt(EmptyToZero(r[inc()])), AnimLeftArm: dh.StringToInt(dh.EmptyToZero(r[inc()])),
AnimTorso: StringToInt(EmptyToZero(r[inc()])), AnimTorso: dh.StringToInt(dh.EmptyToZero(r[inc()])),
AnimLegs: StringToInt(EmptyToZero(r[inc()])), AnimLegs: dh.StringToInt(dh.EmptyToZero(r[inc()])),
AnimRightShoulderPad: StringToInt(EmptyToZero(r[inc()])), AnimRightShoulderPad: dh.StringToInt(dh.EmptyToZero(r[inc()])),
AnimLeftShoulderPad: StringToInt(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, Throwable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
Stackable: StringToInt(EmptyToZero(r[inc()])) == 1, Stackable: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
MinStack: StringToInt(EmptyToZero(r[inc()])), MinStack: dh.StringToInt(dh.EmptyToZero(r[inc()])),
MaxStack: StringToInt(EmptyToZero(r[inc()])), MaxStack: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Type: r[inc()], Type: r[inc()],
Type2: r[inc()], Type2: r[inc()],
DropSound: r[inc()], DropSound: r[inc()],
DropSfxFrame: StringToInt(EmptyToZero(r[inc()])), DropSfxFrame: dh.StringToInt(dh.EmptyToZero(r[inc()])),
UseSound: r[inc()], UseSound: r[inc()],
Unique: StringToInt(EmptyToZero(r[inc()])) == 1, Unique: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
Transparent: StringToInt(EmptyToZero(r[inc()])) == 1, Transparent: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
TransTable: StringToInt(EmptyToZero(r[inc()])), TransTable: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Quivered: StringToInt(EmptyToZero(r[inc()])) == 1, Quivered: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
LightRadius: StringToInt(EmptyToZero(r[inc()])), LightRadius: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Belt: StringToInt(EmptyToZero(r[inc()])) == 1, 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()])), MissileType: dh.StringToInt(dh.EmptyToZero(r[inc()])),
DurabilityWarning: StringToInt(EmptyToZero(r[inc()])), DurabilityWarning: dh.StringToInt(dh.EmptyToZero(r[inc()])),
QuantityWarning: StringToInt(EmptyToZero(r[inc()])), QuantityWarning: dh.StringToInt(dh.EmptyToZero(r[inc()])),
MinDamage: StringToInt(EmptyToZero(r[inc()])), MinDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])),
MaxDamage: StringToInt(EmptyToZero(r[inc()])), MaxDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])),
StrengthBonus: StringToInt(EmptyToZero(r[inc()])), StrengthBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])),
DexterityBonus: StringToInt(EmptyToZero(r[inc()])), DexterityBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])),
GemOffset: StringToInt(EmptyToZero(r[inc()])), GemOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])),
BitField1: StringToInt(EmptyToZero(r[inc()])), BitField1: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Vendors: createArmorVendorParams(&r, inc), Vendors: createArmorVendorParams(&r, inc),
SourceArt: r[inc()], SourceArt: r[inc()],
GameArt: r[inc()], GameArt: r[inc()],
ColorTransform: StringToInt(EmptyToZero(r[inc()])), ColorTransform: dh.StringToInt(dh.EmptyToZero(r[inc()])),
InventoryColorTransform: StringToInt(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()], NightmareUpgrade: r[inc()],
HellUpgrade: r[inc()], HellUpgrade: r[inc()],
UnusedMinDamage: StringToInt(EmptyToZero(r[inc()])), UnusedMinDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])),
UnusedMaxDamage: StringToInt(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 return result
} }
@ -264,9 +268,9 @@ func createArmorVendorParams(r *[]string, inc func() int) map[string]*ItemVendor
var Armors map[string]*ArmorRecord var Armors map[string]*ArmorRecord
func LoadArmors(fileProvider FileProvider) { func LoadArmors(fileProvider d2interface.FileProvider) {
Armors = make(map[string]*ArmorRecord) 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 { for _, line := range data {
if len(line) == 0 { if len(line) == 0 {
continue continue

View File

@ -1,10 +1,14 @@
package common package datadict
import ( import (
"log" "log"
"strings" "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 { type LevelPresetRecord struct {
@ -39,21 +43,21 @@ func createLevelPresetRecord(props []string) LevelPresetRecord {
} }
result := LevelPresetRecord{ result := LevelPresetRecord{
Name: props[inc()], Name: props[inc()],
DefinitionId: StringToInt(props[inc()]), DefinitionId: dh.StringToInt(props[inc()]),
LevelId: StringToInt(props[inc()]), LevelId: dh.StringToInt(props[inc()]),
Populate: StringToUint8(props[inc()]) == 1, Populate: dh.StringToUint8(props[inc()]) == 1,
Logicals: StringToUint8(props[inc()]) == 1, Logicals: dh.StringToUint8(props[inc()]) == 1,
Outdoors: StringToUint8(props[inc()]) == 1, Outdoors: dh.StringToUint8(props[inc()]) == 1,
Animate: StringToUint8(props[inc()]) == 1, Animate: dh.StringToUint8(props[inc()]) == 1,
KillEdge: StringToUint8(props[inc()]) == 1, KillEdge: dh.StringToUint8(props[inc()]) == 1,
FillBlanks: StringToUint8(props[inc()]) == 1, FillBlanks: dh.StringToUint8(props[inc()]) == 1,
SizeX: StringToInt(props[inc()]), SizeX: dh.StringToInt(props[inc()]),
SizeY: StringToInt(props[inc()]), SizeY: dh.StringToInt(props[inc()]),
AutoMap: StringToUint8(props[inc()]) == 1, AutoMap: dh.StringToUint8(props[inc()]) == 1,
Scan: StringToUint8(props[inc()]) == 1, Scan: dh.StringToUint8(props[inc()]) == 1,
Pops: StringToInt(props[inc()]), Pops: dh.StringToInt(props[inc()]),
PopPad: StringToInt(props[inc()]), PopPad: dh.StringToInt(props[inc()]),
FileCount: StringToInt(props[inc()]), FileCount: dh.StringToInt(props[inc()]),
Files: [6]string{ Files: [6]string{
props[inc()], props[inc()],
props[inc()], props[inc()],
@ -62,18 +66,18 @@ func createLevelPresetRecord(props []string) LevelPresetRecord {
props[inc()], props[inc()],
props[inc()], props[inc()],
}, },
Dt1Mask: StringToUint(props[inc()]), Dt1Mask: dh.StringToUint(props[inc()]),
Beta: StringToUint8(props[inc()]) == 1, Beta: dh.StringToUint8(props[inc()]) == 1,
Expansion: StringToUint8(props[inc()]) == 1, Expansion: dh.StringToUint8(props[inc()]) == 1,
} }
return result return result
} }
var LevelPresets map[int]*LevelPresetRecord var LevelPresets map[int]*LevelPresetRecord
func LoadLevelPresets(fileProvider FileProvider) { func LoadLevelPresets(fileProvider d2interface.FileProvider) {
LevelPresets = make(map[int]*LevelPresetRecord) 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 { for _, line := range data {
if len(line) == 0 { if len(line) == 0 {
continue continue

View File

@ -1,10 +1,14 @@
package common package datadict
import ( import (
"log" "log"
"strings" "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 { type LevelTypeRecord struct {
@ -18,8 +22,8 @@ type LevelTypeRecord struct {
var LevelTypes []LevelTypeRecord var LevelTypes []LevelTypeRecord
func LoadLevelTypes(fileProvider FileProvider) { func LoadLevelTypes(fileProvider d2interface.FileProvider) {
data := strings.Split(string(fileProvider.LoadFile(resourcepaths.LevelType)), "\r\n")[1:] data := strings.Split(string(fileProvider.LoadFile(d2common.LevelType)), "\r\n")[1:]
LevelTypes = make([]LevelTypeRecord, len(data)) LevelTypes = make([]LevelTypeRecord, len(data))
for i, line := range data { for i, line := range data {
idx := -1 idx := -1
@ -35,7 +39,7 @@ func LoadLevelTypes(fileProvider FileProvider) {
continue continue
} }
LevelTypes[i].Name = parts[inc()] LevelTypes[i].Name = parts[inc()]
LevelTypes[i].Id = StringToInt(parts[inc()]) LevelTypes[i].Id = dh.StringToInt(parts[inc()])
for fileIdx := range LevelTypes[i].Files { for fileIdx := range LevelTypes[i].Files {
LevelTypes[i].Files[fileIdx] = parts[inc()] LevelTypes[i].Files[fileIdx] = parts[inc()]
if LevelTypes[i].Files[fileIdx] == "0" { if LevelTypes[i].Files[fileIdx] == "0" {
@ -44,7 +48,7 @@ func LoadLevelTypes(fileProvider FileProvider) {
} }
LevelTypes[i].Beta = parts[inc()] != "1" 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" LevelTypes[i].Expansion = parts[inc()] != "1"
} }
log.Printf("Loaded %d LevelType records", len(LevelTypes)) log.Printf("Loaded %d LevelType records", len(LevelTypes))

View File

@ -1,9 +1,11 @@
package common package datadict
import ( import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
) )
type LevelWarpRecord struct { type LevelWarpRecord struct {
@ -23,10 +25,10 @@ type LevelWarpRecord struct {
var LevelWarps map[int]*LevelWarpRecord var LevelWarps map[int]*LevelWarpRecord
func LoadLevelWarps(fileProvider FileProvider) { func LoadLevelWarps(fileProvider d2interface.FileProvider) {
LevelWarps = make(map[int]*LevelWarpRecord) LevelWarps = make(map[int]*LevelWarpRecord)
levelWarpData := fileProvider.LoadFile(resourcepaths.LevelWarp) levelWarpData := fileProvider.LoadFile(d2common.LevelWarp)
streamReader := CreateStreamReader(levelWarpData) streamReader := d2common.CreateStreamReader(levelWarpData)
numRecords := int(streamReader.GetInt32()) numRecords := int(streamReader.GetInt32())
for i := 0; i < numRecords; i++ { for i := 0; i < numRecords; i++ {
id := int(streamReader.GetInt32()) id := int(streamReader.GetInt32())

View File

@ -1,10 +1,14 @@
package common package datadict
import ( import (
"log" "log"
"strings" "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 { type MissileCalcParam struct {
@ -196,16 +200,16 @@ func createMissileRecord(line string) MissileRecord {
return i return i
} }
// note: in this file, empties are equivalent to zero, so all numerical conversions should // 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{ result := MissileRecord{
Name: r[inc()], Name: r[inc()],
Id: StringToInt(EmptyToZero(r[inc()])), Id: dh.StringToInt(dh.EmptyToZero(r[inc()])),
ClientMovementFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), ClientMovementFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
ClientCollisionFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), ClientCollisionFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
ServerMovementFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), ServerMovementFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
ServerCollisionFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), ServerCollisionFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
ServerDamageFunc: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), ServerDamageFunc: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
ServerMovementCalc: loadMissileCalc(&r, inc, 5), ServerMovementCalc: loadMissileCalc(&r, inc, 5),
ClientMovementCalc: loadMissileCalc(&r, inc, 5), ClientMovementCalc: loadMissileCalc(&r, inc, 5),
@ -213,12 +217,12 @@ func createMissileRecord(line string) MissileRecord {
ClientCollisionCalc: loadMissileCalc(&r, inc, 3), ClientCollisionCalc: loadMissileCalc(&r, inc, 3),
ServerDamageCalc: loadMissileCalc(&r, inc, 2), ServerDamageCalc: loadMissileCalc(&r, inc, 2),
Velocity: StringToInt(EmptyToZero(r[inc()])), Velocity: dh.StringToInt(dh.EmptyToZero(r[inc()])),
MaxVelocity: StringToInt(EmptyToZero(r[inc()])), MaxVelocity: dh.StringToInt(dh.EmptyToZero(r[inc()])),
LevelVelocityBonus: StringToInt(EmptyToZero(r[inc()])), LevelVelocityBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Accel: StringToInt(EmptyToZero(r[inc()])), Accel: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Range: StringToInt(EmptyToZero(r[inc()])), Range: dh.StringToInt(dh.EmptyToZero(r[inc()])),
LevelRangeBonus: StringToInt(EmptyToZero(r[inc()])), LevelRangeBonus: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Light: loadMissileLight(&r, inc), Light: loadMissileLight(&r, inc),
@ -226,54 +230,54 @@ func createMissileRecord(line string) MissileRecord {
Collision: loadMissileCollision(&r, inc), Collision: loadMissileCollision(&r, inc),
XOffset: StringToInt(EmptyToZero(r[inc()])), XOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])),
YOffset: StringToInt(EmptyToZero(r[inc()])), YOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])),
ZOffset: StringToInt(EmptyToZero(r[inc()])), ZOffset: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Size: StringToInt(EmptyToZero(r[inc()])), Size: dh.StringToInt(dh.EmptyToZero(r[inc()])),
DestroyedByTP: StringToInt(EmptyToZero(r[inc()])) == 1, DestroyedByTP: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
DestroyedByTPFrame: StringToInt(EmptyToZero(r[inc()])), DestroyedByTPFrame: dh.StringToInt(dh.EmptyToZero(r[inc()])),
CanDestroy: StringToInt(EmptyToZero(r[inc()])) == 1, CanDestroy: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
UseAttackRating: StringToInt(EmptyToZero(r[inc()])) == 1, UseAttackRating: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
AlwaysExplode: StringToInt(EmptyToZero(r[inc()])) == 1, AlwaysExplode: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
ClientExplosion: StringToInt(EmptyToZero(r[inc()])) == 1, ClientExplosion: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
TownSafe: StringToInt(EmptyToZero(r[inc()])) == 1, TownSafe: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
IgnoreBossModifiers: StringToInt(EmptyToZero(r[inc()])) == 1, IgnoreBossModifiers: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
IgnoreMultishot: StringToInt(EmptyToZero(r[inc()])) == 1, IgnoreMultishot: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
HolyFilterType: StringToInt(EmptyToZero(r[inc()])), HolyFilterType: dh.StringToInt(dh.EmptyToZero(r[inc()])),
CanBeSlowed: StringToInt(EmptyToZero(r[inc()])) == 1, CanBeSlowed: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
TriggersHitEvents: StringToInt(EmptyToZero(r[inc()])) == 1, TriggersHitEvents: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
TriggersGetHit: StringToInt(EmptyToZero(r[inc()])) == 1, TriggersGetHit: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
SoftHit: StringToInt(EmptyToZero(r[inc()])) == 1, SoftHit: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
KnockbackPercent: StringToInt(EmptyToZero(r[inc()])), 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, UseQuantity: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
AffectedByPierce: StringToInt(EmptyToZero(r[inc()])) == 1, AffectedByPierce: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
SpecialSetup: StringToInt(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()], SkillName: r[inc()],
ResultFlags: StringToInt(EmptyToZero(r[inc()])), ResultFlags: dh.StringToInt(dh.EmptyToZero(r[inc()])),
HitFlags: StringToInt(EmptyToZero(r[inc()])), HitFlags: dh.StringToInt(dh.EmptyToZero(r[inc()])),
HitShift: StringToInt(EmptyToZero(r[inc()])), HitShift: dh.StringToInt(dh.EmptyToZero(r[inc()])),
ApplyMastery: StringToInt(EmptyToZero(r[inc()])) == 1, ApplyMastery: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
SourceDamage: StringToInt(EmptyToZero(r[inc()])), SourceDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])),
HalfDamageForTwoHander: StringToInt(EmptyToZero(r[inc()])) == 1, HalfDamageForTwoHander: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
SourceMissDamage: StringToInt(EmptyToZero(r[inc()])), SourceMissDamage: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Damage: loadMissileDamage(&r, inc), Damage: loadMissileDamage(&r, inc),
ElementalDamage: loadMissileElementalDamage(&r, inc), ElementalDamage: loadMissileElementalDamage(&r, inc),
HitClass: StringToInt(EmptyToZero(r[inc()])), HitClass: dh.StringToInt(dh.EmptyToZero(r[inc()])),
NumDirections: StringToInt(EmptyToZero(r[inc()])), NumDirections: dh.StringToInt(dh.EmptyToZero(r[inc()])),
LocalBlood: StringToInt(EmptyToZero(r[inc()])), LocalBlood: dh.StringToInt(dh.EmptyToZero(r[inc()])),
DamageReductionRate: StringToInt(EmptyToZero(r[inc()])), DamageReductionRate: dh.StringToInt(dh.EmptyToZero(r[inc()])),
TravelSound: r[inc()], TravelSound: r[inc()],
HitSound: r[inc()], HitSound: r[inc()],
@ -291,9 +295,9 @@ func createMissileRecord(line string) MissileRecord {
var Missiles map[int]*MissileRecord var Missiles map[int]*MissileRecord
func LoadMissiles(fileProvider FileProvider) { func LoadMissiles(fileProvider d2interface.FileProvider) {
Missiles = make(map[int]*MissileRecord) 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 { for _, line := range data {
if len(line) == 0 { if len(line) == 0 {
continue continue
@ -306,7 +310,7 @@ func LoadMissiles(fileProvider FileProvider) {
func loadMissileCalcParam(r *[]string, inc func() int) MissileCalcParam { func loadMissileCalcParam(r *[]string, inc func() int) MissileCalcParam {
result := MissileCalcParam{ result := MissileCalcParam{
Param: StringToInt(EmptyToZero((*r)[inc()])), Param: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
Desc: (*r)[inc()], Desc: (*r)[inc()],
} }
return result return result
@ -326,64 +330,64 @@ func loadMissileCalc(r *[]string, inc func() int, params int) MissileCalc {
func loadMissileLight(r *[]string, inc func() int) MissileLight { func loadMissileLight(r *[]string, inc func() int) MissileLight {
result := MissileLight{ result := MissileLight{
Diameter: StringToInt(EmptyToZero((*r)[inc()])), Diameter: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
Flicker: StringToInt(EmptyToZero((*r)[inc()])), Flicker: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
Red: StringToUint8(EmptyToZero((*r)[inc()])), Red: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])),
Green: StringToUint8(EmptyToZero((*r)[inc()])), Green: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])),
Blue: StringToUint8(EmptyToZero((*r)[inc()])), Blue: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])),
} }
return result return result
} }
func loadMissileAnimation(r *[]string, inc func() int) MissileAnimation { func loadMissileAnimation(r *[]string, inc func() int) MissileAnimation {
result := MissileAnimation{ result := MissileAnimation{
StepsBeforeVisible: StringToInt(EmptyToZero((*r)[inc()])), StepsBeforeVisible: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StepsBeforeActive: StringToInt(EmptyToZero((*r)[inc()])), StepsBeforeActive: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
LoopAnimation: StringToInt(EmptyToZero((*r)[inc()])) == 1, LoopAnimation: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
CelFileName: (*r)[inc()], CelFileName: (*r)[inc()],
AnimationRate: StringToInt(EmptyToZero((*r)[inc()])), AnimationRate: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
AnimationLength: StringToInt(EmptyToZero((*r)[inc()])), AnimationLength: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
AnimationSpeed: StringToInt(EmptyToZero((*r)[inc()])), AnimationSpeed: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StartingFrame: StringToInt(EmptyToZero((*r)[inc()])), StartingFrame: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
HasSubLoop: StringToInt(EmptyToZero((*r)[inc()])) == 1, HasSubLoop: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
SubStartingFrame: StringToInt(EmptyToZero((*r)[inc()])), SubStartingFrame: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
SubEndingFrame: StringToInt(EmptyToZero((*r)[inc()])), SubEndingFrame: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
} }
return result return result
} }
func loadMissileCollision(r *[]string, inc func() int) MissileCollision { func loadMissileCollision(r *[]string, inc func() int) MissileCollision {
result := MissileCollision{ result := MissileCollision{
CollisionType: StringToInt(EmptyToZero((*r)[inc()])), CollisionType: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
DestroyedUponCollision: StringToInt(EmptyToZero((*r)[inc()])) == 1, DestroyedUponCollision: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
FriendlyFire: StringToInt(EmptyToZero((*r)[inc()])) == 1, FriendlyFire: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
LastCollide: StringToInt(EmptyToZero((*r)[inc()])) == 1, LastCollide: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
Collision: StringToInt(EmptyToZero((*r)[inc()])) == 1, Collision: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
ClientCollision: StringToInt(EmptyToZero((*r)[inc()])) == 1, ClientCollision: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
ClientSend: StringToInt(EmptyToZero((*r)[inc()])) == 1, ClientSend: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
UseCollisionTimer: StringToInt(EmptyToZero((*r)[inc()])) == 1, UseCollisionTimer: dh.StringToInt(dh.EmptyToZero((*r)[inc()])) == 1,
TimerFrames: StringToInt(EmptyToZero((*r)[inc()])), TimerFrames: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
} }
return result return result
} }
func loadMissileDamage(r *[]string, inc func() int) MissileDamage { func loadMissileDamage(r *[]string, inc func() int) MissileDamage {
result := MissileDamage{ result := MissileDamage{
MinDamage: StringToInt(EmptyToZero((*r)[inc()])), MinDamage: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
MinLevelDamage: [5]int{ MinLevelDamage: [5]int{
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
}, },
MaxDamage: StringToInt(EmptyToZero((*r)[inc()])), MaxDamage: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
MaxLevelDamage: [5]int{ MaxLevelDamage: [5]int{
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
}, },
DamageSynergyPerCalc: (*r)[inc()], DamageSynergyPerCalc: (*r)[inc()],
} }
@ -394,11 +398,11 @@ func loadMissileElementalDamage(r *[]string, inc func() int) MissileElementalDam
result := MissileElementalDamage{ result := MissileElementalDamage{
ElementType: (*r)[inc()], ElementType: (*r)[inc()],
Damage: loadMissileDamage(r, inc), Damage: loadMissileDamage(r, inc),
Duration: StringToInt(EmptyToZero((*r)[inc()])), Duration: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
LevelDuration: [3]int{ LevelDuration: [3]int{
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
StringToInt(EmptyToZero((*r)[inc()])), dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
}, },
} }
return result return result

View File

@ -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)))
}

View File

@ -1,4 +1,4 @@
package common package datadict
import ( import (
"log" "log"

View File

@ -1,10 +1,12 @@
package common package datadict
import ( import (
"log" "log"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
) )
type ObjectTypeRecord struct { type ObjectTypeRecord struct {
@ -14,9 +16,9 @@ type ObjectTypeRecord struct {
var ObjectTypes []ObjectTypeRecord var ObjectTypes []ObjectTypeRecord
func LoadObjectTypes(fileProvider FileProvider) { func LoadObjectTypes(fileProvider d2interface.FileProvider) {
objectTypeData := fileProvider.LoadFile(resourcepaths.ObjectType) objectTypeData := fileProvider.LoadFile(d2common.ObjectType)
streamReader := CreateStreamReader(objectTypeData) streamReader := d2common.CreateStreamReader(objectTypeData)
count := streamReader.GetInt32() count := streamReader.GetInt32()
ObjectTypes = make([]ObjectTypeRecord, count) ObjectTypes = make([]ObjectTypeRecord, count)
for i := range ObjectTypes { for i := range ObjectTypes {

357
d2data/datadict/Objects.go Normal file
View File

@ -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))
}

View File

@ -1,9 +1,11 @@
package common package datadict
import ( import (
"log" "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 // PaletteRGB represents a color in a palette
@ -13,14 +15,14 @@ type PaletteRGB struct {
// PaletteType represents a palette // PaletteType represents a palette
type PaletteRec struct { type PaletteRec struct {
Name palettedefs.PaletteType Name d2enum.PaletteType
Colors [256]PaletteRGB Colors [256]PaletteRGB
} }
var Palettes map[palettedefs.PaletteType]PaletteRec var Palettes map[d2enum.PaletteType]PaletteRec
// CreatePalette creates a palette // CreatePalette creates a palette
func CreatePalette(name palettedefs.PaletteType, data []byte) PaletteRec { func CreatePalette(name d2enum.PaletteType, data []byte) PaletteRec {
result := PaletteRec{Name: name} result := PaletteRec{Name: name}
for i := 0; i <= 255; i++ { for i := 0; i <= 255; i++ {
@ -33,14 +35,14 @@ func CreatePalette(name palettedefs.PaletteType, data []byte) PaletteRec {
return result return result
} }
func LoadPalettes(mpqFiles map[string]string, fileProvider FileProvider) { func LoadPalettes(mpqFiles map[string]string, fileProvider d2interface.FileProvider) {
Palettes = make(map[palettedefs.PaletteType]PaletteRec) Palettes = make(map[d2enum.PaletteType]PaletteRec)
for _, pal := range []string{ for _, pal := range []string{
"act1", "act2", "act3", "act4", "act5", "endgame", "endgame2", "fechar", "loading", "act1", "act2", "act3", "act4", "act5", "endgame", "endgame2", "fechar", "loading",
"menu0", "menu1", "menu2", "menu3", "menu4", "sky", "static", "trademark", "units", "menu0", "menu1", "menu2", "menu3", "menu4", "sky", "static", "trademark", "units",
} { } {
filePath := `data\global\palette\` + pal + `\pal.dat` filePath := `data\global\palette\` + pal + `\pal.dat`
paletteName := palettedefs.PaletteType(pal) paletteName := d2enum.PaletteType(pal)
palette := CreatePalette(paletteName, fileProvider.LoadFile(filePath)) palette := CreatePalette(paletteName, fileProvider.LoadFile(filePath))
Palettes[paletteName] = palette Palettes[paletteName] = palette
} }

View File

@ -1,10 +1,14 @@
package common package datadict
import ( import (
"log" "log"
"strings" "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 // SoundEntry represents a sound entry
@ -46,39 +50,39 @@ func createSoundEntry(soundLine string) SoundEntry {
} }
result := SoundEntry{ result := SoundEntry{
Handle: props[inc()], Handle: props[inc()],
Index: StringToInt(props[inc()]), Index: dh.StringToInt(props[inc()]),
FileName: props[inc()], FileName: props[inc()],
Volume: StringToUint8(props[inc()]), Volume: dh.StringToUint8(props[inc()]),
GroupSize: StringToUint8(props[inc()]), GroupSize: dh.StringToUint8(props[inc()]),
Loop: StringToUint8(props[inc()]) == 1, Loop: dh.StringToUint8(props[inc()]) == 1,
FadeIn: StringToUint8(props[inc()]), FadeIn: dh.StringToUint8(props[inc()]),
FadeOut: StringToUint8(props[inc()]), FadeOut: dh.StringToUint8(props[inc()]),
DeferInst: StringToUint8(props[inc()]), DeferInst: dh.StringToUint8(props[inc()]),
StopInst: StringToUint8(props[inc()]), StopInst: dh.StringToUint8(props[inc()]),
Duration: StringToUint8(props[inc()]), Duration: dh.StringToUint8(props[inc()]),
Compound: StringToInt8(props[inc()]), Compound: dh.StringToInt8(props[inc()]),
Reverb: StringToUint8(props[inc()]) == 1, Reverb: dh.StringToUint8(props[inc()]) == 1,
Falloff: StringToUint8(props[inc()]), Falloff: dh.StringToUint8(props[inc()]),
Cache: StringToUint8(props[inc()]), Cache: dh.StringToUint8(props[inc()]),
AsyncOnly: StringToUint8(props[inc()]) == 1, AsyncOnly: dh.StringToUint8(props[inc()]) == 1,
Priority: StringToUint8(props[inc()]), Priority: dh.StringToUint8(props[inc()]),
Stream: StringToUint8(props[inc()]), Stream: dh.StringToUint8(props[inc()]),
Stereo: StringToUint8(props[inc()]), Stereo: dh.StringToUint8(props[inc()]),
Tracking: StringToUint8(props[inc()]), Tracking: dh.StringToUint8(props[inc()]),
Solo: StringToUint8(props[inc()]), Solo: dh.StringToUint8(props[inc()]),
MusicVol: StringToUint8(props[inc()]), MusicVol: dh.StringToUint8(props[inc()]),
Block1: StringToInt(props[inc()]), Block1: dh.StringToInt(props[inc()]),
Block2: StringToInt(props[inc()]), Block2: dh.StringToInt(props[inc()]),
Block3: StringToInt(props[inc()]), Block3: dh.StringToInt(props[inc()]),
} }
return result return result
} }
var Sounds map[string]SoundEntry var Sounds map[string]SoundEntry
func LoadSounds(fileProvider FileProvider) { func LoadSounds(fileProvider d2interface.FileProvider) {
Sounds = make(map[string]SoundEntry) 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 { for _, line := range soundData {
if len(line) == 0 { if len(line) == 0 {
continue continue

View File

@ -1,10 +1,14 @@
package common package datadict
import ( import (
"log" "log"
"strings" "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 { type UniqueItemRecord struct {
@ -56,22 +60,22 @@ func createUniqueItemRecord(r []string) UniqueItemRecord {
} }
result := UniqueItemRecord{ result := UniqueItemRecord{
Name: r[inc()], Name: r[inc()],
Version: StringToInt(EmptyToZero(r[inc()])), Version: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Enabled: StringToInt(EmptyToZero(r[inc()])) == 1, Enabled: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
Ladder: StringToInt(EmptyToZero(r[inc()])) == 1, Ladder: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
Rarity: StringToInt(EmptyToZero(r[inc()])), Rarity: dh.StringToInt(dh.EmptyToZero(r[inc()])),
NoLimit: StringToInt(EmptyToZero(r[inc()])) == 1, NoLimit: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
Level: StringToInt(EmptyToZero(r[inc()])), Level: dh.StringToInt(dh.EmptyToZero(r[inc()])),
RequiredLevel: StringToInt(EmptyToZero(r[inc()])), RequiredLevel: dh.StringToInt(dh.EmptyToZero(r[inc()])),
Code: r[inc()], Code: r[inc()],
TypeDescription: r[inc()], TypeDescription: r[inc()],
UberDescription: r[inc()], UberDescription: r[inc()],
SingleCopy: StringToInt(EmptyToZero(r[inc()])) == 1, SingleCopy: dh.StringToInt(dh.EmptyToZero(r[inc()])) == 1,
CostMultiplier: StringToInt(EmptyToZero(r[inc()])), CostMultiplier: dh.StringToInt(dh.EmptyToZero(r[inc()])),
CostAdd: StringToInt(EmptyToZero(r[inc()])), CostAdd: dh.StringToInt(dh.EmptyToZero(r[inc()])),
CharacterGfxTransform: r[inc()], CharacterGfxTransform: r[inc()],
InventoryGfxTransform: r[inc()], InventoryGfxTransform: r[inc()],
@ -79,7 +83,7 @@ func createUniqueItemRecord(r []string) UniqueItemRecord {
InventoryFile: r[inc()], InventoryFile: r[inc()],
DropSound: r[inc()], DropSound: r[inc()],
DropSfxFrame: StringToInt(EmptyToZero(r[inc()])), DropSfxFrame: dh.StringToInt(dh.EmptyToZero(r[inc()])),
UseSound: r[inc()], UseSound: r[inc()],
Properties: [12]UniqueItemProperty{ Properties: [12]UniqueItemProperty{
@ -106,17 +110,17 @@ func createUniqueItemProperty(r *[]string, inc func() int) UniqueItemProperty {
result := UniqueItemProperty{ result := UniqueItemProperty{
Property: (*r)[inc()], Property: (*r)[inc()],
Parameter: (*r)[inc()], Parameter: (*r)[inc()],
Min: StringToInt(EmptyToZero((*r)[inc()])), Min: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
Max: StringToInt(EmptyToZero((*r)[inc()])), Max: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
} }
return result return result
} }
var UniqueItems map[string]*UniqueItemRecord var UniqueItems map[string]*UniqueItemRecord
func LoadUniqueItems(fileProvider FileProvider) { func LoadUniqueItems(fileProvider d2interface.FileProvider) {
UniqueItems = make(map[string]*UniqueItemRecord) 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 { for _, line := range data {
if len(line) == 0 { if len(line) == 0 {
continue continue

View File

@ -1,10 +1,14 @@
package common package datadict
import ( import (
"log" "log"
"strings" "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 { type WeaponRecord struct {
@ -134,36 +138,36 @@ func createWeaponRecord(line string) WeaponRecord {
Code: r[inc()], Code: r[inc()],
AlternateGfx: r[inc()], AlternateGfx: r[inc()],
NameString: r[inc()], NameString: r[inc()],
Version: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Version: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
CompactSave: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, CompactSave: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
Rarity: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Rarity: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Spawnable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, Spawnable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
MinDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MinDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
MaxDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MaxDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
BarbOneOrTwoHanded: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, BarbOneOrTwoHanded: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
UsesTwoHands: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, UsesTwoHands: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
Min2HandDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Min2HandDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Max2HandDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Max2HandDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
MinMissileDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MinMissileDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
MaxMissileDamage: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MaxMissileDamage: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
MissileSpeed: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MissileSpeed: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
ExtraRange: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), ExtraRange: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Speed: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Speed: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
StrengthBonus: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), StrengthBonus: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
DexterityBonus: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), DexterityBonus: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
RequiredStrength: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), RequiredStrength: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
RequiredDexterity: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), RequiredDexterity: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Durability: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Durability: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
NoDurability: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, NoDurability: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
Level: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Level: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
RequiredLevel: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), RequiredLevel: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Cost: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Cost: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
GambleCost: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), GambleCost: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
MagicLevel: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MagicLevel: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
AutoPrefix: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), AutoPrefix: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
OpenBetaGfx: r[inc()], OpenBetaGfx: r[inc()],
NormalCode: r[inc()], NormalCode: r[inc()],
UberCode: r[inc()], UberCode: r[inc()],
@ -171,61 +175,61 @@ func createWeaponRecord(line string) WeaponRecord {
WeaponClass: r[inc()], WeaponClass: r[inc()],
WeaponClass2Hand: r[inc()], WeaponClass2Hand: r[inc()],
Component: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Component: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
HitClass: r[inc()], HitClass: r[inc()],
InventoryWidth: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), InventoryWidth: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
InventoryHeight: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), InventoryHeight: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Stackable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, Stackable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
MinStack: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MinStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
MaxStack: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MaxStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
SpawnStack: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), SpawnStack: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
FlippyFile: r[inc()], FlippyFile: r[inc()],
InventoryFile: r[inc()], InventoryFile: r[inc()],
UniqueInventoryFile: r[inc()], UniqueInventoryFile: r[inc()],
SetInventoryFile: r[inc()], SetInventoryFile: r[inc()],
HasInventory: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, HasInventory: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
GemSockets: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), GemSockets: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
GemApplyType: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), GemApplyType: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
SpecialFeature: 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()], DropSound: r[inc()],
DropSfxFrame: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), DropSfxFrame: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
UseSound: r[inc()], UseSound: r[inc()],
Unique: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, Unique: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
Transparent: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, Transparent: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
TransTable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), TransTable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Quivered: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, Quivered: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
LightRadius: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), LightRadius: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Belt: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, Belt: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
Quest: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), Quest: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
QuestDifficultyCheck: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, QuestDifficultyCheck: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
MissileType: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), MissileType: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
DurabilityWarning: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), DurabilityWarning: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
QuantityWarning: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), QuantityWarning: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
GemOffset: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), GemOffset: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
BitField1: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), BitField1: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
Vendors: createWeaponVendorParams(&r, inc), Vendors: createWeaponVendorParams(&r, inc),
SourceArt: r[inc()], SourceArt: r[inc()],
GameArt: r[inc()], GameArt: r[inc()],
ColorTransform: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))), ColorTransform: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))),
InventoryColorTransform: StringToInt(EmptyToZero(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()], NightmareUpgrade: r[inc()],
HellUpgrade: r[inc()], HellUpgrade: r[inc()],
Nameable: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, Nameable: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
PermStoreItem: StringToInt(EmptyToZero(AsterToEmpty(r[inc()]))) == 1, PermStoreItem: dh.StringToInt(dh.EmptyToZero(dh.AsterToEmpty(r[inc()]))) == 1,
} }
return result return result
} }
@ -258,11 +262,11 @@ func CreateItemVendorParams(r *[]string, inc func() int, vs []string) map[string
for _, name := range vs { for _, name := range vs {
wvp := ItemVendorParams{ wvp := ItemVendorParams{
Min: StringToInt(EmptyToZero((*r)[inc()])), Min: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
Max: StringToInt(EmptyToZero((*r)[inc()])), Max: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
MagicMin: StringToInt(EmptyToZero((*r)[inc()])), MagicMin: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
MagicMax: StringToInt(EmptyToZero((*r)[inc()])), MagicMax: dh.StringToInt(dh.EmptyToZero((*r)[inc()])),
MagicLevel: StringToUint8(EmptyToZero((*r)[inc()])), MagicLevel: dh.StringToUint8(dh.EmptyToZero((*r)[inc()])),
} }
result[name] = &wvp result[name] = &wvp
} }
@ -271,9 +275,9 @@ func CreateItemVendorParams(r *[]string, inc func() int, vs []string) map[string
var Weapons map[string]*WeaponRecord var Weapons map[string]*WeaponRecord
func LoadWeapons(fileProvider FileProvider) { func LoadWeapons(fileProvider d2interface.FileProvider) {
Weapons = make(map[string]*WeaponRecord) 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 { for _, line := range data {
if len(line) == 0 { if len(line) == 0 {
continue continue

View File

@ -10,7 +10,7 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/OpenDiablo2/OpenDiablo2/d2common"
) )
// MPQ represents an MPQ archive // 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 // ReadFile reads a file from the MPQ and returns a memory stream
func (v MPQ) ReadFile(fileName string) ([]byte, error) { 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.ToLower(fileName)
fileName = strings.ReplaceAll(fileName, `/`, "\\") fileName = strings.ReplaceAll(fileName, `/`, "\\")
cached := v.fileCache[fileName] cached := v.fileCache[fileName]

View File

@ -9,9 +9,10 @@ import (
"log" "log"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
"github.com/JoshVarga/blast" "github.com/JoshVarga/blast"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2data/compression"
"github.com/OpenDiablo2/OpenDiablo2/compression"
) )
// Stream represents a stream of data in an MPQ archive // 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() 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]) copy(buffer[offset:offset+bytesToCopy], v.CurrentData[v.CurrentPosition:v.CurrentPosition+bytesToCopy])
v.CurrentPosition += bytesToCopy v.CurrentPosition += bytesToCopy
return 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 { func (v *Stream) readInternal(buffer []byte, offset, count uint32) uint32 {
v.bufferData() v.bufferData()
localPosition := v.CurrentPosition % v.BlockSize 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 { if bytesToCopy <= 0 {
return 0 return 0
} }
@ -121,7 +122,7 @@ func (v *Stream) bufferData() {
if requiredBlock == v.CurrentBlockIndex { if requiredBlock == v.CurrentBlockIndex {
return 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.CurrentData = v.loadBlock(requiredBlock, expectedLength)
v.CurrentBlockIndex = requiredBlock v.CurrentBlockIndex = requiredBlock
} }

View File

@ -1,4 +1,4 @@
package common package mpq
type MpqFileRecord struct { type MpqFileRecord struct {
MpqFile string MpqFile string

View File

@ -3,7 +3,7 @@ package video
import ( import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
) )
type BinkVideoMode uint32 type BinkVideoMode uint32
@ -41,7 +41,7 @@ type BinkDecoder struct {
VideoHeight uint32 VideoHeight uint32
FPS uint32 FPS uint32
FrameTimeMS uint32 FrameTimeMS uint32
streamReader *common.StreamReader streamReader *d2common.StreamReader
VideoMode BinkVideoMode VideoMode BinkVideoMode
HasAlphaPlane bool HasAlphaPlane bool
Grayscale bool Grayscale bool
@ -52,7 +52,7 @@ type BinkDecoder struct {
func CreateBinkDecoder(source []byte) *BinkDecoder { func CreateBinkDecoder(source []byte) *BinkDecoder {
result := &BinkDecoder{ result := &BinkDecoder{
streamReader: common.CreateStreamReader(source), streamReader: d2common.CreateStreamReader(source),
} }
result.loadHeaderInformation() result.loadHeaderInformation()
return result return result

View File

@ -1,4 +1,4 @@
package common package d2helper
import ( import (
"image/color" "image/color"

View File

@ -1,4 +1,4 @@
package common package d2helper
// Min returns the lower of two values // Min returns the lower of two values
func Min(a, b uint32) uint32 { func Min(a, b uint32) uint32 {

View File

@ -1,4 +1,4 @@
package common package d2helper
import ( import (
"bytes" "bytes"

View File

@ -1,4 +1,4 @@
package common package d2render
import ( import (
"fmt" "fmt"
@ -6,7 +6,17 @@ import (
"strings" "strings"
"time" "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" "github.com/hajimehoshi/ebiten"
) )
@ -19,9 +29,9 @@ type AnimatedEntity struct {
LocationX float64 LocationX float64
// LocationY represents the tile Y position of the entity // LocationY represents the tile Y position of the entity
LocationY float64 LocationY float64
dccLayers map[string]*DCC dccLayers map[string]*d2data.DCC
Cof *Cof Cof *d2data.Cof
palette palettedefs.PaletteType palette d2enum.PaletteType
base string base string
token string token string
animationMode string animationMode string
@ -32,19 +42,19 @@ type AnimatedEntity struct {
direction int direction int
currentFrame int currentFrame int
frames map[string][]*ebiten.Image frames map[string][]*ebiten.Image
frameLocations map[string][]Rectangle frameLocations map[string][]d2common.Rectangle
object Object object d2data.Object
} }
// CreateAnimatedEntity creates an instance of AnimatedEntity // 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{ result := &AnimatedEntity{
base: object.Lookup.Base, base: object.Lookup.Base,
token: object.Lookup.Token, token: object.Lookup.Token,
object: object, object: object,
palette: palette, palette: palette,
} }
result.dccLayers = make(map[string]*DCC) result.dccLayers = make(map[string]*d2data.DCC)
result.LocationX = float64(object.X) / 5 result.LocationX = float64(object.X) / 5
result.LocationY = float64(object.Y) / 5 result.LocationY = float64(object.Y) / 5
return result 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} 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 // 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) 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.animationMode = animationMode
v.weaponClass = weaponClass v.weaponClass = weaponClass
v.direction = direction v.direction = direction
@ -64,8 +74,8 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in
v.direction = v.Cof.NumberOfDirections - 1 v.direction = v.Cof.NumberOfDirections - 1
} }
v.frames = make(map[string][]*ebiten.Image) v.frames = make(map[string][]*ebiten.Image)
v.frameLocations = make(map[string][]Rectangle) v.frameLocations = make(map[string][]d2common.Rectangle)
v.dccLayers = make(map[string]*DCC) v.dccLayers = make(map[string]*d2data.DCC)
for _, cofLayer := range v.Cof.CofLayers { for _, cofLayer := range v.Cof.CofLayers {
layerName := DccLayerNames[cofLayer.Type] layerName := DccLayerNames[cofLayer.Type]
v.dccLayers[layerName] = v.LoadLayer(layerName, provider) 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" layerName := "tr"
switch strings.ToUpper(layer) { switch strings.ToUpper(layer) {
case "HD": // Head case "HD": // Head
@ -117,7 +127,7 @@ func (v *AnimatedEntity) LoadLayer(layer string, fileProvider FileProvider) *DCC
return nil 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) 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 // 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) { func (v *AnimatedEntity) cacheFrames(layerName string) {
dcc := v.dccLayers[layerName] dcc := v.dccLayers[layerName]
v.currentFrame = 0 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.animationSpeed = int(1000.0 / ((float64(animationData.AnimationSpeed) * 25.0) / 256.0))
v.framesToAnimate = animationData.FramesPerDirection v.framesToAnimate = animationData.FramesPerDirection
v.lastFrameTime = time.Now() v.lastFrameTime = time.Now()
@ -158,15 +168,15 @@ func (v *AnimatedEntity) cacheFrames(layerName string) {
maxX := int32(-10000) maxX := int32(-10000)
maxY := int32(-10000) maxY := int32(-10000)
for _, layer := range dcc.Directions { for _, layer := range dcc.Directions {
minX = MinInt32(minX, int32(layer.Box.Left)) minX = d2helper.MinInt32(minX, int32(layer.Box.Left))
minY = MinInt32(minY, int32(layer.Box.Top)) minY = d2helper.MinInt32(minY, int32(layer.Box.Top))
maxX = MaxInt32(maxX, int32(layer.Box.Right())) maxX = d2helper.MaxInt32(maxX, int32(layer.Box.Right()))
maxY = MaxInt32(maxY, int32(layer.Box.Bottom())) maxY = d2helper.MaxInt32(maxY, int32(layer.Box.Bottom()))
} }
frameW := maxX - minX frameW := maxX - minX
frameH := maxY - minY frameH := maxY - minY
v.frames[layerName] = make([]*ebiten.Image, v.framesToAnimate) 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] { for frameIndex := range v.frames[layerName] {
v.frames[layerName][frameIndex], _ = ebiten.NewImage(int(frameW), int(frameH), ebiten.FilterNearest) v.frames[layerName][frameIndex], _ = ebiten.NewImage(int(frameW), int(frameH), ebiten.FilterNearest)
for layerIdx := 0; layerIdx < v.Cof.NumberOfLayers; layerIdx++ { for layerIdx := 0; layerIdx < v.Cof.NumberOfLayers; layerIdx++ {
@ -185,7 +195,7 @@ func (v *AnimatedEntity) cacheFrames(layerName string) {
if paletteIndex == 0 { if paletteIndex == 0 {
continue continue
} }
color := Palettes[v.palette].Colors[paletteIndex] color := datadict.Palettes[v.palette].Colors[paletteIndex]
actualX := x + direction.Box.Left - int(minX) actualX := x + direction.Box.Left - int(minX)
actualY := y + direction.Box.Top - int(minY) actualY := y + direction.Box.Top - int(minY)
img.Pix[(actualX*4)+(actualY*int(frameW)*4)] = color.R 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) newImage, _ := ebiten.NewImageFromImage(img, ebiten.FilterNearest)
img = nil img = nil
v.frames[layerName][frameIndex] = newImage v.frames[layerName][frameIndex] = newImage
v.frameLocations[layerName][frameIndex] = Rectangle{ v.frameLocations[layerName][frameIndex] = d2common.Rectangle{
Left: int(minX), Left: int(minX),
Top: int(minY), Top: int(minY),
Width: int(frameW), Width: int(frameW),

27
d2render/NPC.go Normal file
View File

@ -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)
}

View File

@ -1,4 +1,4 @@
package common package d2render
import ( import (
"encoding/binary" "encoding/binary"
@ -7,6 +7,10 @@ import (
"sync" "sync"
"time" "time"
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2data/datadict"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
) )
@ -45,7 +49,7 @@ type SpriteFrame struct {
} }
// CreateSprite creates an instance of a sprite // CreateSprite creates an instance of a sprite
func CreateSprite(data []byte, palette PaletteRec) *Sprite { func CreateSprite(data []byte, palette datadict.PaletteRec) *Sprite {
result := &Sprite{ result := &Sprite{
X: 50, X: 50,
Y: 50, Y: 50,
@ -81,9 +85,9 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite {
dataPointer += 4 dataPointer += 4
result.Frames[i].Height = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4]) result.Frames[i].Height = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
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 dataPointer += 4
result.Frames[i].OffsetY = BytesToInt32(data[dataPointer : dataPointer+4]) result.Frames[i].OffsetY = d2helper.BytesToInt32(data[dataPointer : dataPointer+4])
dataPointer += 4 dataPointer += 4
result.Frames[i].Unknown = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4]) result.Frames[i].Unknown = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
dataPointer += 4 dataPointer += 4
@ -143,7 +147,7 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite {
for d := 0; d < int(result.Directions); d++ { for d := 0; d < int(result.Directions); d++ {
curMaxWidth := 0 curMaxWidth := 0
for f := 0; f < int(result.FramesPerDirection); f++ { 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) totalHeight += int(result.Frames[frame].Height)
frame++ frame++
} }
@ -157,7 +161,7 @@ func CreateSprite(data []byte, palette PaletteRec) *Sprite {
for d := 0; d < int(result.Directions); d++ { for d := 0; d < int(result.Directions); d++ {
curMaxWidth := 0 curMaxWidth := 0
for f := 0; f < int(result.FramesPerDirection); f++ { 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) 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) curY += int(result.Frames[frame].Height)
frame++ frame++
@ -260,7 +264,7 @@ func (v *Sprite) Draw(target *ebiten.Image) {
opts.CompositeMode = ebiten.CompositeModeSourceOver opts.CompositeMode = ebiten.CompositeModeSourceOver
} }
if v.ColorMod != nil { if v.ColorMod != nil {
opts.ColorM = ColorToColorM(v.ColorMod) opts.ColorM = d2helper.ColorToColorM(v.ColorMod)
} }
target.DrawImage(frame.Image, opts) target.DrawImage(frame.Image, opts)
} }
@ -288,11 +292,11 @@ func (v *Sprite) DrawSegments(target *ebiten.Image, xSegments, ySegments, offset
opts.CompositeMode = ebiten.CompositeModeSourceOver opts.CompositeMode = ebiten.CompositeModeSourceOver
} }
if v.ColorMod != nil { if v.ColorMod != nil {
opts.ColorM = ColorToColorM(v.ColorMod) opts.ColorM = d2helper.ColorToColorM(v.ColorMod)
} }
target.DrawImage(frame.Image, opts) target.DrawImage(frame.Image, opts)
xOffset += int32(frame.Width) xOffset += int32(frame.Width)
biggestYOffset = MaxInt32(biggestYOffset, int32(frame.Height)) biggestYOffset = d2helper.MaxInt32(biggestYOffset, int32(frame.Height))
} }
yOffset += biggestYOffset yOffset += biggestYOffset
} }

View File

@ -1,30 +1,36 @@
package _map package mapengine
import ( import (
"math" "math"
"math/rand" "math/rand"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/sound"
"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" "github.com/hajimehoshi/ebiten"
) )
type EngineRegion struct { type EngineRegion struct {
Rect common.Rectangle Rect d2common.Rectangle
Region *Region Region *Region
} }
type Engine struct { type Engine struct {
soundManager *sound.Manager soundManager *d2audio.Manager
gameState *common.GameState gameState *d2core.GameState
fileProvider common.FileProvider fileProvider d2interface.FileProvider
regions []EngineRegion regions []EngineRegion
OffsetX float64 OffsetX float64
OffsetY 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{ result := &Engine{
gameState: gameState, gameState: gameState,
soundManager: soundManager, soundManager: soundManager,
@ -38,7 +44,7 @@ func (v *Engine) GenerateMap(regionType RegionIdType, levelPreset int) {
randomSource := rand.NewSource(v.gameState.Seed) randomSource := rand.NewSource(v.gameState.Seed)
region := LoadRegion(randomSource, regionType, levelPreset, v.fileProvider) region := LoadRegion(randomSource, regionType, levelPreset, v.fileProvider)
v.regions = append(v.regions, EngineRegion{ 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, Region: region,
}) })
} }
@ -48,24 +54,24 @@ func (v *Engine) GenerateAct1Overworld() {
randomSource := rand.NewSource(v.gameState.Seed) randomSource := rand.NewSource(v.gameState.Seed)
region := LoadRegion(randomSource, RegionAct1Town, 1, v.fileProvider) region := LoadRegion(randomSource, RegionAct1Town, 1, v.fileProvider)
v.regions = append(v.regions, EngineRegion{ 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, Region: region,
}) })
if strings.Contains(region.RegionPath, "E1") { if strings.Contains(region.RegionPath, "E1") {
region2 := LoadRegion(randomSource, RegionAct1Town, 2, v.fileProvider) region2 := LoadRegion(randomSource, RegionAct1Town, 2, v.fileProvider)
v.regions = append(v.regions, EngineRegion{ 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, Region: region2,
}) })
} else if strings.Contains(region.RegionPath, "S1") { } else if strings.Contains(region.RegionPath, "S1") {
region2 := LoadRegion(randomSource, RegionAct1Town, 3, v.fileProvider) region2 := LoadRegion(randomSource, RegionAct1Town, 3, v.fileProvider)
v.regions = append(v.regions, EngineRegion{ 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, 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.OffsetX = float64(sx) - 400
v.OffsetY = float64(sy) - 300 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) offX := -((y + region.Rect.Top) * 80) + (region.Rect.Left * 80)
offY := ((y + region.Rect.Top) * 40) + (region.Rect.Left * 40) offY := ((y + region.Rect.Top) * 40) + (region.Rect.Left * 40)
for x := 0; x < int(region.Region.TileWidth); x++ { 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 { if sx > -160 && sy > -160 && sx <= 880 && sy <= 1000 {
v.RenderTile(region.Region, offX, offY, x, y, target) v.RenderTile(region.Region, offX, offY, x, y, target)
} }

View File

@ -1,4 +1,4 @@
package _map package mapengine
import ( import (
"image/color" "image/color"
@ -8,11 +8,19 @@ import (
"strconv" "strconv"
"sync" "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/hajimehoshi/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/common"
) )
type TileCacheRecord struct { type TileCacheRecord struct {
@ -23,18 +31,18 @@ type TileCacheRecord struct {
type Region struct { type Region struct {
RegionPath string RegionPath string
LevelType common.LevelTypeRecord LevelType datadict.LevelTypeRecord
levelPreset *common.LevelPresetRecord levelPreset *datadict.LevelPresetRecord
TileWidth int32 TileWidth int32
TileHeight int32 TileHeight int32
Tiles []Tile Tiles []d2data.Tile
DS1 *DS1 DS1 *d2data.DS1
Palette common.PaletteRec Palette datadict.PaletteRec
FloorCache map[uint32]*TileCacheRecord FloorCache map[uint32]*TileCacheRecord
ShadowCache map[uint32]*TileCacheRecord ShadowCache map[uint32]*TileCacheRecord
WallCache map[uint32]*TileCacheRecord WallCache map[uint32]*TileCacheRecord
AnimationEntities []*common.AnimatedEntity AnimationEntities []*d2render.AnimatedEntity
NPCs []*common.NPC NPCs []*d2render.NPC
StartX float64 StartX float64
StartY float64 StartY float64
} }
@ -87,16 +95,16 @@ const (
RegionAct5Lava RegionIdType = 35 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{ result := &Region{
LevelType: common.LevelTypes[levelType], LevelType: datadict.LevelTypes[levelType],
levelPreset: common.LevelPresets[levelPreset], levelPreset: datadict.LevelPresets[levelPreset],
Tiles: make([]Tile, 0), Tiles: make([]d2data.Tile, 0),
FloorCache: make(map[uint32]*TileCacheRecord), FloorCache: make(map[uint32]*TileCacheRecord),
ShadowCache: make(map[uint32]*TileCacheRecord), ShadowCache: make(map[uint32]*TileCacheRecord),
WallCache: 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 //\bm := result.levelPreset.Dt1Mask
for _, levelTypeDt1 := range result.LevelType.Files { 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" { if len(levelTypeDt1) == 0 || levelTypeDt1 == "" || levelTypeDt1 == "0" {
continue continue
} }
dt1 := LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider) dt1 := d2data.LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider)
result.Tiles = append(result.Tiles, dt1.Tiles...) result.Tiles = append(result.Tiles, dt1.Tiles...)
} }
levelFilesToPick := make([]string, 0) 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())) levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * random.Float64()))
levelFile := levelFilesToPick[levelIndex] levelFile := levelFilesToPick[levelIndex]
result.RegionPath = levelFile 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.TileWidth = result.DS1.Width
result.TileHeight = result.DS1.Height result.TileHeight = result.DS1.Height
result.loadObjects(fileProvider) result.loadObjects(fileProvider)
return result return result
} }
func (v *Region) loadObjects(fileProvider common.FileProvider) { func (v *Region) loadObjects(fileProvider d2interface.FileProvider) {
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(len(v.DS1.Objects)) wg.Add(len(v.DS1.Objects))
v.AnimationEntities = make([]*common.AnimatedEntity, 0) v.AnimationEntities = make([]*d2render.AnimatedEntity, 0)
v.NPCs = make([]*common.NPC, 0) v.NPCs = make([]*d2render.NPC, 0)
for _, object := range v.DS1.Objects { for _, object := range v.DS1.Objects {
go func(object common.Object) { go func(object d2data.Object) {
defer wg.Done() defer wg.Done()
switch object.Lookup.Type { switch object.Lookup.Type {
case common.ObjectTypeCharacter: case datadict.ObjectTypeCharacter:
// Temp code, maybe.. // Temp code, maybe..
if object.Lookup.Base == "" || object.Lookup.Token == "" || object.Lookup.TR == "" { if object.Lookup.Base == "" || object.Lookup.Token == "" || object.Lookup.TR == "" {
return return
} }
npc := common.CreateNPC(object, fileProvider) npc := d2render.CreateNPC(object, fileProvider)
v.NPCs = append(v.NPCs, npc) 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 == "" { if object.ObjectInfo == nil || !object.ObjectInfo.Draw || object.Lookup.Base == "" || object.Lookup.Token == "" {
return 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) entity.SetMode(object.Lookup.Mode, object.Lookup.Class, 0, fileProvider)
v.AnimationEntities = append(v.AnimationEntities, entity) 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 // 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 { for _, tile := range v.Tiles {
if tile.MainIndex != mainIndex || tile.SubIndex != subIndex || tile.Orientation != orientation { 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 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) tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8)
tileCache, exists := v.FloorCache[tileCacheIndex] tileCache, exists := v.FloorCache[tileCacheIndex]
if !exists { if !exists {
@ -198,7 +206,7 @@ func (v *Region) renderFloor(tile FloorShadowRecord, offsetX, offsetY int, targe
target.DrawImage(tileCache.Image, opts) 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)) tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8) | (uint32(tile.Orientation))
tileCache, exists := v.WallCache[tileCacheIndex] tileCache, exists := v.WallCache[tileCacheIndex]
if !exists { if !exists {
@ -213,7 +221,7 @@ func (v *Region) renderWall(tile WallRecord, offsetX, offsetY int, target *ebite
target.DrawImage(tileCache.Image, opts) 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 tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + 0
tileCache, exists := v.ShadowCache[tileCacheIndex] tileCache, exists := v.ShadowCache[tileCacheIndex]
if !exists { if !exists {
@ -225,13 +233,13 @@ func (v *Region) renderShadow(tile FloorShadowRecord, offsetX, offsetY int, targ
} }
opts := &ebiten.DrawImageOptions{} opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset)) 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) 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 { for _, block := range blocks {
if block.Format == BlockFormatIsometric { if block.Format == d2data.BlockFormatIsometric {
// 3D isometric decoding // 3D isometric decoding
xjump := []int32{14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14} 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} 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) tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 0)
if tileData == nil { if tileData == nil {
log.Fatalf("Could not locate tile Idx:%d, Sub: %d, Ori: %d", tile.MainIndex, tile.SubIndex, 0) log.Fatalf("Could not locate tile Idx:%d, Sub: %d, Ori: %d", tile.MainIndex, tile.SubIndex, 0)
} }
tileYMinimum := int32(0) tileYMinimum := int32(0)
for _, block := range tileData.Blocks { for _, block := range tileData.Blocks {
tileYMinimum = common.MinInt32(tileYMinimum, int32(block.Y)) tileYMinimum = d2helper.MinInt32(tileYMinimum, int32(block.Y))
} }
tileYOffset := common.AbsInt32(tileYMinimum) tileYOffset := d2helper.AbsInt32(tileYMinimum)
tileHeight := common.AbsInt32(tileData.Height) tileHeight := d2helper.AbsInt32(tileData.Height)
image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest) image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest)
pixels := make([]byte, 4*tileData.Width*tileHeight) pixels := make([]byte, 4*tileData.Width*tileHeight)
v.decodeTileGfxData(tileData.Blocks, pixels, tileYOffset, tileData.Width) v.decodeTileGfxData(tileData.Blocks, pixels, tileYOffset, tileData.Width)
@ -319,7 +327,7 @@ func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord {
return &TileCacheRecord{image, 0, 0} 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) tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 13)
if tileData == nil { if tileData == nil {
return nil return nil
@ -327,8 +335,8 @@ func (v *Region) generateShadowCache(tile FloorShadowRecord) *TileCacheRecord {
tileMinY := int32(0) tileMinY := int32(0)
tileMaxY := int32(0) tileMaxY := int32(0)
for _, block := range tileData.Blocks { for _, block := range tileData.Blocks {
tileMinY = common.MinInt32(tileMinY, int32(block.Y)) tileMinY = d2helper.MinInt32(tileMinY, int32(block.Y))
tileMaxY = common.MaxInt32(tileMaxY, int32(block.Y+32)) tileMaxY = d2helper.MaxInt32(tileMaxY, int32(block.Y+32))
} }
tileYOffset := -tileMinY tileYOffset := -tileMinY
tileHeight := int(tileMaxY - tileMinY) tileHeight := int(tileMaxY - tileMinY)
@ -339,12 +347,12 @@ func (v *Region) generateShadowCache(tile FloorShadowRecord) *TileCacheRecord {
return &TileCacheRecord{image, 0, int(tileMinY) + 80} 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)) tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(tile.Orientation))
if tileData == nil { if tileData == nil {
return nil return nil
} }
var newTileData *Tile = nil var newTileData *d2data.Tile = nil
if tile.Orientation == 3 { if tile.Orientation == 3 {
newTileData = v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(4)) newTileData = v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(4))
} }
@ -356,10 +364,10 @@ func (v *Region) generateWallCache(tile WallRecord) *TileCacheRecord {
target = newTileData target = newTileData
} }
for _, block := range target.Blocks { for _, block := range target.Blocks {
tileMinY = common.MinInt32(tileMinY, int32(block.Y)) tileMinY = d2helper.MinInt32(tileMinY, int32(block.Y))
tileMaxY = common.MaxInt32(tileMaxY, int32(block.Y+32)) 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 tileYOffset := -tileMinY
//tileHeight := int(tileMaxY - tileMinY) //tileHeight := int(tileMaxY - tileMinY)
image, _ := ebiten.NewImage(160, int(realHeight), ebiten.FilterNearest) image, _ := ebiten.NewImage(160, int(realHeight), ebiten.FilterNearest)

View File

@ -4,9 +4,16 @@ import (
"image" "image"
"image/color" "image/color"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/palettedefs"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "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" "github.com/hajimehoshi/ebiten"
) )
@ -40,25 +47,25 @@ const (
// ButtonLayout defines the type of buttons // ButtonLayout defines the type of buttons
type ButtonLayout struct { type ButtonLayout struct {
XSegments int //1 XSegments int //1
YSegments int // 1 YSegments int // 1
ResourceName string // Font Name ResourceName string // Font Name
PaletteName palettedefs.PaletteType // PaletteType PaletteName d2enum.PaletteType // PaletteType
Toggleable bool // false Toggleable bool // false
BaseFrame int // 0 BaseFrame int // 0
DisabledFrame int // -1 DisabledFrame int // -1
FontPath string // ResourcePaths.FontExocet10 FontPath string // ResourcePaths.FontExocet10
ClickableRect *image.Rectangle // nil ClickableRect *image.Rectangle // nil
AllowFrameChange bool // true AllowFrameChange bool // true
TextOffset int // 0 TextOffset int // 0
} }
// ButtonLayouts define the type of buttons you can have // ButtonLayouts define the type of buttons you can have
var ButtonLayouts = map[ButtonType]ButtonLayout{ var ButtonLayouts = map[ButtonType]ButtonLayout{
ButtonTypeWide: {2, 1, resourcepaths.WideButtonBlank, palettedefs.Units, false, 0, -1, resourcepaths.FontExocet10, nil, true, 1}, ButtonTypeWide: {2, 1, d2common.WideButtonBlank, d2enum.Units, false, 0, -1, d2common.FontExocet10, nil, true, 1},
ButtonTypeShort: {1, 1, resourcepaths.ShortButtonBlank, palettedefs.Units, false, 0, -1, resourcepaths.FontRediculous, nil, true, -1}, ButtonTypeShort: {1, 1, d2common.ShortButtonBlank, d2enum.Units, false, 0, -1, d2common.FontRediculous, nil, true, -1},
ButtonTypeMedium: {1, 1, resourcepaths.MediumButtonBlank, palettedefs.Units, false, 0, 0, resourcepaths.FontExocet10, nil, true, 0}, ButtonTypeMedium: {1, 1, d2common.MediumButtonBlank, d2enum.Units, false, 0, 0, d2common.FontExocet10, nil, true, 0},
ButtonTypeTall: {1, 1, resourcepaths.TallButtonBlank, palettedefs.Units, false, 0, 0, resourcepaths.FontExocet10, nil, true, 5}, 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.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = PaletteDefs.Units } },
{eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = PaletteDefs.Units } }, {eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = PaletteDefs.Units } },
@ -89,7 +96,7 @@ type Button struct {
visible bool visible bool
pressed bool pressed bool
toggled bool toggled bool
fileProvider common.FileProvider fileProvider d2interface.FileProvider
normalImage *ebiten.Image normalImage *ebiten.Image
pressedImage *ebiten.Image pressedImage *ebiten.Image
toggledImage *ebiten.Image toggledImage *ebiten.Image
@ -100,7 +107,7 @@ type Button struct {
} }
// CreateButton creates an instance of Button // 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{ result := &Button{
fileProvider: fileProvider, fileProvider: fileProvider,
width: 0, width: 0,
@ -111,8 +118,9 @@ func CreateButton(buttonType ButtonType, fileProvider common.FileProvider, text
} }
buttonLayout := ButtonLayouts[buttonType] buttonLayout := ButtonLayouts[buttonType]
result.buttonLayout = buttonLayout result.buttonLayout = buttonLayout
font := GetFont(buttonLayout.FontPath, palettedefs.Units, fileProvider) font := GetFont(buttonLayout.FontPath, d2enum.Units, fileProvider)
buttonSprite := fileProvider.LoadSprite(buttonLayout.ResourceName, buttonLayout.PaletteName)
buttonSprite := d2render.CreateSprite(fileProvider.LoadFile(buttonLayout.ResourceName), datadict.Palettes[buttonLayout.PaletteName])
totalButtonTypes := buttonSprite.GetTotalFrames() / (buttonLayout.XSegments * buttonLayout.YSegments) totalButtonTypes := buttonSprite.GetTotalFrames() / (buttonLayout.XSegments * buttonLayout.YSegments)
for i := 0; i < buttonLayout.XSegments; i++ { for i := 0; i < buttonLayout.XSegments; i++ {
w, _ := buttonSprite.GetFrameSize(i) w, _ := buttonSprite.GetFrameSize(i)
@ -179,7 +187,7 @@ func (v *Button) Draw(target *ebiten.Image) {
if !v.enabled { if !v.enabled {
//opts.CompositeMode = ebiten.CompositeModeLighter //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) target.DrawImage(v.disabledImage, opts)
} else if v.toggled && v.pressed { } else if v.toggled && v.pressed {
target.DrawImage(v.pressedToggledImage, opts) target.DrawImage(v.pressedToggledImage, opts)

View File

@ -4,8 +4,16 @@ import (
"image/color" "image/color"
"strings" "strings"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/palettedefs"
"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" "github.com/hajimehoshi/ebiten"
) )
@ -19,12 +27,12 @@ type FontSize struct {
// Font represents a font // Font represents a font
type Font struct { type Font struct {
fontSprite *common.Sprite fontSprite *d2render.Sprite
metrics map[uint8]FontSize metrics map[uint8]FontSize
} }
// GetFont creates or loads an existing font // 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)] cacheItem, exists := fontCache[font+"_"+string(palette)]
if exists { if exists {
return cacheItem return cacheItem
@ -35,11 +43,11 @@ func GetFont(font string, palette palettedefs.PaletteType, fileProvider common.F
} }
// CreateFont creates an instance of a MPQ Font // 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{ result := &Font{
metrics: make(map[uint8]FontSize), 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" woo := "Woo!\x01"
fontData := fileProvider.LoadFile(font + ".tbl") fontData := fileProvider.LoadFile(font + ".tbl")
if string(fontData[0:5]) != woo { if string(fontData[0:5]) != woo {
@ -62,12 +70,12 @@ func (v *Font) GetTextMetrics(text string) (width, height uint32) {
height = uint32(0) height = uint32(0)
maxCharHeight := uint32(0) maxCharHeight := uint32(0)
for _, m := range v.fontSprite.Frames { 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++ { for i := 0; i < len(text); i++ {
ch := text[i] ch := text[i]
if ch == '\n' { if ch == '\n' {
width = common.Max(width, curWidth) width = d2helper.Max(width, curWidth)
curWidth = 0 curWidth = 0
height += maxCharHeight + 6 height += maxCharHeight + 6
continue continue
@ -75,7 +83,7 @@ func (v *Font) GetTextMetrics(text string) (width, height uint32) {
metric := v.metrics[uint8(ch)] metric := v.metrics[uint8(ch)]
curWidth += uint32(metric.Width) curWidth += uint32(metric.Width)
} }
width = common.Max(width, curWidth) width = d2helper.Max(width, curWidth)
height += maxCharHeight height += maxCharHeight
return return
} }
@ -87,7 +95,7 @@ func (v *Font) Draw(x, y int, text string, color color.Color, target *ebiten.Ima
maxCharHeight := uint32(0) maxCharHeight := uint32(0)
for _, m := range v.metrics { for _, m := range v.metrics {
maxCharHeight = common.Max(maxCharHeight, uint32(m.Height)) maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height))
} }
targetWidth, _ := target.Size() targetWidth, _ := target.Size()

View File

@ -3,8 +3,10 @@ package ui
import ( import (
"image/color" "image/color"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/palettedefs"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
) )
@ -34,7 +36,7 @@ type Label struct {
} }
// CreateLabel creates a new instance of a UI label // 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{ result := &Label{
Alignment: LabelAlignLeft, Alignment: LabelAlignLeft,
Color: color.White, Color: color.White,

View File

@ -1,10 +1,12 @@
package ui package ui
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/palettedefs" "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/resourcepaths" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/sound" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2data/datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
) )
@ -21,22 +23,22 @@ const (
// Manager represents the UI manager // Manager represents the UI manager
type Manager struct { type Manager struct {
widgets []Widget widgets []Widget
cursorSprite *common.Sprite cursorSprite *d2render.Sprite
cursorButtons CursorButton cursorButtons CursorButton
pressedIndex int pressedIndex int
CursorX int CursorX int
CursorY int CursorY int
clickSfx *sound.SoundEffect clickSfx *d2audio.SoundEffect
waitForLeftMouseUp bool waitForLeftMouseUp bool
} }
// CreateManager creates a new instance of a UI manager // 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{ result := &Manager{
pressedIndex: -1, pressedIndex: -1,
widgets: make([]Widget, 0), widgets: make([]Widget, 0),
cursorSprite: fileProvider.LoadSprite(resourcepaths.CursorDefault, palettedefs.Units), cursorSprite: d2render.CreateSprite(fileProvider.LoadFile(d2common.CursorDefault), datadict.Palettes[d2enum.Units]),
clickSfx: soundManager.LoadSoundEffect(resourcepaths.SFXButtonClick), clickSfx: soundManager.LoadSoundEffect(d2common.SFXButtonClick),
waitForLeftMouseUp: false, waitForLeftMouseUp: false,
} }
return result return result

View File

@ -1,12 +1,12 @@
package ui package ui
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
// Widget defines an object that is a UI widget // Widget defines an object that is a UI widget
type Widget interface { type Widget interface {
common.Drawable d2interface.Drawable
GetEnabled() bool GetEnabled() bool
SetEnabled(enabled bool) SetEnabled(enabled bool)
SetPressed(pressed bool) SetPressed(pressed bool)

3
go.mod
View File

@ -11,11 +11,12 @@ require (
github.com/gopherjs/gopherwasm v1.1.0 // indirect github.com/gopherjs/gopherwasm v1.1.0 // indirect
github.com/hajimehoshi/ebiten v1.10.1-0.20191108205544-35436ea50457 github.com/hajimehoshi/ebiten v1.10.1-0.20191108205544-35436ea50457
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect 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/mitchellh/go-homedir v1.1.0
github.com/pkg/profile v1.3.0 github.com/pkg/profile v1.3.0
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect
golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect
golang.org/x/mobile v0.0.0-20191031020345-0945064e013a // indirect golang.org/x/mobile v0.0.0-20191031020345-0945064e013a // indirect
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd // 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
) )

5
go.sum
View File

@ -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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 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/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 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 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= 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-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 h1:QFO0Wgcqcp8nI9hbisKDTBsmfwrvLswk2T73QDZZgVo=
golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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 h1:akkRBeitX2EZP59KdtKw310CI4WGPCNPyrLbE7WZA8Y=
golang.org/x/tools v0.0.0-20191107010934-f79515f33823/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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= 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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

16
main.go
View File

@ -4,12 +4,14 @@ import (
"image" "image"
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/scenes"
"github.com/hajimehoshi/ebiten/ebitenutil" "github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/OpenDiablo2/OpenDiablo2/common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/core" "github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/OpenDiablo2/mpq" "github.com/OpenDiablo2/OpenDiablo2/d2data/mpq"
"github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten"
) )
@ -18,16 +20,17 @@ var GitBranch string
// GitCommit is set by the CI build process to the commit hash // GitCommit is set by the CI build process to the commit hash
var GitCommit string var GitCommit string
var d2Engine *core.Engine var d2Engine *d2core.Engine
func main() { func main() {
//defer profile.Start(profile.CPUProfile).Stop()
//runtime.LockOSThread() //runtime.LockOSThread()
//defer runtime.UnlockOSThread() //defer runtime.UnlockOSThread()
if len(GitBranch) == 0 { if len(GitBranch) == 0 {
GitBranch = "Local Build" GitBranch = "Local Build"
GitCommit = "" GitCommit = ""
} }
common.SetBuildInfo(GitBranch, GitCommit) d2common.SetBuildInfo(GitBranch, GitCommit)
log.SetFlags(log.Ldate | log.LUTC | log.Lmicroseconds | log.Llongfile) log.SetFlags(log.Ldate | log.LUTC | log.Lmicroseconds | log.Llongfile)
log.Println("OpenDiablo2 - Open source Diablo 2 engine") log.Println("OpenDiablo2 - Open source Diablo 2 engine")
_, iconImage, err := ebitenutil.NewImageFromFile("d2logo.png", ebiten.FilterLinear) _, iconImage, err := ebitenutil.NewImageFromFile("d2logo.png", ebiten.FilterLinear)
@ -35,7 +38,8 @@ func main() {
ebiten.SetWindowIcon([]image.Image{iconImage}) ebiten.SetWindowIcon([]image.Image{iconImage})
} }
mpq.InitializeCryptoBuffer() mpq.InitializeCryptoBuffer()
d2Engine = core.CreateEngine() d2Engine = d2core.CreateEngine()
d2Engine.SetNextScene(scenes.CreateMainMenu(d2Engine, d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
ebiten.SetCursorVisible(false) ebiten.SetCursorVisible(false)
ebiten.SetFullscreen(d2Engine.Settings.FullScreen) ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
ebiten.SetRunnableInBackground(d2Engine.Settings.RunInBackground) ebiten.SetRunnableInBackground(d2Engine.Settings.RunInBackground)

View File

@ -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("")
}
}

View File

@ -6,19 +6,21 @@ import (
"strings" "strings"
"testing" "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) { func TestMPQScanPerformance(t *testing.T) {
log.SetFlags(log.Ldate | log.LUTC | log.Lmicroseconds | log.Llongfile) log.SetFlags(log.Ldate | log.LUTC | log.Lmicroseconds | log.Llongfile)
mpq.InitializeCryptoBuffer() mpq.InitializeCryptoBuffer()
common.ConfigBasePath = "../" d2common.ConfigBasePath = "../"
config := common.LoadConfiguration() config := d2common.LoadConfiguration()
engine := core.CreateEngine() engine := d2core.CreateEngine()
for _, fileName := range config.MpqLoadOrder { for _, fileName := range config.MpqLoadOrder {
mpqFile := path.Join(config.MpqPath, fileName) mpqFile := path.Join(config.MpqPath, fileName)
archive, _ := mpq.Load(mpqFile) archive, _ := mpq.Load(mpqFile)
@ -34,12 +36,12 @@ func TestMPQScanPerformance(t *testing.T) {
parts := strings.Split(archiveFile, ".") parts := strings.Split(archiveFile, ".")
switch strings.ToLower(parts[len(parts)-1]) { switch strings.ToLower(parts[len(parts)-1]) {
case "coff": case "coff":
_ = common.LoadCof(archiveFile, engine) _ = d2data.LoadCof(archiveFile, engine)
case "dcc": case "dcc":
if strings.ContainsAny(archiveFile, "common") { if strings.ContainsAny(archiveFile, "common") {
continue continue
} }
_ = common.LoadDCC(archiveFile, engine) _ = d2data.LoadDCC(archiveFile, engine)
} }
_, _ = archive.ReadFile(archiveFile) _, _ = archive.ReadFile(archiveFile)

View File

@ -5,19 +5,19 @@ import (
"github.com/hajimehoshi/ebiten" "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/d2common"
"github.com/OpenDiablo2/OpenDiablo2/core" "github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/OpenDiablo2/mpq" "github.com/OpenDiablo2/OpenDiablo2/d2data/mpq"
) )
func TestMapGenerationPerformance(t *testing.T) { func TestMapGenerationPerformance(t *testing.T) {
mpq.InitializeCryptoBuffer() mpq.InitializeCryptoBuffer()
common.ConfigBasePath = "../" d2common.ConfigBasePath = "../"
engine := core.CreateEngine() engine := d2core.CreateEngine()
gameState := common.CreateGameState() gameState := d2core.CreateGameState()
mapEngine := _map.CreateMapEngine(gameState, engine.SoundManager, engine) mapEngine := _map.CreateMapEngine(gameState, engine.SoundManager, engine)
mapEngine.GenerateAct1Overworld() mapEngine.GenerateAct1Overworld()
surface, _ := ebiten.NewImage(800, 600, ebiten.FilterNearest) surface, _ := ebiten.NewImage(800, 600, ebiten.FilterNearest)