First stepping around xyzgrid, still issues
This commit is contained in:
parent
75319d3941
commit
de66313ec9
8 changed files with 159 additions and 16 deletions
|
|
@ -83,7 +83,10 @@ class CmdLook(COMMAND_DEFAULT_CLASS):
|
||||||
target = caller.search(self.args)
|
target = caller.search(self.args)
|
||||||
if not target:
|
if not target:
|
||||||
return
|
return
|
||||||
self.msg((caller.at_look(target), {"type": "look"}), options=None)
|
desc = caller.at_look(target)
|
||||||
|
# add the type=look to the outputfunc to make it
|
||||||
|
# easy to separate this output in client.
|
||||||
|
self.msg(text=(desc, {"type": "look"}), options=None)
|
||||||
|
|
||||||
|
|
||||||
class CmdNick(COMMAND_DEFAULT_CLASS):
|
class CmdNick(COMMAND_DEFAULT_CLASS):
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ class CmdXYZLook(general.CmdLook):
|
||||||
maxw = min(xymap.max_x, self.client_width())
|
maxw = min(xymap.max_x, self.client_width())
|
||||||
sep = "~" * maxw
|
sep = "~" * maxw
|
||||||
map_display = f"|x{sep}|n\n{map_display}\n|x{sep}"
|
map_display = f"|x{sep}|n\n{map_display}\n|x{sep}"
|
||||||
self.msg(map_display, {"type", "xymap"}, options=None)
|
self.msg((map_display, {"type": "xymap"}), options=None)
|
||||||
# now run the normal look command
|
# now run the normal look command
|
||||||
super().func()
|
super().func()
|
||||||
|
|
||||||
|
|
@ -55,6 +55,7 @@ class CmdXYZTeleport(building.CmdTeleport):
|
||||||
tel/tonone box
|
tel/tonone box
|
||||||
tel (3, 3, the small cave)
|
tel (3, 3, the small cave)
|
||||||
tel (4, 1) # on the same map
|
tel (4, 1) # on the same map
|
||||||
|
tel/map Z|mapname
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
quiet - don't echo leave/arrive messages to the source/target
|
quiet - don't echo leave/arrive messages to the source/target
|
||||||
|
|
@ -67,6 +68,7 @@ class CmdXYZTeleport(building.CmdTeleport):
|
||||||
an object from a None location is by direct #dbref
|
an object from a None location is by direct #dbref
|
||||||
reference. A puppeted object cannot be moved to None.
|
reference. A puppeted object cannot be moved to None.
|
||||||
loc - teleport object to the target's location instead of its contents
|
loc - teleport object to the target's location instead of its contents
|
||||||
|
map - show coordinate map of given Zcoord/mapname.
|
||||||
|
|
||||||
Teleports an object somewhere. If no object is given, you yourself are
|
Teleports an object somewhere. If no object is given, you yourself are
|
||||||
teleported to the target location. If (X,Y) or (X,Y,Z) coordinates
|
teleported to the target location. If (X,Y) or (X,Y,Z) coordinates
|
||||||
|
|
@ -74,6 +76,7 @@ class CmdXYZTeleport(building.CmdTeleport):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _search_by_xyz(self, inp):
|
def _search_by_xyz(self, inp):
|
||||||
|
inp = inp.strip("()")
|
||||||
X, Y, *Z = inp.split(",", 2)
|
X, Y, *Z = inp.split(",", 2)
|
||||||
if Z:
|
if Z:
|
||||||
# Z was specified
|
# Z was specified
|
||||||
|
|
@ -93,7 +96,7 @@ class CmdXYZTeleport(building.CmdTeleport):
|
||||||
try:
|
try:
|
||||||
self.destination = XYZRoom.objects.get_xyz(xyz=(X, Y, Z))
|
self.destination = XYZRoom.objects.get_xyz(xyz=(X, Y, Z))
|
||||||
except XYZRoom.DoesNotExist:
|
except XYZRoom.DoesNotExist:
|
||||||
self.caller.msg("Found no target XYZRoom at ({X},{Y},{Y}).")
|
self.caller.msg(f"Found no target XYZRoom at ({X},{Y},{Z}).")
|
||||||
raise InterruptCommand
|
raise InterruptCommand
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
|
|
@ -114,7 +117,7 @@ class CmdXYZTeleport(building.CmdTeleport):
|
||||||
self.destination = self.caller.search(self.rhs, global_search=True)
|
self.destination = self.caller.search(self.rhs, global_search=True)
|
||||||
|
|
||||||
elif self.lhs:
|
elif self.lhs:
|
||||||
if all(char in self.rhs for char in ("(", ")", ",")):
|
if all(char in self.lhs for char in ("(", ")", ",")):
|
||||||
self._search_by_xyz(self.lhs)
|
self._search_by_xyz(self.lhs)
|
||||||
else:
|
else:
|
||||||
self.destination = self.caller.search(self.lhs, global_search=True)
|
self.destination = self.caller.search(self.lhs, global_search=True)
|
||||||
|
|
@ -189,6 +192,5 @@ class XYZGridCmdSet(CmdSet):
|
||||||
key = "xyzgrid_cmdset"
|
key = "xyzgrid_cmdset"
|
||||||
|
|
||||||
def at_cmdset_creation(self):
|
def at_cmdset_creation(self):
|
||||||
self.add(CmdXYZLook())
|
|
||||||
self.add(CmdXYZTeleport())
|
self.add(CmdXYZTeleport())
|
||||||
self.add(CmdXYZOpen())
|
self.add(CmdXYZOpen())
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ Use `evennia xyzgrid help` for usage help.
|
||||||
|
|
||||||
from os.path import join as pathjoin
|
from os.path import join as pathjoin
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from evennia.utils import ansi
|
||||||
from evennia.contrib.xyzgrid.xyzgrid import get_xyzgrid
|
from evennia.contrib.xyzgrid.xyzgrid import get_xyzgrid
|
||||||
|
|
||||||
_HELP_SHORT = """
|
_HELP_SHORT = """
|
||||||
|
|
@ -187,7 +188,7 @@ def _option_list(*suboptions):
|
||||||
print("XYMaps stored in grid:")
|
print("XYMaps stored in grid:")
|
||||||
for zcoord, xymap in sorted(xymap_data.items(), key=lambda tup: tup[0]):
|
for zcoord, xymap in sorted(xymap_data.items(), key=lambda tup: tup[0]):
|
||||||
print("\n" + str(repr(xymap)) + ":\n")
|
print("\n" + str(repr(xymap)) + ":\n")
|
||||||
print(str(xymap))
|
print(ansi.parse_ansi(str(xymap)))
|
||||||
return
|
return
|
||||||
|
|
||||||
for zcoord in suboptions:
|
for zcoord in suboptions:
|
||||||
|
|
@ -216,7 +217,7 @@ def _option_list(*suboptions):
|
||||||
print("Note: This check is not complete; it does not consider changed map "
|
print("Note: This check is not complete; it does not consider changed map "
|
||||||
"topology\nlike relocated nodes/rooms and new/removed links/exits - this "
|
"topology\nlike relocated nodes/rooms and new/removed links/exits - this "
|
||||||
"is calculated only during a build.")
|
"is calculated only during a build.")
|
||||||
print("\nDisplayed map (as appearing in-game):\n\n" + str(xymap))
|
print("\nDisplayed map (as appearing in-game):\n\n" + ansi.parse_ansi(str(xymap)))
|
||||||
print("\nRaw map string (including axes and invisible nodes/links):\n"
|
print("\nRaw map string (including axes and invisible nodes/links):\n"
|
||||||
+ str(xymap.mapstring))
|
+ str(xymap.mapstring))
|
||||||
legend = []
|
legend = []
|
||||||
|
|
|
||||||
|
|
@ -1088,6 +1088,7 @@ class MapTransitionMapNode(TransitionMapNode):
|
||||||
class NSMapLink(MapLink):
|
class NSMapLink(MapLink):
|
||||||
"""Two-way, North-South link"""
|
"""Two-way, North-South link"""
|
||||||
symbol = "|"
|
symbol = "|"
|
||||||
|
display_symbol = "||"
|
||||||
directions = {"n": "s", "s": "n"}
|
directions = {"n": "s", "s": "n"}
|
||||||
prototype = "xyz_exit"
|
prototype = "xyz_exit"
|
||||||
|
|
||||||
|
|
@ -1164,6 +1165,7 @@ class UpMapLink(SmartMapLink):
|
||||||
# all movement over this link is 'up', regardless of where on the xygrid we move.
|
# all movement over this link is 'up', regardless of where on the xygrid we move.
|
||||||
direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
|
direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
|
||||||
's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
|
's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
|
||||||
|
spawn_aliases = {direction: ("up", "u") for direction in direction_aliases}
|
||||||
prototype = "xyz_exit"
|
prototype = "xyz_exit"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1173,6 +1175,7 @@ class DownMapLink(UpMapLink):
|
||||||
# all movement over this link is 'down', regardless of where on the xygrid we move.
|
# all movement over this link is 'down', regardless of where on the xygrid we move.
|
||||||
direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
|
direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
|
||||||
's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
|
's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
|
||||||
|
spawn_aliases = {direction: ("down", "do") for direction in direction_aliases}
|
||||||
prototype = "xyz_exit"
|
prototype = "xyz_exit"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -774,6 +774,7 @@ class XYMap:
|
||||||
character='@',
|
character='@',
|
||||||
target=None, target_path_style="|y{display_symbol}|n",
|
target=None, target_path_style="|y{display_symbol}|n",
|
||||||
max_size=None,
|
max_size=None,
|
||||||
|
indent=0,
|
||||||
return_str=True):
|
return_str=True):
|
||||||
"""
|
"""
|
||||||
Get a part of the grid centered on a specific point and extended a certain number
|
Get a part of the grid centered on a specific point and extended a certain number
|
||||||
|
|
@ -791,7 +792,7 @@ class XYMap:
|
||||||
nodes are reachable or not. If 'nodes', distance measure how many linked nodes
|
nodes are reachable or not. If 'nodes', distance measure how many linked nodes
|
||||||
away from the center coordinate to display.
|
away from the center coordinate to display.
|
||||||
character (str, optional): Place this symbol at the `xy` position
|
character (str, optional): Place this symbol at the `xy` position
|
||||||
of the displayed map. The center node' symbol is shown if this is falsy.
|
of the displayed map. The center node's symbol is shown if this is falsy.
|
||||||
target (tuple, optional): A target XY coordinate to go to. The path to this
|
target (tuple, optional): A target XY coordinate to go to. The path to this
|
||||||
(or the beginning of said path, if outside of visual range) will be
|
(or the beginning of said path, if outside of visual range) will be
|
||||||
marked according to `target_path_style`.
|
marked according to `target_path_style`.
|
||||||
|
|
@ -802,8 +803,11 @@ class XYMap:
|
||||||
will receive the MapNode or MapLink object for every step of the path and and
|
will receive the MapNode or MapLink object for every step of the path and and
|
||||||
must return the suitable string to display at the position of the node/link.
|
must return the suitable string to display at the position of the node/link.
|
||||||
max_size (tuple, optional): A max `(width, height)` to crop the displayed
|
max_size (tuple, optional): A max `(width, height)` to crop the displayed
|
||||||
return to. Make both odd numbers to get a perfect center.
|
return to. Make both odd numbers to get a perfect center. Set either of
|
||||||
If unset, display-size can grow up to the full size of the grid.
|
the tuple values to `None` to make that coordinate unlimited. Set entire
|
||||||
|
tuple to None let display-size able to grow up to full size of grid.
|
||||||
|
indent (int, optional): How far to the right to indent the map area (only
|
||||||
|
applies to `return_str=True`).
|
||||||
return_str (bool, optional): Return result as an already formatted string
|
return_str (bool, optional): Return result as an already formatted string
|
||||||
or a 2D list.
|
or a 2D list.
|
||||||
|
|
||||||
|
|
@ -914,12 +918,15 @@ class XYMap:
|
||||||
if max_size:
|
if max_size:
|
||||||
# crop grid to make sure it doesn't grow too far
|
# crop grid to make sure it doesn't grow too far
|
||||||
max_x, max_y = max_size
|
max_x, max_y = max_size
|
||||||
|
max_x = self.max_x if max_x is None else max_x
|
||||||
|
max_y = self.max_y if max_y is None else max_y
|
||||||
xmin, xmax = max(0, ixc - max_x // 2), min(width, ixc + max_x // 2 + 1)
|
xmin, xmax = max(0, ixc - max_x // 2), min(width, ixc + max_x // 2 + 1)
|
||||||
ymin, ymax = max(0, iyc - max_y // 2), min(height, iyc + max_y // 2 + 1)
|
ymin, ymax = max(0, iyc - max_y // 2), min(height, iyc + max_y // 2 + 1)
|
||||||
gridmap = [line[xmin:xmax] for line in gridmap[ymin:ymax]]
|
gridmap = [line[xmin:xmax] for line in gridmap[ymin:ymax]]
|
||||||
|
|
||||||
if return_str:
|
if return_str:
|
||||||
# we must flip the y-axis before returning the string
|
# we must flip the y-axis before returning the string
|
||||||
return "\n".join("".join(line) for line in gridmap[::-1])
|
indent = indent * " "
|
||||||
|
return indent + f"\n{indent}".join("".join(line) for line in gridmap[::-1])
|
||||||
else:
|
else:
|
||||||
return gridmap
|
return gridmap
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class XYZGrid(DefaultScript):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.db.map_data = {}
|
self.db.map_data = {}
|
||||||
|
self.desc = "Manages maps for XYZ-grid"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def grid(self):
|
def grid(self):
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ used as stand-alone XYZ-coordinate-aware rooms.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.conf import settings
|
||||||
from evennia.objects.objects import DefaultRoom, DefaultExit
|
from evennia.objects.objects import DefaultRoom, DefaultExit
|
||||||
from evennia.objects.manager import ObjectManager
|
from evennia.objects.manager import ObjectManager
|
||||||
|
|
||||||
|
|
@ -226,11 +227,34 @@ class XYZRoom(DefaultRoom):
|
||||||
"""
|
"""
|
||||||
A game location aware of its XYZ-position.
|
A game location aware of its XYZ-position.
|
||||||
|
|
||||||
|
Special properties:
|
||||||
|
map_display (bool): If the return_appearance of the room should
|
||||||
|
show the map or not.
|
||||||
|
map_mode (str): One of 'nodes' or 'scan'. See `return_apperance`
|
||||||
|
for examples of how they differ.
|
||||||
|
map_visual_range (int): How far on the map one can see. This is a
|
||||||
|
fixed value here, but could also be dynamic based on skills,
|
||||||
|
light etc.
|
||||||
|
map_character_symbol (str): The character symbol to use to show
|
||||||
|
the character position. Can contain color info. Default is
|
||||||
|
the @-character.
|
||||||
|
map_area_client (bool): If True, map area will always fill the entire
|
||||||
|
client width. If False, the map area's width will vary with the
|
||||||
|
width of the currently displayed location description.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# makes the `room.objects.filter_xymap` available
|
# makes the `room.objects.filter_xymap` available
|
||||||
objects = XYZManager()
|
objects = XYZManager()
|
||||||
|
|
||||||
|
# default settings for map visualization
|
||||||
|
map_display = True
|
||||||
|
map_mode = 'nodes' # or 'scan'
|
||||||
|
map_visual_range = 2
|
||||||
|
map_character_symbol = "@"
|
||||||
|
map_align = 'c'
|
||||||
|
map_area_client = True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return repr(self)
|
return repr(self)
|
||||||
|
|
||||||
|
|
@ -252,10 +276,12 @@ class XYZRoom(DefaultRoom):
|
||||||
y = self.tags.get(category=MAP_Y_TAG_CATEGORY, return_list=False)
|
y = self.tags.get(category=MAP_Y_TAG_CATEGORY, return_list=False)
|
||||||
z = self.tags.get(category=MAP_Z_TAG_CATEGORY, return_list=False)
|
z = self.tags.get(category=MAP_Z_TAG_CATEGORY, return_list=False)
|
||||||
if x is None or y is None or z is None:
|
if x is None or y is None or z is None:
|
||||||
# don't cache unfinished coordinate
|
# don't cache unfinished coordinate (probably tags have not finished saving)
|
||||||
return (x, y, z)
|
return tuple(int(coord) if coord is not None and coord.isdigit() else coord
|
||||||
# cache result
|
for coord in (x, y, z))
|
||||||
self._xyz = (x, y, z)
|
# cache result, convert to correct types (tags are strings)
|
||||||
|
self._xyz = tuple(int(coord) if coord.isdigit() else coord for coord in (x, y, z))
|
||||||
|
|
||||||
return self._xyz
|
return self._xyz
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
@ -302,6 +328,106 @@ class XYZRoom(DefaultRoom):
|
||||||
|
|
||||||
return DefaultRoom.create(key, account=account, tags=tags, typeclass=cls, **kwargs)
|
return DefaultRoom.create(key, account=account, tags=tags, typeclass=cls, **kwargs)
|
||||||
|
|
||||||
|
def return_appearance(self, looker, **kwargs):
|
||||||
|
"""
|
||||||
|
Displays the map in addition to the room description
|
||||||
|
|
||||||
|
Args:
|
||||||
|
looker (Object): The one looking.
|
||||||
|
|
||||||
|
Keyword Args:
|
||||||
|
map_display (bool): Turn on/off map display.
|
||||||
|
map_visual_range (int): How 'far' one can see on the map. For
|
||||||
|
'nodes' mode, this is how many connected nodes away, for
|
||||||
|
'scan' mode, this is number of characters away on the map.
|
||||||
|
Default is a visual range of 2 (nodes).
|
||||||
|
map_mode (str): One of 'node' (default) or 'scan'.
|
||||||
|
map_character_symbol (str): The character symbol to use. Defaults to '@'.
|
||||||
|
This can also be colored with standard color tags. Set to `None`
|
||||||
|
to just show the current node.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
Assume this is the full map (where '@' is the character location):
|
||||||
|
::
|
||||||
|
#----------------#
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
# @------------#-#
|
||||||
|
| |
|
||||||
|
#----------------#
|
||||||
|
|
||||||
|
This is how it will look in 'nodes' mode with `visual_range=2`:
|
||||||
|
::
|
||||||
|
@------------#-#
|
||||||
|
|
||||||
|
And in 'scan' mode with `visual_range=2`:
|
||||||
|
::
|
||||||
|
|
|
||||||
|
|
|
||||||
|
# @--
|
||||||
|
|
|
||||||
|
#----
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
The map kwargs default to values with the same names set on the
|
||||||
|
XYZRoom class; these can be changed by overriding the room.
|
||||||
|
|
||||||
|
We return the map display as a separate msg() call here, in order
|
||||||
|
to make it easier to break this out into a client pane etc. The
|
||||||
|
map is tagged with type='xymap'.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# normal get_appearance of a room
|
||||||
|
room_desc = super().return_appearance(looker, **kwargs)
|
||||||
|
|
||||||
|
if kwargs.get('map_display', self.map_display):
|
||||||
|
# show the near-area map.
|
||||||
|
|
||||||
|
character_symbol = kwargs.get('map_character_symbol', self.map_character_symbol)
|
||||||
|
visual_range = kwargs.get("visual_range", self.map_visual_range)
|
||||||
|
map_mode = kwargs.get("map_mode", self.map_mode)
|
||||||
|
map_align = kwargs.get("map_align", self.map_align)
|
||||||
|
map_area_client = kwargs.get("fill_width", self.map_area_client)
|
||||||
|
client_width, _ = looker.sessions.get()[0].get_client_size()
|
||||||
|
|
||||||
|
# get current xymap
|
||||||
|
xyz = self.xyz
|
||||||
|
xymap = self.xyzgrid.get_map(xyz[2])
|
||||||
|
map_width = xymap.max_x
|
||||||
|
|
||||||
|
if map_area_client:
|
||||||
|
display_width = client_width
|
||||||
|
else:
|
||||||
|
display_width = max(map_width,
|
||||||
|
max(len(line) for line in room_desc.split("\n")))
|
||||||
|
|
||||||
|
# align map
|
||||||
|
map_indent = 0
|
||||||
|
sep_width = display_width
|
||||||
|
if map_align == 'r':
|
||||||
|
map_indent = max(0, display_width - map_width)
|
||||||
|
elif map_align == 'c':
|
||||||
|
map_indent = max(0, (display_width - map_width) // 2)
|
||||||
|
|
||||||
|
# get visual range display from map
|
||||||
|
map_display = xymap.get_visual_range(
|
||||||
|
(xyz[0], xyz[1]),
|
||||||
|
dist=visual_range,
|
||||||
|
mode=map_mode,
|
||||||
|
character=character_symbol,
|
||||||
|
max_size=(display_width, None),
|
||||||
|
indent=map_indent
|
||||||
|
)
|
||||||
|
sep = "~" * sep_width
|
||||||
|
map_display = f"|x{sep}|n\n{map_display}\n|x{sep}"
|
||||||
|
|
||||||
|
# echo directly to make easier to separate in client
|
||||||
|
looker.msg(text=(map_display, {"type": "xymap"}), options=None)
|
||||||
|
|
||||||
|
return room_desc
|
||||||
|
|
||||||
|
|
||||||
class XYZExit(DefaultExit):
|
class XYZExit(DefaultExit):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -2269,7 +2269,7 @@ class DefaultCharacter(DefaultObject):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if self.location.access(self, "view"):
|
if self.location.access(self, "view"):
|
||||||
self.msg(self.at_look(self.location))
|
self.msg(text=(self.at_look(self.location), {"type": "look"}))
|
||||||
|
|
||||||
def at_pre_puppet(self, account, session=None, **kwargs):
|
def at_pre_puppet(self, account, session=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue