2019-11-10 08:51:02 -05:00
|
|
|
package d2mapengine
|
2019-10-31 21:17:13 -04:00
|
|
|
|
|
|
|
import (
|
2019-11-06 18:25:19 -05:00
|
|
|
"math"
|
2019-11-01 14:12:23 -04:00
|
|
|
"math/rand"
|
2019-11-06 21:25:09 -05:00
|
|
|
"strings"
|
2019-10-31 21:17:13 -04:00
|
|
|
|
2019-11-11 23:48:55 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
|
|
|
2019-11-10 03:36:53 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
|
|
|
|
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
|
|
|
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core"
|
|
|
|
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
2019-10-31 21:17:13 -04:00
|
|
|
"github.com/hajimehoshi/ebiten"
|
|
|
|
)
|
|
|
|
|
|
|
|
type EngineRegion struct {
|
2019-11-10 03:36:53 -05:00
|
|
|
Rect d2common.Rectangle
|
2019-11-01 14:12:23 -04:00
|
|
|
Region *Region
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type Engine struct {
|
2019-11-10 03:36:53 -05:00
|
|
|
soundManager *d2audio.Manager
|
|
|
|
gameState *d2core.GameState
|
|
|
|
fileProvider d2interface.FileProvider
|
2019-11-01 14:12:23 -04:00
|
|
|
regions []EngineRegion
|
|
|
|
OffsetX float64
|
|
|
|
OffsetY float64
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
|
|
|
|
2019-11-10 03:36:53 -05:00
|
|
|
func CreateMapEngine(gameState *d2core.GameState, soundManager *d2audio.Manager, fileProvider d2interface.FileProvider) *Engine {
|
2019-10-31 21:17:13 -04:00
|
|
|
result := &Engine{
|
|
|
|
gameState: gameState,
|
|
|
|
soundManager: soundManager,
|
|
|
|
fileProvider: fileProvider,
|
2019-11-01 14:12:23 -04:00
|
|
|
regions: make([]EngineRegion, 0),
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2019-11-11 23:48:55 -05:00
|
|
|
func (v *Engine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int) {
|
2019-11-01 14:12:23 -04:00
|
|
|
randomSource := rand.NewSource(v.gameState.Seed)
|
|
|
|
region := LoadRegion(randomSource, regionType, levelPreset, v.fileProvider)
|
|
|
|
v.regions = append(v.regions, EngineRegion{
|
2019-11-10 03:36:53 -05:00
|
|
|
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
|
2019-11-01 14:12:23 -04:00
|
|
|
Region: region,
|
|
|
|
})
|
2019-11-06 21:25:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Engine) GenerateAct1Overworld() {
|
2019-11-06 18:25:19 -05:00
|
|
|
v.soundManager.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
2019-11-06 21:25:09 -05:00
|
|
|
randomSource := rand.NewSource(v.gameState.Seed)
|
2019-11-11 23:48:55 -05:00
|
|
|
region := LoadRegion(randomSource, d2enum.RegionAct1Town, 1, v.fileProvider)
|
2019-11-06 21:25:09 -05:00
|
|
|
v.regions = append(v.regions, EngineRegion{
|
2019-11-10 03:36:53 -05:00
|
|
|
Rect: d2common.Rectangle{0, 0, int(region.TileWidth), int(region.TileHeight)},
|
2019-11-06 21:25:09 -05:00
|
|
|
Region: region,
|
|
|
|
})
|
|
|
|
if strings.Contains(region.RegionPath, "E1") {
|
2019-11-11 23:48:55 -05:00
|
|
|
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 2, v.fileProvider)
|
2019-11-06 21:25:09 -05:00
|
|
|
v.regions = append(v.regions, EngineRegion{
|
2019-11-10 03:36:53 -05:00
|
|
|
Rect: d2common.Rectangle{int(region.TileWidth - 1), 0, int(region2.TileWidth), int(region2.TileHeight)},
|
2019-11-06 21:25:09 -05:00
|
|
|
Region: region2,
|
|
|
|
})
|
|
|
|
} else if strings.Contains(region.RegionPath, "S1") {
|
2019-11-11 23:48:55 -05:00
|
|
|
region2 := LoadRegion(randomSource, d2enum.RegionAct1Town, 3, v.fileProvider)
|
2019-11-06 21:25:09 -05:00
|
|
|
v.regions = append(v.regions, EngineRegion{
|
2019-11-10 03:36:53 -05:00
|
|
|
Rect: d2common.Rectangle{0, int(region.TileHeight - 1), int(region2.TileWidth), int(region2.TileHeight)},
|
2019-11-06 21:25:09 -05:00
|
|
|
Region: region2,
|
|
|
|
})
|
|
|
|
}
|
2019-11-07 23:44:03 -05:00
|
|
|
|
2019-11-10 03:36:53 -05:00
|
|
|
sx, sy := d2helper.IsoToScreen(int(region.StartX), int(region.StartY), 0, 0)
|
2019-11-07 23:44:03 -05:00
|
|
|
v.OffsetX = float64(sx) - 400
|
|
|
|
v.OffsetY = float64(sy) - 300
|
2019-11-06 18:25:19 -05:00
|
|
|
}
|
|
|
|
|
2019-11-06 21:25:09 -05:00
|
|
|
func (v *Engine) GetRegionAt(x, y int) *EngineRegion {
|
2019-11-06 18:25:19 -05:00
|
|
|
if v.regions == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
for _, region := range v.regions {
|
|
|
|
if !region.Rect.IsInRect(x, y) {
|
|
|
|
continue
|
|
|
|
}
|
2019-11-06 21:25:09 -05:00
|
|
|
return ®ion
|
2019-11-06 18:25:19 -05:00
|
|
|
}
|
|
|
|
return nil
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Engine) Render(target *ebiten.Image) {
|
2019-11-06 18:25:19 -05:00
|
|
|
for _, region := range v.regions {
|
2019-11-06 21:25:09 -05:00
|
|
|
v.RenderRegion(region, target)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Engine) RenderRegion(region EngineRegion, target *ebiten.Image) {
|
|
|
|
for y := 0; y < int(region.Region.TileHeight); y++ {
|
|
|
|
offX := -((y + region.Rect.Top) * 80) + (region.Rect.Left * 80)
|
|
|
|
offY := ((y + region.Rect.Top) * 40) + (region.Rect.Left * 40)
|
|
|
|
for x := 0; x < int(region.Region.TileWidth); x++ {
|
2019-11-10 03:36:53 -05:00
|
|
|
sx, sy := d2helper.IsoToScreen(x+region.Rect.Left, y+region.Rect.Top, int(v.OffsetX), int(v.OffsetY))
|
2019-11-06 21:25:09 -05:00
|
|
|
if sx > -160 && sy > -160 && sx <= 880 && sy <= 1000 {
|
|
|
|
v.RenderTile(region.Region, offX, offY, x, y, target)
|
2019-11-01 22:12:07 -04:00
|
|
|
}
|
2019-11-06 21:25:09 -05:00
|
|
|
offX += 80
|
|
|
|
offY += 40
|
2019-11-01 22:12:07 -04:00
|
|
|
}
|
|
|
|
}
|
2019-11-06 21:25:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Engine) RenderTile(region *Region, offX, offY, x, y int, target *ebiten.Image) {
|
|
|
|
tile := region.DS1.Tiles[y][x]
|
|
|
|
for i := range tile.Floors {
|
|
|
|
if tile.Floors[i].Hidden || tile.Floors[i].Prop1 == 0 {
|
|
|
|
continue
|
2019-11-06 18:25:19 -05:00
|
|
|
}
|
2019-11-11 23:48:55 -05:00
|
|
|
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeFloors, i, target)
|
2019-11-06 18:25:19 -05:00
|
|
|
}
|
2019-11-06 21:25:09 -05:00
|
|
|
for i := range tile.Shadows {
|
|
|
|
if tile.Shadows[i].Hidden || tile.Shadows[i].Prop1 == 0 {
|
|
|
|
continue
|
2019-11-01 16:51:50 -04:00
|
|
|
}
|
2019-11-11 23:48:55 -05:00
|
|
|
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeShadows, i, target)
|
2019-11-01 16:51:50 -04:00
|
|
|
}
|
2019-11-06 21:25:09 -05:00
|
|
|
for i := range tile.Walls {
|
|
|
|
if tile.Walls[i].Hidden || tile.Walls[i].Orientation == 15 || tile.Walls[i].Orientation == 10 || tile.Walls[i].Orientation == 11 || tile.Walls[i].Orientation == 0 {
|
|
|
|
continue
|
2019-11-01 22:12:07 -04:00
|
|
|
}
|
2019-11-11 23:48:55 -05:00
|
|
|
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeWalls, i, target)
|
2019-11-01 22:12:07 -04:00
|
|
|
}
|
2019-11-06 21:25:09 -05:00
|
|
|
for _, obj := range region.AnimationEntities {
|
|
|
|
if int(math.Floor(obj.LocationX)) == x && int(math.Floor(obj.LocationY)) == y {
|
|
|
|
obj.Render(target, offX+int(v.OffsetX), offY+int(v.OffsetY))
|
|
|
|
}
|
|
|
|
}
|
2019-11-07 23:44:03 -05:00
|
|
|
for _, npc := range region.NPCs {
|
|
|
|
if int(math.Floor(npc.AnimatedEntity.LocationX)) == x && int(math.Floor(npc.AnimatedEntity.LocationY)) == y {
|
|
|
|
npc.Render(target, offX+int(v.OffsetX), offY+int(v.OffsetY))
|
|
|
|
}
|
|
|
|
}
|
2019-11-06 21:25:09 -05:00
|
|
|
for i := range tile.Walls {
|
|
|
|
if tile.Walls[i].Hidden || tile.Walls[i].Orientation != 15 {
|
|
|
|
continue
|
2019-11-01 14:12:23 -04:00
|
|
|
}
|
2019-11-11 23:48:55 -05:00
|
|
|
region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, d2enum.RegionLayerTypeWalls, i, target)
|
2019-11-01 14:12:23 -04:00
|
|
|
}
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|