diff --git a/Common/LevelPresets.go b/Common/LevelPresets.go index f6853996..37f74e6a 100644 --- a/Common/LevelPresets.go +++ b/Common/LevelPresets.go @@ -26,15 +26,17 @@ type LevelPresetRecord struct { Dt1Mask uint32 } -var LevelPresets []LevelPresetRecord +var LevelPresets map[int]*LevelPresetRecord func LoadLevelPresets(fileProvider FileProvider) { levelTypesData := fileProvider.LoadFile(ResourcePaths.LevelPreset) sr := CreateStreamReader(levelTypesData) - numRecords := sr.GetInt32() - LevelPresets = make([]LevelPresetRecord, numRecords) - for i := range LevelPresets { - LevelPresets[i].DefinitionId = sr.GetInt32() + sr.SkipBytes(4) // Count + LevelPresets = make(map[int]*LevelPresetRecord) + for !sr.Eof() { + i := int(sr.GetInt32()) + LevelPresets[i] = &LevelPresetRecord{} + LevelPresets[i].DefinitionId = int32(i) LevelPresets[i].LevelId = sr.GetInt32() LevelPresets[i].Populate = sr.GetInt32() != 0 LevelPresets[i].Logicals = sr.GetInt32() != 0 diff --git a/Map/DS1.go b/Map/DS1.go index 0b21b5f1..d11420ea 100644 --- a/Map/DS1.go +++ b/Map/DS1.go @@ -33,7 +33,7 @@ type FloorShadowRecord struct { Unknown1 byte MainIndex byte Unknown2 byte - Hidden byte + Hidden bool } type WallRecord struct { @@ -44,7 +44,7 @@ type WallRecord struct { Unknown1 byte MainIndex byte Unknown2 byte - Hidden byte + Hidden bool } type SubstitutionRecord struct { @@ -199,7 +199,7 @@ func LoadDS1(path string, fileProvider Common.FileProvider) *DS1 { 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) + ds1.Tiles[y][x].Walls[wallIndex].Hidden = byte((dw&0x80000000)>>31) > 0 case LayerStreamOrientation1: fallthrough case LayerStreamOrientation2: @@ -225,14 +225,14 @@ func LoadDS1(path string, fileProvider Common.FileProvider) *DS1 { 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) + ds1.Tiles[y][x].Floors[floorIndex].Hidden = byte((dw&0x80000000)>>31) > 0 case 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) + ds1.Tiles[y][x].Shadows[0].Hidden = byte((dw&0x80000000)>>31) > 0 case LayerStreamSubstitute: ds1.Tiles[y][x].Substitutions[0].Unknown = dw } diff --git a/Map/Engine.go b/Map/Engine.go index 10e77c7f..ddad265c 100644 --- a/Map/Engine.go +++ b/Map/Engine.go @@ -49,7 +49,24 @@ func (v *Engine) Render(target *ebiten.Image) { offX := -(y * 80) offY := y * 40 for x := 0; x < int(v.regions[0].Region.TileWidth); x++ { - v.regions[0].Region.RenderTile(400+offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeFloors, 0, target) + tile := v.regions[0].Region.DS1.Tiles[y][x] + for i := range tile.Floors { + v.regions[0].Region.RenderTile(400+offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeFloors, i, target) + } + offX += 80 + offY += 40 + } + } + + for y := 0; y < int(v.regions[0].Region.TileHeight); y++ { + offX := -(y * 80) + offY := y * 40 + for x := 0; x < int(v.regions[0].Region.TileWidth); x++ { + tile := v.regions[0].Region.DS1.Tiles[y][x] + for i := range tile.Walls { + // TODO: render back walls, then character, then fore walls + v.regions[0].Region.RenderTile(400+offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeWalls, i, target) + } offX += 80 offY += 40 } diff --git a/Map/Region.go b/Map/Region.go index b1e2d1d4..316c3d82 100644 --- a/Map/Region.go +++ b/Map/Region.go @@ -1,7 +1,6 @@ package Map import ( - "log" "math" "math/rand" "strconv" @@ -21,7 +20,7 @@ type TileCacheRecord struct { type Region struct { levelType Common.LevelTypeRecord - levelPreset Common.LevelPresetRecord + levelPreset *Common.LevelPresetRecord TileWidth int32 TileHeight int32 Tiles []Tile @@ -40,41 +39,41 @@ const ( type RegionIdType int const ( - RegionNoneRegionAct1Town = 1 - RegionAct1Wilderness RegionIdType = 2 - RegionAct1Cave RegionIdType = 3 - RegionAct1Crypt RegionIdType = 4 - RegionAct1Monestary RegionIdType = 5 - RegionAct1Courtyard RegionIdType = 6 - RegionAct1Barracks RegionIdType = 7 - RegionAct1Jail RegionIdType = 8 - RegionAct1Cathedral RegionIdType = 9 - RegionAct1Catacombs RegionIdType = 10 - RegionAct1Tristram RegionIdType = 11 - RegionAct2Town RegionIdType = 12 - RegionAct2Sewer RegionIdType = 13 - RegionAct2Harem RegionIdType = 14 - RegionAct2Basement RegionIdType = 15 - RegionAct2Desert RegionIdType = 16 - RegionAct2Tomb RegionIdType = 17 - RegionAct2Lair RegionIdType = 18 - RegionAct2Arcane RegionIdType = 19 - RegionAct3Town RegionIdType = 20 - RegionAct3Jungle RegionIdType = 21 - RegionAct3Kurast RegionIdType = 22 - RegionAct3Spider RegionIdType = 23 - RegionAct3Dungeon RegionIdType = 24 - RegionAct3Sewer RegionIdType = 25 - RegionAct4Town RegionIdType = 26 - RegionAct4Mesa RegionIdType = 27 - RegionAct4Lava RegionIdType = 28 - RegonAct5Town RegionIdType = 29 - RegionAct5Siege RegionIdType = 30 - RegionAct5Barricade RegionIdType = 31 - RegionAct5Temple RegionIdType = 32 - RegionAct5IceCaves RegionIdType = 33 - RegionAct5Baal RegionIdType = 34 - RegionAct5Lava RegionIdType = 35 + RegionAct1Town RegionIdType = 1 + RegionAct1Wilderness RegionIdType = 2 + RegionAct1Cave RegionIdType = 3 + RegionAct1Crypt RegionIdType = 4 + RegionAct1Monestary RegionIdType = 5 + RegionAct1Courtyard RegionIdType = 6 + RegionAct1Barracks RegionIdType = 7 + RegionAct1Jail RegionIdType = 8 + RegionAct1Cathedral RegionIdType = 9 + RegionAct1Catacombs RegionIdType = 10 + RegionAct1Tristram RegionIdType = 11 + RegionAct2Town RegionIdType = 12 + RegionAct2Sewer RegionIdType = 13 + RegionAct2Harem RegionIdType = 14 + RegionAct2Basement RegionIdType = 15 + RegionAct2Desert RegionIdType = 16 + RegionAct2Tomb RegionIdType = 17 + RegionAct2Lair RegionIdType = 18 + RegionAct2Arcane RegionIdType = 19 + RegionAct3Town RegionIdType = 20 + RegionAct3Jungle RegionIdType = 21 + RegionAct3Kurast RegionIdType = 22 + RegionAct3Spider RegionIdType = 23 + RegionAct3Dungeon RegionIdType = 24 + RegionAct3Sewer RegionIdType = 25 + RegionAct4Town RegionIdType = 26 + RegionAct4Mesa RegionIdType = 27 + RegionAct4Lava RegionIdType = 28 + RegonAct5Town RegionIdType = 29 + RegionAct5Siege RegionIdType = 30 + RegionAct5Barricade RegionIdType = 31 + RegionAct5Temple RegionIdType = 32 + RegionAct5IceCaves RegionIdType = 33 + RegionAct5Baal RegionIdType = 34 + RegionAct5Lava RegionIdType = 35 ) func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileProvider Common.FileProvider) *Region { @@ -85,13 +84,15 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP TileCache: make(map[uint32]*TileCacheRecord), } result.Palette = Common.Palettes[PaletteDefs.PaletteType("act"+strconv.Itoa(int(result.levelType.Act)))] - bm := result.levelPreset.Dt1Mask + //\bm := result.levelPreset.Dt1Mask for _, levelTypeDt1 := range result.levelType.Files { - if bm&1 == 0 { + /* + if bm&1 == 0 { + bm >>= 1 + continue + } bm >>= 1 - continue - } - bm >>= 1 + */ if len(levelTypeDt1) == 0 || levelTypeDt1 == "" || levelTypeDt1 == "0" { continue } @@ -124,45 +125,60 @@ 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) *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 { continue } - return tile + return &tile } - log.Fatalf("Unknown tile ID [%d %d %d]", mainIndex, subIndex, orientation) - return Tile{} + //log.Fatalf("Unknown tile ID [%d %d %d]", mainIndex, subIndex, orientation) + return nil } func (v *Region) renderFloor(tile FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) { + if tile.Hidden { + return + } tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) tileCache := v.TileCache[tileCacheIndex] if tileCache == nil { v.TileCache[tileCacheIndex] = v.generateFloorCache(tile) tileCache = v.TileCache[tileCacheIndex] } + if tileCache == nil { + return + } + opts := &ebiten.DrawImageOptions{} + opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset)) + target.DrawImage(tileCache.Image, opts) +} + +func (v *Region) renderWall(tile WallRecord, offsetX, offsetY int, target *ebiten.Image) { + if tile.Hidden { + return + } + if tile.Prop1 == 0 { + return + } + tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + (uint32(tile.Orientation)) + tileCache := v.TileCache[tileCacheIndex] + if tileCache == nil { + v.TileCache[tileCacheIndex] = v.generateWallCache(tile) + // TODO: Temporary hack + if v.TileCache[tileCacheIndex] == nil { + return + } + tileCache = v.TileCache[tileCacheIndex] + } opts := &ebiten.DrawImageOptions{} opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset)) target.DrawImage(tileCache.Image, opts) } -func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { - var pixels []byte - - tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 0) - tileYMinimum := int32(0) - for _, block := range tileData.Blocks { - tileYMinimum = Common.MinInt32(tileYMinimum, int32(block.Y)) - } - tileYOffset := Common.AbsInt32(tileYMinimum) - - tileHeight := Common.AbsInt32(tileData.Height) - image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest) - special := false - pixels = make([]byte, 4*tileData.Width*tileHeight) - for _, block := range tileData.Blocks { +func (v *Region) decodeFloorData(blocks []Block, pixels []byte, tileYOffset int32, tileWidth int32) { + for _, block := range blocks { // TODO: Move this to a less stupid place if block.Format == BlockFormatIsometric { // 3D isometric decoding @@ -182,12 +198,12 @@ func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { colorIndex := block.EncodedData[idx] if colorIndex != 0 { pixelColor := v.Palette.Colors[colorIndex] - pixels[(4 * (((blockY + y) * tileData.Width) + (blockX + x)))] = pixelColor.R - pixels[(4*(((blockY+y)*tileData.Width)+(blockX+x)))+1] = pixelColor.G - pixels[(4*(((blockY+y)*tileData.Width)+(blockX+x)))+2] = pixelColor.B - pixels[(4*(((blockY+y)*tileData.Width)+(blockX+x)))+3] = 255 + pixels[(4 * (((blockY + y) * tileWidth) + (blockX + x)))] = pixelColor.R + pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+1] = pixelColor.G + pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+2] = pixelColor.B + pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+3] = 255 } else { - pixels[(4*(((blockY+y)*tileData.Width)+(blockX+x)))+3] = 0 + pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+3] = 0 } x++ n-- @@ -197,7 +213,6 @@ func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { } } else { // RLE Encoding - special = true blockX := int32(block.X) blockY := int32(block.Y) x := int32(0) @@ -220,12 +235,12 @@ func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { colorIndex := block.EncodedData[idx] if colorIndex != 0 { pixelColor := v.Palette.Colors[colorIndex] - pixels[(4 * (((blockY + y + tileYOffset) * tileData.Width) + (blockX + x)))] = pixelColor.R - pixels[(4*(((blockY+y+tileYOffset)*tileData.Width)+(blockX+x)))+1] = pixelColor.G - pixels[(4*(((blockY+y+tileYOffset)*tileData.Width)+(blockX+x)))+2] = pixelColor.B - pixels[(4*(((blockY+y+tileYOffset)*tileData.Width)+(blockX+x)))+3] = 255 + pixels[(4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x)))] = pixelColor.R + pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+1] = pixelColor.G + pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+2] = pixelColor.B + pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+3] = 255 } else { - pixels[(4*(((blockY+y+tileYOffset)*tileData.Width)+(blockX+x)))+3] = 0 + pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+3] = 0 } idx++ x++ @@ -234,18 +249,55 @@ func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { } } } +} + +func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord { + tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 0) + if tileData == nil { + return nil + } + tileYMinimum := int32(0) + for _, block := range tileData.Blocks { + tileYMinimum = Common.MinInt32(tileYMinimum, int32(block.Y)) + } + tileYOffset := Common.AbsInt32(tileYMinimum) + tileHeight := Common.AbsInt32(tileData.Height) + image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest) + pixels := make([]byte, 4*tileData.Width*tileHeight) + v.decodeFloorData(tileData.Blocks, pixels, tileYOffset, tileData.Width) image.ReplacePixels(pixels) - yOffset := 0 - if special { - yOffset = int(128 + tileData.Height) + return &TileCacheRecord{image, 0, 0} +} + +func (v *Region) generateWallCache(tile WallRecord) *TileCacheRecord { + tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(tile.Orientation)) + if tileData == nil { + return nil + } + tileYMinimum := int32(0) + for _, block := range tileData.Blocks { + tileYMinimum = Common.MinInt32(tileYMinimum, int32(block.Y)) + } + tileYOffset := -tileYMinimum + tileHeight := Common.AbsInt32(tileData.Height) + image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest) + pixels := make([]byte, 4*tileData.Width*tileHeight) + v.decodeFloorData(tileData.Blocks, pixels, tileYOffset, tileData.Width) + image.ReplacePixels(pixels) + yAdjust := 0 + if tile.Orientation == 15 { + // Roof + yAdjust = -int(tileData.RoofHeight) + } else if tile.Orientation > 15 { + // Lower walls + yAdjust = int(tileYMinimum) + 80 + } else { + // Upper Walls + yAdjust = int(tileYMinimum) + 80 } return &TileCacheRecord{ image, - int(tileData.Width), - yOffset, + 0, + yAdjust, } } - -func (v *Region) renderWall(tile WallRecord, offsetX, offsetY int, target *ebiten.Image) { - -} diff --git a/Scenes/MapEngineTest.go b/Scenes/MapEngineTest.go index 21dcbdd0..ce41091a 100644 --- a/Scenes/MapEngineTest.go +++ b/Scenes/MapEngineTest.go @@ -40,7 +40,21 @@ func (v *MapEngineTest) Load() []func() { return []func(){ func() { v.mapEngine = Map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider) - v.mapEngine.GenerateMap(Map.RegionAct1Tristram, 300) + //v.mapEngine.GenerateMap(Map.RegionAct2Harem, 353) + v.mapEngine.GenerateMap(Map.RegionAct1Town, 1) + //v.mapEngine.GenerateMap(Map.RegionAct1Tristram, 300) + + //v.mapEngine.GenerateMap(Map.RegionAct3Town, 529) + //v.mapEngine.GenerateMap(Map.RegionAct1Cathedral, 257) + //v.mapEngine.GenerateMap(Map.RegionAct5IceCaves, 1038) + //v.mapEngine.GenerateMap(Map.RegionAct3Jungle, 574) + + // Completely broken ---------------------------------------------- + //v.mapEngine.GenerateMap(Map.RegonAct5Town, 863) // CRASHES + // v.mapEngine.GenerateMap(Map.RegionAct5Siege, 879) // CRASHES + //v.mapEngine.GenerateMap(Map.RegionAct5Lava, 1057) // PALETTE ISSUE + // v.mapEngine.GenerateMap(Map.RegionAct2Town, 301) // Really broken rendering + }, } }