diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index f11b43bc51..b17ba11938 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1572,12 +1572,34 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): Args: looker (DefaultObject): Object doing the looking. **kwargs: Arbitrary data for use when overriding. + + Keyword Args: + exit_order (iterable of str): The order in which exits should be listed, with + unspecified exits appearing at the end, alphabetically. + Returns: str: The exits display data. + Examples: + :: + + For a room with exits in the order 'portal', 'south', 'north', and 'out': + obj.get_display_name(looker, exit_order=('north', 'south')) + -> "Exits: north, south, out, and portal." (ANSI codes not shown here) """ + def _sort_exit_names(names): + exit_order = kwargs.get("exit_order") + if not exit_order: + return names + sort_index = {name: key for key, name in enumerate(exit_order)} + names = sorted(names) + end_pos = len(names) + 1 + names.sort(key=lambda name:sort_index.get(name, end_pos)) + return names + exits = self.filter_visible(self.contents_get(content_type="exit"), looker, **kwargs) - exit_names = iter_to_str(exi.get_display_name(looker, **kwargs) for exi in exits) + exit_names = (exi.get_display_name(looker, **kwargs) for exi in exits) + exit_names = iter_to_str(_sort_exit_names(exit_names)) return f"|wExits:|n {exit_names}" if exit_names else "" diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index de23269cdf..e7587b36e0 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -10,6 +10,7 @@ from evennia.typeclasses.tags import ( TagProperty, ) from evennia.utils import create, search +from evennia.utils.ansi import strip_ansi from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTestCase @@ -94,6 +95,21 @@ class DefaultObjectTest(BaseEvenniaTest): all_return_exit = ex1.get_return_exit(return_all=True) self.assertEqual(len(all_return_exit), 2) + def test_exit_order(self): + DefaultExit.create("south", self.room1, self.room2, account=self.account) + DefaultExit.create("portal", self.room1, self.room2, account=self.account) + DefaultExit.create("north", self.room1, self.room2, account=self.account) + DefaultExit.create("aperture", self.room1, self.room2, account=self.account) + + # in creation order + exits = strip_ansi(self.room1.get_display_exits(self.char1)) + self.assertEqual(exits, "Exits: out, south, portal, north, and aperture") + + # in specified order with unspecified exits alpbabetically on the end + exit_order = ('north', 'south', 'out') + exits = strip_ansi(self.room1.get_display_exits(self.char1, exit_order=exit_order)) + self.assertEqual(exits, "Exits: north, south, out, aperture, and portal") + def test_urls(self): "Make sure objects are returning URLs" self.assertTrue(self.char1.get_absolute_url())