2020-02-01 18:55:56 -05:00
|
|
|
package d2map
|
2019-10-31 21:17:13 -04:00
|
|
|
|
|
|
|
import (
|
2020-02-02 12:46:19 -05:00
|
|
|
"math"
|
2019-11-06 21:25:09 -05:00
|
|
|
"strings"
|
2019-10-31 21:17:13 -04:00
|
|
|
|
2020-04-11 14:56:47 -04:00
|
|
|
"github.com/beefsack/go-astar"
|
|
|
|
|
2020-02-02 14:04:37 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
2020-01-31 23:18:11 -05:00
|
|
|
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
|
2020-02-02 14:04:37 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gamestate"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2term"
|
2019-10-31 21:17:13 -04:00
|
|
|
)
|
|
|
|
|
2019-12-13 00:33:11 -05:00
|
|
|
type MapEntity interface {
|
2020-02-01 20:39:28 -05:00
|
|
|
Render(target d2render.Surface)
|
2019-12-13 00:33:11 -05:00
|
|
|
Advance(tickTime float64)
|
2019-12-28 16:46:08 -05:00
|
|
|
GetPosition() (float64, float64)
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
|
|
|
|
2019-12-13 00:33:11 -05:00
|
|
|
type MapEngine struct {
|
2020-01-31 23:18:11 -05:00
|
|
|
gameState *d2gamestate.GameState
|
2019-12-08 22:18:42 -05:00
|
|
|
|
2019-12-13 00:33:11 -05:00
|
|
|
debugVisLevel int
|
|
|
|
|
|
|
|
regions []*MapRegion
|
2020-02-26 08:40:32 -05:00
|
|
|
entities MapEntitiesSearcher
|
2019-12-08 22:18:42 -05:00
|
|
|
viewport *Viewport
|
|
|
|
camera Camera
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
|
|
|
|
2020-01-31 23:18:11 -05:00
|
|
|
func CreateMapEngine(gameState *d2gamestate.GameState) *MapEngine {
|
2019-12-13 00:33:11 -05:00
|
|
|
engine := &MapEngine{
|
2020-01-31 23:18:11 -05:00
|
|
|
gameState: gameState,
|
|
|
|
viewport: NewViewport(0, 0, 800, 600),
|
2020-02-26 08:40:32 -05:00
|
|
|
entities: NewRangeSearcher(),
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
2019-12-08 22:18:42 -05:00
|
|
|
|
2020-02-02 14:04:37 -05:00
|
|
|
d2term.BindAction("mapdebugvis", "set map debug visualization level", func(level int) {
|
|
|
|
engine.debugVisLevel = level
|
|
|
|
})
|
|
|
|
|
2019-12-08 22:18:42 -05:00
|
|
|
engine.viewport.SetCamera(&engine.camera)
|
|
|
|
return engine
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) GetStartPosition() (float64, float64) {
|
2019-12-13 00:33:11 -05:00
|
|
|
var startX, startY float64
|
2020-02-01 21:51:49 -05:00
|
|
|
if len(m.regions) > 0 {
|
|
|
|
region := m.regions[0]
|
2019-12-13 00:33:11 -05:00
|
|
|
startX, startY = region.getStartTilePosition()
|
|
|
|
}
|
2019-12-06 09:44:52 -05:00
|
|
|
|
2019-12-13 00:33:11 -05:00
|
|
|
return startX, startY
|
2019-12-06 09:44:52 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) GetCenterPosition() (float64, float64) {
|
2019-12-13 00:33:11 -05:00
|
|
|
var centerX, centerY float64
|
2020-02-01 21:51:49 -05:00
|
|
|
if len(m.regions) > 0 {
|
|
|
|
region := m.regions[0]
|
2019-12-13 00:33:11 -05:00
|
|
|
centerX = float64(region.tileRect.Left) + float64(region.tileRect.Width)/2
|
|
|
|
centerY = float64(region.tileRect.Top) + float64(region.tileRect.Height)/2
|
|
|
|
}
|
2019-11-17 01:14:58 -05:00
|
|
|
|
2019-12-13 00:33:11 -05:00
|
|
|
return centerX, centerY
|
2019-12-08 22:18:42 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) MoveCameraTo(x, y float64) {
|
|
|
|
m.camera.MoveTo(x, y)
|
2019-12-08 22:18:42 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) MoveCameraBy(x, y float64) {
|
|
|
|
m.camera.MoveBy(x, y)
|
2019-12-08 22:18:42 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) ScreenToWorld(x, y int) (float64, float64) {
|
|
|
|
return m.viewport.ScreenToWorld(x, y)
|
2019-11-17 01:14:58 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) ScreenToOrtho(x, y int) (float64, float64) {
|
|
|
|
return m.viewport.ScreenToOrtho(x, y)
|
2019-11-06 21:25:09 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) WorldToOrtho(x, y float64) (float64, float64) {
|
|
|
|
return m.viewport.WorldToOrtho(x, y)
|
2019-11-06 18:25:19 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) {
|
|
|
|
region, entities := loadRegion(m.gameState.Seed, 0, 0, regionType, levelPreset, fileIndex)
|
|
|
|
m.regions = append(m.regions, region)
|
2020-02-26 08:40:32 -05:00
|
|
|
m.entities.Add(entities...)
|
2019-11-06 21:25:09 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) GenerateAct1Overworld() {
|
2020-01-31 23:18:11 -05:00
|
|
|
d2audio.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
|
2019-11-15 11:03:58 -05:00
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
region, entities := loadRegion(m.gameState.Seed, 0, 0, d2enum.RegionAct1Town, 1, -1)
|
|
|
|
m.regions = append(m.regions, region)
|
2020-02-26 08:40:32 -05:00
|
|
|
m.entities.Add(entities...)
|
2019-11-06 21:25:09 -05:00
|
|
|
|
2019-12-13 00:33:11 -05:00
|
|
|
if strings.Contains(region.regionPath, "E1") {
|
2020-02-01 21:51:49 -05:00
|
|
|
region, entities := loadRegion(m.gameState.Seed, region.tileRect.Width-1, 0, d2enum.RegionAct1Town, 2, -1)
|
2020-02-02 12:46:19 -05:00
|
|
|
m.AppendRegion(region)
|
2020-02-26 08:40:32 -05:00
|
|
|
m.entities.Add(entities...)
|
2019-12-13 00:33:11 -05:00
|
|
|
} else if strings.Contains(region.regionPath, "S1") {
|
2020-02-01 21:51:49 -05:00
|
|
|
region, entities := loadRegion(m.gameState.Seed, 0, region.tileRect.Height-1, d2enum.RegionAct1Town, 3, -1)
|
2020-02-02 12:46:19 -05:00
|
|
|
m.AppendRegion(region)
|
2020-02-26 08:40:32 -05:00
|
|
|
m.entities.Add(entities...)
|
2019-11-17 08:09:54 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-02 12:46:19 -05:00
|
|
|
func (m *MapEngine) AppendRegion(region *MapRegion) {
|
|
|
|
// TODO: Stitch together region.walkableArea
|
|
|
|
m.regions = append(m.regions, region)
|
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) GetRegionAtTile(x, y int) *MapRegion {
|
|
|
|
for _, region := range m.regions {
|
2019-12-13 00:33:11 -05:00
|
|
|
if region.tileRect.IsInRect(x, y) {
|
|
|
|
return region
|
2019-11-16 22:53:55 -05:00
|
|
|
}
|
|
|
|
}
|
2019-12-08 22:18:42 -05:00
|
|
|
|
2019-12-13 00:33:11 -05:00
|
|
|
return nil
|
2019-11-16 22:53:55 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) AddEntity(entity MapEntity) {
|
2020-02-26 08:40:32 -05:00
|
|
|
m.entities.Add(entity)
|
2019-11-15 11:03:58 -05:00
|
|
|
}
|
|
|
|
|
2020-02-22 20:44:30 -05:00
|
|
|
func (m *MapEngine) RemoveEntity(entity MapEntity) {
|
|
|
|
if entity == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-26 08:40:32 -05:00
|
|
|
m.entities.Remove(entity)
|
2020-02-22 20:44:30 -05:00
|
|
|
}
|
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) Advance(tickTime float64) {
|
|
|
|
for _, region := range m.regions {
|
|
|
|
if region.isVisbile(m.viewport) {
|
2019-12-13 00:33:11 -05:00
|
|
|
region.advance(tickTime)
|
2019-11-16 22:53:55 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-26 08:40:32 -05:00
|
|
|
for _, entity := range m.entities.All() {
|
2019-12-13 00:33:11 -05:00
|
|
|
entity.Advance(tickTime)
|
2019-11-01 14:12:23 -04:00
|
|
|
}
|
2020-02-26 08:40:32 -05:00
|
|
|
|
|
|
|
m.entities.Update()
|
2019-11-16 22:53:55 -05:00
|
|
|
}
|
2019-11-15 09:04:27 -05:00
|
|
|
|
2020-02-01 21:51:49 -05:00
|
|
|
func (m *MapEngine) Render(target d2render.Surface) {
|
|
|
|
for _, region := range m.regions {
|
|
|
|
if region.isVisbile(m.viewport) {
|
|
|
|
region.renderPass1(m.viewport, target)
|
|
|
|
region.renderDebug(m.debugVisLevel, m.viewport, target)
|
|
|
|
region.renderPass2(m.entities, m.viewport, target)
|
|
|
|
region.renderPass3(m.viewport, target)
|
2019-11-15 09:04:27 -05:00
|
|
|
}
|
|
|
|
}
|
2019-10-31 21:17:13 -04:00
|
|
|
}
|
2020-02-02 12:46:19 -05:00
|
|
|
|
2020-02-22 20:44:30 -05:00
|
|
|
func (m *MapEngine) PathFind(startX, startY, endX, endY float64) (path []astar.Pather, distance float64, found bool) {
|
2020-02-02 12:46:19 -05:00
|
|
|
startTileX := int(math.Floor(startX))
|
|
|
|
startTileY := int(math.Floor(startY))
|
|
|
|
startSubtileX := int((startX - float64(int(startX))) * 5)
|
|
|
|
startSubtileY := int((startY - float64(int(startY))) * 5)
|
|
|
|
startRegion := m.GetRegionAtTile(startTileX, startTileY)
|
2020-02-22 20:44:30 -05:00
|
|
|
startNode := &startRegion.walkableArea[startSubtileY+((startTileY-startRegion.tileRect.Top)*5)][startSubtileX+((startTileX-startRegion.tileRect.Left)*5)]
|
2020-02-02 12:46:19 -05:00
|
|
|
|
|
|
|
endTileX := int(math.Floor(endX))
|
|
|
|
endTileY := int(math.Floor(endY))
|
|
|
|
endSubtileX := int((endX - float64(int(endX))) * 5)
|
|
|
|
endSubtileY := int((endY - float64(int(endY))) * 5)
|
|
|
|
endRegion := m.GetRegionAtTile(endTileX, endTileY)
|
2020-02-22 20:44:30 -05:00
|
|
|
endNode := &endRegion.walkableArea[endSubtileY+((endTileY-endRegion.tileRect.Top)*5)][endSubtileX+((endTileX-endRegion.tileRect.Left)*5)]
|
2020-02-02 12:46:19 -05:00
|
|
|
|
|
|
|
path, distance, found = astar.Path(endNode, startNode)
|
|
|
|
if path != nil {
|
|
|
|
path = path[1:]
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|