diff --git a/CHANGELOG.md b/CHANGELOG.md index e4d221010d..3a37e982ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -178,6 +178,8 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10 move being done ('teleport', 'disembark', 'give' etc). (volund) - Made RPSystem contrib msg calls pass `pose` or `say` as msg-`type` for use in e.g. webclient pane filtering where desired. (volund) +- Added `Account.uses_screenreader(session=None)` as a quick shortcut for + finding if a user uses a screenreader (and adjust display accordingly). ## Evennia 0.9.5 diff --git a/evennia/accounts/accounts.py b/evennia/accounts/accounts.py index 4b566c7238..9eb9529c0f 100644 --- a/evennia/accounts/accounts.py +++ b/evennia/accounts/accounts.py @@ -12,32 +12,32 @@ instead for most things). """ import re import time +from random import getrandbits + from django.conf import settings from django.contrib.auth import authenticate, password_validation from django.core.exceptions import ImproperlyConfigured, ValidationError from django.utils import timezone from django.utils.module_loading import import_string -from evennia.typeclasses.models import TypeclassBase +from django.utils.translation import gettext as _ from evennia.accounts.manager import AccountManager from evennia.accounts.models import AccountDB -from evennia.objects.models import ObjectDB +from evennia.commands.cmdsethandler import CmdSetHandler from evennia.comms.models import ChannelDB +from evennia.objects.models import ObjectDB +from evennia.scripts.scripthandler import ScriptHandler from evennia.server.models import ServerConfig -from evennia.server.throttle import Throttle -from evennia.utils import class_from_module, create, logger -from evennia.utils.utils import lazy_property, to_str, make_iter, is_iter, variable_from_module from evennia.server.signals import ( SIGNAL_ACCOUNT_POST_CREATE, SIGNAL_OBJECT_POST_PUPPET, SIGNAL_OBJECT_POST_UNPUPPET, ) -from evennia.typeclasses.attributes import NickHandler, ModelAttributeBackend -from evennia.scripts.scripthandler import ScriptHandler -from evennia.commands.cmdsethandler import CmdSetHandler +from evennia.server.throttle import Throttle +from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler +from evennia.typeclasses.models import TypeclassBase +from evennia.utils import class_from_module, create, logger from evennia.utils.optionhandler import OptionHandler - -from django.utils.translation import gettext as _ -from random import getrandbits +from evennia.utils.utils import is_iter, lazy_property, make_iter, to_str, variable_from_module __all__ = ("DefaultAccount", "DefaultGuest") @@ -237,6 +237,22 @@ class DefaultAccount(AccountDB, metaclass=TypeclassBase): return objs + def uses_screenreader(self, session=None): + """ + Shortcut to determine if a session uses a screenreader. If no session given, + will return true if any of the sessions use a screenreader. + + Args: + session (Session, optional): The session to check for screen reader. + + """ + if session: + return bool(session.protocol_flags.get("SCREENREADER", False)) + else: + return any( + session.protocol_flags.get("SCREENREADER") for session in self.sessions.all() + ) + def get_display_name(self, looker, **kwargs): """ This is used by channels and other OOC communications methods to give a diff --git a/evennia/contrib/tutorials/evadventure/rooms.py b/evennia/contrib/tutorials/evadventure/rooms.py index 63ea6240c0..d8bfd61170 100644 --- a/evennia/contrib/tutorials/evadventure/rooms.py +++ b/evennia/contrib/tutorials/evadventure/rooms.py @@ -1,15 +1,24 @@ """ EvAdventure rooms. +The base EvAdventure room has a modified display header that shows a little mini-map. +All EvAdventure rooms inherit from this room, and it is integral to combat as well as +the dungeon generation. But one can also mix with other non-EvAdventure rooms (you will +just not be able to fight in them). """ from copy import deepcopy -from evennia import AttributeProperty, DefaultCharacter, DefaultRoom, TagProperty +from evennia import DefaultCharacter, DefaultRoom from evennia.utils.utils import inherits_from +CHAR_SYMBOL = "|w@|n" +CHAR_ALT_SYMBOL = "|w>|n" +ROOM_SYMBOL = "|bo|n" +LINK_COLOR = "|B" + _MAP_GRID = [ [" ", " ", " ", " ", " "], [" ", " ", " ", " ", " "], @@ -18,9 +27,9 @@ _MAP_GRID = [ [" ", " ", " ", " ", " "], ] _EXIT_GRID_SHIFT = { - "north": (0, 1, "|"), + "north": (0, 1, "||"), "east": (1, 0, "-"), - "south": (0, -1, "|"), + "south": (0, -1, "||"), "west": (-1, 0, "-"), "northeast": (1, 1, "/"), "southeast": (1, -1, "\\"), @@ -46,24 +55,28 @@ class EvAdventureRoom(DefaultRoom): def get_display_header(self, looker, **kwargs): """ Display the current location as a mini-map. + """ - if not inherits_from(looker, DefaultCharacter): - # we don't need a map for npcs/mobs + # make sure to not show make a map for users of screenreaders. + # for optimization we also don't show it to npcs/mobs + if not inherits_from(looker, DefaultCharacter) or ( + looker.account and looker.account.uses_screenreader() + ): return "" # build a map map_grid = deepcopy(_MAP_GRID) dx0, dy0 = 2, 2 - map_grid[dy0][dx0] = "|w@|n" + map_grid[dy0][dx0] = CHAR_SYMBOL for exi in self.exits: dx, dy, symbol = _EXIT_GRID_SHIFT.get(exi.key, (None, None, None)) if symbol is None: - # we have a non-cardinal direction to go to - mark us blue to indicate this - map_grid[dy0][dx0] = "|b>|n" + # we have a non-cardinal direction to go to - indicate this + map_grid[dy0][dx0] = CHAR_ALT_SYMBOL continue - map_grid[dy0 + dy][dx0 + dx] = symbol + map_grid[dy0 + dy][dx0 + dx] = f"{LINK_COLOR}{symbol}|n" if exi.destination != self: - map_grid[dy0 + dy + dy][dx0 + dx + dx] = "X" + map_grid[dy0 + dy + dy][dx0 + dx + dx] = ROOM_SYMBOL # Note that on the grid, dy is really going *downwards* (origo is # in the top left), so we need to reverse the order at the end to mirror it diff --git a/evennia/contrib/tutorials/evadventure/tests/mixins.py b/evennia/contrib/tutorials/evadventure/tests/mixins.py index 1bc4da2cde..f6f1747429 100644 --- a/evennia/contrib/tutorials/evadventure/tests/mixins.py +++ b/evennia/contrib/tutorials/evadventure/tests/mixins.py @@ -4,10 +4,17 @@ Helpers for testing evadventure modules. """ from evennia.utils import create -from ..characters import EvAdventureCharacter -from ..objects import EvAdventureObject -from ..rooms import EvAdventureRoom + from .. import enums +from ..characters import EvAdventureCharacter +from ..objects import ( + EvAdventureArmor, + EvAdventureHelmet, + EvAdventureObject, + EvAdventureShield, + EvAdventureWeapon, +) +from ..rooms import EvAdventureRoom class EvAdventureMixin: @@ -23,27 +30,27 @@ class EvAdventureMixin: EvAdventureCharacter, key="testchar", location=self.location ) self.helmet = create.create_object( - EvAdventureObject, + EvAdventureHelmet, key="helmet", attributes=[("inventory_use_slot", enums.WieldLocation.HEAD), ("armor", 1)], ) self.shield = create.create_object( - EvAdventureObject, + EvAdventureShield, key="shield", attributes=[("inventory_use_slot", enums.WieldLocation.SHIELD_HAND), ("armor", 1)], ) self.armor = create.create_object( - EvAdventureObject, + EvAdventureArmor, key="armor", attributes=[("inventory_use_slot", enums.WieldLocation.BODY), ("armor", 11)], ) self.weapon = create.create_object( - EvAdventureObject, + EvAdventureWeapon, key="weapon", attributes=[("inventory_use_slot", enums.WieldLocation.WEAPON_HAND)], ) self.big_weapon = create.create_object( - EvAdventureObject, + EvAdventureWeapon, key="big_weapon", attributes=[("inventory_use_slot", enums.WieldLocation.TWO_HANDS)], ) diff --git a/evennia/contrib/tutorials/evadventure/tests/test_dungeon.py b/evennia/contrib/tutorials/evadventure/tests/test_dungeon.py index a0290e8807..f96d82a2ff 100644 --- a/evennia/contrib/tutorials/evadventure/tests/test_dungeon.py +++ b/evennia/contrib/tutorials/evadventure/tests/test_dungeon.py @@ -10,7 +10,6 @@ from evennia.utils.test_resources import BaseEvenniaTest from evennia.utils.utils import inherits_from from .. import dungeon -from ..rooms import EvAdventureDungeonRoom from .mixins import EvAdventureMixin @@ -33,7 +32,7 @@ class TestDungeon(EvAdventureMixin, BaseEvenniaTest): self.start_room = create_object(droomclass, key="bottom of well") self.assertEqual( - self.start_room.scripts.get("evadventure_startroom_resetter")[0].interval, -1 + self.start_room.scripts.get("evadventure_dungeon_startroom_resetter")[0].interval, -1 ) self.start_north = create_object( dungeon.EvAdventureDungeonStartRoomExit, @@ -71,7 +70,7 @@ class TestDungeon(EvAdventureMixin, BaseEvenniaTest): # first go north, this should generate a new room new_room_north = self._move_character("north") self.assertNotEqual(self.start_room, new_room_north) - self.assertTrue(inherits_from(new_room_north, EvAdventureDungeonRoom)) + self.assertTrue(inherits_from(new_room_north, dungeon.EvAdventureDungeonRoom)) # check if Orchestrator was created orchestrator = new_room_north.db.dungeon_orchestrator