First stepping around xyzgrid, still issues

This commit is contained in:
Griatch 2021-07-11 11:25:03 +02:00
parent 8c9f7e58ef
commit d06ae0119a
8 changed files with 159 additions and 16 deletions

View file

@ -83,7 +83,10 @@ class CmdLook(COMMAND_DEFAULT_CLASS):
target = caller.search(self.args)
if not target:
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):

View file

@ -36,7 +36,7 @@ class CmdXYZLook(general.CmdLook):
maxw = min(xymap.max_x, self.client_width())
sep = "~" * maxw
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
super().func()
@ -55,6 +55,7 @@ class CmdXYZTeleport(building.CmdTeleport):
tel/tonone box
tel (3, 3, the small cave)
tel (4, 1) # on the same map
tel/map Z|mapname
Switches:
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
reference. A puppeted object cannot be moved to None.
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
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):
inp = inp.strip("()")
X, Y, *Z = inp.split(",", 2)
if Z:
# Z was specified
@ -93,7 +96,7 @@ class CmdXYZTeleport(building.CmdTeleport):
try:
self.destination = XYZRoom.objects.get_xyz(xyz=(X, Y, Z))
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
def parse(self):
@ -114,7 +117,7 @@ class CmdXYZTeleport(building.CmdTeleport):
self.destination = self.caller.search(self.rhs, global_search=True)
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)
else:
self.destination = self.caller.search(self.lhs, global_search=True)
@ -189,6 +192,5 @@ class XYZGridCmdSet(CmdSet):
key = "xyzgrid_cmdset"
def at_cmdset_creation(self):
self.add(CmdXYZLook())
self.add(CmdXYZTeleport())
self.add(CmdXYZOpen())

View file

@ -18,6 +18,7 @@ Use `evennia xyzgrid help` for usage help.
from os.path import join as pathjoin
from django.conf import settings
from evennia.utils import ansi
from evennia.contrib.xyzgrid.xyzgrid import get_xyzgrid
_HELP_SHORT = """
@ -187,7 +188,7 @@ def _option_list(*suboptions):
print("XYMaps stored in grid:")
for zcoord, xymap in sorted(xymap_data.items(), key=lambda tup: tup[0]):
print("\n" + str(repr(xymap)) + ":\n")
print(str(xymap))
print(ansi.parse_ansi(str(xymap)))
return
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 "
"topology\nlike relocated nodes/rooms and new/removed links/exits - this "
"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"
+ str(xymap.mapstring))
legend = []

View file

@ -1088,6 +1088,7 @@ class MapTransitionMapNode(TransitionMapNode):
class NSMapLink(MapLink):
"""Two-way, North-South link"""
symbol = "|"
display_symbol = "||"
directions = {"n": "s", "s": "n"}
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.
direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
spawn_aliases = {direction: ("up", "u") for direction in direction_aliases}
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.
direction_aliases = {'n': symbol, 'ne': symbol, 'e': symbol, 'se': symbol,
's': symbol, 'sw': symbol, 'w': symbol, 'nw': symbol}
spawn_aliases = {direction: ("down", "do") for direction in direction_aliases}
prototype = "xyz_exit"

View file

@ -774,6 +774,7 @@ class XYMap:
character='@',
target=None, target_path_style="|y{display_symbol}|n",
max_size=None,
indent=0,
return_str=True):
"""
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
away from the center coordinate to display.
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
(or the beginning of said path, if outside of visual range) will be
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
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
return to. Make both odd numbers to get a perfect center.
If unset, display-size can grow up to the full size of the grid.
return to. Make both odd numbers to get a perfect center. Set either of
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
or a 2D list.
@ -914,12 +918,15 @@ class XYMap:
if max_size:
# crop grid to make sure it doesn't grow too far
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)
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]]
if return_str:
# 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:
return gridmap

View file

@ -34,6 +34,7 @@ class XYZGrid(DefaultScript):
"""
self.db.map_data = {}
self.desc = "Manages maps for XYZ-grid"
@property
def grid(self):

View file

@ -8,6 +8,7 @@ used as stand-alone XYZ-coordinate-aware rooms.
"""
from django.db.models import Q
from django.conf import settings
from evennia.objects.objects import DefaultRoom, DefaultExit
from evennia.objects.manager import ObjectManager
@ -226,11 +227,34 @@ class XYZRoom(DefaultRoom):
"""
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
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):
return repr(self)
@ -252,10 +276,12 @@ class XYZRoom(DefaultRoom):
y = self.tags.get(category=MAP_Y_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:
# don't cache unfinished coordinate
return (x, y, z)
# cache result
self._xyz = (x, y, z)
# don't cache unfinished coordinate (probably tags have not finished saving)
return tuple(int(coord) if coord is not None and coord.isdigit() else coord
for coord in (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
@classmethod
@ -302,6 +328,106 @@ class XYZRoom(DefaultRoom):
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):
"""

View file

@ -2269,7 +2269,7 @@ class DefaultCharacter(DefaultObject):
"""
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):
"""