From b89ca629ee425c8cb27af19429fdfba45d399603 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Tue, 15 Jul 2025 07:56:15 -0700 Subject: [PATCH] Special rooms allow doors to be opened and closed --- commands/default_cmdsets.py | 5 +++- commands/everyone.py | 14 +++++++--- typeclasses/consumables.py | 4 +-- typeclasses/objects.py | 19 +++++++------ typeclasses/rooms.py | 53 ++++++++++++++++++++++++++++++++++--- 5 files changed, 77 insertions(+), 18 deletions(-) diff --git a/commands/default_cmdsets.py b/commands/default_cmdsets.py index 1aeb336..d92a8e5 100644 --- a/commands/default_cmdsets.py +++ b/commands/default_cmdsets.py @@ -22,7 +22,8 @@ from evennia.contrib.rpg.character_creator.character_creator import ContribCharg from commands.sittables import CmdNoSitStand from commands.everyone import (CmdTake, CmdThink, CmdSay, CmdWhisper, CmdRead, CmdEat, CmdDrink, - CmdUse, CmdPush, CmdPull) + CmdUse, CmdPush, CmdPull, + CmdOpen, CmdClose) from commands.misc import CmdLight from typeclasses.tutorial import CmdTutorial from commands.wizards import (CmdGM, CmdSpell, CmdGMTrigger, @@ -50,6 +51,8 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet): self.add(CmdUse) self.add(CmdPush) self.add(CmdPull) + self.add(CmdOpen) + self.add(CmdClose) self.add(CmdLight) self.add(CmdTake) self.add(CmdThink) diff --git a/commands/everyone.py b/commands/everyone.py index aee8af6..7de1319 100755 --- a/commands/everyone.py +++ b/commands/everyone.py @@ -153,6 +153,10 @@ class CmdOpen(Command): room = opener.location to_open = self.args.strip() + if to_open == "": + opener.msg("What would you like to open?") + return + if room.has_method('do_open'): if room.do_open(opener, to_open): return @@ -184,13 +188,17 @@ class CmdClose(Command): """ closer = self.caller room = closer.location - to_open = self.args.strip() + to_close = self.args.strip() + + if to_close == "": + closer.msg("What would you like to close?") + return if room.has_method('do_close'): - if room.do_close(closer, to_open): + if room.do_close(closer, to_close): return - item = closer.search(to_open) + item = closer.search(to_close) if item: if item.has_method('do_close'): item.do_close(closer) diff --git a/typeclasses/consumables.py b/typeclasses/consumables.py index 80e5c72..44e6d85 100755 --- a/typeclasses/consumables.py +++ b/typeclasses/consumables.py @@ -270,5 +270,5 @@ class Sconce(Producer, Opener): if self.db.pull_msg: self.location.msg_contents(self.db.pull_msg) self.do_open() - delay(15, self.do_close) - delay(16, self.db.room.msg_contents, "The bookshelf slams shut.") + delay(30, self.do_close) + delay(31, self.db.room.msg_contents, "The bookcase slams shut.") diff --git a/typeclasses/objects.py b/typeclasses/objects.py index 7943034..cfcd709 100755 --- a/typeclasses/objects.py +++ b/typeclasses/objects.py @@ -30,6 +30,10 @@ class ObjectParent: def get_display_footer(self, _, **kwargs): return "\n" + def has_method(self, method_name): + """True if this object has a method of a particular name.""" + return hasattr(self, method_name) and callable(getattr(self, method_name)) + class Object(ObjectParent, ContribRPObject): """ @@ -247,10 +251,6 @@ class Object(ObjectParent, ContribRPObject): return None - def has_method(self, method_name): - """True if this object has a method of a particular name.""" - return hasattr(self, method_name) and callable(getattr(self, method_name)) - def characters_here(self, puppets=False): """ Return a list of characters in the current location. @@ -389,10 +389,13 @@ class Listener: def say_triggers(self, label, character, speech): trigs = self.get_attribute_trigger(label, character) if trigs: - for _, trigger in enumerate(dict(trigs)): - seq = trigs[trigger] - if match(trigger, speech, IGNORECASE): - self.trigger_sequence(seq, character) + try: + for _, trigger in enumerate(dict(trigs)): + seq = trigs[trigger] + if match(trigger, speech, IGNORECASE): + self.trigger_sequence(seq, character) + except: + self.trigger_sequence(trigs, character) def other_say(self, speaker, speech): self.say_triggers('say', speaker, speech) diff --git a/typeclasses/rooms.py b/typeclasses/rooms.py index 40d1759..7495a1c 100644 --- a/typeclasses/rooms.py +++ b/typeclasses/rooms.py @@ -9,15 +9,14 @@ from datetime import datetime from re import match from evennia import utils -from evennia.utils import gametime, logger +from evennia.utils import gametime, logger, delay from evennia.contrib.grid.extended_room import ExtendedRoom from evennia.contrib.rpg.rpsystem import ContribRPRoom from django.conf import settings -# from .objects import LightSource -from .pets import Hunger -from .objects import ObjectParent +from typeclasses.pets import Hunger +from typeclasses.objects import ObjectParent _SEARCH_AT_RESULT = utils.object_from_module(settings.SEARCH_AT_RESULT) @@ -144,3 +143,49 @@ class DabblersRoom(Room): full_desc += " " + self.db.final_desc return full_desc + + +class OpenableRoom(Room): + """ + Rooms that accept the "open" and "close" command. + + This will move an exit in and out of this location. + Set the follow properties: + + @set here/open_exit = $search(red door) + @set here/open_exit_msg = "$You() $conj(open) the door!" + @set here/close_exit_msg = "$You() $conj(close) the door!" + @set here/close_automatic = 240 + """ + def do_open(self, opener, item): + """ + Move the 'open_exit' to this location. + """ + the_exit = self.db.open_exit + if the_exit and the_exit.key.endswith(item): + if the_exit.location == self: + opener.msg(f"The {item} is already open.") + return True + the_exit.location = self + opener.announce_action(self.db.open_exit_msg or + f"$You() $conj(open) the {the_exit.name}") + if self.db.close_automatic: + delay(self.db.close_automatic, self.do_close) + return True + + def do_close(self, closer=None, item=None): + """ + Move the 'open_exit' exit to Limbo. + """ + the_exit = self.db.open_exit + if the_exit and (not item or the_exit.key.endswith(item)): + if the_exit.location == self: # It is opened and can be closed: + the_exit.location = None + if closer: + closer.announce_action(self.db.close_exit_msg or + f"$You() $conj(close) the {the_exit.name}") + else: + self.msg_contents(self.db.close_exit_msg) + elif closer: + closer.msg(f"The {item} is already closed.") + return True