func (l Location) NextTileToward(dst entity.Location) entity.Location {
	nextStep := l.Clone()
	if delta := l.X() - dst.X(); delta < 0 {
		nextStep.SetX(nextStep.X()+1)
	} else if delta > 0 {
		nextStep.SetX(nextStep.X()-1)
	}
	if delta := l.Y() - dst.Y(); delta < 0 {
		nextStep.SetY(nextStep.Y()+1)
	} else if delta > 0 {
		nextStep.SetY(nextStep.Y()-1)
	}
	return nextStep
}
NextTileToward Returns the next tile toward the final destination of this pathway from currentLocation
package world
import (
	"fmt"
	"math"
	"go.uber.org/atomic"
	"github.com/spkaeros/rscgo/pkg/game/entity"
	"github.com/spkaeros/rscgo/pkg/rand"
)
type (
	Direction = int
	Plane = int
)
var OrderedDirections = [...]Direction{West, East, North, South, SouthWest, SouthEast, NorthWest, NorthEast}
const (
	North Direction = iota
	NorthWest
	West
	SouthWest
	South
	SouthEast
	East
	NorthEast
	LeftFighting
	RightFighting
)
const (
	PlaneGround Plane = iota
	PlaneSecond
	PlaneThird
	PlaneBasement
)
type Location struct {
	x, y *atomic.Uint32
}
func (l Location) Clone() entity.Location {
	return NewLocation(l.X(), l.Y())
}
func (l Location) X() int {
	if l.x == nil {
		return -1
	}
	return int(l.x.Load())
}
func (l Location) Y() int {
	if l.y == nil {
		return -1
	}
	return int(l.y.Load())
}
func (l Location) SetX(x int) {
	l.x.Store(uint32(x))
}
func (l Location) SetY(y int) {
	l.y.Store(uint32(y))
}
func (l Location) Wilderness() int {
	if l.X() > 344 {
		return 0
	}
	return (2203-(l.Y()+1776))/6 + 1
}
var (
	DeathPoint = NewLocation(0, 0)
	SpawnPoint = Lumbridge.Clone()
	Lumbridge = NewLocation(122, 647)
	Varrock = NewLocation(122, 647)
	Edgeville = NewLocation(220, 445)
)
func NewLocation(x, y int) Location {
	return Location{x: atomic.NewUint32(uint32(x)), y: atomic.NewUint32(uint32(y))}
}
func (l Location) Point() entity.Location {
	return l.Clone()
}
func (l Location) DirectionTo(destX, destY int) int {
	sprites := [3][3]int{{SouthWest, West, NorthWest}, {South, -1, North}, {SouthEast, East, NorthEast}}
	xIndex, yIndex := l.X()-destX+1, l.Y()-destY+1
	if xIndex >= 3 || yIndex >= 3 || yIndex < 0 || xIndex < 0 {
		xIndex, yIndex = 1, 2  
	}
	return sprites[xIndex][yIndex]
}
func NewRandomLocation(bounds [2]Location) Location {
	return NewLocation(rand.Rng.Intn(bounds[1].X()-bounds[0].X())+bounds[0].X(), rand.Rng.Intn(bounds[1].Y()-bounds[0].Y())+bounds[0].Y())
}
func (l Location) String() string {
	return fmt.Sprintf("[%d,%d]", l.X(), l.Y())
}
func (l Location) Within(minX, maxX, minY, maxY int) bool {
	return l.WithinArea([2]entity.Location { NewLocation(minX, minY), NewLocation(maxX, maxY) })
}
func (l Location) IsValid() bool {
	return l.WithinArea([2]entity.Location { NewLocation(0, 0), NewLocation(MaxX, MaxY)})
}
func (l Location) NextStep(d entity.Location) entity.Location {
	next := l.Step(l.DirectionToward(d))
	if l.Collides(next) {
		if l.X() < d.X() {
			if next = l.Step(West); l.Collides(next) {
				return next
			}
		}
		if l.X() > d.X() {
			if next = l.Step(East); l.Collides(next) {
				return next
			}
		}
		if l.Y() < d.Y() {
			if next = l.Step(South); l.Collides(next) {
				return next
			}
			next = l.Step(South)
		}
		if l.Y() > d.Y() {
			if next = l.Step(North); l.Collides(next) {
				return next
			}
			next = l.Step(North)
		}
	}
	return next
}
func (l Location) PivotTo(loc entity.Location) (deltas [2][]int) {
	step := 0.0
	deltaX := float64(loc.X() - l.X())
	deltaY := float64(loc.Y() - l.Y())
	if math.Abs(deltaX) >= math.Abs(deltaY) {
		step = math.Abs(deltaX)
	} else {
		step = math.Abs(deltaY)
	}
	deltaX /= step
	deltaY /= step
	x, y := float64(l.X()), float64(l.Y())
	for i := 1.0; i <= step; i++ {
		if l.Collides(NewLocation(int(math.Floor(x)),int(math.Floor(y)))) {
			return [2][]int { {}, {} }
		} else {
			deltas[0] = append(deltas[0], int(x+deltaX))
			deltas[1] = append(deltas[1], int(y+deltaY))
		}
		x += deltaX
		y += deltaY
	}
	return
}
func (l Location) Collides(dst entity.Location) bool {
	return !l.ReachableCoords(dst.X(), dst.Y())
}
func (l Location) ReachableCoords(x, y int) bool {
	dst := entity.Location(NewLocation(x, y))
	if l.LongestDelta(dst) > 1 {
		dst = l.NextTileToward(dst)
	}
	if IsTileBlocking(l.X(), l.Y(), byte(ClipBit(l.DirectionToward(dst))), true) ||
			IsTileBlocking(dst.X(), dst.Y(), byte(ClipBit(dst.DirectionToward(l))), false) {
		return false
	}
	if dst.X() != l.X() && dst.Y() != l.Y() {
		var vmask, hmask byte
		if dst.X() > l.X() {
			vmask |= ClipSouth
		} else {
			vmask |= ClipNorth
		}
		if dst.Y() > l.Y() {
			hmask |= ClipEast
		} else {
			hmask |= ClipWest
		}
		return !IsTileBlocking(l.X(), dst.Y(), vmask, false) || !IsTileBlocking(dst.X(), l.Y(), hmask, false)
	}
	return true
}
func (l Location) Step(dir int) entity.Location {
	loc := l.Clone()
	if dir == 2 || dir == 1 || dir == 3 {
		loc.SetX(loc.X()+1)
	} else if dir == 5 || dir == 6 || dir == 7 {
		loc.SetX(loc.X()-1)
	}
	if dir == 7 || dir == 0 || dir == 1 {
		loc.SetY(loc.Y()-1)
	} else if dir == 4 || dir == 5 || dir == 6 {
		loc.SetY(loc.Y()+1)
	}
	return loc
}
func (l Location) Equals(o interface{}) bool {
	switch o.(type) {
	case Location:
		return l.LongestDelta(o.(Location)) == 0
	case *Location:
		return l.LongestDelta(*o.(*Location)) == 0
	case *Player:
		return l.LongestDelta(o.(*Player).Point()) == 0
	case Player:
		return l.LongestDelta(o.(Player).Point()) == 0
	case *NPC:
		return l.LongestDelta(o.(*NPC).Point()) == 0
	case NPC:
		return l.LongestDelta(o.(NPC).Point()) == 0
	case *Object:
		return l.LongestDelta(o.(*Object).Entity.Location) == 0
	case Object:
		return l.LongestDelta(o.(Object).Entity.Location) == 0
	case *GroundItem:
		return l.LongestDelta(o.(*GroundItem).Entity.Location) == 0
	case GroundItem:
		return l.LongestDelta(o.(GroundItem).Entity.Location) == 0
	case *Mob:
		return l.LongestDelta(o.(*Mob).Point()) == 0
	case Mob:
		return l.LongestDelta(o.(Mob).Point()) == 0
	}
	return false
}
func (l Location) Delta(other entity.Location) (delta int) {
	return l.LongestDelta(other)
}
func (l Location) DeltaX(other entity.Location) (deltaX int) {
	deltaX = int(math.Abs(float64(other.X()) - float64(l.X())))
	return
}
func (l Location) DeltaY(other entity.Location) (deltaY int) {
	deltaY = int(math.Abs(float64(other.Y()) - float64(l.Y())))
	return
}
func (l Location) TheirDeltaY(other entity.Location) (deltaY int) {
	return other.Y() - l.Y()
}
func (l Location) TheirDeltaX(other entity.Location) (deltaY int) {
	return other.X() - l.X()
}
func (l Location) LongestDelta(other entity.Location) int {
	if x, y := l.DeltaX(other), l.DeltaY(other); x > y {
		return x
	} else {
		return y
	}
}
func (l Location) LongestDeltaCoords(x, y int) int {
	return l.LongestDelta(NewLocation(x, y))
}
func (l Location) EuclideanDistance(other entity.Location) float64 {
	return math.Sqrt(math.Pow(float64(l.DeltaX(other)), 2) + math.Pow(float64(l.DeltaY(other)), 2))
}
func (l Location) WithinRange(other entity.Location, radius int) bool {
	return l.Near(other, radius)
}
func (l Location) Near(other entity.Location, radius int) bool {
	return l.LongestDeltaCoords(other.X(), other.Y()) <= radius
}
func (l Location) Plane() int {
	return int(l.y.Load()+100) / 944  
}
func (l Location) Above() entity.Location {
	return NewLocation(l.X(), l.PlaneY(true))
}
func (l Location) Below() entity.Location {
	return NewLocation(l.X(), l.PlaneY(false))
}
func (l Location) DirectionToward(end entity.Location) int {
	tile := l.NextTileToward(end)
	return l.DirectionTo(tile.X(), tile.Y())
}
func (l Location) PlaneY(up bool) int {
	curPlane := l.Plane()
	var newPlane int
	if up {
		switch curPlane {
		case PlaneBasement:
			newPlane = 0
		case PlaneThird:
			newPlane = curPlane
		default:
			newPlane = curPlane + 1
		}
	} else {
		switch curPlane {
		case PlaneGround:
			newPlane = PlaneBasement
		case PlaneBasement:
			newPlane = curPlane
		default:
			newPlane = curPlane - 1
		}
	}
	return newPlane*944 + l.Y()%944
}