This allows a user to get something, but if they leave an area, they automatically put it back.
167 lines
6.2 KiB
Python
167 lines
6.2 KiB
Python
"""
|
|
Characters
|
|
|
|
Characters are (by default) Objects setup to be puppeted by Accounts.
|
|
They are what you "see" in game. The Character class in this module
|
|
is setup to be the "default" character type created by the default
|
|
creation commands.
|
|
|
|
"""
|
|
|
|
from evennia.objects.objects import DefaultCharacter
|
|
from evennia.prototypes.spawner import spawn
|
|
|
|
from utils.word_list import Token, routput
|
|
from .objects import Object
|
|
from .tutorial import TutorBird, TutorialState
|
|
|
|
from re import match
|
|
|
|
INTRO = """
|
|
As the surrounding mists dissipate, you find yourself in an ancient, halcyon forest dripping with moss. You see an envelope of parchment wedged under a scaly protrusion of bark...inside, a letter in familiar penmanship, personally addressed to you, which you pick up.
|
|
|
|
A little blue bird flies by you, almost grazing your ear!"""
|
|
|
|
READ_LETTER = """You read a letter with an oddly familiar penmanship:
|
|
|
|
My dearest {0},
|
|
|
|
If you are reading this, you've found the world I was overly excited in relaying to you over drinks in Marsivan. Most excellent. Enjoy this halcyon world, unspoiled and idyllic.
|
|
|
|
I'm here, so join me in a cup of tea and we can reconnect and reminisce of glorious days gone by, and the utter curiosity that surrounds us.
|
|
|
|
Your friend,
|
|
Dabbler
|
|
|
|
(Type 'help start' for details on playing this game)"""
|
|
|
|
class Character(Object, DefaultCharacter):
|
|
"""
|
|
The Character just re-implements some of the Object's methods and hooks
|
|
to represent a Character entity in-game.
|
|
|
|
See mygame/typeclasses/objects.py for a list of
|
|
properties and methods available on all Object child classes like this.
|
|
|
|
"""
|
|
def at_object_creation(self):
|
|
"called when a character is first created."
|
|
self.db.tutorstate = 0
|
|
|
|
if self.dbref != "#1":
|
|
self.create_letter()
|
|
TutorBird.do_start_tutorial(self)
|
|
|
|
def at_post_puppet(self):
|
|
if self.db.visited:
|
|
self.msg(f"""\n“Welcome back, {self.key.capitalize()}.”\n""")
|
|
self.execute_cmd("look")
|
|
else:
|
|
self.db.visited = True
|
|
self.db.tutorstate = 0
|
|
self.msg(INTRO)
|
|
self.account.db._last_puppet = self
|
|
|
|
def create_letter(self):
|
|
"create a welcome letter in a character's inventory"
|
|
letter = spawn({
|
|
"typeclass": "typeclasses.readables.Letter",
|
|
"key": "letter",
|
|
"desc": "A letter of familiar penmanship stuffed in an envelope.",
|
|
})[0]
|
|
letter.db.inside = READ_LETTER.format(self.name.capitalize())
|
|
letter.location = self
|
|
|
|
def do_take(self, args):
|
|
"""
|
|
A character has a _steal_command. What are the limitations?
|
|
"""
|
|
args = Token(args)
|
|
if args.empty():
|
|
self.msg("What do you want to take?")
|
|
elif len(args.words) == 1:
|
|
self.msg(f"You want to take {args.words[0]}, but from whom?")
|
|
else:
|
|
to_take = args.words[0]
|
|
from_whom = args.words[-1]
|
|
victim = self.search(from_whom)
|
|
if victim:
|
|
thing = victim.has(to_take)
|
|
if thing and thing.db.can_take:
|
|
self.msg(f"You take {thing.key} from {victim.key}.")
|
|
self.location.msg_contents(
|
|
f"{self.key} takes {thing.key} from {victim.key}!",
|
|
exclude=self)
|
|
thing.move_to(self, quiet=True, use_destination=True)
|
|
return
|
|
|
|
self.msg(f"{victim.key} doesn't have a {to_take} you can take.")
|
|
else:
|
|
self.msg(f"You don't see {from_whom}.")
|
|
|
|
def at_pre_move(self, destination, **kwargs):
|
|
"""
|
|
Called by self.move_to when trying to move somewhere. If this returns
|
|
False, the move is immediately canceled.
|
|
"""
|
|
self.db.tutorstate = self.db.tutorstate | TutorialState.MOVE.value
|
|
|
|
if self.db.is_sitting:
|
|
self.msg("You stand up first...")
|
|
self.db.is_sitting = False;
|
|
|
|
# @lock thing = tethered:id(#19)
|
|
# @set thing/tethered_msg = "Let's put that back"
|
|
for thing in self.contents:
|
|
to = thing.locks.get('tethered')
|
|
if to:
|
|
m = match(r".*:id\(#?(.*)\)", to)
|
|
if m:
|
|
id_num = m.group(1)
|
|
dest = self.global_search(f"#{id_num}")
|
|
msg = thing.db.tethered_msg
|
|
if dest and msg:
|
|
thing.location = dest
|
|
self.msg(msg)
|
|
else:
|
|
print(f"Found tethered, {thing} to #{id_num}, but dest is {dest} and msg is '{msg}'. Set both.")
|
|
else:
|
|
print(f"Found tethered, {thing} to #{to}, but that needs to be 'tethered:id(num) where num is the ID# of an object/place.")
|
|
|
|
return super().at_pre_move(destination)
|
|
|
|
def at_pre_say(self, message, **kwargs):
|
|
"While we could/should do 'at_say', this should be easier."
|
|
self.db.tutorstate = self.db.tutorstate | TutorialState.SAY.value
|
|
return super().at_pre_say(message)
|
|
|
|
def at_look(self, target, **kwargs):
|
|
"""
|
|
When we look at something that _might_ be hidden, we check
|
|
if we are looking at something that _is_ hidden, i.e. has a
|
|
view lock of a particular tag, and if so, we interpret this as
|
|
'you are looking at something by name', therefore you see it.
|
|
So we give ourselves the right to see it from now on.
|
|
|
|
To use this, simply add the following lock:
|
|
|
|
@lock thing = view:tag(hidden_thing, mp)
|
|
|
|
Where thing is the single name of the hidden object.
|
|
"""
|
|
hidden_tag = f"hidden_{target}"
|
|
lock_string = f"view:tag({hidden_tag}, mp)"
|
|
view_lock = target.locks.get("view")
|
|
|
|
if view_lock == lock_string:
|
|
self.tags.add(hidden_tag, category="mp")
|
|
|
|
if target.is_typeclass("typeclasses.rooms.Room"):
|
|
self.db.tutorstate = self.db.tutorstate | TutorialState.LOOK.value
|
|
else:
|
|
self.db.tutorstate = self.db.tutorstate | TutorialState.LOOKAT.value
|
|
|
|
# Regardless of what happened before, we return the normal
|
|
# function call.
|
|
return super().at_look(target)
|