# Source code for bravo.location

```from copy import copy
from math import cos, degrees, radians, pi, sin, sqrt

from construct import Container

from bravo.beta.packets import make_packet

[docs]class Location(object):
"""
The position and orientation of an entity.
"""

__slots__ = (
"grounded",
"phi",
"stance",
"_theta",
"x",
"_y",
"z",
)

def __init__(self):
# Position in pixels.
self.x = 0
self.stance = 0
self.y = 0
self.z = 0

# Theta and phi are like the theta and phi of spherical coordinates,
# except that phi starts perpendicular to the xz-plane.
self._theta = 0
self.phi = 0

# Whether we are in the air.
self.grounded = False

def __repr__(self):
return "<Location(%s, (%d, %d (+%.6f), %d), (%.2f, %.2f))>" % (
"grounded" if self.grounded else "midair", self.x, self.y,
self.stance - self.y, self.z, self.theta, self.phi)

__str__ = __repr__

def _y_setter(self, value):
self._y = value
if not 0.1 < (self.stance - self.y) < 1.65:
self.stance = self.y + 1.0
y = property(lambda self: self._y, _y_setter)

def _yaw_setter(self, value):
yaw = property(lambda self: int(round(degrees(self.theta))), _yaw_setter)

def _theta_setter(self, value):
self._theta = value % (pi * 2)
theta = property(lambda self: self._theta, _theta_setter)

def _pitch_setter(self, value):
pitch = property(lambda self: int(round(degrees(self.phi))),
_pitch_setter)

[docs]    def save_to_packet(self):
"""
Returns a position/look/grounded packet.
"""

position = Container(x=self.x, y=self.stance, z=self.z, stance=self.y)
orientation = Container(rotation=self.yaw, pitch=self.pitch)
grounded = Container(grounded=self.grounded)

packet = make_packet("location", position=position,
orientation=orientation, grounded=grounded)

return packet

[docs]    def distance(self, other):
"""
Return the distance between this location and another location.

Distance is measured in blocks.
"""

dx = (self.x - other.x)**2
dy = (self.y - other.y)**2
dz = (self.z - other.z)**2
return sqrt(dx + dy + dz)

[docs]    def in_front_of(self, distance):
"""
Return a ``Location`` a certain number of blocks in front of this
position.

The orientation of the returned location is undefined.

:param int distance: the number of blocks by which to offset this
position
"""

other = copy(self)

# Do some trig to put the other location a few blocks ahead of the
# player in the direction they are facing. Note that all three
# coordinates are "misnamed;" the unit circle actually starts at (0,
# 1) and goes *backwards* towards (-1, 0).
other.x = self.x - distance * sin(self.theta)
other.z = self.z + distance * cos(self.theta)

return other
```