mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-10 10:36:42 -05:00
Switcher with presets & better tiles randomizing (#173)
* tile choice algo * cycle region files * switcher limited by preset
This commit is contained in:
parent
7222f57c2c
commit
c3ba3f71e4
@ -181,7 +181,7 @@ func (v *MainMenu) Load() []func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *MainMenu) onMapTestClicked() {
|
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) {
|
func openbrowser(url string) {
|
||||||
|
@ -21,6 +21,67 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/inpututil"
|
"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 {
|
type MapEngineTest struct {
|
||||||
uiManager *d2ui.Manager
|
uiManager *d2ui.Manager
|
||||||
soundManager *d2audio.Manager
|
soundManager *d2audio.Manager
|
||||||
@ -28,8 +89,15 @@ type MapEngineTest struct {
|
|||||||
sceneProvider d2coreinterface.SceneProvider
|
sceneProvider d2coreinterface.SceneProvider
|
||||||
gameState *d2core.GameState
|
gameState *d2core.GameState
|
||||||
mapEngine *_map.Engine
|
mapEngine *_map.Engine
|
||||||
|
|
||||||
|
//TODO: this is region specific properties, should be refactored for multi-region rendering
|
||||||
currentRegion int
|
currentRegion int
|
||||||
keyLocked bool
|
levelPreset int
|
||||||
|
fileIndex int
|
||||||
|
regionSpec RegionSpec
|
||||||
|
filesCount int
|
||||||
|
|
||||||
|
keyLocked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateMapEngineTest(
|
func CreateMapEngineTest(
|
||||||
@ -37,50 +105,56 @@ func CreateMapEngineTest(
|
|||||||
sceneProvider d2coreinterface.SceneProvider,
|
sceneProvider d2coreinterface.SceneProvider,
|
||||||
uiManager *d2ui.Manager,
|
uiManager *d2ui.Manager,
|
||||||
soundManager *d2audio.Manager,
|
soundManager *d2audio.Manager,
|
||||||
currentRegion int) *MapEngineTest {
|
currentRegion int, levelPreset int) *MapEngineTest {
|
||||||
result := &MapEngineTest{
|
result := &MapEngineTest{
|
||||||
fileProvider: fileProvider,
|
fileProvider: fileProvider,
|
||||||
uiManager: uiManager,
|
uiManager: uiManager,
|
||||||
soundManager: soundManager,
|
soundManager: soundManager,
|
||||||
sceneProvider: sceneProvider,
|
sceneProvider: sceneProvider,
|
||||||
currentRegion: currentRegion,
|
currentRegion: currentRegion,
|
||||||
|
levelPreset: levelPreset,
|
||||||
|
fileIndex: -1,
|
||||||
|
regionSpec: RegionSpec{},
|
||||||
|
filesCount: 0,
|
||||||
keyLocked: false,
|
keyLocked: false,
|
||||||
}
|
}
|
||||||
result.gameState = d2core.CreateTestGameState()
|
result.gameState = d2core.CreateTestGameState()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
type RegionSpec struct {
|
func (v *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
|
||||||
regionType d2enum.RegionIdType
|
for _, spec := range regions {
|
||||||
levelPreset int
|
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{
|
if levelPreset > spec.endPresetIndex {
|
||||||
{d2enum.RegionAct1Tristram, 300},
|
levelPreset = spec.endPresetIndex
|
||||||
{d2enum.RegionAct1Cathedral, 257},
|
}
|
||||||
{d2enum.RegionAct2Town, 301},
|
}
|
||||||
// {d2enum.RegionAct2Harem, 353},
|
v.levelPreset = levelPreset
|
||||||
{d2enum.RegionAct3Town, 529},
|
}
|
||||||
{d2enum.RegionAct3Jungle, 574},
|
}
|
||||||
{d2enum.RegionAct4Town, 797},
|
|
||||||
{d2enum.RegonAct5Town, 863},
|
|
||||||
{d2enum.RegionAct5IceCaves, 1038},
|
|
||||||
{d2enum.RegionAct5Siege, 879},
|
|
||||||
{d2enum.RegionAct5Lava, 105},
|
|
||||||
{d2enum.RegionAct5Barricade, 880},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *MapEngineTest) LoadRegionByIndex(n int) {
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
v.mapEngine.GenerateAct1Overworld()
|
v.mapEngine.GenerateAct1Overworld()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
region := regions[n-1]
|
|
||||||
|
|
||||||
v.mapEngine = _map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider) // necessary for map name update
|
v.mapEngine = _map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider) // necessary for map name update
|
||||||
v.mapEngine.OffsetY = 0
|
v.mapEngine.OffsetY = 0
|
||||||
v.mapEngine.OffsetX = 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() {
|
func (v *MapEngineTest) Load() []func() {
|
||||||
@ -91,21 +165,7 @@ func (v *MapEngineTest) Load() []func() {
|
|||||||
func() {
|
func() {
|
||||||
v.mapEngine = _map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider)
|
v.mapEngine = _map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider)
|
||||||
|
|
||||||
v.LoadRegionByIndex(v.currentRegion)
|
v.LoadRegionByIndex(v.currentRegion, v.levelPreset, v.fileIndex)
|
||||||
// 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
|
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,13 +193,34 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) {
|
|||||||
int(math.Ceil(tileY))-curRegion.Rect.Top,
|
int(math.Ceil(tileY))-curRegion.Rect.Top,
|
||||||
subtileY,
|
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, line, 5, 5)
|
||||||
ebitenutil.DebugPrintAt(screen, "Map: "+curRegion.Region.LevelType.Name, 5, 17)
|
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, 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 map, P - previous map", 5, 41)
|
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) {
|
func (v *MapEngineTest) Update(tickTime float64) {
|
||||||
|
ctrlPressed := v.uiManager.KeyPressed(ebiten.KeyControl)
|
||||||
|
shiftPressed := v.uiManager.KeyPressed(ebiten.KeyShift)
|
||||||
|
|
||||||
if v.uiManager.KeyPressed(ebiten.KeyDown) {
|
if v.uiManager.KeyPressed(ebiten.KeyDown) {
|
||||||
v.mapEngine.OffsetY -= tickTime * 800
|
v.mapEngine.OffsetY -= tickTime * 800
|
||||||
}
|
}
|
||||||
@ -164,26 +245,50 @@ func (v *MapEngineTest) Update(tickTime float64) {
|
|||||||
if v.uiManager.KeyPressed(ebiten.KeyEscape) {
|
if v.uiManager.KeyPressed(ebiten.KeyEscape) {
|
||||||
os.Exit(0)
|
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 {
|
if !v.keyLocked {
|
||||||
v.currentRegion--
|
|
||||||
if v.currentRegion == -1 {
|
if v.uiManager.KeyPressed(ebiten.KeyN) && ctrlPressed {
|
||||||
v.currentRegion = len(regions) - 1
|
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
|
//FIXME: do it better
|
||||||
@ -191,3 +296,19 @@ func (v *MapEngineTest) Update(tickTime float64) {
|
|||||||
v.keyLocked = false
|
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
|
||||||
|
}
|
||||||
|
@ -214,6 +214,9 @@ func (v *AnimatedEntity) cacheFrames(layerName string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
direction := dcc.Directions[v.direction]
|
direction := dcc.Directions[v.direction]
|
||||||
|
if frameIndex >= len(direction.Frames) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
frame := direction.Frames[frameIndex]
|
frame := direction.Frames[frameIndex]
|
||||||
img := image.NewRGBA(image.Rect(0, 0, int(frameW), int(frameH)))
|
img := image.NewRGBA(image.Rect(0, 0, int(frameW), int(frameH)))
|
||||||
for y := 0; y < direction.Box.Height; y++ {
|
for y := 0; y < direction.Box.Height; y++ {
|
||||||
|
@ -52,9 +52,10 @@ func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager,
|
|||||||
return result
|
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)
|
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{
|
v.regions = append(v.regions, EngineRegion{
|
||||||
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
|
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
|
||||||
Region: region,
|
Region: region,
|
||||||
@ -68,19 +69,19 @@ func (v *Engine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int) {
|
|||||||
func (v *Engine) GenerateAct1Overworld() {
|
func (v *Engine) GenerateAct1Overworld() {
|
||||||
v.soundManager.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
v.soundManager.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
||||||
randomSource := rand.NewSource(v.gameState.Seed)
|
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{
|
v.regions = append(v.regions, EngineRegion{
|
||||||
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
|
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
|
||||||
Region: region,
|
Region: region,
|
||||||
})
|
})
|
||||||
if strings.Contains(region.RegionPath, "E1") {
|
if strings.Contains(region.RegionPath, "E1") {
|
||||||
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 2, v.fileProvider)
|
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 2, v.fileProvider, -1)
|
||||||
v.regions = append(v.regions, EngineRegion{
|
v.regions = append(v.regions, EngineRegion{
|
||||||
Rect: d2common.Rectangle{int(region.TileWidth - 1), 0, int(region2.TileWidth), int(region2.TileHeight)},
|
Rect: d2common.Rectangle{int(region.TileWidth - 1), 0, int(region2.TileWidth), int(region2.TileHeight)},
|
||||||
Region: region2,
|
Region: region2,
|
||||||
})
|
})
|
||||||
} else if strings.Contains(region.RegionPath, "S1") {
|
} else if strings.Contains(region.RegionPath, "S1") {
|
||||||
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 3, v.fileProvider)
|
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 3, v.fileProvider, -1)
|
||||||
v.regions = append(v.regions, EngineRegion{
|
v.regions = append(v.regions, EngineRegion{
|
||||||
Rect: d2common.Rectangle{0, int(region.TileHeight - 1), int(region2.TileWidth), int(region2.TileHeight)},
|
Rect: d2common.Rectangle{0, int(region.TileHeight - 1), int(region2.TileWidth), int(region2.TileHeight)},
|
||||||
Region: region2,
|
Region: region2,
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package d2mapengine
|
package d2mapengine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2dt1"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2dt1"
|
||||||
|
|
||||||
@ -30,32 +33,39 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten"
|
"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 {
|
type Region struct {
|
||||||
RegionPath string
|
RegionPath string
|
||||||
LevelType d2datadict.LevelTypeRecord
|
LevelType d2datadict.LevelTypeRecord
|
||||||
levelPreset d2datadict.LevelPresetRecord
|
LevelPreset d2datadict.LevelPresetRecord
|
||||||
TileWidth int32
|
TileWidth int32
|
||||||
TileHeight int32
|
TileHeight int32
|
||||||
Tiles []d2dt1.Tile
|
Tiles []d2dt1.Tile
|
||||||
DS1 d2ds1.DS1
|
DS1 d2ds1.DS1
|
||||||
Palette d2datadict.PaletteRec
|
Palette d2datadict.PaletteRec
|
||||||
FloorCache map[uint32]*TileCacheRecord
|
FloorCache map[string]*TileCacheRecord
|
||||||
ShadowCache map[uint32]*TileCacheRecord
|
ShadowCache map[string]*TileCacheRecord
|
||||||
WallCache map[uint32]*TileCacheRecord
|
WallCache map[string]*TileCacheRecord
|
||||||
AnimationEntities []d2render.AnimatedEntity
|
AnimationEntities []d2render.AnimatedEntity
|
||||||
NPCs []*d2core.NPC
|
NPCs []*d2core.NPC
|
||||||
StartX float64
|
StartX float64
|
||||||
StartY 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{
|
result := &Region{
|
||||||
LevelType: d2datadict.LevelTypes[levelType],
|
LevelType: d2datadict.LevelTypes[levelType],
|
||||||
levelPreset: d2datadict.LevelPresets[levelPreset],
|
LevelPreset: d2datadict.LevelPresets[levelPreset],
|
||||||
Tiles: make([]d2dt1.Tile, 0),
|
Tiles: make([]d2dt1.Tile, 0),
|
||||||
FloorCache: make(map[uint32]*TileCacheRecord),
|
FloorCache: make(map[string]*TileCacheRecord),
|
||||||
ShadowCache: make(map[uint32]*TileCacheRecord),
|
ShadowCache: make(map[string]*TileCacheRecord),
|
||||||
WallCache: make(map[uint32]*TileCacheRecord),
|
WallCache: make(map[string]*TileCacheRecord),
|
||||||
}
|
}
|
||||||
result.Palette = d2datadict.Palettes[d2enum.PaletteType("act"+strconv.Itoa(int(result.LevelType.Act)))]
|
result.Palette = d2datadict.Palettes[d2enum.PaletteType("act"+strconv.Itoa(int(result.LevelType.Act)))]
|
||||||
//bm := result.levelPreset.Dt1Mask
|
//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...)
|
result.Tiles = append(result.Tiles, dt1.Tiles...)
|
||||||
}
|
}
|
||||||
levelFilesToPick := make([]string, 0)
|
levelFilesToPick := make([]string, 0)
|
||||||
for _, fileRecord := range result.levelPreset.Files {
|
for _, fileRecord := range result.LevelPreset.Files {
|
||||||
if len(fileRecord) == 0 || fileRecord == "" || fileRecord == "0" {
|
if len(fileRecord) == 0 || fileRecord == "" || fileRecord == "0" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -82,6 +92,9 @@ func LoadRegion(seed rand.Source, levelType d2enum.RegionIdType, levelPreset int
|
|||||||
}
|
}
|
||||||
random := rand.New(seed)
|
random := rand.New(seed)
|
||||||
levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * random.Float64()))
|
levelIndex := int(math.Round(float64(len(levelFilesToPick)-1) * random.Float64()))
|
||||||
|
if fileIndex >= 0 && fileIndex < len(levelFilesToPick) {
|
||||||
|
levelIndex = fileIndex
|
||||||
|
}
|
||||||
levelFile := levelFilesToPick[levelIndex]
|
levelFile := levelFilesToPick[levelIndex]
|
||||||
result.RegionPath = levelFile
|
result.RegionPath = levelFile
|
||||||
result.DS1 = d2ds1.LoadDS1("/data/global/tiles/"+levelFile, fileProvider)
|
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
|
offsetX -= 80
|
||||||
switch layerType {
|
switch layerType {
|
||||||
case d2enum.RegionLayerTypeFloors:
|
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:
|
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:
|
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 {
|
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 {
|
for _, tile := range v.Tiles {
|
||||||
if tile.MainIndex != mainIndex || tile.SubIndex != subIndex || tile.Orientation != orientation {
|
if tile.MainIndex != mainIndex || tile.SubIndex != subIndex || tile.Orientation != orientation {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return &tile
|
tiles = append(tiles, tile)
|
||||||
}
|
}
|
||||||
//log.Fatalf("Unknown tile ID [%d %d %d]", mainIndex, subIndex, orientation)
|
if len(tiles) == 0 {
|
||||||
return nil
|
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) {
|
func (v *Region) renderFloor(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
|
||||||
tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8)
|
tileCacheIndex := fmt.Sprintf("%v-%v-%v-%v", tileY, tileX, tile.MainIndex, tile.SubIndex)
|
||||||
tileCache, exists := v.FloorCache[tileCacheIndex]
|
tileCache, exists := v.FloorCache[tileCacheIndex]
|
||||||
if !exists {
|
if !exists {
|
||||||
v.FloorCache[tileCacheIndex] = v.generateFloorCache(tile)
|
v.FloorCache[tileCacheIndex] = v.generateFloorCache(tile)
|
||||||
tileCache = v.FloorCache[tileCacheIndex]
|
tileCache = v.FloorCache[tileCacheIndex]
|
||||||
if tileCache == nil {
|
if tileCache == nil {
|
||||||
log.Println("Could not load floor tile")
|
log.Println("Could not load floor tile: " + tileCacheIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tileCache == nil {
|
if tileCache == nil {
|
||||||
log.Println("Nil tile cache")
|
log.Println("Nil tile cache: " + tileCacheIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
opts := &ebiten.DrawImageOptions{}
|
opts := &ebiten.DrawImageOptions{}
|
||||||
opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset))
|
opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset))
|
||||||
target.DrawImage(tileCache.Image, opts)
|
target.DrawImage(tileCache.Image, opts)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Region) renderWall(tile d2ds1.WallRecord, offsetX, offsetY int, target *ebiten.Image) {
|
func (v *Region) renderWall(tile d2ds1.WallRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
|
||||||
tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8) | (uint32(tile.Orientation))
|
tileCacheIndex := fmt.Sprintf("%v-%v-%v-%v-%v", tileY, tileX, tile.MainIndex, tile.SubIndex, tile.Orientation)
|
||||||
tileCache, exists := v.WallCache[tileCacheIndex]
|
tileCache, exists := v.WallCache[tileCacheIndex]
|
||||||
if !exists {
|
if !exists {
|
||||||
v.WallCache[tileCacheIndex] = v.generateWallCache(tile)
|
v.WallCache[tileCacheIndex] = v.generateWallCache(tile)
|
||||||
if v.WallCache[tileCacheIndex] == nil {
|
if v.WallCache[tileCacheIndex] == nil {
|
||||||
log.Println("Could not generate wall")
|
log.Println("Could not generate wall: " + tileCacheIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tileCache = v.WallCache[tileCacheIndex]
|
tileCache = v.WallCache[tileCacheIndex]
|
||||||
}
|
}
|
||||||
if tileCache == nil {
|
if tileCache == nil {
|
||||||
log.Println("Nil tile cache")
|
log.Println("Nil tile cache: " + tileCacheIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
opts := &ebiten.DrawImageOptions{}
|
opts := &ebiten.DrawImageOptions{}
|
||||||
@ -185,19 +225,19 @@ func (v *Region) renderWall(tile d2ds1.WallRecord, offsetX, offsetY int, target
|
|||||||
target.DrawImage(tileCache.Image, opts)
|
target.DrawImage(tileCache.Image, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Region) renderShadow(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
|
func (v *Region) renderShadow(tile d2ds1.FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image, tileX, tileY int) {
|
||||||
tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + 0
|
tileCacheIndex := fmt.Sprintf("%v-%v-%v-%v", tileY, tileX, tile.MainIndex, tile.SubIndex)
|
||||||
tileCache, exists := v.ShadowCache[tileCacheIndex]
|
tileCache, exists := v.ShadowCache[tileCacheIndex]
|
||||||
if !exists {
|
if !exists {
|
||||||
v.ShadowCache[tileCacheIndex] = v.generateShadowCache(tile)
|
v.ShadowCache[tileCacheIndex] = v.generateShadowCache(tile)
|
||||||
tileCache = v.ShadowCache[tileCacheIndex]
|
tileCache = v.ShadowCache[tileCacheIndex]
|
||||||
if tileCache == nil {
|
if tileCache == nil {
|
||||||
log.Println("Could not load shadow tile")
|
log.Println("Could not load shadow tile: " + tileCacheIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tileCache == nil {
|
if tileCache == nil {
|
||||||
log.Println("Nil tile cache")
|
log.Println("Nil tile cache: " + tileCacheIndex)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
opts := &ebiten.DrawImageOptions{}
|
opts := &ebiten.DrawImageOptions{}
|
||||||
|
5
go.mod
5
go.mod
@ -3,6 +3,10 @@ module github.com/OpenDiablo2/OpenDiablo2
|
|||||||
go 1.12
|
go 1.12
|
||||||
|
|
||||||
require (
|
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/OpenDiablo2/D2Shared v0.0.0-20191117044836-c56c888bec7d
|
||||||
github.com/hajimehoshi/ebiten v1.11.0-alpha.0.20191116200143-acc933b7c399
|
github.com/hajimehoshi/ebiten v1.11.0-alpha.0.20191116200143-acc933b7c399
|
||||||
github.com/hajimehoshi/oto v0.5.3 // indirect
|
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/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect
|
||||||
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba // indirect
|
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba // indirect
|
||||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 // indirect
|
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 // indirect
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6
|
||||||
)
|
)
|
||||||
|
11
main.go
11
main.go
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
||||||
"github.com/OpenDiablo2/D2Shared/d2data/d2mpq"
|
"github.com/OpenDiablo2/D2Shared/d2data/d2mpq"
|
||||||
"github.com/hajimehoshi/ebiten"
|
"github.com/hajimehoshi/ebiten"
|
||||||
|
"gopkg.in/alecthomas/kingpin.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitBranch is set by the CI build process to the name of the branch
|
// 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 GitCommit string
|
||||||
var d2Engine d2core.Engine
|
var d2Engine d2core.Engine
|
||||||
|
|
||||||
|
var region = kingpin.Arg("region", "Region type id").Int()
|
||||||
|
var preset = kingpin.Arg("preset", "Level preset").Int()
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//defer profile.Start(profile.CPUProfile).Stop()
|
//defer profile.Start(profile.CPUProfile).Stop()
|
||||||
//runtime.LockOSThread()
|
//runtime.LockOSThread()
|
||||||
@ -39,7 +43,12 @@ func main() {
|
|||||||
}
|
}
|
||||||
d2mpq.InitializeCryptoBuffer()
|
d2mpq.InitializeCryptoBuffer()
|
||||||
d2Engine = d2core.CreateEngine()
|
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.SetCursorVisible(false)
|
||||||
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
|
ebiten.SetFullscreen(d2Engine.Settings.FullScreen)
|
||||||
ebiten.SetRunnableInBackground(d2Engine.Settings.RunInBackground)
|
ebiten.SetRunnableInBackground(d2Engine.Settings.RunInBackground)
|
||||||
|
Loading…
Reference in New Issue
Block a user