1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-12 10:40:42 +00:00

Simple LOS pathfinding without walkmesh (#610)

* Reorganize MapEngine

This is already turning into a mess...

* Map engine selects tile index to use

Still very ugly

* Fix subtile flag combination

* Prepare randomly generated base tiles

* Restore collision viewer

* Movement works again, searches for straight paths

Paths are now d2vector slices

* Fix LOS calculation

* Fix test (I think)
This commit is contained in:
Ziemas 2020-07-21 14:50:45 +02:00 committed by GitHub
parent aadfa35e6b
commit d0c6cd61dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 286 additions and 321 deletions

View File

@ -1,16 +1,9 @@
package d2ds1 package d2ds1
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
)
// TileRecord represents a tile record in a DS1 file. // TileRecord represents a tile record in a DS1 file.
type TileRecord struct { type TileRecord struct {
Floors []FloorShadowRecord // Collection of floor records Floors []FloorShadowRecord // Collection of floor records
Walls []WallRecord // Collection of wall records Walls []WallRecord // Collection of wall records
Shadows []FloorShadowRecord // Collection of shadow records Shadows []FloorShadowRecord // Collection of shadow records
Substitutions []SubstitutionRecord // Collection of substitutions Substitutions []SubstitutionRecord // Collection of substitutions
// This is set and used internally by the engine to determine what region this map is from
RegionType d2enum.RegionIdType
} }

View File

@ -1,10 +1,8 @@
package d2maprenderer package d2dt1
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1" func DecodeTileGfxData(blocks []Block, pixels *[]byte, tileYOffset int32, tileWidth int32) {
func (mr *MapRenderer) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, tileYOffset int32, tileWidth int32) {
for _, block := range blocks { for _, block := range blocks {
if block.Format == d2dt1.BlockFormatIsometric { if block.Format == BlockFormatIsometric {
// 3D isometric decoding // 3D isometric decoding
xjump := []int32{14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14} xjump := []int32{14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14}
nbpix := []int32{4, 8, 12, 16, 20, 24, 28, 32, 28, 24, 20, 16, 12, 8, 4} nbpix := []int32{4, 8, 12, 16, 20, 24, 28, 32, 28, 24, 20, 16, 12, 8, 4}

View File

@ -12,6 +12,18 @@ type SubTileFlags struct {
Unknown3 bool Unknown3 bool
} }
// Combine combines a second set of flags into the current one
func (s *SubTileFlags) Combine(f SubTileFlags) {
s.BlockWalk = s.BlockWalk || f.BlockWalk
s.BlockLOS = s.BlockLOS || f.BlockLOS
s.BlockJump = s.BlockJump || f.BlockJump
s.BlockPlayerWalk = s.BlockPlayerWalk || f.BlockPlayerWalk
s.Unknown1 = s.Unknown1 || f.Unknown1
s.BlockLight = s.BlockLight || f.BlockLight
s.Unknown2 = s.Unknown2 || f.Unknown2
s.Unknown3 = s.Unknown3 || f.Unknown3
}
// DebugString returns the debug string // DebugString returns the debug string
func (s *SubTileFlags) DebugString() string { func (s *SubTileFlags) DebugString() string {
result := "" result := ""

View File

@ -16,16 +16,3 @@ type Tile struct {
blockHeaderSize int32 blockHeaderSize int32
Blocks []Block Blocks []Block
} }
// GetSubTileFlags returns the tile flags for the given subtile
func (t *Tile) GetSubTileFlags(x, y int) *SubTileFlags {
var subtileLookup = [5][5]int{
{20, 21, 22, 23, 24},
{15, 16, 17, 18, 19},
{10, 11, 12, 13, 14},
{5, 6, 7, 8, 9},
{0, 1, 2, 3, 4},
}
return &t.SubTileFlags[subtileLookup[y][x]]
}

View File

@ -71,7 +71,7 @@ func (p *Position) RenderOffset() *Vector {
return p.subTileOffset().AddScalar(1) return p.subTileOffset().AddScalar(1)
} }
// SubTileOffset is the offset from the current map tile in sub tiles. // subTileOffset is the offset from the current map tile in sub tiles.
func (p *Position) subTileOffset() *Vector { func (p *Position) subTileOffset() *Vector {
t := p.Tile().Scale(subTilesPerTile) t := p.Tile().Scale(subTilesPerTile)
c := p.Clone() c := p.Clone()

View File

@ -20,13 +20,12 @@ import (
// MapEngine loads the tiles which make up the isometric map and the entities // MapEngine loads the tiles which make up the isometric map and the entities
type MapEngine struct { type MapEngine struct {
seed int64 // The map seed seed int64 // The map seed
entities []d2interface.MapEntity // Entities on the map entities []d2interface.MapEntity // Entities on the map
tiles []d2ds1.TileRecord // Map tiles tiles []MapTile
size d2common.Size // Size of the map, in tiles size d2common.Size // Size of the map, in tiles
levelType d2datadict.LevelTypeRecord // Level type of this map levelType d2datadict.LevelTypeRecord // Level type of this map
dt1TileData []d2dt1.Tile // DT1 tile data dt1TileData []d2dt1.Tile // DT1 tile data
walkMesh []d2common.PathTile // Sub tiles representing the walkable map area
startSubTileX int // Starting X position startSubTileX int // Starting X position
startSubTileY int // Starting Y position startSubTileY int // Starting Y position
dt1Files []string // List of DS1 strings dt1Files []string // List of DS1 strings
@ -39,11 +38,6 @@ func CreateMapEngine() *MapEngine {
return engine return engine
} }
// WalkMesh returns a pointer to a slice with the map's PathTiles.
func (m *MapEngine) WalkMesh() *[]d2common.PathTile {
return &m.walkMesh
}
// GetStartingPosition returns the starting position on the map in // GetStartingPosition returns the starting position on the map in
// sub-tiles. // sub-tiles.
func (m *MapEngine) GetStartingPosition() (int, int) { func (m *MapEngine) GetStartingPosition() (int, int) {
@ -56,9 +50,8 @@ func (m *MapEngine) ResetMap(levelType d2enum.RegionIdType, width, height int) {
m.entities = make([]d2interface.MapEntity, 0) m.entities = make([]d2interface.MapEntity, 0)
m.levelType = d2datadict.LevelTypes[levelType] m.levelType = d2datadict.LevelTypes[levelType]
m.size = d2common.Size{Width: width, Height: height} m.size = d2common.Size{Width: width, Height: height}
m.tiles = make([]d2ds1.TileRecord, width*height) m.tiles = make([]MapTile, width*height)
m.dt1TileData = make([]d2dt1.Tile, 0) m.dt1TileData = make([]d2dt1.Tile, 0)
m.walkMesh = make([]d2common.PathTile, width*height*25)
m.dt1Files = make([]string, 0) m.dt1Files = make([]string, 0)
for idx := range m.levelType.Files { for idx := range m.levelType.Files {
@ -67,7 +60,7 @@ func (m *MapEngine) ResetMap(levelType d2enum.RegionIdType, width, height int) {
} }
func (m *MapEngine) addDT1(fileName string) { func (m *MapEngine) addDT1(fileName string) {
if len(fileName) == 0 || fileName == "0" { if fileName == "" || fileName == "0" {
return return
} }
@ -81,8 +74,8 @@ func (m *MapEngine) addDT1(fileName string) {
fileData, err := d2asset.LoadFile("/data/global/tiles/" + fileName) fileData, err := d2asset.LoadFile("/data/global/tiles/" + fileName)
if err != nil { if err != nil {
log.Printf("Could not load /data/global/tiles/%s", fileName) log.Printf("Could not load /data/global/tiles/%s", fileName)
return
// panic(err) // panic(err)
return
} }
dt1, _ := d2dt1.LoadDT1(fileData) dt1, _ := d2dt1.LoadDT1(fileData)
@ -94,7 +87,7 @@ func (m *MapEngine) addDT1(fileName string) {
// appends the tile data and files to MapEngine.dt1TileData and // appends the tile data and files to MapEngine.dt1TileData and
// MapEngine.dt1Files. // MapEngine.dt1Files.
func (m *MapEngine) AddDS1(fileName string) { func (m *MapEngine) AddDS1(fileName string) {
if len(fileName) == 0 || fileName == "0" { if fileName == "" || fileName == "0" {
return return
} }
@ -108,24 +101,13 @@ func (m *MapEngine) AddDS1(fileName string) {
for idx := range ds1.Files { for idx := range ds1.Files {
dt1File := ds1.Files[idx] dt1File := ds1.Files[idx]
dt1File = strings.ToLower(dt1File) dt1File = strings.ToLower(dt1File)
dt1File = strings.Replace(dt1File, "c:", "", -1) // Yes they did... dt1File = strings.ReplaceAll(dt1File, "c:", "") // Yes they did...
dt1File = strings.Replace(dt1File, ".tg1", ".dt1", -1) // Yes they did... dt1File = strings.ReplaceAll(dt1File, ".tg1", ".dt1") // Yes they did...
dt1File = strings.Replace(dt1File, "\\d2\\data\\global\\tiles\\", "", -1) dt1File = strings.ReplaceAll(dt1File, "\\d2\\data\\global\\tiles\\", "")
m.addDT1(strings.Replace(dt1File, "\\", "/", -1)) m.addDT1(strings.ReplaceAll(dt1File, "\\", "/"))
} }
} }
// FindTile returns the tile of given stye, sequence and tileType.
func (m *MapEngine) FindTile(style, sequence, tileType int32) d2dt1.Tile {
for idx := range m.dt1TileData {
if m.dt1TileData[idx].Style == style && m.dt1TileData[idx].Sequence == sequence && m.dt1TileData[idx].Type == tileType {
return m.dt1TileData[idx]
}
}
panic("Could not find the requested tile!")
}
// LevelType returns the level type of this map. // LevelType returns the level type of this map.
func (m *MapEngine) LevelType() d2datadict.LevelTypeRecord { func (m *MapEngine) LevelType() d2datadict.LevelTypeRecord {
return m.levelType return m.levelType
@ -144,13 +126,13 @@ func (m *MapEngine) Size() d2common.Size {
// Tile returns the TileRecord containing the data // Tile returns the TileRecord containing the data
// for a single map tile. // for a single map tile.
func (m *MapEngine) Tile(x, y int) *d2ds1.TileRecord { func (m *MapEngine) Tile(x, y int) *MapTile {
return &m.tiles[x+(y*m.size.Width)] return &m.tiles[x+(y*m.size.Width)]
} }
// Tiles returns a pointer to a slice contaning all // Tiles returns a pointer to a slice contaning all
// map tile data. // map tile data.
func (m *MapEngine) Tiles() *[]d2ds1.TileRecord { func (m *MapEngine) Tiles() *[]MapTile {
return &m.tiles return &m.tiles
} }
@ -178,7 +160,9 @@ func (m *MapEngine) PlaceStamp(stamp *d2mapstamp.Stamp, tileOffsetX, tileOffsetY
for x := 0; x < stampW; x++ { for x := 0; x < stampW; x++ {
targetTileIndex := m.tileCoordinateToIndex((x + xMin), (y + yMin)) targetTileIndex := m.tileCoordinateToIndex((x + xMin), (y + yMin))
stampTile := *stamp.Tile(x, y) stampTile := *stamp.Tile(x, y)
m.tiles[targetTileIndex] = stampTile m.tiles[targetTileIndex].RegionType = stamp.RegionID()
m.tiles[targetTileIndex].Components = stampTile
m.tiles[targetTileIndex].PrepareTile(x, y, m)
} }
} }
@ -196,9 +180,16 @@ func (m *MapEngine) tileIndexToCoordinate(index int) (int, int) {
return (index % m.size.Width), (index / m.size.Width) return (index % m.size.Width), (index / m.size.Width)
} }
// SubTileAt gets the flags for the given subtile
func (m *MapEngine) SubTileAt(subX, subY int) *d2dt1.SubTileFlags {
tile := m.TileAt(subX/5, subY/5)
return tile.GetSubTileFlags(subX%5, subY%5)
}
// TileAt returns a pointer to the data for the map tile at the given // TileAt returns a pointer to the data for the map tile at the given
// x and y index. // x and y index.
func (m *MapEngine) TileAt(tileX, tileY int) *d2ds1.TileRecord { func (m *MapEngine) TileAt(tileX, tileY int) *MapTile {
idx := m.tileCoordinateToIndex(tileX, tileY) idx := m.tileCoordinateToIndex(tileX, tileY)
if idx < 0 || idx >= len(m.tiles) { if idx < 0 || idx >= len(m.tiles) {
return nil return nil
@ -232,11 +223,12 @@ func (m *MapEngine) RemoveEntity(entity d2interface.MapEntity) {
// GetTiles returns a slice of all tiles matching the given style, // GetTiles returns a slice of all tiles matching the given style,
// sequence and tileType. // sequence and tileType.
func (m *MapEngine) GetTiles(style, sequence, tileType int32) []d2dt1.Tile { func (m *MapEngine) GetTiles(style, sequence, tileType int) []d2dt1.Tile {
var tiles []d2dt1.Tile var tiles []d2dt1.Tile
for idx := range m.dt1TileData { for idx := range m.dt1TileData {
if m.dt1TileData[idx].Style != style || m.dt1TileData[idx].Sequence != sequence || m.dt1TileData[idx].Type != tileType { if m.dt1TileData[idx].Style != int32(style) || m.dt1TileData[idx].Sequence != int32(sequence) ||
m.dt1TileData[idx].Type != int32(tileType) {
continue continue
} }
@ -255,7 +247,7 @@ func (m *MapEngine) GetTiles(style, sequence, tileType int32) []d2dt1.Tile {
func (m *MapEngine) GetStartPosition() (float64, float64) { func (m *MapEngine) GetStartPosition() (float64, float64) {
for tileY := 0; tileY < m.size.Height; tileY++ { for tileY := 0; tileY < m.size.Height; tileY++ {
for tileX := 0; tileX < m.size.Width; tileX++ { for tileX := 0; tileX < m.size.Width; tileX++ {
tile := m.tiles[tileX+(tileY*m.size.Width)] tile := m.tiles[tileX+(tileY*m.size.Width)].Components
for idx := range tile.Walls { for idx := range tile.Walls {
if tile.Walls[idx].Type.Special() && tile.Walls[idx].Style == 30 { if tile.Walls[idx].Type.Special() && tile.Walls[idx].Style == 30 {
return float64(tileX) + 0.5, float64(tileY) + 0.5 return float64(tileX) + 0.5, float64(tileY) + 0.5
@ -285,7 +277,7 @@ func (m *MapEngine) TileExists(tileX, tileY int) bool {
tileIndex := m.tileCoordinateToIndex(tileX, tileY) tileIndex := m.tileCoordinateToIndex(tileX, tileY)
if valid := (tileIndex >= 0) && (tileIndex <= len(m.tiles)); valid { if valid := (tileIndex >= 0) && (tileIndex <= len(m.tiles)); valid {
tile := m.tiles[tileIndex] tile := m.tiles[tileIndex].Components
numFeatures := len(tile.Floors) numFeatures := len(tile.Floors)
numFeatures += len(tile.Shadows) numFeatures += len(tile.Shadows)
numFeatures += len(tile.Walls) numFeatures += len(tile.Walls)
@ -305,10 +297,11 @@ func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int,
m.PlaceStamp(region, 0, 0) m.PlaceStamp(region, 0, 0)
} }
// GetTileData returns the tile with the given style, sequence and tileType. // GetTileData returns the tile with the given style, sequence, tileType and index.
func (m *MapEngine) GetTileData(style int32, sequence int32, tileType d2enum.TileType) *d2dt1.Tile { func (m *MapEngine) GetTileData(style, sequence int, tileType d2enum.TileType, index byte) *d2dt1.Tile {
for idx := range m.dt1TileData { for idx := range m.dt1TileData {
if m.dt1TileData[idx].Style == style && m.dt1TileData[idx].Sequence == sequence && m.dt1TileData[idx].Type == int32(tileType) { if m.dt1TileData[idx].Style == int32(style) && m.dt1TileData[idx].Sequence == int32(sequence) &&
m.dt1TileData[idx].Type == int32(tileType) && m.dt1TileData[idx].RarityFrameIndex == int32(index) {
return &m.dt1TileData[idx] return &m.dt1TileData[idx]
} }
} }

View File

@ -0,0 +1,118 @@
package d2mapengine
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
)
// MapTile is a tile placed on the map
type MapTile struct {
Components d2ds1.TileRecord
RegionType d2enum.RegionIdType
SubTiles [25]d2dt1.SubTileFlags
}
// GetSubTileFlags returns the tile flags for the given subtile
func (t *MapTile) GetSubTileFlags(x, y int) *d2dt1.SubTileFlags {
var subtileLookup = [5][5]int{
{20, 21, 22, 23, 24},
{15, 16, 17, 18, 19},
{10, 11, 12, 13, 14},
{5, 6, 7, 8, 9},
{0, 1, 2, 3, 4},
}
return &t.SubTiles[subtileLookup[y][x]]
}
// PrepareTile selects which graphic to use and updates the tiles subtileflags
func (t *MapTile) PrepareTile(x, y int, me *MapEngine) {
for wIdx := range t.Components.Walls {
wall := &t.Components.Walls[wIdx]
options := me.GetTiles(int(wall.Style), int(wall.Sequence), int(wall.Type))
if options == nil {
break
}
wall.RandomIndex = getRandomTile(options, x, y, me.seed)
for i := range t.SubTiles {
t.SubTiles[i].Combine(options[wall.RandomIndex].SubTileFlags[i])
}
}
for fIdx := range t.Components.Floors {
floor := &t.Components.Floors[fIdx]
options := me.GetTiles(int(floor.Style), int(floor.Sequence), 0)
if options == nil {
break
}
if options[0].MaterialFlags.Lava {
floor.Animated = true
floor.RandomIndex = 0
} else {
floor.RandomIndex = getRandomTile(options, x, y, me.seed)
}
for i := range t.SubTiles {
t.SubTiles[i].Combine(options[floor.RandomIndex].SubTileFlags[i])
}
}
for sIdx := range t.Components.Shadows {
shadow := &t.Components.Shadows[sIdx]
options := me.GetTiles(int(shadow.Style), int(shadow.Sequence), 13)
if options == nil {
break
}
shadow.RandomIndex = getRandomTile(options, x, y, me.seed)
for i := range t.SubTiles {
t.SubTiles[i].Combine(options[shadow.RandomIndex].SubTileFlags[i])
}
}
}
// Selects a random tile from the slice, rest of args just used for seeding
func getRandomTile(tiles []d2dt1.Tile, x, y int, seed int64) byte {
/* Walker's Alias Method for weighted random selection
* with xorshifting for random numbers */
var tileSeed uint64
tileSeed = uint64(seed) + uint64(x)
tileSeed *= uint64(y)
tileSeed ^= tileSeed << 13
tileSeed ^= tileSeed >> 17
tileSeed ^= tileSeed << 5
weightSum := 0
for i := range tiles {
weightSum += int(tiles[i].RarityFrameIndex)
}
if weightSum == 0 {
return 0
}
random := tileSeed % uint64(weightSum)
sum := 0
for i := range tiles {
sum += int(tiles[i].RarityFrameIndex)
if sum >= int(random) {
return byte(i)
}
}
// This return shouldn't be hit
return 0
}

View File

@ -0,0 +1,47 @@
package d2mapengine
import (
"math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
)
func (m *MapEngine) PathFind(start, dest d2vector.Position) []d2vector.Position {
points := make([]d2vector.Position, 0)
_, point := m.checkLos(start, dest)
points = append(points, point)
return points
}
// checkLos finds out if there is a clear line of sight between two points
func (m *MapEngine) checkLos(start, end d2vector.Position) (bool, d2vector.Position) {
dv := d2vector.Position{Vector: end.Clone()}
dv.Subtract(&start.Vector)
dx := dv.X()
dy := dv.Y()
N := math.Max(math.Abs(dx), math.Abs(dy))
var divN float64
if N == 0 {
divN = 0.0
} else {
divN = 1.0 / N
}
xstep := dx * divN
ystep := dy * divN
x := start.X()
y := start.Y()
for i := 0; i <= int(N); i++ {
x += xstep
y += ystep
if m.SubTileAt(int(math.Floor(x)), int(math.Floor(y))).BlockWalk {
return false, d2vector.NewPosition(x-xstep, y-ystep)
}
}
return true, end
}

View File

@ -1,133 +0,0 @@
package d2mapengine
import (
"math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2astar"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
)
// RegenerateWalkPaths based on current tile data.
func (m *MapEngine) RegenerateWalkPaths() {
for subTileY := 0; subTileY < m.size.Height*5; subTileY++ {
tileY := int(float64(subTileY) / 5.0)
for subTileX := 0; subTileX < m.size.Width*5; subTileX++ {
tileX := int(float64(subTileX) / 5.0)
tile := m.TileAt(tileX, tileY)
isBlocked := false
for _, floor := range tile.Floors {
tileData := m.GetTileData(int32(floor.Style), int32(floor.Sequence), d2enum.TileFloor)
if tileData == nil {
continue
}
tileSubAttributes := tileData.GetSubTileFlags(subTileX%5, subTileY%5)
isBlocked = isBlocked || tileSubAttributes.BlockWalk
if isBlocked {
break
}
}
if !isBlocked {
for _, wall := range tile.Walls {
tileData := m.GetTileData(int32(wall.Style), int32(wall.Sequence), wall.Type)
if tileData == nil {
continue
}
tileSubAttributes := tileData.GetSubTileFlags(subTileX%5, subTileY%5)
isBlocked = isBlocked || tileSubAttributes.BlockWalk
if isBlocked {
break
}
}
}
index := subTileX + (subTileY * m.size.Width * 5)
m.walkMesh[index] = d2common.PathTile{
Walkable: !isBlocked,
Position: d2vector.NewPosition(
float64(subTileX),
float64(subTileY)),
}
ySkew := m.size.Width * 5
if !isBlocked && subTileY > 0 && m.walkMesh[index-ySkew].Walkable {
m.walkMesh[index].Up = &m.walkMesh[index-ySkew]
m.walkMesh[index-ySkew].Down = &m.walkMesh[index]
}
if !isBlocked && subTileX > 0 && m.walkMesh[index-1].Walkable {
m.walkMesh[index].Left = &m.walkMesh[index-1]
m.walkMesh[index-1].Right = &m.walkMesh[index]
}
if !isBlocked && subTileX > 0 && subTileY > 0 && m.walkMesh[(index-ySkew)-1].Walkable {
m.walkMesh[index].UpLeft = &m.walkMesh[(index-ySkew)-1]
m.walkMesh[(index-ySkew)-1].DownRight = &m.walkMesh[index]
}
if !isBlocked && subTileY > 0 && subTileX < (m.size.Width*5)-1 && m.walkMesh[(index-ySkew)+1].Walkable {
m.walkMesh[index].UpRight = &m.walkMesh[(index-ySkew)+1]
m.walkMesh[(index-ySkew)+1].DownLeft = &m.walkMesh[index]
}
}
}
}
// PathFind finds a walkable path between two points.
func (m *MapEngine) PathFind(startX, startY, endX, endY float64) (path []d2astar.Pather, distance float64, found bool) {
startTileX := int(math.Floor(startX))
startTileY := int(math.Floor(startY))
if !m.TileExists(startTileX, startTileY) {
return
}
startSubtileX := int((startX - float64(int(startX))) * 5)
startSubtileY := int((startY - float64(int(startY))) * 5)
startNodeIndex := ((startSubtileY + (startTileY * 5)) * m.size.Width * 5) + startSubtileX + ((startTileX) * 5)
if startNodeIndex < 0 || startNodeIndex >= len(m.walkMesh) {
return
}
startNode := &m.walkMesh[startNodeIndex]
endTileX := int(math.Floor(endX))
endTileY := int(math.Floor(endY))
if !m.TileExists(endTileX, endTileY) {
return
}
endSubtileX := int((endX - float64(int(endX))) * 5)
endSubtileY := int((endY - float64(int(endY))) * 5)
endNodeIndex := ((endSubtileY + (endTileY * 5)) * m.size.Width * 5) + endSubtileX + ((endTileX) * 5)
if endNodeIndex < 0 || endNodeIndex >= len(m.walkMesh) {
return
}
endNode := &m.walkMesh[endNodeIndex]
path, distance, found = d2astar.Path(startNode, endNode, 80)
if path != nil {
// Reverse the path to fit what the game expects.
for i := len(path)/2 - 1; i >= 0; i-- {
opp := len(path) - 1 - i
path[i], path[opp] = path[opp], path[i]
}
path = path[1:]
}
return
}

View File

@ -3,8 +3,6 @@ package d2mapentity
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2astar"
) )
// mapEntity represents an entity on the map that can be animated // mapEntity represents an entity on the map that can be animated
@ -14,7 +12,7 @@ type mapEntity struct {
velocity d2vector.Vector velocity d2vector.Vector
Speed float64 Speed float64
path []d2astar.Pather path []d2vector.Position
drawLayer int drawLayer int
done func() done func()
@ -38,7 +36,7 @@ func (m *mapEntity) GetLayer() int {
// SetPath sets the entity movement path. done() is called when the entity reaches it's path destination. For example, // SetPath sets the entity movement path. done() is called when the entity reaches it's path destination. For example,
// when the player entity reaches the point a player clicked. // when the player entity reaches the point a player clicked.
func (m *mapEntity) SetPath(path []d2astar.Pather, done func()) { func (m *mapEntity) SetPath(path []d2vector.Position, done func()) {
m.path = path m.path = path
m.done = done m.done = done
m.nextPath() m.nextPath()
@ -140,14 +138,14 @@ func (m *mapEntity) nextPath() {
if m.hasPath() { if m.hasPath() {
// Set next path node // Set next path node
m.setTarget( m.setTarget(
m.path[0].(*d2common.PathTile).Position, m.path[0],
m.done, m.done,
) )
if len(m.path) > 1 { if len(m.path) > 1 {
m.path = m.path[1:] m.path = m.path[1:]
} else { } else {
m.path = []d2astar.Pather{} m.path = []d2vector.Position{}
} }
} else { } else {
// End of path. // End of path.

View File

@ -5,9 +5,6 @@ import (
"testing" "testing"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2astar"
) )
var stepEntity mapEntity var stepEntity mapEntity
@ -38,8 +35,8 @@ func movingEntity() mapEntity {
return e return e
} }
func path(length int, origin d2vector.Position) []d2astar.Pather { func path(length int, origin d2vector.Position) []d2vector.Position {
path := make([]d2astar.Pather, length) path := make([]d2vector.Position, length)
for i := 0; i < length; i++ { for i := 0; i < length; i++ {
origin.AddScalar(float64(i+1) / 5) origin.AddScalar(float64(i+1) / 5)
@ -50,8 +47,8 @@ func path(length int, origin d2vector.Position) []d2astar.Pather {
return path return path
} }
func pathTile(x, y float64) *d2common.PathTile { func pathTile(x, y float64) d2vector.Position {
return &d2common.PathTile{Position: d2vector.NewPositionTile(x, y)} return d2vector.NewPositionTile(x, y)
} }
func TestMapEntity_Step(t *testing.T) { func TestMapEntity_Step(t *testing.T) {

View File

@ -66,7 +66,7 @@ func GenerateAct1Overworld(mapEngine *d2mapengine.MapEngine) {
mapEngine.PlaceStamp(townStamp, mapWidth-townSize.Width, mapHeight-townSize.Height) mapEngine.PlaceStamp(townStamp, mapWidth-townSize.Width, mapHeight-townSize.Height)
} }
mapEngine.RegenerateWalkPaths() //mapEngine.RegenerateWalkPaths()
} }
func generateWilderness1TownEast(mapEngine *d2mapengine.MapEngine, startX, startY int) { func generateWilderness1TownEast(mapEngine *d2mapengine.MapEngine, startX, startY int) {
@ -264,7 +264,8 @@ func generateWilderness1Contents(mapEngine *d2mapengine.MapEngine, rect d2common
for x := 0; x < rect.Width; x++ { for x := 0; x < rect.Width; x++ {
tile := mapEngine.Tile(rect.Left+x, rect.Top+y) tile := mapEngine.Tile(rect.Left+x, rect.Top+y)
tile.RegionType = d2enum.RegionIdType(levelDetails.LevelType) tile.RegionType = d2enum.RegionIdType(levelDetails.LevelType)
tile.Floors = []d2ds1.FloorShadowRecord{wildernessGrass} tile.Components.Floors = []d2ds1.FloorShadowRecord{wildernessGrass}
tile.PrepareTile(x, y, mapEngine)
} }
} }
@ -320,11 +321,11 @@ func areaEmpty(mapEngine *d2mapengine.MapEngine, rect d2common.Rectangle) bool {
for y := rect.Top; y <= rect.Bottom(); y++ { for y := rect.Top; y <= rect.Bottom(); y++ {
for x := rect.Left; x <= rect.Right(); x++ { for x := rect.Left; x <= rect.Right(); x++ {
if len(mapEngine.Tile(x, y).Floors) == 0 { if len(mapEngine.Tile(x, y).Components.Floors) == 0 {
continue continue
} }
floor := mapEngine.Tile(x, y).Floors[0] floor := mapEngine.Tile(x, y).Components.Floors[0]
if floor.Style != 0 || floor.Sequence != 0 || floor.Prop1 != 1 { if floor.Style != 0 || floor.Sequence != 0 || floor.Prop1 != 1 {
return false return false

View File

@ -208,36 +208,36 @@ func (mr *MapRenderer) renderPass4(target d2interface.Surface, startX, startY, e
} }
} }
func (mr *MapRenderer) renderTilePass1(tile *d2ds1.TileRecord, target d2interface.Surface) { func (mr *MapRenderer) renderTilePass1(tile *d2mapengine.MapTile, target d2interface.Surface) {
for _, wall := range tile.Walls { for _, wall := range tile.Components.Walls {
if !wall.Hidden && wall.Prop1 != 0 && wall.Type.LowerWall() { if !wall.Hidden && wall.Prop1 != 0 && wall.Type.LowerWall() {
mr.renderWall(wall, mr.viewport, target) mr.renderWall(wall, mr.viewport, target)
} }
} }
for _, floor := range tile.Floors { for _, floor := range tile.Components.Floors {
if !floor.Hidden && floor.Prop1 != 0 { if !floor.Hidden && floor.Prop1 != 0 {
mr.renderFloor(floor, target) mr.renderFloor(floor, target)
} }
} }
for _, shadow := range tile.Shadows { for _, shadow := range tile.Components.Shadows {
if !shadow.Hidden && shadow.Prop1 != 0 { if !shadow.Hidden && shadow.Prop1 != 0 {
mr.renderShadow(shadow, target) mr.renderShadow(shadow, target)
} }
} }
} }
func (mr *MapRenderer) renderTilePass2(tile *d2ds1.TileRecord, target d2interface.Surface) { func (mr *MapRenderer) renderTilePass2(tile *d2mapengine.MapTile, target d2interface.Surface) {
for _, wall := range tile.Walls { for _, wall := range tile.Components.Walls {
if !wall.Hidden && wall.Type.UpperWall() { if !wall.Hidden && wall.Type.UpperWall() {
mr.renderWall(wall, mr.viewport, target) mr.renderWall(wall, mr.viewport, target)
} }
} }
} }
func (mr *MapRenderer) renderTilePass3(tile *d2ds1.TileRecord, target d2interface.Surface) { func (mr *MapRenderer) renderTilePass3(tile *d2mapengine.MapTile, target d2interface.Surface) {
for _, wall := range tile.Walls { for _, wall := range tile.Components.Walls {
if wall.Type == d2enum.TileRoof { if wall.Type == d2enum.TileRoof {
mr.renderWall(wall, mr.viewport, target) mr.renderWall(wall, mr.viewport, target)
} }
@ -359,7 +359,7 @@ func (mr *MapRenderer) renderTileDebug(ax, ay int, debugVisLevel int, target d2i
target.Pop() target.Pop()
}*/ }*/
for i, wall := range tile.Walls { for i, wall := range tile.Components.Walls {
if wall.Type.Special() { if wall.Type.Special() {
target.PushTranslation(-20, 10+(i+1)*14) target.PushTranslation(-20, 10+(i+1)*14)
target.DrawTextf("s: %v-%v", wall.Style, wall.Sequence) target.DrawTextf("s: %v-%v", wall.Style, wall.Sequence)
@ -372,9 +372,9 @@ func (mr *MapRenderer) renderTileDebug(ax, ay int, debugVisLevel int, target d2i
isoX := (xx - yy) * 16 isoX := (xx - yy) * 16
isoY := (xx + yy) * 8 isoY := (xx + yy) * 8
var walkableArea = (*mr.mapEngine.WalkMesh())[((yy+(ay*5))*mr.mapEngine.Size().Width*5)+xx+(ax*5)] blocked := tile.GetSubTileFlags(xx, yy).BlockWalk
if !walkableArea.Walkable { if blocked {
target.PushTranslation(isoX-3, isoY+4) target.PushTranslation(isoX-3, isoY+4)
target.DrawRect(5, 5, tileCollisionColor) target.DrawRect(5, 5, tileCollisionColor)
target.Pop() target.Pop()

View File

@ -18,33 +18,31 @@ func (mr *MapRenderer) generateTileCache() {
tileX := idx % mapEngineSize.Width tileX := idx % mapEngineSize.Width
tileY := (idx - tileX) / mapEngineSize.Width tileY := (idx - tileX) / mapEngineSize.Width
for i := range tile.Floors { for i := range tile.Components.Floors {
if !tile.Floors[i].Hidden && tile.Floors[i].Prop1 != 0 { if !tile.Components.Floors[i].Hidden && tile.Components.Floors[i].Prop1 != 0 {
mr.generateFloorCache(&tile.Floors[i], tileX, tileY) mr.generateFloorCache(&tile.Components.Floors[i], tileX, tileY)
} }
} }
for i := range tile.Shadows { for i := range tile.Components.Shadows {
if !tile.Shadows[i].Hidden && tile.Shadows[i].Prop1 != 0 { if !tile.Components.Shadows[i].Hidden && tile.Components.Shadows[i].Prop1 != 0 {
mr.generateShadowCache(&tile.Shadows[i], tileX, tileY) mr.generateShadowCache(&tile.Components.Shadows[i], tileX, tileY)
} }
} }
for i := range tile.Walls { for i := range tile.Components.Walls {
if !tile.Walls[i].Hidden && tile.Walls[i].Prop1 != 0 { if !tile.Components.Walls[i].Hidden && tile.Components.Walls[i].Prop1 != 0 {
mr.generateWallCache(&tile.Walls[i], tileX, tileY) mr.generateWallCache(&tile.Components.Walls[i], tileX, tileY)
} }
} }
} }
} }
func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) { func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) {
tileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), 0) tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 0)
var tileData []*d2dt1.Tile var tileData []*d2dt1.Tile
var tileIndex byte
if tileOptions == nil { if tileOptions == nil {
log.Printf("Could not locate tile Style:%d, Seq: %d, Type: %d\n", tile.Style, tile.Sequence, 0) log.Printf("Could not locate tile Style:%d, Seq: %d, Type: %d\n", tile.Style, tile.Sequence, 0)
@ -53,8 +51,7 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
tileData[0].Height = 10 tileData[0].Height = 10
} else { } else {
if !tileOptions[0].MaterialFlags.Lava { if !tileOptions[0].MaterialFlags.Lava {
tileIndex = mr.getRandomTile(tileOptions, tileX, tileY, mr.mapEngine.Seed()) tileData = append(tileData, &tileOptions[tile.RandomIndex])
tileData = append(tileData, &tileOptions[tileIndex])
} else { } else {
tile.Animated = true tile.Animated = true
for i := range tileOptions { for i := range tileOptions {
@ -63,11 +60,13 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
} }
} }
var tileIndex byte
for i := range tileData { for i := range tileData {
if !tileData[i].MaterialFlags.Lava { if tileData[i].MaterialFlags.Lava {
tile.RandomIndex = tileIndex
} else {
tileIndex = byte(tileData[i].RarityFrameIndex) tileIndex = byte(tileData[i].RarityFrameIndex)
} else {
tileIndex = tile.RandomIndex
} }
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex) cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex)
@ -86,7 +85,7 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
tileHeight := d2common.AbsInt32(tileData[i].Height) tileHeight := d2common.AbsInt32(tileData[i].Height)
image, _ := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2enum.FilterNearest) image, _ := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2enum.FilterNearest)
indexData := make([]byte, tileData[i].Width*tileHeight) indexData := make([]byte, tileData[i].Width*tileHeight)
mr.decodeTileGfxData(tileData[i].Blocks, &indexData, tileYOffset, tileData[i].Width) d2dt1.DecodeTileGfxData(tileData[i].Blocks, &indexData, tileYOffset, tileData[i].Width)
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette) pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
_ = image.ReplacePixels(pixels) _ = image.ReplacePixels(pixels)
@ -95,24 +94,20 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
} }
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) { func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) {
tileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), 13) tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 13)
var tileIndex byte
var tileData *d2dt1.Tile var tileData *d2dt1.Tile
if tileOptions == nil { if tileOptions == nil {
return return
} else { } else {
tileIndex = mr.getRandomTile(tileOptions, tileX, tileY, mr.mapEngine.Seed()) tileData = &tileOptions[tile.RandomIndex]
tileData = &tileOptions[tileIndex]
} }
if tileData.Width == 0 || tileData.Height == 0 { if tileData.Width == 0 || tileData.Height == 0 {
return return
} }
tile.RandomIndex = tileIndex
tileMinY := int32(0) tileMinY := int32(0)
tileMaxY := int32(0) tileMaxY := int32(0)
@ -125,41 +120,35 @@ func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX,
tileHeight := int(tileMaxY - tileMinY) tileHeight := int(tileMaxY - tileMinY)
tile.YAdjust = int(tileMinY + 80) tile.YAdjust = int(tileMinY + 80)
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, 13, tileIndex) cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex)
if cachedImage != nil { if cachedImage != nil {
return return
} }
image, _ := mr.renderer.NewSurface(int(tileData.Width), tileHeight, d2enum.FilterNearest) image, _ := mr.renderer.NewSurface(int(tileData.Width), tileHeight, d2enum.FilterNearest)
indexData := make([]byte, tileData.Width*int32(tileHeight)) indexData := make([]byte, tileData.Width*int32(tileHeight))
mr.decodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileData.Width) d2dt1.DecodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileData.Width)
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette) pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
_ = image.ReplacePixels(pixels) _ = image.ReplacePixels(pixels)
mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tileIndex, image) mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex, image)
} }
func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY int) { func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY int) {
tileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), int32(tile.Type)) tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), int(tile.Type))
var tileIndex byte
var tileData *d2dt1.Tile var tileData *d2dt1.Tile
if tileOptions == nil { if tileOptions == nil {
return return
} else {
tileIndex = mr.getRandomTile(tileOptions, tileX, tileY, mr.mapEngine.Seed())
tileData = &tileOptions[tileIndex]
} }
tile.RandomIndex = tileIndex tileData = &tileOptions[tile.RandomIndex]
var newTileData *d2dt1.Tile = nil var newTileData *d2dt1.Tile = nil
if tile.Type == 3 { if tile.Type == 3 {
newTileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), int32(4)) newTileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), int(4))
newTileIndex := mr.getRandomTile(newTileOptions, tileX, tileY, mr.mapEngine.Seed()) newTileData = &newTileOptions[tile.RandomIndex]
newTileData = &newTileOptions[newTileIndex]
} }
tileMinY := int32(0) tileMinY := int32(0)
@ -186,7 +175,7 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY in
tile.YAdjust = int(tileMinY) + 80 tile.YAdjust = int(tileMinY) + 80
} }
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tileIndex) cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
if cachedImage != nil { if cachedImage != nil {
return return
} }
@ -199,10 +188,10 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY in
image, _ := mr.renderer.NewSurface(160, int(realHeight), d2enum.FilterNearest) image, _ := mr.renderer.NewSurface(160, int(realHeight), d2enum.FilterNearest)
indexData := make([]byte, 160*realHeight) indexData := make([]byte, 160*realHeight)
mr.decodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, 160) d2dt1.DecodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, 160)
if newTileData != nil { if newTileData != nil {
mr.decodeTileGfxData(newTileData.Blocks, &indexData, tileYOffset, 160) d2dt1.DecodeTileGfxData(newTileData.Blocks, &indexData, tileYOffset, 160)
} }
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette) pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
@ -211,42 +200,5 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY in
log.Panicf(err.Error()) log.Panicf(err.Error())
} }
mr.setImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tileIndex, image) mr.setImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex, image)
}
func (mr *MapRenderer) getRandomTile(tiles []d2dt1.Tile, x, y int, seed int64) byte {
/* Walker's Alias Method for weighted random selection
* with xorshifting for random numbers */
var tileSeed uint64
tileSeed = uint64(seed) + uint64(x)
tileSeed *= uint64(y) + uint64(mr.mapEngine.LevelType().ID)
tileSeed ^= tileSeed << 13
tileSeed ^= tileSeed >> 17
tileSeed ^= tileSeed << 5
weightSum := 0
for _, tile := range tiles {
weightSum += int(tile.RarityFrameIndex)
}
if weightSum == 0 {
return 0
}
random := tileSeed % uint64(weightSum)
sum := 0
for i, tile := range tiles {
sum += int(tile.RarityFrameIndex)
if sum >= int(random) {
return byte(i)
}
}
// This return shouldn't be hit
return 0
} }

View File

@ -21,7 +21,8 @@ import (
// Stamp represents a pre-fabricated map stamp that can be placed on a map. // Stamp represents a pre-fabricated map stamp that can be placed on a map.
type Stamp struct { type Stamp struct {
regionPath string // The file path of the region regionPath string // The file path of the region
regionID d2enum.RegionIdType
levelType d2datadict.LevelTypeRecord // The level type id for this stamp levelType d2datadict.LevelTypeRecord // The level type id for this stamp
levelPreset d2datadict.LevelPresetRecord // The level preset id for this stamp levelPreset d2datadict.LevelPresetRecord // The level preset id for this stamp
tiles []d2dt1.Tile // The tiles contained on this stamp tiles []d2dt1.Tile // The tiles contained on this stamp
@ -31,6 +32,7 @@ type Stamp struct {
// LoadStamp loads the Stamp data from file. // LoadStamp loads the Stamp data from file.
func LoadStamp(levelType d2enum.RegionIdType, levelPreset, fileIndex int) *Stamp { func LoadStamp(levelType d2enum.RegionIdType, levelPreset, fileIndex int) *Stamp {
stamp := &Stamp{ stamp := &Stamp{
regionID: levelType,
levelType: d2datadict.LevelTypes[levelType], levelType: d2datadict.LevelTypes[levelType],
levelPreset: d2datadict.LevelPresets[levelPreset], levelPreset: d2datadict.LevelPresets[levelPreset],
} }
@ -74,13 +76,6 @@ func LoadStamp(levelType d2enum.RegionIdType, levelPreset, fileIndex int) *Stamp
stamp.ds1, _ = d2ds1.LoadDS1(fileData) stamp.ds1, _ = d2ds1.LoadDS1(fileData)
// Update the region info for the tiles
for rx := 0; rx < len(stamp.ds1.Tiles); rx++ {
for x := 0; x < len(stamp.ds1.Tiles[rx]); x++ {
stamp.ds1.Tiles[rx][x].RegionType = levelType
}
}
return stamp return stamp
} }
@ -99,6 +94,11 @@ func (mr *Stamp) LevelType() d2datadict.LevelTypeRecord {
return mr.levelType return mr.levelType
} }
// RegionPath returns the file path of the region.
func (mr *Stamp) RegionID() d2enum.RegionIdType {
return mr.regionID
}
// RegionPath returns the file path of the region. // RegionPath returns the file path of the region.
func (mr *Stamp) RegionPath() string { func (mr *Stamp) RegionPath() string {
return mr.regionPath return mr.regionPath

View File

@ -14,7 +14,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player" "github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
@ -92,7 +91,7 @@ type MapEngineTest struct {
lastMouseX, lastMouseY int lastMouseX, lastMouseY int
selX, selY int selX, selY int
selectedTile *d2ds1.TileRecord selectedTile *d2mapengine.MapTile
//TODO: this is region specific properties, should be refactored for multi-region rendering //TODO: this is region specific properties, should be refactored for multi-region rendering
currentRegion int currentRegion int
@ -164,7 +163,7 @@ func (met *MapEngineTest) loadRegionByIndex(n, levelPreset, fileIndex int) {
met.mapEngine = d2mapengine.CreateMapEngine() // necessary for map name update met.mapEngine = d2mapengine.CreateMapEngine() // necessary for map name update
met.mapEngine.SetSeed(time.Now().UnixNano()) met.mapEngine.SetSeed(time.Now().UnixNano())
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex, true) met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex, true)
met.mapEngine.RegenerateWalkPaths() //met.mapEngine.RegenerateWalkPaths()
} }
met.mapRenderer.SetMapEngine(met.mapEngine) met.mapRenderer.SetMapEngine(met.mapEngine)
@ -227,7 +226,7 @@ func (met *MapEngineTest) Render(screen d2interface.Surface) error {
screen.PushTranslation(15, 16) screen.PushTranslation(15, 16)
screen.DrawTextf("Walls") screen.DrawTextf("Walls")
tpop := 0 tpop := 0
for _, wall := range met.selectedTile.Walls { for _, wall := range met.selectedTile.Components.Walls {
screen.PushTranslation(0, 12) screen.PushTranslation(0, 12)
tpop++ tpop++
tmpString := fmt.Sprintf("%#v", wall) tmpString := fmt.Sprintf("%#v", wall)
@ -245,7 +244,7 @@ func (met *MapEngineTest) Render(screen d2interface.Surface) error {
screen.PushTranslation(170, 0) screen.PushTranslation(170, 0)
screen.DrawTextf("Floors") screen.DrawTextf("Floors")
tpop = 0 tpop = 0
for _, floor := range met.selectedTile.Floors { for _, floor := range met.selectedTile.Components.Floors {
screen.PushTranslation(0, 12) screen.PushTranslation(0, 12)
tpop++ tpop++
tmpString := fmt.Sprintf("%#v", floor) tmpString := fmt.Sprintf("%#v", floor)
@ -263,7 +262,7 @@ func (met *MapEngineTest) Render(screen d2interface.Surface) error {
tpop = 0 tpop = 0
screen.PushTranslation(170, 0) screen.PushTranslation(170, 0)
screen.DrawTextf("Shadows") screen.DrawTextf("Shadows")
for _, shadow := range met.selectedTile.Shadows { for _, shadow := range met.selectedTile.Components.Shadows {
screen.PushTranslation(0, 12) screen.PushTranslation(0, 12)
tpop++ tpop++
tmpString := fmt.Sprintf("%#v", shadow) tmpString := fmt.Sprintf("%#v", shadow)
@ -281,7 +280,7 @@ func (met *MapEngineTest) Render(screen d2interface.Surface) error {
tpop = 0 tpop = 0
screen.PushTranslation(170, 0) screen.PushTranslation(170, 0)
screen.DrawTextf("Substitutions") screen.DrawTextf("Substitutions")
for _, subst := range met.selectedTile.Substitutions { for _, subst := range met.selectedTile.Components.Substitutions {
screen.PushTranslation(0, 12) screen.PushTranslation(0, 12)
tpop++ tpop++
tmpString := fmt.Sprintf("%#v", subst) tmpString := fmt.Sprintf("%#v", subst)

View File

@ -8,6 +8,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math/d2vector"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen" "github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapgen"
@ -175,7 +176,9 @@ func (g *GameClient) handleAddPlayerPacket(packet d2netpacket.NetPacket) error {
func (g *GameClient) handleMovePlayerPacket(packet d2netpacket.NetPacket) error { func (g *GameClient) handleMovePlayerPacket(packet d2netpacket.NetPacket) error {
movePlayer := packet.PacketData.(d2netpacket.MovePlayerPacket) movePlayer := packet.PacketData.(d2netpacket.MovePlayerPacket)
player := g.Players[movePlayer.PlayerID] player := g.Players[movePlayer.PlayerID]
path, _, _ := g.MapEngine.PathFind(movePlayer.StartX, movePlayer.StartY, movePlayer.DestX, movePlayer.DestY) start := d2vector.NewPositionTile(movePlayer.StartX, movePlayer.StartY)
dest := d2vector.NewPositionTile(movePlayer.DestX, movePlayer.DestY)
path := g.MapEngine.PathFind(start, dest)
if len(path) > 0 { if len(path) > 0 {
player.SetPath(path, func() { player.SetPath(path, func() {