Refactor of ExtendedRoom

This commit is contained in:
Griatch 2023-05-31 22:24:08 +02:00
parent 6066f33a9b
commit 615b98c171
6 changed files with 1271 additions and 494 deletions

View file

@ -94,6 +94,7 @@ EvEditor = None
EvMore = None
ANSIString = None
signals = None
FuncParser = None
# Handlers
SESSION_HANDLER = None
@ -157,7 +158,7 @@ def _init(portal_mode=False):
global TASK_HANDLER
global GLOBAL_SCRIPTS, OPTION_CLASSES
global EvMenu, EvTable, EvForm, EvMore, EvEditor
global ANSIString
global ANSIString, FuncParser
global AttributeProperty, TagProperty, TagCategoryProperty
# Parent typeclasses
@ -203,6 +204,7 @@ def _init(portal_mode=False):
from .utils.evmenu import EvMenu
from .utils.evmore import EvMore
from .utils.evtable import EvTable
from .utils.funcparser import FuncParser
# search functions
from .utils.search import (

View file

@ -1,15 +1,19 @@
# Extended Room
Contribution - Griatch 2012, vincent-lg 2019
Contribution - Griatch 2012, vincent-lg 2019, Griatch 2023
This extends the normal `Room` typeclass to allow its description to change
with time-of-day and/or season. It also adds 'details' for the player to look at
in the room (without having to create a new in-game object for each). The room is
supported by new `look` and `desc` commands.
This extends the normal `Room` typeclass to allow its description to change with
time-of-day and/or season as well as any other state (like flooded or dark).
Embedding `$state(burning, This place is on fire!)` in the description will
allow for changing the description based on room state. The room also supports
`details` for the player to look at in the room (without having to create a new
in-game object for each), as well as support for random echoes. The room
comes with a set of alternate commands for `look` and `@desc`, as well as new
commands `detail`, `roomstate` and `time`.
## Installation/testing:
## Installation
Adding the `ExtendedRoomCmdset` to the default character cmdset will add all
Add the `ExtendedRoomCmdset` to the default character cmdset will add all
new commands for use.
In more detail, in `mygame/commands/default_cmdsets.py`:
@ -30,52 +34,157 @@ class CharacterCmdset(default_cmds.CharacterCmdSet):
Then reload to make the new commands available. Note that they only work
on rooms with the typeclass `ExtendedRoom`. Create new rooms with the right
typeclass or use the `typeclass` command to swap existing rooms. Note that since
this contrib overrides the `look` command, you will need to add the
this contrib overrides the `look` and `@desc` commands, you will need to add the
`extended_room.ExtendedRoomCmdSet` to the default character cmdset *after*
super().at_cmdset_creation(), or it will be overridden by the default look.
`super().at_cmdset_creation()`, or they will be overridden by the default look.
To dig a new extended room:
dig myroom:evennia.contrib.grid.extended_room.ExtendedRoom = north,south
To make all new rooms ExtendedRooms without having to specify it, make your
`Room` typeclass inherit from the `ExtendedRoom` and then reload:
```python
# in mygame/typeclasses/rooms.py
from evennia.contrib.grid.extended_room import ExtendedRoom
# ...
class Room(ObjectParent, ExtendedRoom):
# ...
```
## Features
### Time-changing description slots
### State-dependent description slots
This allows to change the full description text the room shows
depending on larger time variations. Four seasons (spring, summer,
autumn and winter) are used by default. The season is calculated
on-demand (no Script or timer needed) and updates the full text block.
By default, the normal `room.db.desc` description is used. You can however
add new state-ful descriptions with `room.add_desc(description,
room_state=roomstate)` or with the in-game command
There is also a general description which is used as fallback if
one or more of the seasonal descriptions are not set when their
time comes.
```
@desc/roomstate [<description>]
```
An updated `desc` command allows for setting seasonal descriptions.
For example
The room uses the `evennia.utils.gametime.GameTime` global script. This is
started by default, but if you have deactivated it, you need to
supply your own time keeping mechanism.
```
@desc/dark This room is pitch black.`.
### In-description changing tags
```
Within each seasonal (or general) description text, you can also embed
time-of-day dependent sections. Text inside such a tag will only show
during that particular time of day. The tags looks like `<timeslot> ...
</timeslot>`. By default there are four timeslots per day - morning,
afternoon, evening and night.
These will be stored in Attributes `desc_<roomstate>`. To set the default,
fallback description, just use `@desc <description>`.
To activate a state on the room, use `room.add/remove_state(*roomstate)` or the in-game
command
```
roomstate <state> (use it again to toggle the state off)
```
For example
```
roomstate dark
```
There is one in-built, time-based state `season`. By default these are 'spring',
'summer', 'autumn' and 'winter'. The `room.get_season()` method returns the
current season based on the in-game time. By default they change with a 12-month
in-game time schedule. You can control them with
```
ExtendedRoom.months_per_year # default 12
ExtendedRoom.seasons_per year # a dict of {"season": (start, end), ...} where
# start/end are given in fractions of the whole year
```
To set a seasonal description, just set it as normal, with `room.add_desc` or
in-game with
```
@desc/winter This room is filled with snow.
@desc/autumn Red and yellow leaves cover the ground.
```
Normally the season changes with the in-game time, you can also 'force' a given
season by setting its state
```
roomstate winter
```
If you set the season manually like this, it won't change automatically again
until you unset it.
You can get the stateful description from the room with `room.get_stateful_desc()`.
### Changing parts of description based on state
All descriptions can have embedded `$state(roomstate, description)`
[FuncParser tags](FuncParser) embedded in them. Here is an example:
```py
room.add_desc("This a nice beach. "
"$state(empty, It is completely empty)"
"$state(full, It is full of people).", room_state="summer")
```
This is a summer-description with special embedded strings. If you set the room
with
> room.add_room_state("summer", "empty")
> room.get_stateful_desc()
This is a nice beach. It is completely empty
> room.remove_room_state("empty")
> room.add_room_state("full")
> room.get_stateful_desc()
This is a nice beach. It is full of people.
There are four time-of-day states that are meant to be used with these tags. The
room tracks and changes these automatically. By default they are 'morning',
'afternoon', 'evening' and 'night'. You can get the current time-slot with
`room.get_time_of_day`. You can control them with
```
ExtendedRoom.hours_per_day # default 24
ExtendedRoom.times_of_day # dict of {season: (start, end), ...} where
# the start/end are given as fractions of the day
```
You use these inside descriptions as normal:
"A glade. $(morning, The morning sun shines down through the branches)."
### Details
The Extended Room can be "detailed" with special keywords. This makes
use of a special `Look` command. Details are "virtual" targets to look
at, without there having to be a database object created for it. The
Details are simply stored in a dictionary on the room and if the look
command cannot find an object match for a `look <target>` command it
will also look through the available details at the current location
if applicable. The `detail` command is used to change details.
_Details_ are "virtual" targets to look at in a room, without having to create a
new database instance for every thing. It's good to add more information to a
location. The details are stored as strings in a dictionary.
detail window = There is a window leading out.
detail rock = The rock has a text written on it: 'Do not dare lift me'.
When you are in the room you can then do `look window` or `look rock` and get
the matching detail-description. This requires the new custom `look` command.
### Random echoes
The `ExtendedRoom` supports random echoes. Just set them as an Attribute list
`room_messages`:
```
room.room_message_rate = 120 # in seconds. 0 to disable
room.db.room_messages = ["A car passes by.", "You hear the sound of car horns."]
room.start_repeat_broadcast_messages() # also a server reload works
```
These will start randomly echoing to the room every 120s.
### Extra commands
- `CmdExtendedRoomLook` - look command supporting room details
- `CmdExtendedRoomDesc` - desc command allowing to add seasonal descs,
- `CmdExtendedRoomDetail` - command allowing to manipulate details in this room
as well as listing them
- `CmdExtendedRoomGameTime` - A simple `time` command, displaying the current
time and season.
- `CmdExtendedRoomLook` (`look`) - look command supporting room details
- `CmdExtendedRoomDesc` (`@desc`) - desc command allowing to add stateful descs,
- `CmdExtendeRoomState` (`roomstate`) - toggle room states
- `CmdExtendedRoomDetail` (`detail`) - list and manipulate room details
- `CmdExtendedRoomGameTime` (`time`) - Shows the current time and season in the room.

View file

@ -1,5 +1,5 @@
"""
Extended Room - Griatch 2012, vincent-lg 2019
Extended Room - Griatch 2012, vincent-lg 2019, Griatch 2023
"""
@ -7,5 +7,6 @@ from .extended_room import CmdExtendedRoomDesc # noqa
from .extended_room import CmdExtendedRoomDetail # noqa
from .extended_room import CmdExtendedRoomGameTime # noqa
from .extended_room import CmdExtendedRoomLook # noqa
from .extended_room import CmdExtendedRoomState # noqa
from .extended_room import ExtendedRoom # noqa
from .extended_room import ExtendedRoomCmdSet # noqa

File diff suppressed because it is too large Load diff

View file

@ -6,118 +6,392 @@ Testing of ExtendedRoom contrib
import datetime
from django.conf import settings
from evennia import create_object
from evennia.utils.test_resources import BaseEvenniaCommandTest, EvenniaTestCase
from mock import Mock, patch
from evennia.commands.default.tests import BaseEvenniaCommandTest
from evennia.objects.objects import DefaultRoom
from parameterized import parameterized
from . import extended_room
class ForceUTCDatetime(datetime.datetime):
def _get_timestamp(season, time_of_day):
"""
Utility to get a timestamp for a given season and time of day.
"""Force UTC datetime."""
@classmethod
def fromtimestamp(cls, timestamp):
"""Force fromtimestamp to run with naive datetimes."""
return datetime.datetime.utcfromtimestamp(timestamp)
"""
# grab a month / time given a season and time of day
seasons = {"spring": 3, "summer": 6, "autumn": 9, "winter": 12}
times_of_day = {"morning": 6, "afternoon": 12, "evening": 18, "night": 0}
# return a datetime object for the 1st of the month at the given hour
return datetime.datetime(2064, seasons[season], 1, times_of_day[time_of_day]).timestamp()
@patch("evennia.contrib.grid.extended_room.extended_room.datetime.datetime", ForceUTCDatetime)
# mock gametime to return April 9, 2064, at 21:06 (spring evening)
@patch("evennia.utils.gametime.gametime", new=Mock(return_value=2975000766))
class TestExtendedRoom(BaseEvenniaCommandTest):
room_typeclass = extended_room.ExtendedRoom
DETAIL_DESC = "A test detail."
SPRING_DESC = "A spring description."
OLD_DESC = "Old description."
settings.TIME_ZONE = "UTC"
class TestExtendedRoom(EvenniaTestCase):
"""
Test Extended Room typeclass.
"""
base_room_desc = "Base room description."
def setUp(self):
self.room = create_object(extended_room.ExtendedRoom, key="Test Room")
self.room.desc = self.base_room_desc
def test_room_description(self):
"""
Test that the vanilla room description is returned as expected.
"""
room_desc = self.room.get_display_desc(None)
self.assertEqual(room_desc, self.base_room_desc)
@parameterized.expand(
[
("spring", "Spring room description."),
("summer", "Summer room description."),
("autumn", "Autumn room description."),
("winter", "Winter room description."),
]
)
@patch("evennia.utils.gametime.gametime")
def test_seasonal_room_descriptions(self, season, desc, mock_gametime):
"""
Test that the room description changes with the season.
"""
mock_gametime.return_value = _get_timestamp(season, "morning")
self.room.add_desc(desc, room_state=season)
room_desc = self.room.get_display_desc(None)
self.assertEqual(room_desc, desc)
@parameterized.expand(
[
("morning", "Morning room description."),
("afternoon", "Afternoon room description."),
("evening", "Evening room description."),
("night", "Night room description."),
]
)
@patch("evennia.utils.gametime.gametime")
def test_get_time_of_day_tags(self, time_of_day, desc, mock_gametime):
"""
Test room with $
"""
mock_gametime.return_value = _get_timestamp("spring", time_of_day)
room_time_of_day = self.room.get_time_of_day()
self.assertEqual(room_time_of_day, time_of_day)
self.room.add_desc(
"$state(morning, Morning room description.)"
"$state(afternoon, Afternoon room description.)"
"$state(evening, Evening room description.)"
"$state(night, Night room description.)"
" What a great day!"
)
room_desc = self.room.get_display_desc(None)
self.assertEqual(room_desc, f"{desc} What a great day!")
def test_room_states(self):
"""
Test rooms with custom game states.
"""
self.room.add_desc(
"$state(under_construction, This room is under construction.)"
" $state(under_repair, This room is under repair.)"
)
self.room.add_room_state("under_construction")
self.assertEqual(self.room.room_states, ["under_construction"])
self.assertEqual(self.room.get_display_desc(None), "This room is under construction. ")
self.room.add_room_state("under_repair")
self.assertEqual(self.room.room_states, ["under_construction", "under_repair"])
self.assertEqual(
self.room.get_display_desc(None),
"This room is under construction. This room is under repair.",
)
self.room.remove_room_state("under_construction")
self.assertEqual(
self.room.get_display_desc(None),
" This room is under repair.",
)
def test_alternative_descs(self):
"""
Test rooms with alternate descriptions.
"""
self.room.add_desc("The room is burning!", room_state="burning")
self.room.add_desc("The room is flooding!", room_state="flooding")
self.assertEqual(self.room.get_display_desc(None), self.base_room_desc)
self.room.add_room_state("burning")
self.assertEqual(self.room.get_display_desc(None), "The room is burning!")
self.room.add_room_state("flooding")
self.room.remove_room_state("burning")
self.assertEqual(self.room.get_display_desc(None), "The room is flooding!")
self.room.clear_room_state()
self.assertEqual(self.room.get_display_desc(None), self.base_room_desc)
def test_details(self):
"""
Test room details.
"""
self.room.add_detail("test", "Test detail.")
self.room.add_detail("test2", "Test detail 2.")
self.room.add_detail("window", "Window detail.")
self.room.add_detail("window pane", "Window Pane detail.")
self.assertEqual(self.room.get_detail("test"), "Test detail.")
self.assertEqual(self.room.get_detail("test2"), "Test detail 2.")
self.assertEqual(self.room.get_detail("window"), "Window detail.")
self.assertEqual(self.room.get_detail("window pane"), "Window Pane detail.")
self.assertEqual(self.room.get_detail("win"), "Window detail.")
self.assertEqual(self.room.get_detail("window p"), "Window Pane detail.")
self.room.remove_detail("test")
self.assertEqual(self.room.get_detail("test"), "Test detail 2.") # finding nearest
self.room.remove_detail("test2")
self.assertEqual(self.room.get_detail("test"), None) # all test* gone
class TestExtendedRoomCommands(BaseEvenniaCommandTest):
"""
Test the ExtendedRoom commands.
"""
base_room_desc = "Base room description."
def setUp(self):
super().setUp()
self.room1.ndb.last_timeslot = "afternoon"
self.room1.ndb.last_season = "winter"
self.room1.db.details = {"testdetail": self.DETAIL_DESC}
self.room1.db.spring_desc = self.SPRING_DESC
self.room1.db.desc = self.OLD_DESC
self.room1.swap_typeclass("evennia.contrib.grid.extended_room.ExtendedRoom")
self.room1.desc = self.base_room_desc
def test_return_appearance(self):
# get the appearance of a non-extended room for contrast purposes
old_desc = DefaultRoom.return_appearance(self.room1, self.char1)
# the new appearance should be the old one, but with the desc switched
self.assertEqual(
old_desc.replace(self.OLD_DESC, self.SPRING_DESC),
self.room1.return_appearance(self.char1),
@patch("evennia.utils.gametime.gametime")
def test_cmd_desc(self, mock_gametime):
"""Test new desc command"""
mock_gametime.return_value = _get_timestamp("autumn", "afternoon")
# view base desc
self.call(
extended_room.CmdExtendedRoomDesc(),
"",
f"""
Room Room(#{self.room1.id}) Season: autumn. Time: afternoon. States: None
Room state (default) (active):
Base room description.
""".strip(),
)
self.assertEqual("spring", self.room1.ndb.last_season)
self.assertEqual("evening", self.room1.ndb.last_timeslot)
def test_return_detail(self):
self.assertEqual(self.DETAIL_DESC, self.room1.return_detail("testdetail"))
# add spring desc
self.call(
extended_room.CmdExtendedRoomDesc(),
"/spring Spring description.",
"The spring-description was set on Room",
)
self.call(
extended_room.CmdExtendedRoomDesc(),
"/burning Burning description.",
"The burning-description was set on Room",
)
self.call(
extended_room.CmdExtendedRoomDesc(),
"",
"""
Room Room(#1) Season: autumn. Time: afternoon. States: None
Room state spring:
Spring description.
Room state burning:
Burning description.
Room state (default) (active):
Base room description.
""".strip(),
)
# remove a desc
self.call(
extended_room.CmdExtendedRoomDesc(),
"/del/burning/spring",
(
"The burning-description was deleted, if it existed.|The spring-description was"
" deleted, if it existed"
),
)
# add autumn, which should be active
self.call(
extended_room.CmdExtendedRoomDesc(),
"/autumn Autumn description.",
"The autumn-description was set on Room",
)
self.call(
extended_room.CmdExtendedRoomDesc(),
"",
"""
Room Room(#1) Season: autumn. Time: afternoon. States: None
Room state autumn (active):
Autumn description.
Room state (default):
Base room description.
""".strip(),
)
def test_cmd_detail(self):
"""Test adding details"""
self.call(
extended_room.CmdExtendedRoomDetail(),
"test=Test detail.",
"Set detail 'test': 'Test detail.'",
)
self.call(
extended_room.CmdExtendedRoomDetail(),
"",
"""
Details on Room:
test: Test detail.
""".strip(),
)
# remove a detail
self.call(
extended_room.CmdExtendedRoomDetail(),
"/del test",
"Deleted detail 'test', if it existed.",
)
self.call(
extended_room.CmdExtendedRoomDetail(),
"",
f"""
The room Room(#{self.room1.id}) doesn't have any details.
""".strip(),
)
@patch("evennia.utils.gametime.gametime")
def test_cmd_roomstate(self, mock_gametime):
"""
Test the roomstate command
"""
mock_gametime.return_value = _get_timestamp("autumn", "afternoon")
# show existing room states (season/time doesn't count)
self.assertEqual(self.room1.room_states, [])
self.call(
extended_room.CmdExtendedRoomState(),
"",
f"Room states (not counting automatic time/season) on Room(#{self.room1.id}):\n None",
)
# add room states
self.call(
extended_room.CmdExtendedRoomState(),
"burning",
"Added room state 'burning' to this room.",
)
self.call(
extended_room.CmdExtendedRoomState(),
"windy",
"Added room state 'windy' to this room.",
)
self.call(
extended_room.CmdExtendedRoomState(),
"",
(
f"Room states (not counting automatic time/season) on Room(#{self.room1.id}):\n "
"'burning' and 'windy'"
),
)
# toggle windy
self.call(
extended_room.CmdExtendedRoomState(),
"windy",
"Cleared room state 'windy' from this room.",
)
self.call(
extended_room.CmdExtendedRoomState(),
"",
(
f"Room states (not counting automatic time/season) on Room(#{self.room1.id}):\n "
"'burning'"
),
)
# add a autumn state and make sure we override it
self.room1.add_desc("Autumn description.", room_state="autumn")
self.room1.add_desc("Spring description.", room_state="spring")
self.assertEqual(self.room1.get_stateful_desc(), "Autumn description.")
self.call(
extended_room.CmdExtendedRoomState(),
"spring",
"Added room state 'spring' to this room.",
)
self.assertEqual(self.room1.get_stateful_desc(), "Spring description.")
@patch("evennia.utils.gametime.gametime")
def test_cmd_roomtime(self, mock_gametime):
"""
Test the time command
"""
mock_gametime.return_value = _get_timestamp("autumn", "afternoon")
self.call(
extended_room.CmdExtendedRoomGameTime(), "", "It's a autumn day, in the afternoon."
)
@patch("evennia.utils.gametime.gametime")
def test_cmd_look(self, mock_gametime):
"""
Test the look command.
"""
mock_gametime.return_value = _get_timestamp("autumn", "afternoon")
autumn_desc = (
"This is a nice autumnal forest."
"$state(morning,|_The morning sun is just rising)"
"$state(afternoon,|_The afternoon sun is shining through the trees)"
"$state(burning,|_and this place is on fire!)"
"$state(afternoon, .)"
"$state(flooded, and it's raining heavily!)"
)
self.room1.add_desc(autumn_desc, room_state="autumn")
def test_cmdextendedlook(self):
rid = self.room1.id
self.call(
extended_room.CmdExtendedRoomLook(),
"here",
"Room(#{})\n{}".format(rid, self.SPRING_DESC),
"",
f"Room(#{self.room1.id})\nThis is a nice autumnal forest.",
)
self.call(
extended_room.CmdExtendedRoomLook(),
"testdetail",
"You look closely at {}.\n|{}".format("testdetail", self.DETAIL_DESC)
extended_room.CmdExtendedRoomLook(),
"",
(
f"Room(#{self.room1.id})\nThis is a nice autumnal forest. The afternoon sun is"
" shining through the trees."
),
)
self.room1.add_room_state("burning")
self.call(
extended_room.CmdExtendedRoomLook(), "nonexistent", "Could not find 'nonexistent'."
extended_room.CmdExtendedRoomLook(),
"",
(
f"Room(#{self.room1.id})\nThis is a nice autumnal forest. The afternoon sun is"
" shining through the trees and this place is on fire!"
),
)
def test_cmdextendedlook_second_person(self):
# char2 is already in the same room.
# replace char2.msg with a Mock; this disables it and will catch what it is called with
self.char2.msg = Mock()
self.call(
extended_room.CmdExtendedRoomLook(),
"testdetail"
)
# check what char2 saw.
self.char2.msg.assert_called_with(text=('Char looks closely at testdetail.\n', {}), from_obj=self.char1)
def test_cmdsetdetail(self):
self.call(extended_room.CmdExtendedRoomDetail(), "", "Details on Room")
self.call(
extended_room.CmdExtendedRoomDetail(),
"thingie = newdetail with spaces",
"Detail set 'thingie': 'newdetail with spaces'",
)
self.call(extended_room.CmdExtendedRoomDetail(), "thingie", "Detail 'thingie' on Room:\n")
self.call(
extended_room.CmdExtendedRoomDetail(),
"/del thingie",
"Detail thingie deleted, if it existed.",
cmdstring="detail",
)
self.call(extended_room.CmdExtendedRoomDetail(), "thingie", "Detail 'thingie' not found.")
# Test with aliases
self.call(extended_room.CmdExtendedRoomDetail(), "", "Details on Room")
self.call(
extended_room.CmdExtendedRoomDetail(),
"thingie;other;stuff = newdetail with spaces",
"Detail set 'thingie;other;stuff': 'newdetail with spaces'",
)
self.call(extended_room.CmdExtendedRoomDetail(), "thingie", "Detail 'thingie' on Room:\n")
self.call(extended_room.CmdExtendedRoomDetail(), "other", "Detail 'other' on Room:\n")
self.call(extended_room.CmdExtendedRoomDetail(), "stuff", "Detail 'stuff' on Room:\n")
self.call(
extended_room.CmdExtendedRoomDetail(),
"/del other;stuff",
"Detail other;stuff deleted, if it existed.",
)
self.call(extended_room.CmdExtendedRoomDetail(), "other", "Detail 'other' not found.")
self.call(extended_room.CmdExtendedRoomDetail(), "stuff", "Detail 'stuff' not found.")
def test_cmdgametime(self):
self.call(extended_room.CmdExtendedRoomGameTime(), "", "It's a spring day, in the evening.")

View file

@ -10,10 +10,10 @@ This is the v1.0 develop version (for ref in doc building).
import time
from collections import defaultdict
import evennia
import inflect
from django.conf import settings
from django.utils.translation import gettext as _
import evennia
from evennia.commands import cmdset
from evennia.commands.cmdsethandler import CmdSetHandler
from evennia.objects.manager import ObjectManager
@ -72,7 +72,9 @@ class ObjectSessionHandler:
)
if any(sessid for sessid in self._sessid_cache if sessid not in evennia.SESSION_HANDLER):
# cache is out of sync with sessionhandler! Only retain the ones in the handler.
self._sessid_cache = [sessid for sessid in self._sessid_cache if sessid in evennia.SESSION_HANDLER]
self._sessid_cache = [
sessid for sessid in self._sessid_cache if sessid in evennia.SESSION_HANDLER
]
self.obj.db_sessid = ",".join(str(val) for val in self._sessid_cache)
self.obj.save(update_fields=["db_sessid"])
@ -100,7 +102,8 @@ class ObjectSessionHandler:
)
else:
sessions = [
evennia.SESSION_HANDLER[ssid] if ssid in evennia.SESSION_HANDLER else None for ssid in self._sessid_cache
evennia.SESSION_HANDLER[ssid] if ssid in evennia.SESSION_HANDLER else None
for ssid in self._sessid_cache
]
if None in sessions:
# this happens only if our cache has gone out of sync with the SessionHandler.
@ -761,7 +764,6 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
contents = [obj for obj in contents if obj not in exclude]
for receiver in contents:
# actor-stance replacements
outmessage = _MSG_CONTENTS_PARSER.parse(
inmessage,
@ -1290,7 +1292,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
looker (Object): Object doing the looking.
**kwargs: Arbitrary data for use when overriding.
Returns:
str: The desc display string..
str: The desc display string.
"""
return self.db.desc or "You see nothing special."