Hide and go seek game

Which includes magic rings to hide and monocles to find.
This commit is contained in:
Howard Abrams 2025-08-23 18:25:59 -07:00
parent d717e7c852
commit 7daf75c167
4 changed files with 240 additions and 13 deletions

View file

@ -220,7 +220,7 @@ class CmdSetRummage(CmdSet):
class CmdCat(Command): class CmdCat(Command):
"""Have you cat do some antic. """Have your cat do some antic.
Usage: Usage:
@ -333,3 +333,102 @@ class CmdPress(Command):
class CmdSetPress(CmdSet): class CmdSetPress(CmdSet):
def at_cmdset_creation(self): def at_cmdset_creation(self):
self.add(CmdPress) self.add(CmdPress)
class CmdTransform(MuxCommand):
"""Transform yourself into an object.
Usage:
|gtransform <object> = <description>|n
Where the 'object' is what you might see when looking around a
room, and 'description' is what is shown when a character 'look's
at you.
See |guntransform|n.
"""
key = "transform"
alias = ["transmogrify"]
def func(self):
if self.caller.attributes.get('transformed'):
self.caller.msg(f"You have already transformed into a {self.caller.name}."
f" You need to |guntransform|n first.")
elif not self.lhs:
self.caller.msg("What do you want to transform into?")
elif not self.rhs:
self.caller.msg(f"You need to describe this '{self.lhs}'.")
else:
self.caller.transmogrify(self.lhs, self.rhs)
class CmdUntransform(Command):
"""
Untransform yourself from a previous 'transform' command.
Usage:
|guntransform|n
"""
key = "untransform"
alias = ["untransmogrify"]
def func(self):
if self.caller.attributes.get('transformed'):
self.caller.untransmogrify()
else:
self.caller.msg("You are not an object.")
class CmdSetTransform(CmdSet):
"""
Transforming set.
"""
def at_cmdset_creation(self):
self.add(CmdTransform)
self.add(CmdUntransform)
class CmdPeer(Command):
"""
Closely examine an object past the magic and see if they are a
transformed character, or really the object.
Usage:
|gpeer <object>|n
"""
key = "peer"
alias = ["seek"]
def func(self):
looker = self.caller
label = self.args.strip()
if label == "":
looker.msg("What do you want to closely examine?")
return
thing = looker.search(label)
if thing:
if thing.attributes.get("transformed"):
self.obj.found_someone(thing)
looker.msg(f"Aha! The {label} is not how it appears!|/" +
f"It is really a |c{thing.db.orig_sdesc}|n... " +
thing.db.orig_desc)
thing.msg(f"The {looker.get_display_name(thing)} peers closely at you.|/" +
f"The jig is up! {looker.pronoun_subjective()} knows " +
f"that you are not a {label}.")
else:
self.obj.failed_at_looking()
looker.msg(f"The {label} is what it is...|/" + thing.db.desc)
class CmdSetPeer(CmdSet):
"""
Peering set.
"""
def at_cmdset_creation(self):
self.add(CmdPeer)

View file

@ -365,6 +365,9 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
Can be overridden or appended with an effect. Can be overridden or appended with an effect.
Does the looker affect this? Does the looker affect this?
""" """
if self.db.transformed:
return self.db.desc
# To replace, temporarily, a description: # To replace, temporarily, a description:
# @set woman/temp_desc:effect = "They fade away from view." # @set woman/temp_desc:effect = "They fade away from view."
new_desc = self.attributes.get(category="effect", new_desc = self.attributes.get(category="effect",
@ -384,6 +387,9 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
'|S has') + '|S has') +
post_desc) post_desc)
def at_look(self, target, **kwargs):
return "Whacka whacka!"
def at_pre_move(self, destination, *args, **kwargs): def at_pre_move(self, destination, *args, **kwargs):
""" """
Called by self.move_to when trying to move somewhere. If this returns Called by self.move_to when trying to move somewhere. If this returns
@ -416,7 +422,8 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
logger.warn(f"Found tethered, {thing} to #{to}, but that needs to be 'tethered:id(num) where num is the ID# of an object/place.") logger.warn(f"Found tethered, {thing} to #{to}, but that needs to be 'tethered:id(num) where num is the ID# of an object/place.")
# Tell the room and any puppets here that we are leaving: # Tell the room and any puppets here that we are leaving:
self.location.other_leave(self) if not self.location.is_typeclass(Character):
self.location.other_leave(self)
for puppet in self.puppets_here(): for puppet in self.puppets_here():
puppet.other_leave(self) puppet.other_leave(self)
@ -424,7 +431,8 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
def at_post_move(self, past_location, move_type="move", **kwargs): def at_post_move(self, past_location, move_type="move", **kwargs):
super().at_post_move(past_location, move_type) super().at_post_move(past_location, move_type)
self.location.other_arrive(self) if not self.location.is_typeclass(Character):
self.location.other_arrive(self)
for puppet in self.puppets_here(): for puppet in self.puppets_here():
puppet.other_arrive(self) puppet.other_arrive(self)
@ -531,6 +539,32 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
self.db.reappear_msg.split(';;'), self.db.reappear_msg.split(';;'),
self.db.appear_delay or 2) self.db.appear_delay or 2)
def transmogrify(self, name, description):
"""
Convert the appearance of this character into an object.
"""
self.db.orig_name = self.name
self.db.orig_desc = self.db.desc
self.db.orig_sdesc = self.sdesc.get()
self.announce_action(f"Octarine sparks fly, as $you() $conj(transform) into a {name}.")
self.db.transformed = True
self.name = name
self.sdesc.add(name)
self.db.desc = description
def untransmogrify(self):
"""
Undo the conversion of this character from an object.
"""
self.name = self.db.orig_name
self.sdesc.add(self.db.orig_sdesc)
self.db.desc = self.db.orig_desc
self.db.transformed = False
self.announce_action(f"Octarine sparks glint, as $you() $conj(transform) back into $pron(your) old form.")
# Hooks to the puppets and storycubes: # Hooks to the puppets and storycubes:
def puppets_here(self): def puppets_here(self):

View file

@ -5,11 +5,15 @@ Rooms are simple containers that has no location of their own.
""" """
from collections import defaultdict
from datetime import datetime from datetime import datetime
from re import match from re import match
from django.utils.translation import gettext as _
from evennia import utils from evennia import utils
from evennia.utils import gametime, logger, delay from evennia.utils import gametime, logger, delay
from evennia.utils.utils import iter_to_str
from evennia.contrib.grid.extended_room import ExtendedRoom from evennia.contrib.grid.extended_room import ExtendedRoom
from evennia.contrib.rpg.rpsystem import ContribRPRoom from evennia.contrib.rpg.rpsystem import ContribRPRoom
@ -39,6 +43,7 @@ def articlize_character(character, capitalize=False):
else: else:
return f"{article} " + character return f"{article} " + character
def captialize_characters(characters): def captialize_characters(characters):
""" """
Capitalizes and prefixes an article on string of characters. Capitalizes and prefixes an article on string of characters.
@ -96,7 +101,8 @@ class Room(ObjectParent, ExtendedRoom, ContribRPRoom, Listener):
return "|n" return "|n"
def get_display_characters(self, looker, *args, **kwargs): def get_display_characters(self, looker, *args, **kwargs):
chars = self.contents_get(content_type="character") chars = [c for c in self.contents_get(content_type="character")
if not c.attributes.get('transformed')]
vchars = self.filter_visible(chars, looker, **kwargs) vchars = self.filter_visible(chars, looker, **kwargs)
num_chars = len(vchars) num_chars = len(vchars)
@ -129,16 +135,31 @@ class Room(ObjectParent, ExtendedRoom, ContribRPRoom, Listener):
return '' return ''
def get_display_things(self, looker, *args, **kwargs): def get_display_things(self, looker, *args, **kwargs):
std_msg = super().get_display_things(looker, pose=False) """
if std_msg: Replace
return std_msg.replace('|wYou see:|n', 'You notice') + '.' """
else: things = self.filter_visible(self.contents_get(content_type="object"),
return '' looker, **kwargs)
tchars = [c for c in self.contents_get(content_type="character")
if c.attributes.get('transformed')]
def msg_contents(self, message, exclude=None, from_obj=None, mapping=None, grouped_things = defaultdict(list)
for thing in things + tchars:
grouped_things[thing.get_display_name(looker, **kwargs)].append(thing)
thing_names = []
for thingname, thinglist in sorted(grouped_things.items()):
nthings = len(thinglist)
thing = thinglist[0]
singular, plural = thing.get_numbered_name(nthings, looker, key=thingname)
thing_names.append(singular if nthings == 1 else plural)
thing_names = iter_to_str(thing_names, endsep=_(", and"))
return _(f"You notice {thing_names}." if thing_names else "")
def msg_contents(self, text, exclude=None, from_obj=None, mapping=None,
raise_funcparse_errors=False, **kwargs): raise_funcparse_errors=False, **kwargs):
message = fix_msg(message) text = fix_msg(text)
super().msg_contents(message, exclude, from_obj, mapping, super().msg_contents(text, exclude, from_obj, mapping,
raise_funcparse_errors) raise_funcparse_errors)

View file

@ -10,6 +10,7 @@ from evennia.prototypes.spawner import spawn
from evennia.utils import (logger, delay, from evennia.utils import (logger, delay,
iter_to_str, int2str, iter_to_str, int2str,
search) search)
from evennia.utils.search import search_channel
from commands.misc import (CmdSetPuddle, from commands.misc import (CmdSetPuddle,
CmdSetStick, CmdSetStick,
@ -17,7 +18,8 @@ from commands.misc import (CmdSetPuddle,
CmdSetSmoke, CmdSetSmoke,
CmdSetRummage, CmdSetRummage,
CmdSetDice, CmdSetDice,
CmdSetPress) CmdSetPress,
CmdSetTransform, CmdSetPeer)
from commands.consumables import CmdSetMakeConsumable from commands.consumables import CmdSetMakeConsumable
from commands.wizards import CmdSetWand from commands.wizards import CmdSetWand
from utils.word_list import routput, choices, paragraph from utils.word_list import routput, choices, paragraph
@ -1066,3 +1068,74 @@ class Teleporter(Object):
self.db.destination, move_type="traverse") self.db.destination, move_type="traverse")
else: else:
announce_seq(time_to_delay, victim, self.db.fail_msg) announce_seq(time_to_delay, victim, self.db.fail_msg)
class MagicRing(Object):
"""
Ring that can change someone into an object.
"""
def at_object_creation(self):
self.cmdset.add_default(CmdSetTransform)
class MagicMonocle(Object):
"""
Monocle that sees past the 'transform' magic.
"""
def at_object_creation(self):
"""
Sets the scoreboard as well as the 'peer' command.
"""
self.cmdset.add_default(CmdSetPeer)
self.reset_counts()
def found_someone(self, found):
"""
Store a set as an attribute with 'found'.
"""
the_set = self.attributes.get('found', set())
the_set.add(found)
self.attributes.add('found', the_set)
def failed_at_looking(self):
"""
nv Increment the failures on the scoreboard.
"""
self.db.failed = self.db.failed + 1
def reset_counts(self):
"""
Resets the scoreboard to 0.
"""
self.attributes.add('found', set())
self.attributes.add('failed', 0)
def report_score(self, seeker=None):
"""
Reports the score for the object to the room.
"""
if not seeker:
seeker = self.location
room = seeker.location
name = seeker.sdesc.get()
room.msg_contents(f"The score for the seeker, {name} is:|/" +
f" - Found: {len(self.db.found)}|/" +
f" - Misses: {self.db.failed}")
class GlobalAlarmClock(Object):
"""
Clock that announces timers on a public channel.
"""
def at_object_creation(self):
"""
Sets up the attributes.
"""
self.db.channel = "Hide and Seek Game"
def start_timer(self, seconds=30, start=None, finish=None):
chan = search_channel(self.db.channel).first()
if chan:
if start:
chan.msg(start)
delay(seconds, chan.msg, finish)