mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-20 07:27:19 -05:00
More optimizations and cleanup. (#131)
This commit is contained in:
parent
f2b1bdfba4
commit
e8292e9c42
@ -20,8 +20,8 @@ func LoadDataDictionary(text string) *DataDictionary {
|
||||
for i, fieldName := range fileNames {
|
||||
result.FieldNameLookup[fieldName] = i
|
||||
}
|
||||
result.Data = make([][]string, 0)
|
||||
for _, line := range lines[1:] {
|
||||
result.Data = make([][]string, len(lines)-1)
|
||||
for i, line := range lines[1:] {
|
||||
if len(strings.TrimSpace(line)) == 0 {
|
||||
continue
|
||||
}
|
||||
@ -29,7 +29,7 @@ func LoadDataDictionary(text string) *DataDictionary {
|
||||
if len(values) != len(result.FieldNameLookup) {
|
||||
continue
|
||||
}
|
||||
result.Data = append(result.Data, values)
|
||||
result.Data[i] = values
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
18
d2common/d2enum/LayerStreamType.go
Normal file
18
d2common/d2enum/LayerStreamType.go
Normal file
@ -0,0 +1,18 @@
|
||||
package d2enum
|
||||
|
||||
type LayerStreamType int
|
||||
|
||||
const (
|
||||
LayerStreamWall1 LayerStreamType = 0
|
||||
LayerStreamWall2 LayerStreamType = 1
|
||||
LayerStreamWall3 LayerStreamType = 2
|
||||
LayerStreamWall4 LayerStreamType = 3
|
||||
LayerStreamOrientation1 LayerStreamType = 4
|
||||
LayerStreamOrientation2 LayerStreamType = 5
|
||||
LayerStreamOrientation3 LayerStreamType = 6
|
||||
LayerStreamOrientation4 LayerStreamType = 7
|
||||
LayerStreamFloor1 LayerStreamType = 8
|
||||
LayerStreamFloor2 LayerStreamType = 9
|
||||
LayerStreamShadow LayerStreamType = 10
|
||||
LayerStreamSubstitute LayerStreamType = 11
|
||||
)
|
@ -41,7 +41,7 @@ type Engine struct {
|
||||
Settings *d2common.Configuration // Engine configuration settings from json file
|
||||
Files map[string]string // Map that defines which files are in which MPQs
|
||||
CheckedPatch map[string]bool // First time we check a file, we'll check if it's in the patch. This notes that we've already checked that.
|
||||
LoadingSprite *d2render.Sprite // The sprite shown when loading stuff
|
||||
LoadingSprite d2render.Sprite // The sprite shown when loading stuff
|
||||
loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays.
|
||||
loadingIndex int // Determines which load function is currently being called
|
||||
thingsToLoad []func() // The load functions for the next scene
|
||||
@ -56,31 +56,31 @@ type Engine struct {
|
||||
}
|
||||
|
||||
// CreateEngine creates and instance of the OpenDiablo2 engine
|
||||
func CreateEngine() *Engine {
|
||||
result := &Engine{
|
||||
func CreateEngine() Engine {
|
||||
result := Engine{
|
||||
CurrentScene: nil,
|
||||
nextScene: nil,
|
||||
}
|
||||
result.loadConfigurationFile()
|
||||
d2resource.LanguageCode = result.Settings.Language
|
||||
result.mapMpqFiles()
|
||||
d2datadict.LoadPalettes(result.Files, result)
|
||||
d2common.LoadTextDictionary(result)
|
||||
d2datadict.LoadLevelTypes(result)
|
||||
d2datadict.LoadLevelPresets(result)
|
||||
d2datadict.LoadLevelWarps(result)
|
||||
d2datadict.LoadObjectTypes(result)
|
||||
d2datadict.LoadObjects(result)
|
||||
d2datadict.LoadWeapons(result)
|
||||
d2datadict.LoadArmors(result)
|
||||
d2datadict.LoadUniqueItems(result)
|
||||
d2datadict.LoadMissiles(result)
|
||||
d2datadict.LoadSounds(result)
|
||||
d2data.LoadAnimationData(result)
|
||||
d2datadict.LoadMonStats(result)
|
||||
result.SoundManager = d2audio.CreateManager(result)
|
||||
d2datadict.LoadPalettes(result.Files, &result)
|
||||
d2common.LoadTextDictionary(&result)
|
||||
d2datadict.LoadLevelTypes(&result)
|
||||
d2datadict.LoadLevelPresets(&result)
|
||||
d2datadict.LoadLevelWarps(&result)
|
||||
d2datadict.LoadObjectTypes(&result)
|
||||
d2datadict.LoadObjects(&result)
|
||||
d2datadict.LoadWeapons(&result)
|
||||
d2datadict.LoadArmors(&result)
|
||||
d2datadict.LoadUniqueItems(&result)
|
||||
d2datadict.LoadMissiles(&result)
|
||||
d2datadict.LoadSounds(&result)
|
||||
d2data.LoadAnimationData(&result)
|
||||
d2datadict.LoadMonStats(&result)
|
||||
result.SoundManager = d2audio.CreateManager(&result)
|
||||
result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume)
|
||||
result.UIManager = d2ui.CreateManager(result, *result.SoundManager)
|
||||
result.UIManager = d2ui.CreateManager(&result, *result.SoundManager)
|
||||
result.LoadingSprite = result.LoadSprite(d2resource.LoadingScreen, d2enum.Loading)
|
||||
loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetSize()
|
||||
result.LoadingSprite.MoveTo(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2)))
|
||||
@ -135,12 +135,12 @@ func (v *Engine) LoadFile(fileName string) []byte {
|
||||
}
|
||||
|
||||
// IsLoading returns true if the engine is currently in a loading state
|
||||
func (v *Engine) IsLoading() bool {
|
||||
func (v Engine) IsLoading() bool {
|
||||
return v.loadingProgress < 1.0
|
||||
}
|
||||
|
||||
// LoadSprite loads a sprite from the game's data files
|
||||
func (v *Engine) LoadSprite(fileName string, palette d2enum.PaletteType) *d2render.Sprite {
|
||||
func (v Engine) LoadSprite(fileName string, palette d2enum.PaletteType) d2render.Sprite {
|
||||
data := v.LoadFile(fileName)
|
||||
sprite := d2render.CreateSprite(data, d2datadict.Palettes[palette])
|
||||
return sprite
|
||||
@ -215,7 +215,7 @@ func (v *Engine) Update() {
|
||||
}
|
||||
|
||||
// Draw draws the game
|
||||
func (v *Engine) Draw(screen *ebiten.Image) {
|
||||
func (v Engine) Draw(screen *ebiten.Image) {
|
||||
if v.loadingProgress < 1.0 {
|
||||
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)
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
type NPC struct {
|
||||
AnimatedEntity *d2render.AnimatedEntity
|
||||
AnimatedEntity d2render.AnimatedEntity
|
||||
Paths []d2common.Path
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ type CharacterSelect struct {
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2interface.SceneProvider
|
||||
background *d2render.Sprite
|
||||
background d2render.Sprite
|
||||
newCharButton *d2ui.Button
|
||||
convertCharButton *d2ui.Button
|
||||
deleteCharButton *d2ui.Button
|
||||
|
@ -33,7 +33,7 @@ type Credits struct {
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2interface.SceneProvider
|
||||
creditsBackground *d2render.Sprite
|
||||
creditsBackground d2render.Sprite
|
||||
exitButton *d2ui.Button
|
||||
creditsText []string
|
||||
labels []*labelItem
|
||||
|
@ -31,12 +31,12 @@ type MainMenu struct {
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2interface.SceneProvider
|
||||
trademarkBackground *d2render.Sprite
|
||||
background *d2render.Sprite
|
||||
diabloLogoLeft *d2render.Sprite
|
||||
diabloLogoRight *d2render.Sprite
|
||||
diabloLogoLeftBack *d2render.Sprite
|
||||
diabloLogoRightBack *d2render.Sprite
|
||||
trademarkBackground d2render.Sprite
|
||||
background d2render.Sprite
|
||||
diabloLogoLeft d2render.Sprite
|
||||
diabloLogoRight d2render.Sprite
|
||||
diabloLogoLeftBack d2render.Sprite
|
||||
diabloLogoRightBack d2render.Sprite
|
||||
singlePlayerButton *d2ui.Button
|
||||
githubButton *d2ui.Button
|
||||
exitDiabloButton *d2ui.Button
|
||||
|
@ -21,14 +21,14 @@ import (
|
||||
|
||||
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
|
||||
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
|
||||
@ -39,8 +39,8 @@ type SelectHeroClass struct {
|
||||
soundManager *d2audio.Manager
|
||||
fileProvider d2interface.FileProvider
|
||||
sceneProvider d2interface.SceneProvider
|
||||
bgImage *d2render.Sprite
|
||||
campfire *d2render.Sprite
|
||||
bgImage d2render.Sprite
|
||||
campfire d2render.Sprite
|
||||
headingLabel *d2ui.Label
|
||||
heroClassLabel *d2ui.Label
|
||||
heroDesc1Label *d2ui.Label
|
||||
@ -67,7 +67,7 @@ func CreateSelectHeroClass(
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *SelectHeroClass) loadSprite(path string, palette d2enum.PaletteType) *d2render.Sprite {
|
||||
func (v *SelectHeroClass) loadSprite(path string, palette d2enum.PaletteType) d2render.Sprite {
|
||||
return d2render.CreateSprite(v.fileProvider.LoadFile(path), d2datadict.Palettes[palette])
|
||||
}
|
||||
|
||||
@ -125,9 +125,9 @@ func (v *SelectHeroClass) Load() []func() {
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianForwardWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianForwardWalkOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianSelected, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectBarbarianBackWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
image.Rectangle{Min: image.Point{364, 201}, Max: image.Point{90, 170}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXBarbarianDeselect),
|
||||
@ -245,9 +245,9 @@ func (v *SelectHeroClass) Load() []func() {
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinForwardWalk, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinForwardWalkOverlay, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinSelected, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelecPaladinBackWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
image.Rectangle{Min: image.Point{490, 210}, Max: image.Point{65, 180}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXPaladinDeselect),
|
||||
@ -277,11 +277,11 @@ func (v *SelectHeroClass) Load() []func() {
|
||||
v.loadSprite(d2resource.CharacterSelectAmazonUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectAmazonUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelecAmazonForwardWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelecAmazonSelected, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelecAmazonBackWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
image.Rectangle{Min: image.Point{70, 220}, Max: image.Point{55, 200}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAmazonDeselect),
|
||||
@ -307,11 +307,11 @@ func (v *SelectHeroClass) Load() []func() {
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinForwardWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinSelected, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectAssassinBackWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
image.Rectangle{Min: image.Point{175, 235}, Max: image.Point{50, 180}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXAssassinDeselect),
|
||||
@ -337,11 +337,11 @@ func (v *SelectHeroClass) Load() []func() {
|
||||
v.loadSprite(d2resource.CharacterSelectDruidUnselected, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectDruidUnselectedH, d2enum.Fechar),
|
||||
v.loadSprite(d2resource.CharacterSelectDruidForwardWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectDruidSelected, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
v.loadSprite(d2resource.CharacterSelectDruidBackWalk, d2enum.Fechar),
|
||||
nil,
|
||||
d2render.Sprite{},
|
||||
image.Rectangle{Min: image.Point{680, 220}, Max: image.Point{70, 195}},
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXDruidSelect),
|
||||
v.soundManager.LoadSoundEffect(d2resource.SFXDruidDeselect),
|
||||
@ -421,7 +421,7 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
||||
if renderInfo.ForwardWalkSprite.OnLastFrame() {
|
||||
renderInfo.Stance = d2enum.HeroStanceSelected
|
||||
renderInfo.SelectedSprite.ResetAnimation()
|
||||
if renderInfo.SelectedSpriteOverlay != nil {
|
||||
if renderInfo.SelectedSpriteOverlay.IsValid() {
|
||||
renderInfo.SelectedSpriteOverlay.ResetAnimation()
|
||||
}
|
||||
}
|
||||
@ -447,7 +447,7 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
||||
// showEntryUi = true;
|
||||
renderInfo.Stance = d2enum.HeroStanceApproaching
|
||||
renderInfo.ForwardWalkSprite.ResetAnimation()
|
||||
if renderInfo.ForwardWalkSpriteOverlay != nil {
|
||||
if renderInfo.ForwardWalkSpriteOverlay.IsValid() {
|
||||
renderInfo.ForwardWalkSpriteOverlay.ResetAnimation()
|
||||
}
|
||||
for _, heroInfo := range v.heroRenderInfo {
|
||||
@ -458,7 +458,7 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
|
||||
heroInfo.DeselectSfx.Play()
|
||||
heroInfo.Stance = d2enum.HeroStanceRetreating
|
||||
heroInfo.BackWalkSprite.ResetAnimation()
|
||||
if heroInfo.BackWalkSpriteOverlay != nil {
|
||||
if heroInfo.BackWalkSpriteOverlay.IsValid() {
|
||||
heroInfo.BackWalkSpriteOverlay.ResetAnimation()
|
||||
}
|
||||
}
|
||||
@ -491,17 +491,17 @@ func (v *SelectHeroClass) renderHero(screen *ebiten.Image, hero d2enum.Hero) {
|
||||
renderInfo.IdleSelectedSprite.Draw(screen)
|
||||
case d2enum.HeroStanceApproaching:
|
||||
renderInfo.ForwardWalkSprite.Draw(screen)
|
||||
if renderInfo.ForwardWalkSpriteOverlay != nil {
|
||||
if renderInfo.ForwardWalkSpriteOverlay.IsValid() {
|
||||
renderInfo.ForwardWalkSpriteOverlay.Draw(screen)
|
||||
}
|
||||
case d2enum.HeroStanceSelected:
|
||||
renderInfo.SelectedSprite.Draw(screen)
|
||||
if renderInfo.SelectedSpriteOverlay != nil {
|
||||
if renderInfo.SelectedSpriteOverlay.IsValid() {
|
||||
renderInfo.SelectedSpriteOverlay.Draw(screen)
|
||||
}
|
||||
case d2enum.HeroStanceRetreating:
|
||||
renderInfo.BackWalkSprite.Draw(screen)
|
||||
if renderInfo.BackWalkSpriteOverlay != nil {
|
||||
if renderInfo.BackWalkSpriteOverlay.IsValid() {
|
||||
renderInfo.BackWalkSpriteOverlay.Draw(screen)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package d2data
|
||||
package d2cof
|
||||
|
||||
import (
|
||||
"strings"
|
||||
@ -10,36 +10,28 @@ import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
)
|
||||
|
||||
type CofLayer struct {
|
||||
Type d2enum.CompositeType
|
||||
Shadow byte
|
||||
Transparent bool
|
||||
DrawEffect d2enum.DrawEffect
|
||||
WeaponClass d2enum.WeaponClass
|
||||
}
|
||||
|
||||
type Cof struct {
|
||||
type COF struct {
|
||||
NumberOfDirections int
|
||||
FramesPerDirection int
|
||||
NumberOfLayers int
|
||||
CofLayers []*CofLayer
|
||||
CofLayers []CofLayer
|
||||
CompositeLayers map[d2enum.CompositeType]int
|
||||
AnimationFrames []d2enum.AnimationFrame
|
||||
Priority [][][]d2enum.CompositeType
|
||||
}
|
||||
|
||||
func LoadCof(fileName string, fileProvider d2interface.FileProvider) *Cof {
|
||||
result := &Cof{}
|
||||
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.CofLayers = make([]CofLayer, result.NumberOfLayers)
|
||||
result.CompositeLayers = make(map[d2enum.CompositeType]int, 0)
|
||||
for i := 0; i < result.NumberOfLayers; i++ {
|
||||
layer := &CofLayer{}
|
||||
layer := CofLayer{}
|
||||
layer.Type = d2enum.CompositeType(streamReader.GetByte())
|
||||
layer.Shadow = streamReader.GetByte()
|
||||
streamReader.SkipBytes(1) // Unknown
|
||||
@ -47,7 +39,7 @@ func LoadCof(fileName string, fileProvider d2interface.FileProvider) *Cof {
|
||||
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.CofLayers[i] = layer
|
||||
result.CompositeLayers[layer.Type] = i
|
||||
}
|
||||
animationFrameBytes, _ := streamReader.ReadBytes(result.FramesPerDirection)
|
11
d2data/d2cof/CofLayer.go
Normal file
11
d2data/d2cof/CofLayer.go
Normal file
@ -0,0 +1,11 @@
|
||||
package d2cof
|
||||
|
||||
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||
|
||||
type CofLayer struct {
|
||||
Type d2enum.CompositeType
|
||||
Shadow byte
|
||||
Transparent bool
|
||||
DrawEffect d2enum.DrawEffect
|
||||
WeaponClass d2enum.WeaponClass
|
||||
}
|
@ -73,10 +73,10 @@ func createLevelPresetRecord(props []string) LevelPresetRecord {
|
||||
return result
|
||||
}
|
||||
|
||||
var LevelPresets map[int]*LevelPresetRecord
|
||||
var LevelPresets map[int]LevelPresetRecord
|
||||
|
||||
func LoadLevelPresets(fileProvider d2interface.FileProvider) {
|
||||
LevelPresets = make(map[int]*LevelPresetRecord)
|
||||
LevelPresets = make(map[int]LevelPresetRecord)
|
||||
data := strings.Split(string(fileProvider.LoadFile(d2resource.LevelPreset)), "\r\n")[1:]
|
||||
for _, line := range data {
|
||||
if len(line) == 0 {
|
||||
@ -87,7 +87,7 @@ func LoadLevelPresets(fileProvider d2interface.FileProvider) {
|
||||
continue // any line without a definition id is skipped (e.g. the "Expansion" line)
|
||||
}
|
||||
rec := createLevelPresetRecord(props)
|
||||
LevelPresets[rec.DefinitionId] = &rec
|
||||
LevelPresets[rec.DefinitionId] = rec
|
||||
}
|
||||
log.Printf("Loaded %d level presets", len(LevelPresets))
|
||||
}
|
||||
|
11
d2data/d2dcc/CommonData.go
Normal file
11
d2data/d2dcc/CommonData.go
Normal file
@ -0,0 +1,11 @@
|
||||
package d2dcc
|
||||
|
||||
var crazyBitTable = []byte{0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 26, 28, 30, 32}
|
||||
var pixelMaskLookup = []int{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}
|
||||
var dccDir4 = []byte{0, 1, 2, 3}
|
||||
var dccDir8 = []byte{4, 0, 5, 1, 6, 2, 7, 3}
|
||||
var dccDir16 = []byte{4, 8, 0, 9, 5, 10, 1, 11, 6, 12, 2, 13, 7, 14, 3, 15}
|
||||
var dccDir32 = []byte{
|
||||
4, 16, 8, 17, 0, 18, 9, 19, 5, 20, 10, 21, 1, 22, 11, 23,
|
||||
6, 24, 12, 25, 2, 26, 13, 27, 7, 28, 14, 29, 3, 30, 15, 31,
|
||||
}
|
62
d2data/d2dcc/DCC.go
Normal file
62
d2data/d2dcc/DCC.go
Normal file
@ -0,0 +1,62 @@
|
||||
package d2dcc
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
)
|
||||
|
||||
type DCC struct {
|
||||
Signature int
|
||||
Version int
|
||||
NumberOfDirections int
|
||||
FramesPerDirection int
|
||||
Directions []DCCDirection
|
||||
valid bool
|
||||
}
|
||||
|
||||
func (v DCC) IsValid() bool {
|
||||
return v.valid
|
||||
}
|
||||
|
||||
func LoadDCC(path string, fileProvider d2interface.FileProvider) DCC {
|
||||
result := DCC{}
|
||||
fileData := fileProvider.LoadFile(path)
|
||||
var bm = d2common.CreateBitMuncher(fileData, 0)
|
||||
result.Signature = int(bm.GetByte())
|
||||
if result.Signature != 0x74 {
|
||||
log.Fatal("Signature expected to be 0x74 but it is not.")
|
||||
}
|
||||
result.Version = int(bm.GetByte())
|
||||
result.NumberOfDirections = int(bm.GetByte())
|
||||
result.FramesPerDirection = int(bm.GetInt32())
|
||||
if bm.GetInt32() != 1 {
|
||||
log.Fatal("This value isn't 1. It has to be 1.")
|
||||
}
|
||||
bm.GetInt32() // TotalSizeCoded
|
||||
directionOffsets := make([]int, result.NumberOfDirections)
|
||||
for i := 0; i < result.NumberOfDirections; i++ {
|
||||
directionOffsets[i] = int(bm.GetInt32())
|
||||
}
|
||||
result.Directions = make([]DCCDirection, result.NumberOfDirections)
|
||||
for i := 0; i < result.NumberOfDirections; i++ {
|
||||
dir := byte(0)
|
||||
switch result.NumberOfDirections {
|
||||
case 1:
|
||||
dir = 0
|
||||
case 4:
|
||||
dir = dccDir4[i]
|
||||
case 8:
|
||||
dir = dccDir8[i]
|
||||
case 16:
|
||||
dir = dccDir16[i]
|
||||
case 32:
|
||||
dir = dccDir32[i]
|
||||
}
|
||||
result.Directions[dir] = CreateDCCDirection(d2common.CreateBitMuncher(fileData, directionOffsets[i]*8), result)
|
||||
}
|
||||
result.valid = true
|
||||
return result
|
||||
}
|
12
d2data/d2dcc/DCCCell.go
Normal file
12
d2data/d2dcc/DCCCell.go
Normal file
@ -0,0 +1,12 @@
|
||||
package d2dcc
|
||||
|
||||
type DCCCell struct {
|
||||
Width int
|
||||
Height int
|
||||
XOffset int
|
||||
YOffset int
|
||||
LastWidth int
|
||||
LastHeight int
|
||||
LastXOffset int
|
||||
LastYOffset int
|
||||
}
|
@ -1,47 +1,12 @@
|
||||
package d2data
|
||||
package d2dcc
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
|
||||
)
|
||||
|
||||
type DCCPixelBufferEntry struct {
|
||||
Value []byte
|
||||
Frame int
|
||||
FrameCellIndex int
|
||||
}
|
||||
|
||||
type DCCCell struct {
|
||||
Width int
|
||||
Height int
|
||||
XOffset int
|
||||
YOffset int
|
||||
LastWidth int
|
||||
LastHeight int
|
||||
LastXOffset int
|
||||
LastYOffset int
|
||||
}
|
||||
|
||||
type DCCDirectionFrame struct {
|
||||
Width int
|
||||
Height int
|
||||
XOffset int
|
||||
YOffset int
|
||||
NumberOfOptionalBytes int
|
||||
NumberOfCodedBytes int
|
||||
FrameIsBottomUp bool
|
||||
Box d2common.Rectangle
|
||||
Cells []DCCCell
|
||||
PixelData []byte
|
||||
HorizontalCellCount int
|
||||
VerticalCellCount int
|
||||
}
|
||||
|
||||
type DCCDirection struct {
|
||||
OutSizeCoded int
|
||||
CompressionFlags int
|
||||
@ -66,108 +31,8 @@ type DCCDirection struct {
|
||||
PixelBuffer []*DCCPixelBufferEntry
|
||||
}
|
||||
|
||||
type DCC struct {
|
||||
Signature int
|
||||
Version int
|
||||
NumberOfDirections int
|
||||
FramesPerDirection int
|
||||
Directions []*DCCDirection
|
||||
}
|
||||
|
||||
var crazyBitTable = []byte{0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 26, 28, 30, 32}
|
||||
var pixelMaskLookup = []int{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}
|
||||
var dccDir4 = []byte{0, 1, 2, 3}
|
||||
var dccDir8 = []byte{4, 0, 5, 1, 6, 2, 7, 3}
|
||||
var dccDir16 = []byte{4, 8, 0, 9, 5, 10, 1, 11, 6, 12, 2, 13, 7, 14, 3, 15}
|
||||
var dccDir32 = []byte{4, 16, 8, 17, 0, 18, 9, 19, 5, 20, 10, 21, 1, 22, 11, 23,
|
||||
6, 24, 12, 25, 2, 26, 13, 27, 7, 28, 14, 29, 3, 30, 15, 31}
|
||||
|
||||
func CreateDCCDirectionFrame(bits *d2common.BitMuncher, direction *DCCDirection) *DCCDirectionFrame {
|
||||
result := &DCCDirectionFrame{}
|
||||
bits.GetBits(direction.Variable0Bits) // Variable0
|
||||
result.Width = int(bits.GetBits(direction.WidthBits))
|
||||
result.Height = int(bits.GetBits(direction.HeightBits))
|
||||
result.XOffset = bits.GetSignedBits(direction.XOffsetBits)
|
||||
result.YOffset = bits.GetSignedBits(direction.YOffsetBits)
|
||||
result.NumberOfOptionalBytes = int(bits.GetBits(direction.OptionalDataBits))
|
||||
result.NumberOfCodedBytes = int(bits.GetBits(direction.CodedBytesBits))
|
||||
result.FrameIsBottomUp = bits.GetBit() == 1
|
||||
if result.FrameIsBottomUp {
|
||||
log.Panic("Bottom up frames are not implemented.")
|
||||
} else {
|
||||
result.Box = d2common.Rectangle{
|
||||
result.XOffset,
|
||||
result.YOffset - result.Height + 1,
|
||||
result.Width,
|
||||
result.Height,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *DCCDirectionFrame) CalculateCells(direction *DCCDirection) {
|
||||
var w = 4 - ((v.Box.Left - direction.Box.Left) % 4) // Width of the first column (in pixels)
|
||||
if (v.Width - w) <= 1 {
|
||||
v.HorizontalCellCount = 1
|
||||
} else {
|
||||
tmp := v.Width - w - 1
|
||||
v.HorizontalCellCount = 2 + (tmp / 4)
|
||||
if (tmp % 4) == 0 {
|
||||
v.HorizontalCellCount--
|
||||
}
|
||||
}
|
||||
h := 4 - ((v.Box.Top - direction.Box.Top) % 4) // Height of the first column (in pixels)
|
||||
if (v.Height - h) <= 1 {
|
||||
v.VerticalCellCount = 1
|
||||
} else {
|
||||
tmp := v.Height - h - 1
|
||||
v.VerticalCellCount = 2 + (tmp / 4)
|
||||
if (tmp % 4) == 0 {
|
||||
v.VerticalCellCount--
|
||||
}
|
||||
}
|
||||
// Calculate the cell widths and heights
|
||||
cellWidths := make([]int, v.HorizontalCellCount)
|
||||
if v.HorizontalCellCount == 1 {
|
||||
cellWidths[0] = v.Width
|
||||
} else {
|
||||
cellWidths[0] = w
|
||||
for i := 1; i < (v.HorizontalCellCount - 1); i++ {
|
||||
cellWidths[i] = 4
|
||||
}
|
||||
cellWidths[v.HorizontalCellCount-1] = v.Width - w - (4 * (v.HorizontalCellCount - 2))
|
||||
}
|
||||
|
||||
cellHeights := make([]int, v.VerticalCellCount)
|
||||
if v.VerticalCellCount == 1 {
|
||||
cellHeights[0] = v.Height
|
||||
} else {
|
||||
cellHeights[0] = h
|
||||
for i := 1; i < (v.VerticalCellCount - 1); i++ {
|
||||
cellHeights[i] = 4
|
||||
}
|
||||
cellHeights[v.VerticalCellCount-1] = v.Height - h - (4 * (v.VerticalCellCount - 2))
|
||||
}
|
||||
|
||||
v.Cells = make([]DCCCell, v.HorizontalCellCount*v.VerticalCellCount)
|
||||
offsetY := v.Box.Top - direction.Box.Top
|
||||
for y := 0; y < v.VerticalCellCount; y++ {
|
||||
offsetX := v.Box.Left - direction.Box.Left
|
||||
for x := 0; x < v.HorizontalCellCount; x++ {
|
||||
v.Cells[x+(y*v.HorizontalCellCount)] = DCCCell{
|
||||
XOffset: offsetX,
|
||||
YOffset: offsetY,
|
||||
Width: cellWidths[x],
|
||||
Height: cellHeights[y],
|
||||
}
|
||||
offsetX += cellWidths[x]
|
||||
}
|
||||
offsetY += cellHeights[y]
|
||||
}
|
||||
}
|
||||
|
||||
func CreateDCCDirection(bm *d2common.BitMuncher, file *DCC) *DCCDirection {
|
||||
result := &DCCDirection{}
|
||||
func CreateDCCDirection(bm *d2common.BitMuncher, file DCC) DCCDirection {
|
||||
result := DCCDirection{}
|
||||
result.OutSizeCoded = int(bm.GetUInt32())
|
||||
result.CompressionFlags = int(bm.GetBits(2))
|
||||
result.Variable0Bits = int(crazyBitTable[bm.GetBits(4)])
|
||||
@ -498,43 +363,3 @@ func (v *DCCDirection) CalculateCells() {
|
||||
yOffset += 4
|
||||
}
|
||||
}
|
||||
|
||||
func LoadDCC(path string, fileProvider d2interface.FileProvider) *DCC {
|
||||
result := &DCC{}
|
||||
fileData := fileProvider.LoadFile(path)
|
||||
var bm = d2common.CreateBitMuncher(fileData, 0)
|
||||
result.Signature = int(bm.GetByte())
|
||||
if result.Signature != 0x74 {
|
||||
log.Fatal("Signature expected to be 0x74 but it is not.")
|
||||
}
|
||||
result.Version = int(bm.GetByte())
|
||||
result.NumberOfDirections = int(bm.GetByte())
|
||||
result.FramesPerDirection = int(bm.GetInt32())
|
||||
if bm.GetInt32() != 1 {
|
||||
log.Fatal("This value isn't 1. It has to be 1.")
|
||||
}
|
||||
bm.GetInt32() // TotalSizeCoded
|
||||
directionOffsets := make([]int, result.NumberOfDirections)
|
||||
for i := 0; i < result.NumberOfDirections; i++ {
|
||||
directionOffsets[i] = int(bm.GetInt32())
|
||||
}
|
||||
result.Directions = make([]*DCCDirection, result.NumberOfDirections)
|
||||
for i := 0; i < result.NumberOfDirections; i++ {
|
||||
dir := byte(0)
|
||||
switch result.NumberOfDirections {
|
||||
case 1:
|
||||
dir = 0
|
||||
case 4:
|
||||
dir = dccDir4[i]
|
||||
case 8:
|
||||
dir = dccDir8[i]
|
||||
case 16:
|
||||
dir = dccDir16[i]
|
||||
case 32:
|
||||
dir = dccDir32[i]
|
||||
}
|
||||
result.Directions[dir] = CreateDCCDirection(d2common.CreateBitMuncher(fileData, directionOffsets[i]*8), result)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
108
d2data/d2dcc/DCCDirectionFrame.go
Normal file
108
d2data/d2dcc/DCCDirectionFrame.go
Normal file
@ -0,0 +1,108 @@
|
||||
package d2dcc
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||
)
|
||||
|
||||
type DCCDirectionFrame struct {
|
||||
Width int
|
||||
Height int
|
||||
XOffset int
|
||||
YOffset int
|
||||
NumberOfOptionalBytes int
|
||||
NumberOfCodedBytes int
|
||||
FrameIsBottomUp bool
|
||||
Box d2common.Rectangle
|
||||
Cells []DCCCell
|
||||
PixelData []byte
|
||||
HorizontalCellCount int
|
||||
VerticalCellCount int
|
||||
valid bool
|
||||
}
|
||||
|
||||
func CreateDCCDirectionFrame(bits *d2common.BitMuncher, direction DCCDirection) *DCCDirectionFrame {
|
||||
result := &DCCDirectionFrame{}
|
||||
bits.GetBits(direction.Variable0Bits) // Variable0
|
||||
result.Width = int(bits.GetBits(direction.WidthBits))
|
||||
result.Height = int(bits.GetBits(direction.HeightBits))
|
||||
result.XOffset = bits.GetSignedBits(direction.XOffsetBits)
|
||||
result.YOffset = bits.GetSignedBits(direction.YOffsetBits)
|
||||
result.NumberOfOptionalBytes = int(bits.GetBits(direction.OptionalDataBits))
|
||||
result.NumberOfCodedBytes = int(bits.GetBits(direction.CodedBytesBits))
|
||||
result.FrameIsBottomUp = bits.GetBit() == 1
|
||||
if result.FrameIsBottomUp {
|
||||
log.Panic("Bottom up frames are not implemented.")
|
||||
} else {
|
||||
result.Box = d2common.Rectangle{
|
||||
result.XOffset,
|
||||
result.YOffset - result.Height + 1,
|
||||
result.Width,
|
||||
result.Height,
|
||||
}
|
||||
}
|
||||
result.valid = true
|
||||
return result
|
||||
}
|
||||
|
||||
func (v *DCCDirectionFrame) CalculateCells(direction DCCDirection) {
|
||||
var w = 4 - ((v.Box.Left - direction.Box.Left) % 4) // Width of the first column (in pixels)
|
||||
if (v.Width - w) <= 1 {
|
||||
v.HorizontalCellCount = 1
|
||||
} else {
|
||||
tmp := v.Width - w - 1
|
||||
v.HorizontalCellCount = 2 + (tmp / 4)
|
||||
if (tmp % 4) == 0 {
|
||||
v.HorizontalCellCount--
|
||||
}
|
||||
}
|
||||
h := 4 - ((v.Box.Top - direction.Box.Top) % 4) // Height of the first column (in pixels)
|
||||
if (v.Height - h) <= 1 {
|
||||
v.VerticalCellCount = 1
|
||||
} else {
|
||||
tmp := v.Height - h - 1
|
||||
v.VerticalCellCount = 2 + (tmp / 4)
|
||||
if (tmp % 4) == 0 {
|
||||
v.VerticalCellCount--
|
||||
}
|
||||
}
|
||||
// Calculate the cell widths and heights
|
||||
cellWidths := make([]int, v.HorizontalCellCount)
|
||||
if v.HorizontalCellCount == 1 {
|
||||
cellWidths[0] = v.Width
|
||||
} else {
|
||||
cellWidths[0] = w
|
||||
for i := 1; i < (v.HorizontalCellCount - 1); i++ {
|
||||
cellWidths[i] = 4
|
||||
}
|
||||
cellWidths[v.HorizontalCellCount-1] = v.Width - w - (4 * (v.HorizontalCellCount - 2))
|
||||
}
|
||||
|
||||
cellHeights := make([]int, v.VerticalCellCount)
|
||||
if v.VerticalCellCount == 1 {
|
||||
cellHeights[0] = v.Height
|
||||
} else {
|
||||
cellHeights[0] = h
|
||||
for i := 1; i < (v.VerticalCellCount - 1); i++ {
|
||||
cellHeights[i] = 4
|
||||
}
|
||||
cellHeights[v.VerticalCellCount-1] = v.Height - h - (4 * (v.VerticalCellCount - 2))
|
||||
}
|
||||
|
||||
v.Cells = make([]DCCCell, v.HorizontalCellCount*v.VerticalCellCount)
|
||||
offsetY := v.Box.Top - direction.Box.Top
|
||||
for y := 0; y < v.VerticalCellCount; y++ {
|
||||
offsetX := v.Box.Left - direction.Box.Left
|
||||
for x := 0; x < v.HorizontalCellCount; x++ {
|
||||
v.Cells[x+(y*v.HorizontalCellCount)] = DCCCell{
|
||||
XOffset: offsetX,
|
||||
YOffset: offsetY,
|
||||
Width: cellWidths[x],
|
||||
Height: cellHeights[y],
|
||||
}
|
||||
offsetX += cellWidths[x]
|
||||
}
|
||||
offsetY += cellHeights[y]
|
||||
}
|
||||
}
|
7
d2data/d2dcc/DCCPixelBufferEntry.go
Normal file
7
d2data/d2dcc/DCCPixelBufferEntry.go
Normal file
@ -0,0 +1,7 @@
|
||||
package d2dcc
|
||||
|
||||
type DCCPixelBufferEntry struct {
|
||||
Value []byte
|
||||
Frame int
|
||||
FrameCellIndex int
|
||||
}
|
7
d2data/d2ds1/CommonData.go
Normal file
7
d2data/d2ds1/CommonData.go
Normal file
@ -0,0 +1,7 @@
|
||||
package d2ds1
|
||||
|
||||
var dirLookup = []int32{
|
||||
0x00, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03, 0x05, 0x05, 0x06,
|
||||
0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
||||
0x0F, 0x10, 0x11, 0x12, 0x14,
|
||||
}
|
@ -1,93 +1,33 @@
|
||||
package d2data
|
||||
package d2ds1
|
||||
|
||||
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/OpenDiablo2/OpenDiablo2/d2data/d2datadict"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
|
||||
)
|
||||
|
||||
var dirLookup = []int32{
|
||||
0x00, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03, 0x05, 0x05, 0x06,
|
||||
0x06, 0x07, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
|
||||
0x0F, 0x10, 0x11, 0x12, 0x14,
|
||||
}
|
||||
|
||||
type LayerStreamType int
|
||||
|
||||
const (
|
||||
LayerStreamWall1 LayerStreamType = 0
|
||||
LayerStreamWall2 LayerStreamType = 1
|
||||
LayerStreamWall3 LayerStreamType = 2
|
||||
LayerStreamWall4 LayerStreamType = 3
|
||||
LayerStreamOrientation1 LayerStreamType = 4
|
||||
LayerStreamOrientation2 LayerStreamType = 5
|
||||
LayerStreamOrientation3 LayerStreamType = 6
|
||||
LayerStreamOrientation4 LayerStreamType = 7
|
||||
LayerStreamFloor1 LayerStreamType = 8
|
||||
LayerStreamFloor2 LayerStreamType = 9
|
||||
LayerStreamShadow LayerStreamType = 10
|
||||
LayerStreamSubstitute LayerStreamType = 11
|
||||
)
|
||||
|
||||
type FloorShadowRecord struct {
|
||||
Prop1 byte
|
||||
SubIndex byte
|
||||
Unknown1 byte
|
||||
MainIndex byte
|
||||
Unknown2 byte
|
||||
Hidden bool
|
||||
}
|
||||
|
||||
type WallRecord struct {
|
||||
Orientation byte
|
||||
Zero byte
|
||||
Prop1 byte
|
||||
SubIndex byte
|
||||
Unknown1 byte
|
||||
MainIndex byte
|
||||
Unknown2 byte
|
||||
Hidden bool
|
||||
}
|
||||
|
||||
type SubstitutionRecord struct {
|
||||
Unknown uint32
|
||||
}
|
||||
|
||||
type TileRecord struct {
|
||||
Floors []FloorShadowRecord
|
||||
Walls []WallRecord
|
||||
Shadows []FloorShadowRecord
|
||||
Substitutions []SubstitutionRecord
|
||||
}
|
||||
|
||||
type SubstitutionGroup struct {
|
||||
TileX int32
|
||||
TileY int32
|
||||
WidthInTiles int32
|
||||
HeightInTiles int32
|
||||
Unknown int32
|
||||
}
|
||||
|
||||
type DS1 struct {
|
||||
Version int32 // The version of the DS1
|
||||
Width int32 // Width of map, in # of tiles
|
||||
Height int32 // Height of map, in # of tiles
|
||||
Act int32 // Act, from 1 to 5. This tells which act table to use for the Objects list
|
||||
SubstitutionType int32 // SubstitutionType (layer type): 0 if no layer, else type 1 or type 2
|
||||
Files []string // FilePtr table of file string pointers
|
||||
NumberOfWalls int32 // WallNum number of wall & orientation layers used
|
||||
NumberOfFloors int32 // number of floor layers used
|
||||
NumberOfShadowLayers int32 // ShadowNum number of shadow layer used
|
||||
NumberOfSubstitutionLayers int32 // SubstitutionNum number of substitution layer used
|
||||
SubstitutionGroupsNum int32 // SubstitutionGroupsNum number of substitution groups, datas between objects & NPC paths
|
||||
Objects []Object // Objects
|
||||
Version int32 // The version of the DS1
|
||||
Width int32 // Width of map, in # of tiles
|
||||
Height int32 // Height of map, in # of tiles
|
||||
Act int32 // Act, from 1 to 5. This tells which act table to use for the Objects list
|
||||
SubstitutionType int32 // SubstitutionType (layer type): 0 if no layer, else type 1 or type 2
|
||||
Files []string // FilePtr table of file string pointers
|
||||
NumberOfWalls int32 // WallNum number of wall & orientation layers used
|
||||
NumberOfFloors int32 // number of floor layers used
|
||||
NumberOfShadowLayers int32 // ShadowNum number of shadow layer used
|
||||
NumberOfSubstitutionLayers int32 // SubstitutionNum number of substitution layer used
|
||||
SubstitutionGroupsNum int32 // SubstitutionGroupsNum number of substitution groups, datas between objects & NPC paths
|
||||
Objects []d2data.Object // Objects
|
||||
Tiles [][]TileRecord
|
||||
SubstitutionGroups []SubstitutionGroup
|
||||
}
|
||||
|
||||
func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 {
|
||||
ds1 := &DS1{
|
||||
func LoadDS1(path string, fileProvider d2interface.FileProvider) DS1 {
|
||||
ds1 := DS1{
|
||||
NumberOfFloors: 1,
|
||||
NumberOfWalls: 1,
|
||||
NumberOfShadowLayers: 1,
|
||||
@ -134,29 +74,34 @@ func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 {
|
||||
ds1.NumberOfFloors = 1
|
||||
}
|
||||
}
|
||||
var layerStream []LayerStreamType
|
||||
var layerStream []d2enum.LayerStreamType
|
||||
if ds1.Version < 4 {
|
||||
layerStream = []LayerStreamType{
|
||||
LayerStreamWall1,
|
||||
LayerStreamFloor1,
|
||||
LayerStreamOrientation1,
|
||||
LayerStreamSubstitute,
|
||||
LayerStreamShadow,
|
||||
layerStream = []d2enum.LayerStreamType{
|
||||
d2enum.LayerStreamWall1,
|
||||
d2enum.LayerStreamFloor1,
|
||||
d2enum.LayerStreamOrientation1,
|
||||
d2enum.LayerStreamSubstitute,
|
||||
d2enum.LayerStreamShadow,
|
||||
}
|
||||
} else {
|
||||
layerStream = make([]LayerStreamType, 0)
|
||||
layerStream = make([]d2enum.LayerStreamType, (ds1.NumberOfWalls*2)+ds1.NumberOfFloors+ds1.NumberOfShadowLayers+ds1.NumberOfSubstitutionLayers)
|
||||
layerIdx := 0
|
||||
for i := 0; i < int(ds1.NumberOfWalls); i++ {
|
||||
layerStream = append(layerStream, LayerStreamType(int(LayerStreamWall1)+i))
|
||||
layerStream = append(layerStream, LayerStreamType(int(LayerStreamOrientation1)+i))
|
||||
layerStream[layerIdx] = d2enum.LayerStreamType(int(d2enum.LayerStreamWall1) + i)
|
||||
layerStream[layerIdx+1] = d2enum.LayerStreamType(int(d2enum.LayerStreamOrientation1) + i)
|
||||
layerIdx += 2
|
||||
}
|
||||
for i := 0; i < int(ds1.NumberOfFloors); i++ {
|
||||
layerStream = append(layerStream, LayerStreamType(int(LayerStreamFloor1)+i))
|
||||
layerStream[layerIdx] = d2enum.LayerStreamType(int(d2enum.LayerStreamFloor1) + i)
|
||||
layerIdx++
|
||||
}
|
||||
if ds1.NumberOfShadowLayers > 0 {
|
||||
layerStream = append(layerStream, LayerStreamShadow)
|
||||
layerStream[layerIdx] = d2enum.LayerStreamShadow
|
||||
layerIdx++
|
||||
}
|
||||
if ds1.NumberOfSubstitutionLayers > 0 {
|
||||
layerStream = append(layerStream, LayerStreamSubstitute)
|
||||
layerStream[layerIdx] = d2enum.LayerStreamSubstitute
|
||||
layerIdx++
|
||||
}
|
||||
}
|
||||
ds1.Tiles = make([][]TileRecord, ds1.Height)
|
||||
@ -174,28 +119,28 @@ func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 {
|
||||
for x := 0; x < int(ds1.Width); x++ {
|
||||
dw := br.GetUInt32()
|
||||
switch layerStreamType {
|
||||
case LayerStreamWall1:
|
||||
case d2enum.LayerStreamWall1:
|
||||
fallthrough
|
||||
case LayerStreamWall2:
|
||||
case d2enum.LayerStreamWall2:
|
||||
fallthrough
|
||||
case LayerStreamWall3:
|
||||
case d2enum.LayerStreamWall3:
|
||||
fallthrough
|
||||
case LayerStreamWall4:
|
||||
wallIndex := int(layerStreamType) - int(LayerStreamWall1)
|
||||
case d2enum.LayerStreamWall4:
|
||||
wallIndex := int(layerStreamType) - int(d2enum.LayerStreamWall1)
|
||||
ds1.Tiles[y][x].Walls[wallIndex].Prop1 = byte(dw & 0x000000FF)
|
||||
ds1.Tiles[y][x].Walls[wallIndex].SubIndex = byte((dw & 0x00003F00) >> 8)
|
||||
ds1.Tiles[y][x].Walls[wallIndex].Unknown1 = byte((dw & 0x000FC000) >> 14)
|
||||
ds1.Tiles[y][x].Walls[wallIndex].MainIndex = byte((dw & 0x03F00000) >> 20)
|
||||
ds1.Tiles[y][x].Walls[wallIndex].Unknown2 = byte((dw & 0x7C000000) >> 26)
|
||||
ds1.Tiles[y][x].Walls[wallIndex].Hidden = byte((dw&0x80000000)>>31) > 0
|
||||
case LayerStreamOrientation1:
|
||||
case d2enum.LayerStreamOrientation1:
|
||||
fallthrough
|
||||
case LayerStreamOrientation2:
|
||||
case d2enum.LayerStreamOrientation2:
|
||||
fallthrough
|
||||
case LayerStreamOrientation3:
|
||||
case d2enum.LayerStreamOrientation3:
|
||||
fallthrough
|
||||
case LayerStreamOrientation4:
|
||||
wallIndex := int(layerStreamType) - int(LayerStreamOrientation1)
|
||||
case d2enum.LayerStreamOrientation4:
|
||||
wallIndex := int(layerStreamType) - int(d2enum.LayerStreamOrientation1)
|
||||
c := int32(dw & 0x000000FF)
|
||||
if ds1.Version < 7 {
|
||||
if c < 25 {
|
||||
@ -204,34 +149,34 @@ func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 {
|
||||
}
|
||||
ds1.Tiles[y][x].Walls[wallIndex].Orientation = byte(c)
|
||||
ds1.Tiles[y][x].Walls[wallIndex].Zero = byte((dw & 0xFFFFFF00) >> 8)
|
||||
case LayerStreamFloor1:
|
||||
case d2enum.LayerStreamFloor1:
|
||||
fallthrough
|
||||
case LayerStreamFloor2:
|
||||
floorIndex := int(layerStreamType) - int(LayerStreamFloor1)
|
||||
case d2enum.LayerStreamFloor2:
|
||||
floorIndex := int(layerStreamType) - int(d2enum.LayerStreamFloor1)
|
||||
ds1.Tiles[y][x].Floors[floorIndex].Prop1 = byte(dw & 0x000000FF)
|
||||
ds1.Tiles[y][x].Floors[floorIndex].SubIndex = byte((dw & 0x00003F00) >> 8)
|
||||
ds1.Tiles[y][x].Floors[floorIndex].Unknown1 = byte((dw & 0x000FC000) >> 14)
|
||||
ds1.Tiles[y][x].Floors[floorIndex].MainIndex = byte((dw & 0x03F00000) >> 20)
|
||||
ds1.Tiles[y][x].Floors[floorIndex].Unknown2 = byte((dw & 0x7C000000) >> 26)
|
||||
ds1.Tiles[y][x].Floors[floorIndex].Hidden = byte((dw&0x80000000)>>31) > 0
|
||||
case LayerStreamShadow:
|
||||
case d2enum.LayerStreamShadow:
|
||||
ds1.Tiles[y][x].Shadows[0].Prop1 = byte(dw & 0x000000FF)
|
||||
ds1.Tiles[y][x].Shadows[0].SubIndex = byte((dw & 0x00003F00) >> 8)
|
||||
ds1.Tiles[y][x].Shadows[0].Unknown1 = byte((dw & 0x000FC000) >> 14)
|
||||
ds1.Tiles[y][x].Shadows[0].MainIndex = byte((dw & 0x03F00000) >> 20)
|
||||
ds1.Tiles[y][x].Shadows[0].Unknown2 = byte((dw & 0x7C000000) >> 26)
|
||||
ds1.Tiles[y][x].Shadows[0].Hidden = byte((dw&0x80000000)>>31) > 0
|
||||
case LayerStreamSubstitute:
|
||||
case d2enum.LayerStreamSubstitute:
|
||||
ds1.Tiles[y][x].Substitutions[0].Unknown = dw
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ds1.Objects = make([]Object, 0)
|
||||
if ds1.Version >= 2 {
|
||||
numberOfObjects := br.GetInt32()
|
||||
ds1.Objects = make([]d2data.Object, numberOfObjects)
|
||||
for objIdx := 0; objIdx < int(numberOfObjects); objIdx++ {
|
||||
newObject := Object{}
|
||||
newObject := d2data.Object{}
|
||||
newObject.Type = br.GetInt32()
|
||||
newObject.Id = br.GetInt32()
|
||||
newObject.X = br.GetInt32()
|
||||
@ -241,15 +186,17 @@ func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 {
|
||||
if newObject.Lookup != nil && newObject.Lookup.ObjectsTxtId != -1 {
|
||||
newObject.ObjectInfo = d2datadict.Objects[newObject.Lookup.ObjectsTxtId]
|
||||
}
|
||||
ds1.Objects = append(ds1.Objects, newObject)
|
||||
ds1.Objects[objIdx] = newObject
|
||||
}
|
||||
} else {
|
||||
ds1.Objects = make([]d2data.Object, 0)
|
||||
}
|
||||
ds1.SubstitutionGroups = make([]SubstitutionGroup, 0)
|
||||
if ds1.Version >= 12 && (ds1.SubstitutionType == 1 || ds1.SubstitutionType == 2) {
|
||||
if ds1.Version >= 18 {
|
||||
br.GetUInt32()
|
||||
}
|
||||
numberOfSubGroups := br.GetInt32()
|
||||
ds1.SubstitutionGroups = make([]SubstitutionGroup, numberOfSubGroups)
|
||||
for subIdx := 0; subIdx < int(numberOfSubGroups); subIdx++ {
|
||||
newSub := SubstitutionGroup{}
|
||||
newSub.TileX = br.GetInt32()
|
||||
@ -258,8 +205,10 @@ func LoadDS1(path string, fileProvider d2interface.FileProvider) *DS1 {
|
||||
newSub.HeightInTiles = br.GetInt32()
|
||||
newSub.Unknown = br.GetInt32()
|
||||
|
||||
ds1.SubstitutionGroups = append(ds1.SubstitutionGroups, newSub)
|
||||
ds1.SubstitutionGroups[subIdx] = newSub
|
||||
}
|
||||
} else {
|
||||
ds1.SubstitutionGroups = make([]SubstitutionGroup, 0)
|
||||
}
|
||||
if ds1.Version >= 14 {
|
||||
numberOfNpcs := br.GetInt32()
|
10
d2data/d2ds1/FloorShadowRecord.go
Normal file
10
d2data/d2ds1/FloorShadowRecord.go
Normal file
@ -0,0 +1,10 @@
|
||||
package d2ds1
|
||||
|
||||
type FloorShadowRecord struct {
|
||||
Prop1 byte
|
||||
SubIndex byte
|
||||
Unknown1 byte
|
||||
MainIndex byte
|
||||
Unknown2 byte
|
||||
Hidden bool
|
||||
}
|
9
d2data/d2ds1/SubstitutionGroup.go
Normal file
9
d2data/d2ds1/SubstitutionGroup.go
Normal file
@ -0,0 +1,9 @@
|
||||
package d2ds1
|
||||
|
||||
type SubstitutionGroup struct {
|
||||
TileX int32
|
||||
TileY int32
|
||||
WidthInTiles int32
|
||||
HeightInTiles int32
|
||||
Unknown int32
|
||||
}
|
5
d2data/d2ds1/SubstitutionRecord.go
Normal file
5
d2data/d2ds1/SubstitutionRecord.go
Normal file
@ -0,0 +1,5 @@
|
||||
package d2ds1
|
||||
|
||||
type SubstitutionRecord struct {
|
||||
Unknown uint32
|
||||
}
|
8
d2data/d2ds1/TileRecord.go
Normal file
8
d2data/d2ds1/TileRecord.go
Normal file
@ -0,0 +1,8 @@
|
||||
package d2ds1
|
||||
|
||||
type TileRecord struct {
|
||||
Floors []FloorShadowRecord
|
||||
Walls []WallRecord
|
||||
Shadows []FloorShadowRecord
|
||||
Substitutions []SubstitutionRecord
|
||||
}
|
12
d2data/d2ds1/WallRecord.go
Normal file
12
d2data/d2ds1/WallRecord.go
Normal file
@ -0,0 +1,12 @@
|
||||
package d2ds1
|
||||
|
||||
type WallRecord struct {
|
||||
Orientation byte
|
||||
Zero byte
|
||||
Prop1 byte
|
||||
SubIndex byte
|
||||
Unknown1 byte
|
||||
MainIndex byte
|
||||
Unknown2 byte
|
||||
Hidden bool
|
||||
}
|
12
d2data/d2dt1/Block.go
Normal file
12
d2data/d2dt1/Block.go
Normal file
@ -0,0 +1,12 @@
|
||||
package d2dt1
|
||||
|
||||
type Block struct {
|
||||
X int16
|
||||
Y int16
|
||||
GridX byte
|
||||
GridY byte
|
||||
Format BlockDataFormat
|
||||
EncodedData []byte
|
||||
Length int32
|
||||
FileOffset int32
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package d2data
|
||||
package d2dt1
|
||||
|
||||
import (
|
||||
"log"
|
||||
@ -10,34 +10,6 @@ import (
|
||||
|
||||
// https://d2mods.info/forum/viewtopic.php?t=65163
|
||||
|
||||
type Block struct {
|
||||
X int16
|
||||
Y int16
|
||||
GridX byte
|
||||
GridY byte
|
||||
Format BlockDataFormat
|
||||
EncodedData []byte
|
||||
Length int32
|
||||
FileOffset int32
|
||||
}
|
||||
|
||||
type Tile struct {
|
||||
Direction int32
|
||||
RoofHeight int16
|
||||
SoundIndex byte
|
||||
Animated bool
|
||||
Height int32
|
||||
Width int32
|
||||
Orientation int32
|
||||
MainIndex int32
|
||||
SubIndex int32
|
||||
RarityFrameIndex int32
|
||||
SubTileFlags [25]byte
|
||||
blockHeaderPointer int32
|
||||
blockHeaderSize int32
|
||||
Blocks []Block
|
||||
}
|
||||
|
||||
type DT1 struct {
|
||||
Tiles []Tile
|
||||
}
|
||||
@ -49,8 +21,8 @@ const (
|
||||
BlockFormatIsometric BlockDataFormat = 1
|
||||
)
|
||||
|
||||
func LoadDT1(path string, fileProvider d2interface.FileProvider) *DT1 {
|
||||
result := &DT1{}
|
||||
func LoadDT1(path string, fileProvider d2interface.FileProvider) DT1 {
|
||||
result := DT1{}
|
||||
fileData := fileProvider.LoadFile(path)
|
||||
br := d2common.CreateStreamReader(fileData)
|
||||
ver1 := br.GetInt32()
|
18
d2data/d2dt1/Tile.go
Normal file
18
d2data/d2dt1/Tile.go
Normal file
@ -0,0 +1,18 @@
|
||||
package d2dt1
|
||||
|
||||
type Tile struct {
|
||||
Direction int32
|
||||
RoofHeight int16
|
||||
SoundIndex byte
|
||||
Animated bool
|
||||
Height int32
|
||||
Width int32
|
||||
Orientation int32
|
||||
MainIndex int32
|
||||
SubIndex int32
|
||||
RarityFrameIndex int32
|
||||
SubTileFlags [25]byte
|
||||
blockHeaderPointer int32
|
||||
blockHeaderSize int32
|
||||
Blocks []Block
|
||||
}
|
@ -6,6 +6,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2cof"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2dcc"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -29,8 +33,8 @@ type AnimatedEntity struct {
|
||||
LocationX float64
|
||||
// LocationY represents the tile Y position of the entity
|
||||
LocationY float64
|
||||
dccLayers map[string]*d2data.DCC
|
||||
Cof *d2data.Cof
|
||||
dccLayers map[string]d2dcc.DCC
|
||||
Cof *d2cof.COF
|
||||
palette d2enum.PaletteType
|
||||
base string
|
||||
token string
|
||||
@ -47,14 +51,14 @@ type AnimatedEntity struct {
|
||||
}
|
||||
|
||||
// CreateAnimatedEntity creates an instance of AnimatedEntity
|
||||
func CreateAnimatedEntity(object d2data.Object, fileProvider d2interface.FileProvider, palette d2enum.PaletteType) *AnimatedEntity {
|
||||
result := &AnimatedEntity{
|
||||
func CreateAnimatedEntity(object d2data.Object, fileProvider d2interface.FileProvider, palette d2enum.PaletteType) AnimatedEntity {
|
||||
result := AnimatedEntity{
|
||||
base: object.Lookup.Base,
|
||||
token: object.Lookup.Token,
|
||||
object: object,
|
||||
palette: palette,
|
||||
}
|
||||
result.dccLayers = make(map[string]*d2data.DCC)
|
||||
result.dccLayers = make(map[string]d2dcc.DCC)
|
||||
result.LocationX = float64(object.X) / 5
|
||||
result.LocationY = float64(object.Y) / 5
|
||||
return result
|
||||
@ -65,8 +69,8 @@ var DirectionLookup = []int{3, 15, 4, 8, 0, 9, 5, 10, 1, 11, 6, 12, 2, 13, 7, 14
|
||||
|
||||
// SetMode changes the graphical mode of this animated entity
|
||||
func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction int, provider d2interface.FileProvider) {
|
||||
cofPath := fmt.Sprintf("%s/%s/Cof/%s%s%s.Cof", v.base, v.token, v.token, animationMode, weaponClass)
|
||||
v.Cof = d2data.LoadCof(cofPath, provider)
|
||||
cofPath := fmt.Sprintf("%s/%s/COF/%s%s%s.COF", v.base, v.token, v.token, animationMode, weaponClass)
|
||||
v.Cof = d2cof.LoadCOF(cofPath, provider)
|
||||
v.animationMode = animationMode
|
||||
v.weaponClass = weaponClass
|
||||
v.direction = direction
|
||||
@ -75,11 +79,11 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in
|
||||
}
|
||||
v.frames = make(map[string][]*ebiten.Image)
|
||||
v.frameLocations = make(map[string][]d2common.Rectangle)
|
||||
v.dccLayers = make(map[string]*d2data.DCC)
|
||||
v.dccLayers = make(map[string]d2dcc.DCC)
|
||||
for _, cofLayer := range v.Cof.CofLayers {
|
||||
layerName := DccLayerNames[cofLayer.Type]
|
||||
v.dccLayers[layerName] = v.LoadLayer(layerName, provider)
|
||||
if v.dccLayers[layerName] == nil {
|
||||
if !v.dccLayers[layerName].IsValid() {
|
||||
continue
|
||||
}
|
||||
v.cacheFrames(layerName)
|
||||
@ -87,7 +91,7 @@ func (v *AnimatedEntity) SetMode(animationMode, weaponClass string, direction in
|
||||
|
||||
}
|
||||
|
||||
func (v *AnimatedEntity) LoadLayer(layer string, fileProvider d2interface.FileProvider) *d2data.DCC {
|
||||
func (v *AnimatedEntity) LoadLayer(layer string, fileProvider d2interface.FileProvider) d2dcc.DCC {
|
||||
layerName := "tr"
|
||||
switch strings.ToUpper(layer) {
|
||||
case "HD": // Head
|
||||
@ -124,10 +128,10 @@ func (v *AnimatedEntity) LoadLayer(layer string, fileProvider d2interface.FilePr
|
||||
layerName = v.object.Lookup.S8
|
||||
}
|
||||
if len(layerName) == 0 {
|
||||
return nil
|
||||
return d2dcc.DCC{}
|
||||
}
|
||||
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 d2data.LoadDCC(dccPath, fileProvider)
|
||||
return d2dcc.LoadDCC(dccPath, fileProvider)
|
||||
}
|
||||
|
||||
// Render draws this animated entity onto the target
|
||||
|
@ -20,7 +20,7 @@ type Sprite struct {
|
||||
FramesPerDirection uint32
|
||||
atlas *ebiten.Image
|
||||
atlasBytes []byte
|
||||
Frames []*SpriteFrame
|
||||
Frames []SpriteFrame
|
||||
SpecialFrameTime int
|
||||
StopOnLastFrame bool
|
||||
X, Y int
|
||||
@ -30,6 +30,7 @@ type Sprite struct {
|
||||
Animate bool
|
||||
ColorMod color.Color
|
||||
visible bool
|
||||
valid bool
|
||||
}
|
||||
|
||||
// SpriteFrame represents a single frame of a sprite
|
||||
@ -49,8 +50,8 @@ type SpriteFrame struct {
|
||||
}
|
||||
|
||||
// CreateSprite creates an instance of a sprite
|
||||
func CreateSprite(data []byte, palette d2datadict.PaletteRec) *Sprite {
|
||||
result := &Sprite{
|
||||
func CreateSprite(data []byte, palette d2datadict.PaletteRec) Sprite {
|
||||
result := Sprite{
|
||||
X: 50,
|
||||
Y: 50,
|
||||
Frame: 0,
|
||||
@ -63,6 +64,7 @@ func CreateSprite(data []byte, palette d2datadict.PaletteRec) *Sprite {
|
||||
LastFrameTime: time.Now(),
|
||||
SpecialFrameTime: -1,
|
||||
StopOnLastFrame: false,
|
||||
valid: false,
|
||||
}
|
||||
dataPointer := uint32(24)
|
||||
totalFrames := result.Directions * result.FramesPerDirection
|
||||
@ -71,14 +73,14 @@ func CreateSprite(data []byte, palette d2datadict.PaletteRec) *Sprite {
|
||||
framePointers[i] = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||
dataPointer += 4
|
||||
}
|
||||
result.Frames = make([]*SpriteFrame, totalFrames)
|
||||
result.Frames = make([]SpriteFrame, totalFrames)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(int(totalFrames))
|
||||
for i := uint32(0); i < totalFrames; i++ {
|
||||
go func(i uint32) {
|
||||
defer wg.Done()
|
||||
dataPointer := framePointers[i]
|
||||
result.Frames[i] = &SpriteFrame{}
|
||||
result.Frames[i] = SpriteFrame{}
|
||||
result.Frames[i].Flip = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||
dataPointer += 4
|
||||
result.Frames[i].Width = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||
@ -169,14 +171,18 @@ func CreateSprite(data []byte, palette d2datadict.PaletteRec) *Sprite {
|
||||
curX += curMaxWidth
|
||||
curY = 0
|
||||
}
|
||||
result.valid = true
|
||||
return result
|
||||
}
|
||||
|
||||
func (v Sprite) IsValid() bool {
|
||||
return v.valid
|
||||
}
|
||||
|
||||
func (v *Sprite) cacheFrame(frame int) {
|
||||
if v.Frames[frame].cached {
|
||||
return
|
||||
}
|
||||
|
||||
r := v.Frames[frame].Image.Bounds().Min
|
||||
curX := r.X
|
||||
curY := r.Y
|
||||
@ -196,7 +202,7 @@ func (v *Sprite) cacheFrame(frame int) {
|
||||
}
|
||||
|
||||
// GetSize returns the size of the sprite
|
||||
func (v *Sprite) GetSize() (uint32, uint32) {
|
||||
func (v Sprite) GetSize() (uint32, uint32) {
|
||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
||||
return frame.Width, frame.Height
|
||||
}
|
||||
@ -230,19 +236,19 @@ func (v *Sprite) ResetAnimation() {
|
||||
v.Frame = 0
|
||||
}
|
||||
|
||||
func (v *Sprite) OnLastFrame() bool {
|
||||
func (v Sprite) OnLastFrame() bool {
|
||||
return v.Frame == uint8(v.FramesPerDirection-1)
|
||||
}
|
||||
|
||||
// GetFrameSize returns the size of the specific frame
|
||||
func (v *Sprite) GetFrameSize(frame int) (width, height uint32) {
|
||||
func (v Sprite) GetFrameSize(frame int) (width, height uint32) {
|
||||
width = v.Frames[frame].Width
|
||||
height = v.Frames[frame].Height
|
||||
return
|
||||
}
|
||||
|
||||
// GetTotalFrames returns the number of frames in this sprite (for all directions)
|
||||
func (v *Sprite) GetTotalFrames() int {
|
||||
func (v Sprite) GetTotalFrames() int {
|
||||
return len(v.Frames)
|
||||
}
|
||||
|
||||
@ -309,6 +315,6 @@ func (v *Sprite) MoveTo(x, y int) {
|
||||
}
|
||||
|
||||
// GetLocation returns the location of the sprite
|
||||
func (v *Sprite) GetLocation() (int, int) {
|
||||
func (v Sprite) GetLocation() (int, int) {
|
||||
return v.X, v.Y
|
||||
}
|
||||
|
@ -8,6 +8,10 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2dt1"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2ds1"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
|
||||
@ -34,16 +38,16 @@ type TileCacheRecord struct {
|
||||
type Region struct {
|
||||
RegionPath string
|
||||
LevelType d2datadict.LevelTypeRecord
|
||||
levelPreset *d2datadict.LevelPresetRecord
|
||||
levelPreset d2datadict.LevelPresetRecord
|
||||
TileWidth int32
|
||||
TileHeight int32
|
||||
Tiles []d2data.Tile
|
||||
DS1 *d2data.DS1
|
||||
Tiles []d2dt1.Tile
|
||||
DS1 d2ds1.DS1
|
||||
Palette d2datadict.PaletteRec
|
||||
FloorCache map[uint32]*TileCacheRecord
|
||||
ShadowCache map[uint32]*TileCacheRecord
|
||||
WallCache map[uint32]*TileCacheRecord
|
||||
AnimationEntities []*d2render.AnimatedEntity
|
||||
AnimationEntities []d2render.AnimatedEntity
|
||||
NPCs []*d2core.NPC
|
||||
StartX float64
|
||||
StartY float64
|
||||
@ -101,7 +105,7 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP
|
||||
result := &Region{
|
||||
LevelType: d2datadict.LevelTypes[levelType],
|
||||
levelPreset: d2datadict.LevelPresets[levelPreset],
|
||||
Tiles: make([]d2data.Tile, 0),
|
||||
Tiles: make([]d2dt1.Tile, 0),
|
||||
FloorCache: make(map[uint32]*TileCacheRecord),
|
||||
ShadowCache: make(map[uint32]*TileCacheRecord),
|
||||
WallCache: make(map[uint32]*TileCacheRecord),
|
||||
@ -119,7 +123,7 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP
|
||||
if len(levelTypeDt1) == 0 || levelTypeDt1 == "" || levelTypeDt1 == "0" {
|
||||
continue
|
||||
}
|
||||
dt1 := d2data.LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider)
|
||||
dt1 := d2dt1.LoadDT1("/data/global/tiles/"+levelTypeDt1, fileProvider)
|
||||
result.Tiles = append(result.Tiles, dt1.Tiles...)
|
||||
}
|
||||
levelFilesToPick := make([]string, 0)
|
||||
@ -133,7 +137,7 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP
|
||||
levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * random.Float64()))
|
||||
levelFile := levelFilesToPick[levelIndex]
|
||||
result.RegionPath = levelFile
|
||||
result.DS1 = d2data.LoadDS1("/data/global/tiles/"+levelFile, fileProvider)
|
||||
result.DS1 = d2ds1.LoadDS1("/data/global/tiles/"+levelFile, fileProvider)
|
||||
result.TileWidth = result.DS1.Width
|
||||
result.TileHeight = result.DS1.Height
|
||||
result.loadObjects(fileProvider)
|
||||
@ -143,7 +147,7 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP
|
||||
func (v *Region) loadObjects(fileProvider d2interface.FileProvider) {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(v.DS1.Objects))
|
||||
v.AnimationEntities = make([]*d2render.AnimatedEntity, 0)
|
||||
v.AnimationEntities = make([]d2render.AnimatedEntity, 0)
|
||||
v.NPCs = make([]*d2core.NPC, 0)
|
||||
for _, object := range v.DS1.Objects {
|
||||
go func(object d2data.Object) {
|
||||
@ -181,7 +185,7 @@ func (v *Region) RenderTile(offsetX, offsetY, tileX, tileY int, layerType Region
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Region) getTile(mainIndex, subIndex, orientation int32) *d2data.Tile {
|
||||
func (v *Region) getTile(mainIndex, subIndex, orientation int32) *d2dt1.Tile {
|
||||
// TODO: Need to support randomly grabbing tile based on x/y as there can be multiple matches for same main/sub index
|
||||
for _, tile := range v.Tiles {
|
||||
if tile.MainIndex != mainIndex || tile.SubIndex != subIndex || tile.Orientation != orientation {
|
||||
@ -193,7 +197,7 @@ func (v *Region) getTile(mainIndex, subIndex, orientation int32) *d2data.Tile {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Region) renderFloor(tile d2data.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
|
||||
func (v *Region) renderFloor(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
|
||||
tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8)
|
||||
tileCache, exists := v.FloorCache[tileCacheIndex]
|
||||
if !exists {
|
||||
@ -208,7 +212,7 @@ func (v *Region) renderFloor(tile d2data.FloorShadowRecord, offsetX, offsetY int
|
||||
target.DrawImage(tileCache.Image, opts)
|
||||
}
|
||||
|
||||
func (v *Region) renderWall(tile d2data.WallRecord, offsetX, offsetY int, target *ebiten.Image) {
|
||||
func (v *Region) renderWall(tile d2ds1.WallRecord, offsetX, offsetY int, target *ebiten.Image) {
|
||||
tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8) | (uint32(tile.Orientation))
|
||||
tileCache, exists := v.WallCache[tileCacheIndex]
|
||||
if !exists {
|
||||
@ -223,7 +227,7 @@ func (v *Region) renderWall(tile d2data.WallRecord, offsetX, offsetY int, target
|
||||
target.DrawImage(tileCache.Image, opts)
|
||||
}
|
||||
|
||||
func (v *Region) renderShadow(tile d2data.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
|
||||
func (v *Region) renderShadow(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
|
||||
tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + 0
|
||||
tileCache, exists := v.ShadowCache[tileCacheIndex]
|
||||
if !exists {
|
||||
@ -239,9 +243,9 @@ func (v *Region) renderShadow(tile d2data.FloorShadowRecord, offsetX, offsetY in
|
||||
target.DrawImage(tileCache.Image, opts)
|
||||
}
|
||||
|
||||
func (v *Region) decodeTileGfxData(blocks []d2data.Block, pixels []byte, tileYOffset int32, tileWidth int32) {
|
||||
func (v *Region) decodeTileGfxData(blocks []d2dt1.Block, pixels []byte, tileYOffset int32, tileWidth int32) {
|
||||
for _, block := range blocks {
|
||||
if block.Format == d2data.BlockFormatIsometric {
|
||||
if block.Format == d2dt1.BlockFormatIsometric {
|
||||
// 3D isometric decoding
|
||||
xjump := []int32{14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14}
|
||||
nbpix := []int32{4, 8, 12, 16, 20, 24, 28, 32, 28, 24, 20, 16, 12, 8, 4}
|
||||
@ -311,7 +315,7 @@ func (v *Region) decodeTileGfxData(blocks []d2data.Block, pixels []byte, tileYOf
|
||||
}
|
||||
}
|
||||
|
||||
func (v *Region) generateFloorCache(tile d2data.FloorShadowRecord) *TileCacheRecord {
|
||||
func (v *Region) generateFloorCache(tile d2ds1.FloorShadowRecord) *TileCacheRecord {
|
||||
tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 0)
|
||||
if tileData == nil {
|
||||
log.Fatalf("Could not locate tile Idx:%d, Sub: %d, Ori: %d", tile.MainIndex, tile.SubIndex, 0)
|
||||
@ -329,7 +333,7 @@ func (v *Region) generateFloorCache(tile d2data.FloorShadowRecord) *TileCacheRec
|
||||
return &TileCacheRecord{image, 0, 0}
|
||||
}
|
||||
|
||||
func (v *Region) generateShadowCache(tile d2data.FloorShadowRecord) *TileCacheRecord {
|
||||
func (v *Region) generateShadowCache(tile d2ds1.FloorShadowRecord) *TileCacheRecord {
|
||||
tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 13)
|
||||
if tileData == nil {
|
||||
return nil
|
||||
@ -349,12 +353,12 @@ func (v *Region) generateShadowCache(tile d2data.FloorShadowRecord) *TileCacheRe
|
||||
return &TileCacheRecord{image, 0, int(tileMinY) + 80}
|
||||
}
|
||||
|
||||
func (v *Region) generateWallCache(tile d2data.WallRecord) *TileCacheRecord {
|
||||
func (v *Region) generateWallCache(tile d2ds1.WallRecord) *TileCacheRecord {
|
||||
tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(tile.Orientation))
|
||||
if tileData == nil {
|
||||
return nil
|
||||
}
|
||||
var newTileData *d2data.Tile = nil
|
||||
var newTileData *d2dt1.Tile = nil
|
||||
if tile.Orientation == 3 {
|
||||
newTileData = v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(4))
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ type FontSize struct {
|
||||
|
||||
// Font represents a font
|
||||
type Font struct {
|
||||
fontSprite *d2render.Sprite
|
||||
fontSprite d2render.Sprite
|
||||
metrics map[uint8]FontSize
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ const (
|
||||
// Manager represents the UI manager
|
||||
type Manager struct {
|
||||
widgets []Widget
|
||||
cursorSprite *d2render.Sprite
|
||||
cursorSprite d2render.Sprite
|
||||
cursorButtons CursorButton
|
||||
pressedIndex int
|
||||
CursorX int
|
||||
|
4
main.go
4
main.go
@ -20,7 +20,7 @@ var GitBranch string
|
||||
|
||||
// GitCommit is set by the CI build process to the commit hash
|
||||
var GitCommit string
|
||||
var d2Engine *d2core.Engine
|
||||
var d2Engine d2core.Engine
|
||||
|
||||
func main() {
|
||||
//defer profile.Start(profile.CPUProfile).Stop()
|
||||
@ -39,7 +39,7 @@ func main() {
|
||||
}
|
||||
d2mpq.InitializeCryptoBuffer()
|
||||
d2Engine = d2core.CreateEngine()
|
||||
d2Engine.SetNextScene(d2scene.CreateMainMenu(d2Engine, d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
|
||||
d2Engine.SetNextScene(d2scene.CreateMainMenu(&d2Engine, &d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
|
||||
ebiten.SetCursorVisible(false)
|
||||
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
|
||||
ebiten.SetRunnableInBackground(d2Engine.Settings.RunInBackground)
|
||||
|
@ -6,7 +6,9 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2data"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2cof"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2dcc"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||
|
||||
@ -36,12 +38,12 @@ func TestMPQScanPerformance(t *testing.T) {
|
||||
parts := strings.Split(archiveFile, ".")
|
||||
switch strings.ToLower(parts[len(parts)-1]) {
|
||||
case "coff":
|
||||
_ = d2data.LoadCof(archiveFile, engine)
|
||||
_ = d2cof.LoadCOF(archiveFile, engine)
|
||||
case "dcc":
|
||||
if strings.ContainsAny(archiveFile, "common") {
|
||||
continue
|
||||
}
|
||||
_ = d2data.LoadDCC(archiveFile, engine)
|
||||
_ = d2dcc.LoadDCC(archiveFile, engine)
|
||||
}
|
||||
|
||||
_, _ = archive.ReadFile(archiveFile)
|
||||
|
Loading…
x
Reference in New Issue
Block a user