diff --git a/Common/LevelPresets.go b/Common/LevelPresets.go new file mode 100644 index 00000000..b9043c40 --- /dev/null +++ b/Common/LevelPresets.go @@ -0,0 +1,66 @@ +package Common + +import ( + "log" + "strings" + + "github.com/essial/OpenDiablo2/ResourcePaths" +) + +type LevelPresetRecord struct { + DefinitionId int32 + LevelId int32 + Populate bool + Logicals bool + Outdoors bool + Animate bool + KillEdge bool + FillBlanks bool + SizeX int32 + SizeY int32 + AutoMap bool + Scan bool + Pops int32 + PopPad int32 + Files [6]string + Dt1Mask uint32 +} + +var LevelPresets []LevelPresetRecord + +func LoadLevelPresets(fileProvider FileProvider) { + LevelPresets = make([]LevelPresetRecord, 0) + levelTypesData := fileProvider.LoadFile(ResourcePaths.LevelPreset) + sr := CreateStreamReader(levelTypesData) + numRecords := sr.GetInt32() + LevelPresets = make([]LevelPresetRecord, numRecords) + for i := range LevelPresets { + LevelPresets[i].DefinitionId = sr.GetInt32() + LevelPresets[i].LevelId = sr.GetInt32() + LevelPresets[i].Populate = sr.GetInt32() != 0 + LevelPresets[i].Logicals = sr.GetInt32() != 0 + LevelPresets[i].Outdoors = sr.GetInt32() != 0 + LevelPresets[i].Animate = sr.GetInt32() != 0 + LevelPresets[i].KillEdge = sr.GetInt32() != 0 + LevelPresets[i].FillBlanks = sr.GetInt32() != 0 + LevelPresets[i].SizeX = sr.GetInt32() + LevelPresets[i].SizeY = sr.GetInt32() + LevelPresets[i].AutoMap = sr.GetInt32() != 0 + LevelPresets[i].Scan = sr.GetInt32() != 0 + LevelPresets[i].Pops = sr.GetInt32() + LevelPresets[i].PopPad = sr.GetInt32() + sr.GetInt32() + for fileIdx := 0; fileIdx < 6; fileIdx++ { + strData, _ := sr.ReadBytes(60) + s := strings.Trim(string(strData), string(0)) + if s == "0" { + LevelPresets[i].Files[fileIdx] = "" + } else { + LevelPresets[i].Files[fileIdx] = s + } + + } + LevelPresets[i].Dt1Mask = sr.GetUInt32() + } + log.Printf("Loaded %d LevelPreset records") +} diff --git a/Common/LevelTypes.go b/Common/LevelTypes.go new file mode 100644 index 00000000..5e3f451b --- /dev/null +++ b/Common/LevelTypes.go @@ -0,0 +1,38 @@ +package Common + +import ( + "log" + "strings" + + "github.com/essial/OpenDiablo2/ResourcePaths" +) + +type LevelTypeRecord struct { + Files [32]string + Act int32 +} + +var LevelTypes []LevelTypeRecord + +func LoadLevelTypes(fileProvider FileProvider) { + LevelTypes = make([]LevelTypeRecord, 0) + levelTypesData := fileProvider.LoadFile(ResourcePaths.LevelType) + sr := CreateStreamReader(levelTypesData) + numRecords := sr.GetInt32() + LevelTypes = make([]LevelTypeRecord, numRecords) + for i := range LevelTypes { + for fileIdx := 0; fileIdx < 32; fileIdx++ { + strData, _ := sr.ReadBytes(60) + s := strings.Trim(string(strData), string(0)) + if s == "0" { + LevelTypes[i].Files[fileIdx] = "" + } else { + LevelTypes[i].Files[fileIdx] = s + } + + } + LevelTypes[i].Act = int32(sr.GetByte()) + + } + log.Printf("Loaded %d LevelType records", numRecords) +} diff --git a/Common/StreamReader.go b/Common/StreamReader.go index cbb62b33..bb4b9ddf 100644 --- a/Common/StreamReader.go +++ b/Common/StreamReader.go @@ -110,6 +110,10 @@ func (v *StreamReader) ReadBytes(count int) ([]byte, error) { return result, nil } +func (v *StreamReader) SkipBytes(count int) { + v.position += uint64(count) +} + // Read implements io.Reader func (v *StreamReader) Read(p []byte) (n int, err error) { streamLength := v.GetSize() diff --git a/Core/Engine.go b/Core/Engine.go index dac5b244..a63906dc 100644 --- a/Core/Engine.go +++ b/Core/Engine.go @@ -61,6 +61,8 @@ func CreateEngine() *Engine { result.loadPalettes() result.loadSoundEntries() Common.LoadTextDictionary(result) + Common.LoadLevelTypes(result) + //Common.LoadLevelPresets(result) result.SoundManager = Sound.CreateManager(result) result.SoundManager.SetVolumes(result.Settings.BgmVolume, result.Settings.SfxVolume) result.UIManager = UI.CreateManager(result, *result.SoundManager) diff --git a/MPQ/MPQ.go b/MPQ/MPQ.go index bee3cd88..0bd3294c 100644 --- a/MPQ/MPQ.go +++ b/MPQ/MPQ.go @@ -232,7 +232,7 @@ func (v *MPQ) Close() { func (v MPQ) ReadFile(fileName string) ([]byte, error) { fileBlockData, err := v.GetFileBlockData(fileName) if err != nil { - return nil, err + log.Panic(err) } fileBlockData.FileName = strings.ToLower(fileName) fileBlockData.calculateEncryptionSeed() diff --git a/MapEngine/DS1.go b/MapEngine/DS1.go index 57546e43..3a95a5fe 100644 --- a/MapEngine/DS1.go +++ b/MapEngine/DS1.go @@ -136,7 +136,7 @@ func LoadDS1(path string, fileProvider Common.FileProvider) *DS1 { } if ds1.Version >= 9 && ds1.Version <= 13 { // Skipping two dwords because they are "meaningless"? - _, _ = br.ReadBytes(16) + br.SkipBytes(16) } if ds1.Version >= 4 { ds1.NumberOfWalls = br.GetInt32() @@ -297,9 +297,9 @@ func LoadDS1(path string, fileProvider Common.FileProvider) *DS1 { } } else { if ds1.Version >= 15 { - _, _ = br.ReadBytes(int(numPaths) * 3) + br.SkipBytes(int(numPaths) * 3) } else { - _, _ = br.ReadBytes(int(numPaths) * 2) + br.SkipBytes(int(numPaths) * 2) } } } diff --git a/MapEngine/DT1.go b/MapEngine/DT1.go new file mode 100644 index 00000000..49e48369 --- /dev/null +++ b/MapEngine/DT1.go @@ -0,0 +1,101 @@ +package MapEngine + +import ( + "log" + + "github.com/essial/OpenDiablo2/Common" +) + +// https://d2mods.info/forum/viewtopic.php?t=65163 + +type Block struct { + X int16 + Y int16 + GridX byte + GridY byte + Format int16 + Length int32 + FileOffset int32 +} + +type Tile struct { + Direction int32 + RoofHeight int16 + SoundIndex byte + Animated byte + 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 +} + +func LoadDT1(path string, fileProvider Common.FileProvider) *DT1 { + result := &DT1{} + fileData := fileProvider.LoadFile(path) + br := Common.CreateStreamReader(fileData) + ver1 := br.GetInt32() + ver2 := br.GetInt32() + if ver1 != 7 || ver2 != 6 { + log.Panicf("Expected %s to have a version of 7.6, but got %d.%d instead", path, ver1, ver2) + } + br.SkipBytes(260) + numberOfTiles := br.GetInt32() + br.SkipBytes(4) + result.Tiles = make([]Tile, numberOfTiles) + for tileIdx := range result.Tiles { + newTile := Tile{} + newTile.Direction = br.GetInt32() + newTile.RoofHeight = br.GetInt16() + newTile.SoundIndex = br.GetByte() + newTile.Animated = br.GetByte() + newTile.Height = br.GetInt32() + newTile.Width = br.GetInt32() + br.SkipBytes(4) + newTile.Orientation = br.GetInt32() + newTile.MainIndex = br.GetInt32() + newTile.SubIndex = br.GetInt32() + newTile.RarityFrameIndex = br.GetInt32() + br.SkipBytes(4) + for i := range newTile.SubTileFlags { + newTile.SubTileFlags[i] = br.GetByte() + } + br.SkipBytes(7) + newTile.blockHeaderPointer = br.GetInt32() + newTile.blockHeaderSize = br.GetInt32() + newTile.blocks = make([]Block, br.GetInt32()) + br.SkipBytes(12) + result.Tiles[tileIdx] = newTile + } + for tileIdx, tile := range result.Tiles { + br.SetPosition(uint64(tile.blockHeaderPointer)) + for blockIdx := range tile.blocks { + result.Tiles[tileIdx].blocks[blockIdx].X = br.GetInt16() + result.Tiles[tileIdx].blocks[blockIdx].Y = br.GetInt16() + br.SkipBytes(2) + result.Tiles[tileIdx].blocks[blockIdx].GridX = br.GetByte() + result.Tiles[tileIdx].blocks[blockIdx].GridY = br.GetByte() + result.Tiles[tileIdx].blocks[blockIdx].Format = br.GetInt16() + result.Tiles[tileIdx].blocks[blockIdx].Length = br.GetInt32() + br.SkipBytes(2) + result.Tiles[tileIdx].blocks[blockIdx].FileOffset = br.GetInt32() + } + /* + for blockIdx, block := range tile.blocks { + br.SetPosition(uint64(tile.blockHeaderPointer + block.FileOffset)) + encodedData, _ := br.ReadBytes(block.Length) + bs := Common.CreateBitStream(encodedData) + } + */ + } + return result +} diff --git a/MapEngine/Orientation.go b/MapEngine/Orientation.go new file mode 100644 index 00000000..0ae335c8 --- /dev/null +++ b/MapEngine/Orientation.go @@ -0,0 +1,26 @@ +package MapEngine + +type Orientation int32 + +const ( + Floors Orientation = 0 + LeftWall Orientation = 1 + RightWall Orientation = 2 + RightPartOfNorthCornerWall Orientation = 3 + LeftPartOfNorthCornerWall Orientation = 4 + LeftEndWall Orientation = 5 + RightEndWall Orientation = 6 + SouthCornerWall Orientation = 7 + LeftWallWithDoor Orientation = 8 + RightWallWithDoor Orientation = 9 + SpecialTile1 Orientation = 10 + SpecialTile2 Orientation = 11 + PillarsColumnsAndStandaloneObjects Orientation = 12 + Shadows Orientation = 13 + Trees Orientation = 14 + Roofs Orientation = 15 + LowerWallsEquivalentToLeftWall Orientation = 16 + LowerWallsEquivalentToRightWall Orientation = 17 + LowerWallsEquivalentToRightLeftNorthCornerWall Orientation = 18 + LowerWallsEquivalentToSouthCornerwall Orientation = 19 +) diff --git a/ResourcePaths/ResourcePaths.go b/ResourcePaths/ResourcePaths.go index 634e15b5..171347ed 100644 --- a/ResourcePaths/ResourcePaths.go +++ b/ResourcePaths/ResourcePaths.go @@ -159,10 +159,10 @@ const ( ExpansionStringTable = "/data/local/lng/eng/expansionstring.tbl" StringTable = "/data/local/lng/eng/string.tbl" PatchStringTable = "/data/local/lng/eng/patchstring.tbl" - LevelPreset = "/data/global/excel/LvlPrest.txt" - LevelType = "/data/global/excel/LvlTypes.txt" - LevelDetails = "/data/global/excel/Levels.txt" - ObjectDetails = "/data/global/excel/Objects.txt" + LevelPreset = "/data/global/excel/LvlPrest.bin" + LevelType = "/data/global/excel/LvlTypes.bin" + LevelDetails = "/data/global/excel/Levels.bin" + ObjectDetails = "/data/global/excel/Objects.bin" SoundSettings = "/data/global/excel/Sounds.txt" // --- Animations --- diff --git a/Scenes/MapEngineTest.go b/Scenes/MapEngineTest.go index 5d3f2614..e7fb2245 100644 --- a/Scenes/MapEngineTest.go +++ b/Scenes/MapEngineTest.go @@ -29,7 +29,8 @@ func (v *MapEngineTest) Load() []func() { v.soundManager.PlayBGM("") return []func(){ func() { - _ = MapEngine.LoadDS1("/data/global/tiles/ACT1/town/townE1.ds1", v.fileProvider) + //_ = MapEngine.LoadDS1("/data/global/tiles/ACT1/town/townE1.ds1", v.fileProvider) + _ = MapEngine.LoadDT1("/data/global/tiles/ACT1/town/floor.dt1", v.fileProvider) }, } }