package d2mapengine import ( "math" "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, X: float64(subTileX) / 5.0, Y: float64(subTileY) / 5.0, } 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 }