Switcher with presets & better tiles randomizing (#173)

* tile choice algo
* cycle region files
* switcher limited by preset
This commit is contained in:
Averrin 2019-11-17 06:52:13 +01:00 committed by Tim Sarbin
parent 7222f57c2c
commit c3ba3f71e4
7 changed files with 273 additions and 94 deletions

View File

@ -181,7 +181,7 @@ func (v *MainMenu) Load() []func() {
}
func (v *MainMenu) onMapTestClicked() {
v.sceneProvider.SetNextScene(CreateMapEngineTest(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager, 0))
v.sceneProvider.SetNextScene(CreateMapEngineTest(v.fileProvider, v.sceneProvider, v.uiManager, v.soundManager, 0, 1))
}
func openbrowser(url string) {

View File

@ -21,6 +21,67 @@ import (
"github.com/hajimehoshi/ebiten/inpututil"
)
type RegionSpec struct {
regionType d2enum.RegionIdType
startPresetIndex int
endPresetIndex int
extra []int
}
var regions []RegionSpec = []RegionSpec{
//Act I
{d2enum.RegionAct1Town, 1, 3, []int{}},
{d2enum.RegionAct1Wilderness, 4, 52, []int{
108,
160, 161, 162, 163, 164,
}},
{d2enum.RegionAct1Cave, 53, 107, []int{}},
{d2enum.RegionAct1Crypt, 109, 159, []int{}},
{d2enum.RegionAct1Monestary, 165, 165, []int{}},
{d2enum.RegionAct1Courtyard, 166, 166, []int{256}},
{d2enum.RegionAct1Barracks, 167, 205, []int{}},
{d2enum.RegionAct1Jail, 206, 255, []int{}},
{d2enum.RegionAct1Cathedral, 257, 257, []int{}},
{d2enum.RegionAct1Catacombs, 258, 299, []int{}},
{d2enum.RegionAct1Tristram, 300, 300, []int{}},
//Act II
{d2enum.RegionAct2Town, 301, 301, []int{}},
{d2enum.RegionAct2Sewer, 302, 352, []int{}},
{d2enum.RegionAct2Harem, 353, 357, []int{}},
{d2enum.RegionAct2Basement, 358, 361, []int{}},
{d2enum.RegionAct2Desert, 362, 413, []int{}},
{d2enum.RegionAct2Tomb, 414, 481, []int{}},
{d2enum.RegionAct2Lair, 482, 509, []int{}},
{d2enum.RegionAct2Arcane, 510, 528, []int{}},
//Act III
{d2enum.RegionAct3Town, 529, 529, []int{}},
{d2enum.RegionAct3Jungle, 530, 604, []int{}},
{d2enum.RegionAct3Kurast, 605, 658, []int{
748, 749, 750, 751, 752, 753, 754,
755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796,
//yeah, i know =(
}},
{d2enum.RegionAct3Spider, 659, 664, []int{}},
{d2enum.RegionAct3Dungeon, 665, 704, []int{}},
{d2enum.RegionAct3Sewer, 705, 747, []int{}},
//Act IV
{d2enum.RegionAct4Town, 797, 798, []int{}},
{d2enum.RegionAct4Mesa, 799, 835, []int{}},
{d2enum.RegionAct4Lava, 836, 862, []int{}},
//Act V -- broken or wrong order
{d2enum.RegonAct5Town, 863, 864, []int{}},
{d2enum.RegionAct5Siege, 865, 879, []int{}},
{d2enum.RegionAct5Barricade, 880, 1002, []int{}},
{d2enum.RegionAct5IceCaves, 1003, 1041, []int{}},
{d2enum.RegionAct5Temple, 1042, 1052, []int{}},
{d2enum.RegionAct5Baal, 1059, 1090, []int{}},
{d2enum.RegionAct5Lava, 1053, 1058, []int{}},
}
type MapEngineTest struct {
uiManager *d2ui.Manager
soundManager *d2audio.Manager
@ -28,8 +89,15 @@ type MapEngineTest struct {
sceneProvider d2coreinterface.SceneProvider
gameState *d2core.GameState
mapEngine *_map.Engine
//TODO: this is region specific properties, should be refactored for multi-region rendering
currentRegion int
keyLocked bool
levelPreset int
fileIndex int
regionSpec RegionSpec
filesCount int
keyLocked bool
}
func CreateMapEngineTest(
@ -37,50 +105,56 @@ func CreateMapEngineTest(
sceneProvider d2coreinterface.SceneProvider,
uiManager *d2ui.Manager,
soundManager *d2audio.Manager,
currentRegion int) *MapEngineTest {
currentRegion int, levelPreset int) *MapEngineTest {
result := &MapEngineTest{
fileProvider: fileProvider,
uiManager: uiManager,
soundManager: soundManager,
sceneProvider: sceneProvider,
currentRegion: currentRegion,
levelPreset: levelPreset,
fileIndex: -1,
regionSpec: RegionSpec{},
filesCount: 0,
keyLocked: false,
}
result.gameState = d2core.CreateTestGameState()
return result
}
type RegionSpec struct {
regionType d2enum.RegionIdType
levelPreset int
}
func (v *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
for _, spec := range regions {
if spec.regionType == d2enum.RegionIdType(n) {
v.regionSpec = spec
inExtra := false
for _, e := range spec.extra {
if e == levelPreset {
inExtra = true
break
}
}
if !inExtra {
if levelPreset < spec.startPresetIndex {
levelPreset = spec.startPresetIndex
}
var regions []RegionSpec = []RegionSpec{
{d2enum.RegionAct1Tristram, 300},
{d2enum.RegionAct1Cathedral, 257},
{d2enum.RegionAct2Town, 301},
// {d2enum.RegionAct2Harem, 353},
{d2enum.RegionAct3Town, 529},
{d2enum.RegionAct3Jungle, 574},
{d2enum.RegionAct4Town, 797},
{d2enum.RegonAct5Town, 863},
{d2enum.RegionAct5IceCaves, 1038},
{d2enum.RegionAct5Siege, 879},
{d2enum.RegionAct5Lava, 105},
{d2enum.RegionAct5Barricade, 880},
}
if levelPreset > spec.endPresetIndex {
levelPreset = spec.endPresetIndex
}
}
v.levelPreset = levelPreset
}
}
func (v *MapEngineTest) LoadRegionByIndex(n int) {
if n == 0 {
v.mapEngine.GenerateAct1Overworld()
return
}
region := regions[n-1]
v.mapEngine = _map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider) // necessary for map name update
v.mapEngine.OffsetY = 0
v.mapEngine.OffsetX = 0
v.mapEngine.GenerateMap(region.regionType, region.levelPreset)
v.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex)
}
func (v *MapEngineTest) Load() []func() {
@ -91,21 +165,7 @@ func (v *MapEngineTest) Load() []func() {
func() {
v.mapEngine = _map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider)
v.LoadRegionByIndex(v.currentRegion)
// v.mapEngine.GenerateAct1Overworld()
// v.mapEngine.GenerateMap(d2enum.RegionAct1Tristram, 300)
// v.mapEngine.GenerateMap(d2enum.RegionAct1Cathedral, 257)
//v.mapEngine.GenerateMap(d2enum.RegionAct2Town, 301)
//v.mapEngine.GenerateMap(d2enum.RegionAct2Harem, 353) // Crashes on dcc load
//v.mapEngine.GenerateMap(d2enum.RegionAct3Town, 529)
//v.mapEngine.GenerateMap(d2enum.RegionAct3Jungle, 574)
//v.mapEngine.GenerateMap(d2enum.RegionAct4Town, 797) // Broken height of large objects
//v.mapEngine.GenerateMap(d2enum.RegonAct5Town, 863) // Completely broken!!
//v.mapEngine.GenerateMap(d2enum.RegionAct5IceCaves, 1038) // Completely broken!
//v.mapEngine.GenerateMap(d2enum.RegionAct5Siege, 879) // Completely broken!
//v.mapEngine.GenerateMap(d2enum.RegionAct5Lava, 1057) // Broken
//v.mapEngine.GenerateMap(d2enum.RegionAct5Barricade, 880) // Broken
v.LoadRegionByIndex(v.currentRegion, v.levelPreset, v.fileIndex)
},
}
}
@ -133,13 +193,34 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) {
int(math.Ceil(tileY))-curRegion.Rect.Top,
subtileY,
)
levelFilesToPick := make([]string, 0)
fileIndex := v.fileIndex
for n, fileRecord := range curRegion.Region.LevelPreset.Files {
if len(fileRecord) == 0 || fileRecord == "" || fileRecord == "0" {
continue
}
levelFilesToPick = append(levelFilesToPick, fileRecord)
if fileRecord == curRegion.Region.RegionPath {
fileIndex = n
}
}
if v.fileIndex == -1 {
v.fileIndex = fileIndex
}
v.filesCount = len(levelFilesToPick)
ebitenutil.DebugPrintAt(screen, line, 5, 5)
ebitenutil.DebugPrintAt(screen, "Map: "+curRegion.Region.LevelType.Name, 5, 17)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%v [%v]", curRegion.Region.RegionPath, v.currentRegion), 5, 29)
ebitenutil.DebugPrintAt(screen, "N - next map, P - previous map", 5, 41)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%v: %v/%v [%v, %v]", curRegion.Region.RegionPath, fileIndex+1, v.filesCount, v.currentRegion, v.levelPreset), 5, 29)
ebitenutil.DebugPrintAt(screen, "N - next region, P - previous region", 5, 41)
ebitenutil.DebugPrintAt(screen, "Shift+N - next preset, Shift+P - previous preset", 5, 53)
ebitenutil.DebugPrintAt(screen, "Ctrl+N - next file, Ctrl+P - previous file", 5, 65)
}
func (v *MapEngineTest) Update(tickTime float64) {
ctrlPressed := v.uiManager.KeyPressed(ebiten.KeyControl)
shiftPressed := v.uiManager.KeyPressed(ebiten.KeyShift)
if v.uiManager.KeyPressed(ebiten.KeyDown) {
v.mapEngine.OffsetY -= tickTime * 800
}
@ -164,26 +245,50 @@ func (v *MapEngineTest) Update(tickTime float64) {
if v.uiManager.KeyPressed(ebiten.KeyEscape) {
os.Exit(0)
}
if v.uiManager.KeyPressed(ebiten.KeyN) && !v.keyLocked {
v.currentRegion++
if v.currentRegion == len(regions) {
v.currentRegion = 0
}
v.keyLocked = true
fmt.Println("---")
v.sceneProvider.SetNextScene(v)
return
}
if v.uiManager.KeyPressed(ebiten.KeyP) && !v.keyLocked {
v.currentRegion--
if v.currentRegion == -1 {
v.currentRegion = len(regions) - 1
if !v.keyLocked {
if v.uiManager.KeyPressed(ebiten.KeyN) && ctrlPressed {
v.fileIndex = increment(v.fileIndex, 0, v.filesCount-1)
v.keyLocked = true
v.sceneProvider.SetNextScene(v)
return
}
if v.uiManager.KeyPressed(ebiten.KeyP) && ctrlPressed {
v.fileIndex = decrement(v.fileIndex, 0, v.filesCount-1)
v.keyLocked = true
v.sceneProvider.SetNextScene(v)
return
}
if v.uiManager.KeyPressed(ebiten.KeyN) && shiftPressed {
v.levelPreset = increment(v.levelPreset, v.regionSpec.startPresetIndex, v.regionSpec.endPresetIndex)
v.keyLocked = true
v.sceneProvider.SetNextScene(v)
return
}
if v.uiManager.KeyPressed(ebiten.KeyP) && shiftPressed {
v.levelPreset = decrement(v.levelPreset, v.regionSpec.startPresetIndex, v.regionSpec.endPresetIndex)
v.keyLocked = true
v.sceneProvider.SetNextScene(v)
return
}
if v.uiManager.KeyPressed(ebiten.KeyN) {
v.currentRegion = increment(v.currentRegion, 0, len(regions))
v.keyLocked = true
v.sceneProvider.SetNextScene(v)
return
}
if v.uiManager.KeyPressed(ebiten.KeyP) {
v.currentRegion = decrement(v.currentRegion, 0, len(regions))
v.keyLocked = true
v.sceneProvider.SetNextScene(v)
return
}
v.keyLocked = true
fmt.Println("---")
v.sceneProvider.SetNextScene(v)
return
}
//FIXME: do it better
@ -191,3 +296,19 @@ func (v *MapEngineTest) Update(tickTime float64) {
v.keyLocked = false
}
}
func increment(v, min, max int) int {
v++
if v > max {
return min
}
return v
}
func decrement(v, min, max int) int {
v--
if v < min {
return max
}
return v
}

View File

@ -214,6 +214,9 @@ func (v *AnimatedEntity) cacheFrames(layerName string) {
}
direction := dcc.Directions[v.direction]
if frameIndex >= len(direction.Frames) {
continue
}
frame := direction.Frames[frameIndex]
img := image.NewRGBA(image.Rect(0, 0, int(frameW), int(frameH)))
for y := 0; y < direction.Box.Height; y++ {

View File

@ -52,9 +52,10 @@ func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager,
return result
}
func (v *Engine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int) {
func (v *Engine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
randomSource := rand.NewSource(v.gameState.Seed)
region := LoadRegion(randomSource, regionType, levelPreset, v.fileProvider)
region := LoadRegion(randomSource, regionType, levelPreset, v.fileProvider, fileIndex)
fmt.Printf("Loading region: %v\n", region.RegionPath)
v.regions = append(v.regions, EngineRegion{
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
Region: region,
@ -68,19 +69,19 @@ func (v *Engine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int) {
func (v *Engine) GenerateAct1Overworld() {
v.soundManager.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
randomSource := rand.NewSource(v.gameState.Seed)
region := LoadRegion(randomSource, d2enum.RegionAct1Town, 1, v.fileProvider)
region := LoadRegion(randomSource, d2enum.RegionAct1Town, 1, v.fileProvider, -1)
v.regions = append(v.regions, EngineRegion{
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
Region: region,
})
if strings.Contains(region.RegionPath, "E1") {
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 2, v.fileProvider)
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 2, v.fileProvider, -1)
v.regions = append(v.regions, EngineRegion{
Rect: d2common.Rectangle{int(region.TileWidth - 1), 0, int(region2.TileWidth), int(region2.TileHeight)},
Region: region2,
})
} else if strings.Contains(region.RegionPath, "S1") {
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 3, v.fileProvider)
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 3, v.fileProvider, -1)
v.regions = append(v.regions, EngineRegion{
Rect: d2common.Rectangle{0, int(region.TileHeight - 1), int(region2.TileWidth), int(region2.TileHeight)},
Region: region2,

View File

@ -1,12 +1,15 @@
package d2mapengine
import (
"fmt"
"image/color"
"log"
"math"
"math/rand"
"sort"
"strconv"
"sync"
"time"
"github.com/OpenDiablo2/D2Shared/d2data/d2dt1"
@ -30,32 +33,39 @@ import (
"github.com/hajimehoshi/ebiten"
)
//TODO: move to corresponding file
type ByRarity []d2dt1.Tile
func (a ByRarity) Len() int { return len(a) }
func (a ByRarity) Less(i, j int) bool { return a[i].RarityFrameIndex < a[j].RarityFrameIndex }
func (a ByRarity) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
type Region struct {
RegionPath string
LevelType d2datadict.LevelTypeRecord
levelPreset d2datadict.LevelPresetRecord
LevelPreset d2datadict.LevelPresetRecord
TileWidth int32
TileHeight int32
Tiles []d2dt1.Tile
DS1 d2ds1.DS1
Palette d2datadict.PaletteRec
FloorCache map[uint32]*TileCacheRecord
ShadowCache map[uint32]*TileCacheRecord
WallCache map[uint32]*TileCacheRecord
FloorCache map[string]*TileCacheRecord
ShadowCache map[string]*TileCacheRecord
WallCache map[string]*TileCacheRecord
AnimationEntities []d2render.AnimatedEntity
NPCs []*d2core.NPC
StartX float64
StartY float64
}
func LoadRegion(seed rand.Source, levelType d2enum.RegionIdType, levelPreset int, fileProvider d2interface.FileProvider) *Region {
func LoadRegion(seed rand.Source, levelType d2enum.RegionIdType, levelPreset int, fileProvider d2interface.FileProvider, fileIndex int) *Region {
result := &Region{
LevelType: d2datadict.LevelTypes[levelType],
levelPreset: d2datadict.LevelPresets[levelPreset],
LevelPreset: d2datadict.LevelPresets[levelPreset],
Tiles: make([]d2dt1.Tile, 0),
FloorCache: make(map[uint32]*TileCacheRecord),
ShadowCache: make(map[uint32]*TileCacheRecord),
WallCache: make(map[uint32]*TileCacheRecord),
FloorCache: make(map[string]*TileCacheRecord),
ShadowCache: make(map[string]*TileCacheRecord),
WallCache: make(map[string]*TileCacheRecord),
}
result.Palette = d2datadict.Palettes[d2enum.PaletteType("act"+strconv.Itoa(int(result.LevelType.Act)))]
//bm := result.levelPreset.Dt1Mask
@ -74,7 +84,7 @@ func LoadRegion(seed rand.Source, levelType d2enum.RegionIdType, levelPreset int
result.Tiles = append(result.Tiles, dt1.Tiles...)
}
levelFilesToPick := make([]string, 0)
for _, fileRecord := range result.levelPreset.Files {
for _, fileRecord := range result.LevelPreset.Files {
if len(fileRecord) == 0 || fileRecord == "" || fileRecord == "0" {
continue
}
@ -82,6 +92,9 @@ func LoadRegion(seed rand.Source, levelType d2enum.RegionIdType, levelPreset int
}
random := rand.New(seed)
levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * random.Float64()))
if fileIndex >= 0 && fileIndex < len(levelFilesToPick) {
levelIndex = fileIndex
}
levelFile := levelFilesToPick[levelIndex]
result.RegionPath = levelFile
result.DS1 = d2ds1.LoadDS1("/data/global/tiles/"+levelFile, fileProvider)
@ -125,59 +138,86 @@ func (v *Region) RenderTile(offsetX, offsetY, tileX, tileY int, layerType d2enum
offsetX -= 80
switch layerType {
case d2enum.RegionLayerTypeFloors:
v.renderFloor(v.DS1.Tiles[tileY][tileX].Floors[layerIndex], offsetX, offsetY, target)
v.renderFloor(v.DS1.Tiles[tileY][tileX].Floors[layerIndex], offsetX, offsetY, target, tileX, tileY)
case d2enum.RegionLayerTypeWalls:
v.renderWall(v.DS1.Tiles[tileY][tileX].Walls[layerIndex], offsetX, offsetY, target)
v.renderWall(v.DS1.Tiles[tileY][tileX].Walls[layerIndex], offsetX, offsetY, target, tileX, tileY)
case d2enum.RegionLayerTypeShadows:
v.renderShadow(v.DS1.Tiles[tileY][tileX].Shadows[layerIndex], offsetX, offsetY, target)
v.renderShadow(v.DS1.Tiles[tileY][tileX].Shadows[layerIndex], offsetX, offsetY, target, tileX, tileY)
}
}
func (v *Region) getRandomTile(tiles []d2dt1.Tile) *d2dt1.Tile {
if len(tiles) == 1 {
return &tiles[0]
}
sort.Sort(ByRarity(tiles))
s := 0
for _, t := range tiles {
s += int(t.RarityFrameIndex)
}
rand.Seed(time.Now().UnixNano())
r := 0
if s != 0 {
r = rand.Intn(s) + 1
}
for _, t := range tiles {
r -= int(t.RarityFrameIndex)
if r <= 0 {
return &t
}
}
return &tiles[0]
}
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
tiles := []d2dt1.Tile{}
for _, tile := range v.Tiles {
if tile.MainIndex != mainIndex || tile.SubIndex != subIndex || tile.Orientation != orientation {
continue
}
return &tile
tiles = append(tiles, tile)
}
//log.Fatalf("Unknown tile ID [%d %d %d]", mainIndex, subIndex, orientation)
return nil
if len(tiles) == 0 {
log.Printf("Unknown tile ID [%d %d %d]\n", mainIndex, subIndex, orientation)
return nil
}
return v.getRandomTile(tiles)
}
func (v *Region) renderFloor(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8)
func (v *Region) renderFloor(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
tileCacheIndex := fmt.Sprintf("%v-%v-%v-%v", tileY, tileX, tile.MainIndex, tile.SubIndex)
tileCache, exists := v.FloorCache[tileCacheIndex]
if !exists {
v.FloorCache[tileCacheIndex] = v.generateFloorCache(tile)
tileCache = v.FloorCache[tileCacheIndex]
if tileCache == nil {
log.Println("Could not load floor tile")
log.Println("Could not load floor tile: " + tileCacheIndex)
return
}
}
if tileCache == nil {
log.Println("Nil tile cache")
log.Println("Nil tile cache: " + tileCacheIndex)
return
}
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset))
target.DrawImage(tileCache.Image, opts)
return
}
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))
func (v *Region) renderWall(tile d2ds1.WallRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
tileCacheIndex := fmt.Sprintf("%v-%v-%v-%v-%v", tileY, tileX, tile.MainIndex, tile.SubIndex, tile.Orientation)
tileCache, exists := v.WallCache[tileCacheIndex]
if !exists {
v.WallCache[tileCacheIndex] = v.generateWallCache(tile)
if v.WallCache[tileCacheIndex] == nil {
log.Println("Could not generate wall")
log.Println("Could not generate wall: " + tileCacheIndex)
return
}
tileCache = v.WallCache[tileCacheIndex]
}
if tileCache == nil {
log.Println("Nil tile cache")
log.Println("Nil tile cache: " + tileCacheIndex)
return
}
opts := &ebiten.DrawImageOptions{}
@ -185,19 +225,19 @@ func (v *Region) renderWall(tile d2ds1.WallRecord, offsetX, offsetY int, target
target.DrawImage(tileCache.Image, opts)
}
func (v *Region) renderShadow(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + 0
func (v *Region) renderShadow(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
tileCacheIndex := fmt.Sprintf("%v-%v-%v-%v", tileY, tileX, tile.MainIndex, tile.SubIndex)
tileCache, exists := v.ShadowCache[tileCacheIndex]
if !exists {
v.ShadowCache[tileCacheIndex] = v.generateShadowCache(tile)
tileCache = v.ShadowCache[tileCacheIndex]
if tileCache == nil {
log.Println("Could not load shadow tile")
log.Println("Could not load shadow tile: " + tileCacheIndex)
return
}
}
if tileCache == nil {
log.Println("Nil tile cache")
log.Println("Nil tile cache: " + tileCacheIndex)
return
}
opts := &ebiten.DrawImageOptions{}

5
go.mod
View File

@ -3,6 +3,10 @@ module github.com/OpenDiablo2/OpenDiablo2
go 1.12
require (
github.com/JoshVarga/blast v0.0.0-20180421040937-681c804fb9f0
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/hajimehoshi/ebiten v1.11.0-alpha.0.20191115171053-e42cff071c36
github.com/OpenDiablo2/D2Shared v0.0.0-20191117044836-c56c888bec7d
github.com/hajimehoshi/ebiten v1.11.0-alpha.0.20191116200143-acc933b7c399
github.com/hajimehoshi/oto v0.5.3 // indirect
@ -10,4 +14,5 @@ require (
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba // indirect
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6
)

11
main.go
View File

@ -13,6 +13,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/D2Shared/d2data/d2mpq"
"github.com/hajimehoshi/ebiten"
"gopkg.in/alecthomas/kingpin.v2"
)
// GitBranch is set by the CI build process to the name of the branch
@ -22,6 +23,9 @@ var GitBranch string
var GitCommit string
var d2Engine d2core.Engine
var region = kingpin.Arg("region", "Region type id").Int()
var preset = kingpin.Arg("preset", "Level preset").Int()
func main() {
//defer profile.Start(profile.CPUProfile).Stop()
//runtime.LockOSThread()
@ -39,7 +43,12 @@ func main() {
}
d2mpq.InitializeCryptoBuffer()
d2Engine = d2core.CreateEngine()
d2Engine.SetNextScene(d2scene.CreateMainMenu(&d2Engine, &d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
kingpin.Parse()
if *region == 0 {
d2Engine.SetNextScene(d2scene.CreateMainMenu(&d2Engine, &d2Engine, d2Engine.UIManager, d2Engine.SoundManager))
} else {
d2Engine.SetNextScene(d2scene.CreateMapEngineTest(&d2Engine, &d2Engine, d2Engine.UIManager, d2Engine.SoundManager, *region, *preset))
}
ebiten.SetCursorVisible(false)
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
ebiten.SetRunnableInBackground(d2Engine.Settings.RunInBackground)