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):
"""Have you cat do some antic.
"""Have your cat do some antic.
Usage:
@ -333,3 +333,102 @@ class CmdPress(Command):
class CmdSetPress(CmdSet):
def at_cmdset_creation(self):
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.
Does the looker affect this?
"""
if self.db.transformed:
return self.db.desc
# To replace, temporarily, a description:
# @set woman/temp_desc:effect = "They fade away from view."
new_desc = self.attributes.get(category="effect",
@ -384,6 +387,9 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
'|S has') +
post_desc)
def at_look(self, target, **kwargs):
return "Whacka whacka!"
def at_pre_move(self, destination, *args, **kwargs):
"""
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.")
# 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():
puppet.other_leave(self)
@ -424,7 +431,8 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
def at_post_move(self, past_location, move_type="move", **kwargs):
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():
puppet.other_arrive(self)
@ -531,6 +539,32 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
self.db.reappear_msg.split(';;'),
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:
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 re import match
from django.utils.translation import gettext as _
from evennia import utils
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.rpg.rpsystem import ContribRPRoom
@ -39,6 +43,7 @@ def articlize_character(character, capitalize=False):
else:
return f"{article} " + character
def captialize_characters(characters):
"""
Capitalizes and prefixes an article on string of characters.
@ -96,7 +101,8 @@ class Room(ObjectParent, ExtendedRoom, ContribRPRoom, Listener):
return "|n"
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)
num_chars = len(vchars)
@ -129,16 +135,31 @@ class Room(ObjectParent, ExtendedRoom, ContribRPRoom, Listener):
return ''
def get_display_things(self, looker, *args, **kwargs):
std_msg = super().get_display_things(looker, pose=False)
if std_msg:
return std_msg.replace('|wYou see:|n', 'You notice') + '.'
else:
return ''
"""
Replace
"""
things = self.filter_visible(self.contents_get(content_type="object"),
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):
message = fix_msg(message)
super().msg_contents(message, exclude, from_obj, mapping,
text = fix_msg(text)
super().msg_contents(text, exclude, from_obj, mapping,
raise_funcparse_errors)

View file

@ -10,6 +10,7 @@ from evennia.prototypes.spawner import spawn
from evennia.utils import (logger, delay,
iter_to_str, int2str,
search)
from evennia.utils.search import search_channel
from commands.misc import (CmdSetPuddle,
CmdSetStick,
@ -17,7 +18,8 @@ from commands.misc import (CmdSetPuddle,
CmdSetSmoke,
CmdSetRummage,
CmdSetDice,
CmdSetPress)
CmdSetPress,
CmdSetTransform, CmdSetPeer)
from commands.consumables import CmdSetMakeConsumable
from commands.wizards import CmdSetWand
from utils.word_list import routput, choices, paragraph
@ -1066,3 +1068,74 @@ class Teleporter(Object):
self.db.destination, move_type="traverse")
else:
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)