Casting spells ... first, is donkey head

Spells can affect a characters speech and their appearance.
All spells should create attributes with a 'effect' category,
and spell scripts will clean up after they are stopped.
This commit is contained in:
Howard Abrams 2025-05-10 21:57:12 -07:00
parent 0a955fe2b6
commit 951d35356d
8 changed files with 411 additions and 247 deletions

View file

@ -21,7 +21,7 @@ from evennia.contrib.rpg.rpsystem import RPSystemCmdSet
from evennia.contrib.rpg.character_creator.character_creator import ContribChargenCmdSet
from commands.sittables import CmdNoSitStand
from commands.everyone import CmdTake, CmdThink, CmdSay, CmdWhisper
from commands.wizards import CmdGM, CmdGMTrigger
from commands.wizards import CmdGM, CmdSpell, CmdGMTrigger
class CharacterCmdSet(default_cmds.CharacterCmdSet):
"""
@ -46,6 +46,7 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet):
self.add(CmdSay)
self.add(CmdWhisper)
self.add(CmdGM)
self.add(CmdSpell)
self.add(CmdGMTrigger)

View file

@ -9,7 +9,29 @@ from evennia.commands.default.muxcommand import MuxCommand
from evennia.contrib.rpg.rpsystem import send_emote
from evennia.utils import iter_to_str, logger
from utils.word_list import routput, paragraph
from utils.word_list import routput, paragraph, choices
def speech_effect(speech, verb, target, effects):
"""
Returns a tuple for what a user thinks he said, and what
others actually here. If no effect, just return speech twice.
Effects:
- mute ... can't talk
- donkied ... target and others hear the value of effect
- sloshed ... slurred speech
To administer:
@set woman/donkied:effect = "Heehaw! ;; Heehaw, heehaw!"
"""
for effect in effects:
if effect:
if effect.db_key == 'donkied':
msg = choices(effect.value)
return (msg, msg, "bray")
return (speech, speech, verb)
class CmdWhisper(MuxCommand):
@ -146,12 +168,19 @@ class CmdSay(MuxCommand):
else:
verb = "say"
for_me, for_others, verb = \
speech_effect(speech, verb,
self.caller,
self.caller.attributes.get(category="effect",
return_obj=True,
return_list=True))
# The `send_emote` is _global_, so if we want to say to 'Bob',
# 'You say ...', we have to both send him a message with the
# 'You' as well as everyone else with the 'send_emote'.
to_whom = chars_list(self.lhs, verb, for_rp=False) if 'to' in self.switches else ''
full_speech = f"You {adverb}{verb}{to_whom}, \"{speech}\""
full_speech = f"You {adverb}{verb}{to_whom}, \"{for_me}\""
self.caller.msg(full_speech, from_obj=self.caller)
# English is weird...
@ -160,7 +189,7 @@ class CmdSay(MuxCommand):
targets = [item for item in self.caller.location.contents if item != self.caller]
to_whom = chars_list(self.lhs, verb) if 'to' in self.switches else ''
full_speech = f"/Me {adverb}{verb}s{to_whom}, \"{speech}\""
full_speech = f"/Me {adverb}{verb}s{to_whom}, \"{for_others}\""
send_emote(self.caller, targets, full_speech, msg_type="say", anonymous_add=None, quiet=True)

View file

@ -2,11 +2,13 @@
from re import match
from evennia import CmdSet
from evennia import CmdSet, create_script
from evennia.utils import delay, logger
from evennia.commands.default.muxcommand import MuxCommand
from evennia.contrib.rpg.rpsystem import send_emote
from .command import Command
from typeclasses.scripts import DonkeyHeadSpell
from utils.word_list import routput
class CmdFly(Command):
@ -65,8 +67,42 @@ class CmdGM(MuxCommand):
elif o.is_typeclass('typeclasses.characters.Character'):
o.msg(self.args)
logger.info(f"switches = {self.switches} lhs={self.lhs} rhs={self.rhs} / args={self.args}")
class CmdSpell(Command):
key = "spell"
aliases = ['cast']
locks = "cmd:perm(gm) or perm(Admin)"
def parse(self):
self.spell = None
self.target = None
m = match(r"([^ ]+)( +on +(.+))?", self.args.strip())
if m:
self.spell = m.group(1)
self.target = m.group(3)
def func(self):
caster = self.caller
if not self.spell:
caster.msg('Usage: cast <spell> [on <target>]')
return
char = None
if self.target:
char = caster.search(self.target)
if not char:
return
if self.spell == 'donkey' and char:
create_script(key="donkey_head",
typeclass=DonkeyHeadSpell,
interval=130,
start_delay=True,
attributes=[("target", char)])
caster.msg(f"You cast |wHead of Donkey|n on {char}")
else:
caster.msg(f"You fail to cast {self.spell}")
class CmdGMTrigger(Command):
"""The trigger command kicks off a series of named events.

View file

@ -8,7 +8,7 @@ creation commands.
"""
from re import match
from re import match, compile
from evennia.contrib.game_systems.gendersub import GenderCharacter
from evennia.contrib.rpg.rpsystem import ContribRPCharacter
@ -16,7 +16,7 @@ from evennia.contrib.rpg.rpsystem import send_emote
from evennia.prototypes.spawner import spawn
from evennia.utils import delay # , logger
from utils.word_list import routput
from utils.word_list import routput, choices
from .objects import Object
from .tutorial import TutorBird, TutorialState
@ -115,6 +115,51 @@ class Character(Object, GenderCharacter, ContribRPCharacter):
self.msg(f"{victim.key} doesn't have a {to_take} you can take.")
def pronoun_subjective(self, uppercase=False):
gender = self.attributes.get('gender')
if gender == "male":
results = 'He'
elif gender == "female":
results = 'She'
elif gender == "neutral":
results = 'It'
else:
results = 'They'
return results if uppercase else results.lower()
def gendered_text(self, text):
"""
Replace entries, like |s and |p with pronouns.
Like 'he' and 'her'
"""
gender_rx = compile(r"(?<!\|)\|(?!\|)[sSoOpPaA]")
return gender_rx.sub(lambda x: self._get_pronoun(x), text)
def return_appearance(self, looker, **kwargs):
"""
Can be overridden or appended with an effect.
Does the looker affect this?
"""
# To replace, temporarily, a description:
# @set woman/temp_desc:effect = "They fade away from view."
new_desc = self.attributes.get(category="effect",
key="temp_desc")
if new_desc:
return self.gendered_text(new_desc)
pre_desc = self.attributes.get(category="effect",
key="pre_desc") or ""
post_desc = self.attributes.get(category="effect",
key="post_desc") or ""
reg_desc = super().return_appearance(looker)
pronoun = self.pronoun_subjective(True)
return self.gendered_text(pre_desc + \
reg_desc.replace('|wYou see:|n',
'|S has') + \
post_desc)
def at_pre_move(self, destination, *args, **kwargs):
"""
Called by self.move_to when trying to move somewhere. If this returns

View file

@ -551,7 +551,7 @@ class BHB(Friendly):
self.adjust_character(feeder, 40)
feeder.has('berries').delete()
else:
msg = f"{noun} doesn't appear interesting in anything you have."
msg = f"{noun} doesn't appear interested in anything you have."
feeder.msg(msg)

View file

@ -25,7 +25,7 @@ class Puppet(Character):
puppeting this Object.
"""
self.msg("\nYou are puppeting |c{name}|n.\n".format(name=self.key))
self.msg("\nYou are puppeting |c{name}|n.".format(name=self.key))
self.msg((self.at_look(self.location), {"type": "look"}), options=None)
def at_post_unpuppet(self, account=None, session=None, **kwargs):

View file

@ -145,3 +145,28 @@ Well, by sticky, we mean, wizardly-sticky...an absolutely amazing looking stick.
})[0]
stick.location = woods
class Spell(Script):
"""
A script to clean up the effects of a spell.
"""
def at_stop(self, **kwargs):
target = self.attributes.get("target")
target.attributes.clear(category="effect")
self.delete()
class DonkeyHeadSpell(Spell):
def at_start(self, **kwargs):
target = self.attributes.get("target")
target.attributes.add(
"donkied",
"Heehaw! ;; Heehaw, heehaw!",
category="effect")
target.attributes.add(
"post_desc",
"\nOh, and |s has a donkey's head!",
category="effect")
target.msg("You suddenly feel quite peculiar.")
def at_repeat(self, **kwargs):
self.stop()

File diff suppressed because it is too large Load diff