329 lines
9.7 KiB
Python
Executable file
329 lines
9.7 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
from random import choice
|
|
from re import match
|
|
|
|
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 typeclasses.drinkables import Cocktail
|
|
from utils.word_list import routput
|
|
|
|
|
|
class CmdFly(Command):
|
|
"""Cast the 'fly' spell.
|
|
|
|
Make sure you set the following properties, for instance:
|
|
|
|
@set self/disappear_msg = "The wizard disappears in a puff of smoke."
|
|
@set self/reappear_msg = "A plume of <<white ^ light blue ^ gray ^ >>
|
|
smoke appears... ;; When the smoke clears, a
|
|
wizard <<emerges ^ materializes>>."
|
|
@set self/appear_delay = 3
|
|
|
|
The last setting is the number of seconds between message segments
|
|
(those are separated by double semicolons).
|
|
|
|
"""
|
|
key = "fly"
|
|
locks = "cmd:holds()"
|
|
|
|
def func(self):
|
|
"""
|
|
Call the 'do_fly' method on the caller.
|
|
"""
|
|
self.caller.do_fly(self.args.strip())
|
|
|
|
|
|
class CmdMagic(Command):
|
|
"""
|
|
Cast a generic 'magic' spell.
|
|
|
|
Usage:
|
|
|
|
wave [ effect(s) ]
|
|
|
|
Where 'effects' is a statement of what happens after the magic erupts.
|
|
Note that you can have multiple effects separated by two semicolons.
|
|
|
|
You can tailor the effects to your character with the following:
|
|
|
|
- |y$you()|n: Replaced by "you" and your name for others, like "old gnome"
|
|
- |y$your()|n: Replaced by "your" and your possessive name for others, like "old gnome's"
|
|
- |y$conj(verb)|n: Replaced by "verb" for you, and "verbs" for others.
|
|
- |y$pron(you)|n: Replaced by "you" for you, but "he" or "she" for others.
|
|
- |y$pron(your)|n: Replaced by "your" for you, but "his" or "her" for others.
|
|
|
|
While flexible, you would use this complex replacement in either
|
|
|gnicks|n or as part of a standard magical prefix, by setting the
|
|
property:
|
|
|
|
@set self/magic_msg = "$You() $conj(shake) $pron(your) necklace of bones!"
|
|
"""
|
|
key = "magic"
|
|
aliases = ["wave"]
|
|
locks = "cmd:holds()"
|
|
|
|
def func(self):
|
|
"""
|
|
Call the 'do_magic' method on the caller.
|
|
"""
|
|
wizard = self.caller
|
|
msgs = wizard.db.magic_msg
|
|
if msgs:
|
|
msgs = msgs.split(';;')
|
|
else:
|
|
msgs = [
|
|
"$You() $conj(wave) $pron(your) " + self.obj.key + ".",
|
|
"<< Sparks ^ Colored lights ^ Flashes ^ Flashes >> of |yoctarine|n << appear ^ emerge ^ materialize >> as << the ^ >> magic << coalesces into an amorphous show of power ^ blends into swirling patterns ^ weaves together>>."
|
|
]
|
|
|
|
if self.args:
|
|
msgs = msgs + self.args.strip().split(';;')
|
|
|
|
wizard.spell_sequence(None, msgs, wizard.db.magic_delay or 3)
|
|
|
|
|
|
class CmdSetWand(CmdSet):
|
|
"""
|
|
All wizard spells are tied to a 'wand' that might be flavored.
|
|
"""
|
|
def at_cmdset_creation(self):
|
|
super().at_cmdset_creation()
|
|
self.add(CmdFly)
|
|
self.add(CmdMagic)
|
|
|
|
|
|
class CmdMakeCocktail(MuxCommand):
|
|
"""
|
|
For the 'Bartender' especially.
|
|
|
|
Usage:
|
|
|
|
shake |wcocktail|n = |wpatron|n
|
|
|
|
If patron is not given or not found, the drink will be in your
|
|
inventory, and you can call |ggive|n to pass it along.
|
|
|
|
If cocktail name isn't given (or matches anything), a random
|
|
one will be created.
|
|
"""
|
|
key = 'shake'
|
|
locks = "cmd:perm(gm) or perm(Admin)"
|
|
|
|
def func(self):
|
|
dest = self.caller
|
|
if self.rhs:
|
|
dest = self.caller.search(self.rhs)
|
|
Cocktail.make(dest, self.caller, self.lhs)
|
|
|
|
|
|
class CmdGM(MuxCommand):
|
|
"""
|
|
The gm command allows anything to be emoted into a room.
|
|
|
|
Usage:
|
|
|
|
gm A bat flies into the room!
|
|
gm/gnome You hear a distant ringing
|
|
"""
|
|
key = "gm"
|
|
aliases = ["#"]
|
|
locks = "cmd:perm(gm) or perm(Admin)"
|
|
|
|
def func(self):
|
|
send_to = []
|
|
for switch in self.switches:
|
|
o = self.caller.search(switch, global_search=True)
|
|
if o:
|
|
send_to = send_to + [o]
|
|
|
|
if not send_to:
|
|
send_to = [self.caller.location]
|
|
|
|
me = self.caller
|
|
|
|
msg = routput(self.args)
|
|
for o in send_to:
|
|
if o.is_typeclass('typeclasses.rooms.Room'):
|
|
chars = o.contents_get(None, 'character')
|
|
send_emote(me, chars, msg, 'say', None)
|
|
elif o.is_typeclass('typeclasses.characters.Character'):
|
|
o.msg(msg)
|
|
|
|
|
|
class CmdSpell(Command):
|
|
"""
|
|
Cast one of the few spells we've created that affect others.
|
|
|
|
Usage:
|
|
|
|
spell donkey on lizardman
|
|
"""
|
|
|
|
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.
|
|
|
|
Usage:
|
|
|
|
trigger trigger-name
|
|
trigger :game trigger-name
|
|
trigger/character trigger-name
|
|
trigger/character:game trigger-name
|
|
|
|
Where 'game' defaults to the value previously set:
|
|
|
|
@set npc/currentgame = "session1"
|
|
|
|
Triggers are typically set on the NPC (which would be in the room
|
|
with the PCs) or the room. Using the command:
|
|
|
|
@set npc/triggers:session1 = {"darkness": {"desc": "Make the
|
|
room go black", "timer": 1, "events": [ "The room gets dark",
|
|
"And then pitch-black.", ("You can't help it, but scream!", "You
|
|
hear a scream!")]}}
|
|
|
|
The 'set' command, as a complicated data structure, should be set
|
|
in a batchcommand.
|
|
|
|
"""
|
|
key = "trigger"
|
|
aliases = ["trig"]
|
|
locks = "cmd:perm(gm) or perm(Admin)"
|
|
|
|
def parse(self):
|
|
m = match(r" *(/[^: ]+)?(:[^ ]+)? *(.*)", self.args)
|
|
if m:
|
|
self.name = m.group(3)
|
|
if m.group(2):
|
|
self.game = m.group(2)[1:]
|
|
else:
|
|
self.game = None
|
|
if m.group(1):
|
|
self.switches = m.group(1)[1:].split(',')
|
|
else:
|
|
self.switches = []
|
|
else:
|
|
self.caller.msg("Usage trigger/dest:game trigger")
|
|
return False
|
|
|
|
def func(self):
|
|
npc = self.caller
|
|
self.send_to = []
|
|
|
|
for switch in self.switches:
|
|
o = npc.search(switch)
|
|
if o:
|
|
self.send_to = self.send_to + [o]
|
|
else:
|
|
return
|
|
|
|
game = self.game or npc.db.currentgame
|
|
if not game:
|
|
npc.msg("Specify the game, or set a default with |g@set self/currentgame = <game>")
|
|
return
|
|
|
|
triggers = dict(npc.attributes.get(key='triggers', category=game))
|
|
|
|
if not self.name:
|
|
npc.msg("What event do you want to trigger?")
|
|
for name, details in triggers.items():
|
|
npc.msg(f" - {name} : {details['desc']}")
|
|
return
|
|
|
|
trigger = triggers[self.name]
|
|
if trigger:
|
|
npc.msg(f"Triggering: |w{trigger['desc']}")
|
|
self.trigger(trigger['events'],
|
|
trigger.get('timer', 5),
|
|
self.send_to)
|
|
else:
|
|
npc.msg(f"Didn't find '{self.name}' to trigger.")
|
|
|
|
def trigger(self, events, time_delay, dests=[]):
|
|
"""
|
|
Given a list of events, send each events at an interval.
|
|
If an event is a tuple instead of a string, the first
|
|
element goes to 'dests' and the second goes to the room
|
|
(based on the caller's location).
|
|
"""
|
|
target = None
|
|
if len(self.send_to) > 0:
|
|
target = self.send_to[0]
|
|
else:
|
|
targets = self.caller.characters_here()
|
|
if targets:
|
|
target = choice(targets)
|
|
|
|
if target:
|
|
name = target.db._sdesc or target.key
|
|
else:
|
|
name = ''
|
|
|
|
for idx, event in enumerate(events):
|
|
if isinstance(event, str):
|
|
if event.startswith("@"):
|
|
self.caller.execute_cmd(event[1:])
|
|
else:
|
|
if target:
|
|
msg = target.gendered_text(routput(event, name))
|
|
else:
|
|
msg = routput(event)
|
|
|
|
delay(time_delay * idx,
|
|
self.caller.location.msg_contents,
|
|
"\n" + msg)
|
|
else:
|
|
char = target.gendered_text(routput(event[0], name))
|
|
room = target.gendered_text(routput(event[1], name))
|
|
|
|
if room:
|
|
delay(time_delay * idx,
|
|
self.caller.location.msg_contents,
|
|
"\n" + routput(room),
|
|
exclude=dests)
|
|
if char:
|
|
for dest in dests:
|
|
delay(time_delay * idx,
|
|
dest.msg,
|
|
"\n" + routput(char))
|