diff --git a/commands/everyone.py b/commands/everyone.py index 496adbc..702e35b 100755 --- a/commands/everyone.py +++ b/commands/everyone.py @@ -1,14 +1,15 @@ #!/usr/bin/env python from random import random -from re import split +from re import split, sub, MULTILINE -from commands.command import Command +from django.conf import settings from evennia.commands.default.general import CmdGet, NumberedTargetCommand from evennia.commands.default.muxcommand import MuxCommand from evennia.contrib.rpg.rpsystem import send_emote from evennia.utils import evmore, iter_to_str, logger +from commands.command import Command from typeclasses.characters import Character from typeclasses.tutorial import TutorBird, TutorialState from utils.word_list import routput, paragraph, choices @@ -471,21 +472,37 @@ class CmdRead(Command): def func(self): """Return the 'inside' attribute.""" + reader = self.caller target_str = self.args.strip() if target_str == "": - self.caller.msg("Usage: |gread |n") + reader.msg("Usage: |gread |n") return - book = self.find_readable(self.caller, target_str) + book = self.find_readable(reader, target_str) if book: contents = book.db.inside + prefix = book.db.prefix + if prefix: + prefix = prefix + "|/" if contents.startswith("file:"): - filename = contents[5:] - with open(filename, "r") as myfile: - evmore.msg(self.caller, myfile.read()) + self.show_file(reader, contents[5:], prefix) else: - self.caller.msg(contents) + reader.msg(prefix + contents) + def show_file(self, reader, filename, prefix): + """ + Display a file to the user. + + The file is _somewhat_ Markdown formatted. + """ + width = self.client_width() - 1 + with open(filename, "r") as myfile: + no_data = sub(r">.*", "", myfile.read(), MULTILINE) + brk = '─' if reader.utf() else '-' + no_head = sub(r"#.*", '|W' + (brk * width) + '|n', + no_data, MULTILINE) + buf = prefix + paragraph(no_head) + evmore.msg(reader, buf) class CmdTake(CmdGet, NumberedTargetCommand): """ diff --git a/commands/misc.py b/commands/misc.py index 5439a95..857078c 100755 --- a/commands/misc.py +++ b/commands/misc.py @@ -3,6 +3,7 @@ from evennia.commands.default.muxcommand import MuxCommand from evennia import CmdSet from evennia.utils import logger +from evennia.utils.eveditor import EvEditor from .command import Command @@ -142,6 +143,33 @@ class CmdSetSmoke(CmdSet): self.add(CmdSmoke) + +class CmdWrite(MuxCommand): + """Write something down. + + Usage: + + write + + This brings up a strange little editor, where you can type the + message, and edit the individual lines. + + """ + key = "write" + + def func(self): + EvEditor(self.caller, + loadfunc=self.obj.do_write_begin, + savefunc=self.obj.do_write, + quitfunc=self.obj.do_write_end, + key="Type ':q' on its own line when done.") + + +class CmdSetWrite(CmdSet): + def at_cmdset_creation(self): + self.add(CmdWrite) + + class CmdRummage(MuxCommand): """ Rummage around in an object that contains stuff. diff --git a/typeclasses/characters.py b/typeclasses/characters.py index d21e1ac..e956df3 100644 --- a/typeclasses/characters.py +++ b/typeclasses/characters.py @@ -72,6 +72,16 @@ class Character(Object, GenderCharacter, ContribRPCharacter): self.create_ticket() self.create_pouch() + def utf(self): + """ + Return True if character's user encoding is UTF-8. + """ + session = self.sessions.get()[0] + if session: + flags = session.protocol_flags + return flags.get("ENCODING") == 'utf-8' + return False + def delete_inv(self, typeclass): for obj in self.contents: if obj.is_typeclass(typeclass): diff --git a/typeclasses/lightables.py b/typeclasses/lightables.py index 5366714..4312120 100755 --- a/typeclasses/lightables.py +++ b/typeclasses/lightables.py @@ -86,6 +86,8 @@ class LightSource(Object): self.db.is_giving_light = True if self.db.desc_lit: self.db.desc = self.db.desc_lit + if owner.location.db.desc_lit: + owner.location.msg_contents(owner.location.db.desc_lit) # if we are in a dark room, trigger its light check try: diff --git a/typeclasses/readables.py b/typeclasses/readables.py index ef48058..7784425 100755 --- a/typeclasses/readables.py +++ b/typeclasses/readables.py @@ -3,12 +3,15 @@ import random from evennia import Command, CmdSet +from evennia.utils import logger from evennia.prototypes.spawner import spawn from typeclasses.objects import Object -from typeclasses.rooms import DabblersRoom from utils.word_list import routput +from commands.misc import CmdSetWrite + + BOOK_EMOTIONS = [ "sad", "heartfelt", @@ -159,6 +162,53 @@ class Book(Readable): return True +class WriteableBook(Book): + """ + Along with reading, the user can write in this book. + + Actually, append to the text file associated with it. + """ + def at_object_creation(self): + """ + called at creation + """ + self.cmdset.add_default(CmdSetWrite) + + def do_read(self, reader): + reader.announce_action(f"$You() $conj(read) the {self.name}.") + + def do_write_begin(self, writer): + writer.announce_action( + self.db.pre_write_msg or + "$You() $conj(grab) the quill, $conj(dip) it in the ink well, " + "and $conj(begin) to pen a message in the book...") + writer.msg("|/<< Pardon the quaint, twentieth-century approach to " + "capturing your prose (but this works with all MUD " + "clients). Easiest approach: just type your message, hit " + "the |wReturn|n key, type |g:q|n, and his the " + "|wReturn|n key again...>>|/") + return "" + + def do_write(self, writer, message): + session = writer.sessions.get()[0] + contents = self.db.inside + + if contents.startswith("file:"): + filename = contents[5:] + with open(filename, "a") as myfile: + myfile.write(f"# {writer.name}\n\n") + myfile.write(message) + myfile.write("\n\n") + myfile.write(f"> User: {writer.account.name}\n") + myfile.write(f"> Addr: {session.protocol_key}:{session.address}\n") + myfile.write(f"> Cmds: {session.cmd_total}\n\n") + + def do_write_end(self, writer): + writer.announce_action( + self.db.pre_write_msg or + "$You() $conj(put) down the quill, and $conj(stop) writing.") + + class Books(Object): book_prototype = { "typeclass": "typeclasses.readables.Book", diff --git a/world/version1.ev b/world/version1.ev index 70b1e11..5f280ea 100644 --- a/world/version1.ev +++ b/world/version1.ev @@ -109,6 +109,51 @@ py timed_script = evennia.create_script(key="Create Sticks", attributes=[("destination", here)] ) # Sticks:1 ends here +# Guest Book +# Players can leave messages in this book. We’ll see how long I want to leave this. + + +# [[file:../../../projects/mud.org::*Guest Book][Guest Book:1]] +@create/drop guest book:typeclasses.readables.WriteableBook +# +@set guest book/inside = "file:world/guest-book.md" +# +@set guest book/prefix = "You open the leather-bound book, and begin to read from page one..."" +# Guest Book:1 ends here + + + +# Note that we don’t mention this in the area’s description. + + +# [[file:../../../projects/mud.org::*Guest Book][Guest Book:2]] +@desc guest book = The root from one of the collosal trees has erupted from the ground, forming a dry alcove that harbors a colony of mushroom caps. Jauntily perched on the largest of these, a leather-bound book, sports the title, |wGuest Book|n. Next to it, a feather quill and an ink well invite you to read the register, and leave a note for other travelers. +# Guest Book:2 ends here + + + +# Can’t get it: + + +# [[file:../../../projects/mud.org::*Guest Book][Guest Book:3]] +@lock guest book = get:false() +# +@set guest book/get_err_msg = "The owner designed a guest book to be read and written by guests. Pocketing it for selfish interests sort of defeats the purpose." +# Guest Book:3 ends here + + + +# And some details: + + +# [[file:../../../projects/mud.org::*Guest Book][Guest Book:4]] +@detail quill = The black feathered quill may once belonged to a raven, but if so, it must have been large. +# +@detail ink = Black, like the ichor of the gods ... or perhaps, someone just started a squid. +# +@detail well = The well appears to be little more than a depression on the back of the mushroom's cap. +# Guest Book:4 ends here + # Boulder # More details about the room that describes aspects of the boulder in the =desc= above. First, the symbol: