-Copyright (c) 2005, 2006 Jeremy Stanley <fungi@yuggoth.org>. All rights
-reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
- - Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- - Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
+Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[__control__]
read_only = yes
--- /dev/null
+ O OOO O O O OOOO O O O O OO OOO OO OOO OOO OOO OOO
+ OOOOO OO O O O O O O O O O O O O O O O O O O O O O
+ O O OOO O O O O O O OO OOOO O OOOO OOO OO O OO
+ O O O O O O O O O O O O O O O O O O O O O O O
+ O OO OO O OO O O O O O O O O O O O O O O OOO OOO OOO
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[__control__]
read_only = yes
action = command_show(actor, parameters)
administrative = yes
description = Show various data.
-help = Here are the possible incantations (<parameter> is required, [parameter] is optional, (note) is a note):$(eol)$(eol) show categories (list all element category names)$(eol) show category <category> (list the elements in a category)$(eol) show element <element> (list facet definitions for an element)$(eol) show file <filename> (list elements in a file)$(eol) show files (list all element data files)$(eol) show log [level [start [stop]]] (list logs above level from start to stop)$(eol) show result <expression> (evaluates a python expression)$(eol) show time (returns several current timer values)
+help = Here are the possible incantations (<parameter> is required, [option] is optional, (note) is a note):$(eol)$(eol) show categories (list all element category names)$(eol) show category <category> (list the elements in a category)$(eol) show element <element> (list facet definitions for an element)$(eol) show file <filename> (list elements in a file)$(eol) show files (list all element data files)$(eol) show log [level [start [stop]]] (list logs above level from start to stop)$(eol) show result <expression> (evaluates a python expression)$(eol) show time (returns several current timer values)
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[__control__]
include_files = pride_square/index
read_only = yes
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[__control__]
include_files = [ "location", "prop" ]
read_only = yes
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[location:-1,-1,0]
description = This booth sells cloth garments of every description. Fine silks and linens line the walls, draped from every protrusion and stacked on every surface.
gridlinks = ['north']
terrain = city
[location:0,0,1]
-description = The stand is currently not in use for a performance, but shoppers gather here to rest and chat with one another. A pleasantly cool breeze coupled with a nice view of the market make this a good place to relax.
+description = The stand is currently not in use for a performance, but shoppers gather here to rest and chat with one another. A pleasantly cool breeze coupled with a nice view of the market makes this a good place to relax.
gridlinks = ['down']
name = The Bandstand
terrain = inside
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[prop:fountain]
impression = An inviting public fountain bubbles here, tempting you with thirst.
keywords = fountain water
--- /dev/null
+ \e[37;1m888 888 888 888 `788b, 8888888888b
+ 88\e[0;37m8 8888\e[1m8\e[0;37m8\e[1m8\e[0;37m8\e[1m888\e[0;37m8 \e[1m8\e[0;37m8\e[1m8 8\e[0;37m8\e[1m8 \e[0;37m`\e[1m7\e[0;37m8\e[1m8b\e[0;37m, \e[1m8\e[0;37m8\e[1m88\e[0;37m888\e[1m88\e[0;37m88
+ 888\e[1m88\e[0;37m888\e[1m8\e[0;37m88\e[1m88\e[0;37mb 8\e[1m8\e[0;37m8\e[1m88\e[0;37m8888888 \e[1m888 \e[0;37m888 `\e[1m7\e[0;37m8\e[1m8\e[0;37mb, \e[1md88P d\e[0;37m88\e[1mP
+ \e[0;37m88\e[36;1m8\e[0;37m8\e[36;1m88\e[0;37m8\e[36;1m8\e[37m888\e[0;37m88\e[1m8b \e[0;37md\e[1m8\e[36m88\e[37m, 88\e[0;37m8 \e[36;1m8\e[37m8\e[0;37m8 \e[36;1m888 \e[0;37m`\e[36;1m7\e[0;37m8\e[1m8b\e[36m, \e[0;37md\e[1m8\e[36m8P d88\e[37mP
+ 88\e[0;37m8 \e[1m`\e[36m88\e[37m8 \e[36md\e[37m8\e[0;37m8A88\e[36;1mb\e[0;37m, \e[1m8\e[36m8\e[0;37m8 \e[1m8\e[36m88 8\e[37m88 d8\e[36m8P d88\e[37mP d\e[0;37m8\e[36;1m8P
+ \e[0;37m8\e[36;1m8\e[0;36m8 8\e[0;37m88 \e[0;36md\e[0;37m8\e[0;36m8\e[1mP \e[0;37m`\e[0;36m7\e[0;37m8\e[0;36m8\e[1mb,\e[0;37md\e[36;1m8\e[0;37m8\e[36;1mP \e[0;36m88\e[0;37m8 \e[36;1m8\e[0;37m8\e[36;1m8 d\e[0;36m8\e[1m8\e[0;36mP \e[1md8\e[0;37m8\e[36;1m8 \e[0;37md\e[36;1m8\e[0;36m88\e[0;37mb,
+ 888\e[36;1m`\e[0;36m88\e[1mb \e[0;36m8\e[1m88 `\e[0;37m7\e[0;36m8\e[0;37m8o\e[36;1m8\e[0;36mP \e[0;37md8\e[0;36m8\e[1mP 888\e[0;37md\e[36;1m88P \e[0;37m,d\e[0;36m8\e[1m8\e[0;37mP\e[36;1m' \e[0;37md\e[36;1m8\e[0;37m8\e[0;36mP78\e[0;37m8b,
+ \e[0;36md8\e[1m8P \e[0;36m`88\e[1mb 88\e[0;36m8 \e[1m,d88\e[0;36mP\e[1m' \e[0;36md88\e[1mP \e[0;36m888\e[1m8\e[0;36m8\e[1mP ,\e[0;36md8\e[1m8\e[0;36mP' \e[1md88P \e[0;36m`78\e[1m8\e[0;36mb
+ d8\e[1m8P \e[0;36m`\e[1m888\e[0;36m88\e[1mP \e[0;36m,\e[1md8\e[0;36m8\e[1mP' d\e[0;36m8\e[1m8\e[0;36mP 8888P ,\e[1md\e[0;36m8\e[1m8\e[0;36mP\e[1m' \e[0;36md\e[1m8\e[0;36m8\e[1mP `\e[0;36m88b
+ d88P `888P ,d88P' d88P 888P ,d88P' d88P `88b
+ \e[31;1m88888 d8888P db 8888888888 db 888888b d888b 88 d888b
+ 88888 d8888P d88b 88 d88b 88 `8b d8P `8b 88 d8P `8b
+ \e[0;31m8\e[1m8\e[0;31m888 \e[1md8\e[0;31m8\e[1m88P \e[0;31md8\e[1mP\e[0;31m`\e[1m8b 88 \e[0;31md\e[1m8P`\e[0;31m8\e[1mb \e[0;31m8\e[1m8 \e[0;31md8P `\e[1m8b 88 \e[0;31m`\e[1m8b
+ \e[0;31m8\e[1m8\e[0;31m8\e[1m88 d8\e[0;31m88\e[1m8P d\e[0;31m8P \e[1m`\e[0;31m8b \e[1m8\e[0;31m8 \e[1md\e[0;31m8P `\e[1m8b \e[0;31m888\e[1m8\e[0;31m8\e[1m8P \e[0;31m`7\e[1m8b, 88 `\e[0;31m78b\e[1m,
+ \e[30m8\e[0;31m8\e[30;1m88\e[31m8 \e[30md\e[31m88\e[0;31m8\e[1m8\e[30mP d\e[0;31m88\e[30;1m8\e[31m888\e[30m88b \e[0;31m8\e[1m8 \e[30md\e[31m8\e[0;31m88\e[1m8\e[0;31m88\e[1m88\e[0;31mb \e[30;1m88 `\e[0;31m8\e[30;1mb \e[31m`\e[30m7\e[0;31m8\e[1mb\e[0;31m, \e[30;1m8\e[0;31m8 \e[30;1m`\e[31m7\e[0;31m8\e[30;1mb,
+ \e[31m888\e[30m8888\e[31m8\e[30m88\e[0;31m8 \e[1m8\e[0;31m8 \e[30;1m8\e[31m8 88 \e[0;31m88 \e[30;1m8\e[0;31m8 \e[30;1m88 \e[0;31m`8\e[1mb \e[0;31m`\e[30;1m8b d8\e[0;31mP \e[30;1m8\e[0;31m8 \e[30;1m`\e[0;31m8\e[30;1mb d\e[0;31m8P
+ 88\e[30;1m8\e[31m8\e[0;31m8 \e[1m`\e[30m88\e[31m8\e[30m8\e[31mb 88 88 \e[30m8\e[0;31m8 \e[1m8\e[30m8 \e[0;31m8\e[1m8 \e[0;31m88 \e[30;1m88 `888\e[0;31m88\e[30;1mP \e[31m88 `8\e[30m8\e[31m888P
+ \e[30m8\e[0;31m88\e[30;1m88 \e[0;31m`\e[30;1m888\e[0;31m8b
+ \e[30;1m88\e[0;31m88\e[30;1m8 \e[0;31m`8\e[30;1m88\e[0;31m8b \e[32;1mAeons ago, in a time long since forgotten, this land was fair
+ \e[30;1m8\e[0;31m8\e[30;1m888 `8\e[0;31m8\e[30;1m88b \e[32mand peaceful, governed by harmony and untouched by despair...
+ \e[0;31m888\e[30;1m88 \e[0;31m`\e[30;1m8\e[0;31m888b \e[1mBut then the evil came.\e[0m
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[__control__]
read_only = yes
choice_a = abort selection
create = dict([(str(x+1),y) for x,y in enumerate(user.list_avatar_names())])
default = a
-description = This is the list of avatars available for you to awaken.
+description = This is the list of avatars available for you to delete.
prompt = Whom would you like to delete?
[menu:disconnecting]
prompt = $(red)Closing your previous connection...$(nrm)$(eol)
[menu:entering_account_name]
-description = $(red) :;$(bld)%$(nrm)$(red). $(bld)%S%$(nrm)$(red); $(bld)%$(eol)$(nrm)$(red)t$(bld)S@@@@@ G@S$(nrm)$(red); $(bld)G@@$(nrm)$(red)t .$(bld)G@$(nrm)$(red)t$(eol)$(bld)%@@@@@@ $(nrm)$(red);$(bld)@@@@G @@@$(nrm)$(red). .t$(bld)SG@% $(nrm)$(red);$(bld)S$(nrm)$(red)t;.$(eol);$(bld)@@@@@S G@@@G @@G $(nrm)$(red): :$(bld)@@@@$(nrm)$(red): t$(bld)@ $(nrm)$(red):;$(eol).$(bld)@@@@@% $(nrm)$(red):$(bld)@@@G @@@@@$(nrm)$(red). :$(bld)@@@@ S@@$(nrm)$(red): . .$(bld)%G@@$(nrm)$(red); .$(eol) $(bld)@@@@@$(nrm)$(red); $(bld)G@@G $(nrm)$(red):;; .;$(bld)S@@S%%$(nrm)$(red): . .$(bld)%SS $(nrm)$(red).$(bld)@@@%$(nrm)$(red).$(bld)G@@S$(nrm)$(red): ;$(bld)@S $(nrm)$(red)t$(bld)@@@@ $(nrm)$(red);$(bld)@G$(eol) G@@@@$(nrm)$(red)::$(bld)@@S $(nrm)$(red):$(bld)@$(nrm)$(red)t.$(bld)@@G $(nrm)$(red).$(bld)@G $(nrm)$(red);$(bld)@S$(nrm)$(red);$(bld)G@G @@@S%$(nrm)$(red); $(bld)S@@@S $(nrm)$(red);$(bld)@@@S S@@@$(eol) %@@@@ S@S G@@S$(nrm)$(red)t$(bld)@G $(nrm)$(red):$(bld)@$(nrm)$(red)t $(bld)@@@$(nrm)$(red);:$(bld)@G @@@ $(nrm)$(red)t$(bld)GGG%$(nrm)$(red);. :$(bld)@@@$(nrm)$(red): ;$(bld)@GS$(nrm)$(red)t:$(eol) ;$(bld)@@@@$(nrm)$(red).$(bld)@S $(nrm)$(red). .$(bld)@@$(nrm)$(red)t $(bld)GG $(nrm)$(red);$(bld)@$(nrm)$(red). ;$(bld)@G$(nrm)$(red). $(bld)SG @@% @@@$(nrm)$(red)t .$(bld)@@@ @@@S$(eol) $(nrm)$(red).$(bld)@@@G%@S@G SG$(nrm)$(red). .$(bld)G $(nrm)$(red)t$(bld)@ GS @$(nrm)$(red):: $(bld)@@$(nrm)$(red): ;$(bld)%S@SSS @@% $(nrm)$(red):t$(bld)%GGSG$(eol) @@@GS$(nrm)$(red):$(bld)@@@$(nrm)$(red). .$(bld)S $(nrm)$(red):t$(bld)S@@% tt $(nrm)$(red):t .;$(bld)%G@@@% G@ %@@@S @@$(nrm)$(red). $(bld)%@@@$(eol) G@@S $(nrm)$(red)t$(bld)@@% $(nrm)$(red)::t$(bld)%SSGGG@% %$(nrm)$(red). .::;;;tt$(bld)%%$(nrm)$(red); $(bld)GS $(nrm)$(red);$(bld)S%$(nrm)$(red);: $(bld)@G $(nrm)$(red);$(bld)S$(nrm)$(red)t;.$(eol) $(bld)%@@$(nrm)$(red): $(bld)S@@ S S$(nrm)$(red): $(bld)G$(nrm)$(red);$(eol) ;$(bld)@@$(nrm)$(red). $(bld)G@$(nrm)$(red); t $(bld)t %$(eol) GS $(nrm)$(red).$(bld)S% $(nrm)$(red). . :$(eol) $(bld)%$(nrm)$(red)t :$(bld)t$(eol) $(nrm)$(red);: :. $(bld)$(grn)Aeons ago, in a time long since forgotten, this land was fair$(eol) $(nrm)$(red).. ; $(bld)$(grn)and peaceful, governed by harmony and untouched by despair...$(eol)$(eol) $(red)But then the evil came.$(eol) $(blk)[ http://katarsis.mudpy.org/ ]$(nrm)
+description = $(inc:login.txt)
error_bad_name = Your account name needs to contain only digits (0-9) and letters (a-z).
prompt = Identify yourself:
demand_a = user.account.getlist("avatars")
demand_c = len(user.account.getlist("avatars")) < universe.categories["internal"]["limits"].getint("max_avatars")
demand_d = user.account.getlist("avatars")
-description = From here you can awaken, create and delete avatars. An avatar is your persona in the world of Katarsis. You can also leave or permanently delete your account.
+description = $(red)$(inc:banner.txt)$(nrm)$(eol)$(eol)From here you can awaken, create and delete avatars. An avatar is your persona in the world of Katarsis. You can also leave or permanently delete your account.
prompt = What would you like to do?
[menu:verifying_new_password]
#!/usr/bin/python
"""Skeletal executable for the mudpy engine."""
-# Copyright (c) 2005, 2006 Jeremy Stanley <fungi@yuggoth.org>. All rights
-# reserved. Licensed per terms in the LICENSE file distributed with this
-# software.
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
# core objects for the mudpy engine
import mudpy
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
+
[__control__]
default_files = { "account": "account", "actor": "actor", "command": "command", "internal": "internal", "location": "location", "menu": "menu", "other": "other", "prop": "prop" }
include_files = [ "archetype", "katarsis/index" ]
definition_y = 12mo
frequency_log = 6000
frequency_save = 600
+linkdead = { "default": 6000, "entering_account_name": 600, "active": 6048000 }
+idle = { "default": 5000, "entering_account_name": 500, "active": 5040000 }
increment = 0.1
[internal:directions]
"""Core objects for the mudpy engine."""
-# Copyright (c) 2005, 2006 Jeremy Stanley <fungi@yuggoth.org>. All rights
-# reserved. Licensed per terms in the LICENSE file distributed with this
-# software.
+# Copyright (c) 2004-2008 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# to use, copy, modify, and distribute this software is granted under
+# terms provided in the LICENSE file distributed with this software.
# import some things we need
from ConfigParser import RawConfigParser
self.error = ""
self.input_queue = []
self.last_address = ""
+ self.last_input = universe.get_time()
self.menu_choices = {}
self.menu_seen = False
self.negotiation_pause = 0
self.connection.close()
self.remove()
+ def check_idle(self):
+ """Warn or disconnect idle users as appropriate."""
+ idletime = universe.get_time() - self.last_input
+ linkdead_dict = universe.categories["internal"]["time"].getdict("linkdead")
+ if self.state in linkdead_dict: linkdead_state = self.state
+ else: linkdead_state = "default"
+ if idletime > linkdead_dict[linkdead_state]:
+ self.send("$(eol)$(red)You've done nothing for far too long... goodbye!$(nrm)$(eol)", flush=True, add_prompt=False)
+ logline = "Disconnecting "
+ if self.account and self.account.get("name"): logline += self.account.get("name")
+ else: logline += "an unknown user"
+ logline += " after idling too long in a " + self.state + " state."
+ log(logline, 2)
+ self.state = "disconnecting"
+ self.menu_seen = False
+ idle_dict = universe.categories["internal"]["time"].getdict("idle")
+ if self.state in idle_dict: idle_state = self.state
+ else: idle_state = "default"
+ if idletime == idle_dict[idle_state]:
+ self.send("$(eol)$(red)If you continue to be unproductive, you'll be shown the door...$(nrm)$(eol)")
+
def reload(self):
"""Save, load a new user and relocate the connection."""
self.state = "disconnecting"
self.menu_seen = False
+ # check for an idle connection and act appropriately
+ else: self.check_idle()
+
# if output is paused, decrement the counter
if self.state == "initial":
if self.negotiation_pause: self.negotiation_pause -= 1
# ignoring color escape sequences
relative_position = 0
+ # whether the current character is part of a telnet IAC sequence
+ iac_counter = 0
+
# whether the current character is part of a color escape sequence
escape = False
# iterate over each character from the begining of the text
for each_character in text:
+ # the current character is the telnet IAC character
+ if each_character == IAC and not iac_counter:
+ iac_counter = 2
+
+ # the current character is within an IAC sequence
+ elif iac_counter:
+
+ # the current character is another IAC,
+ # terminating the sequence
+ if each_character == IAC:
+ iac_counter = 0
+
+ # otherwise, decrement the IAC counter
+ else:
+ iac_counter -= 1
+
# the current character is the escape character
- if each_character == chr(27):
+ elif each_character == chr(27) and not escape:
escape = True
# the current character is within an escape sequence
elif escape:
# the current character is m, which terminates the
- # current escape sequence
+ # escape sequence
if each_character == "m":
escape = False
# the current character meets the requested maximum line width,
# so we need to backtrack and find a space at which to wrap
- elif relative_position == width:
+ elif relative_position == width and not each_character == "\r":
# distance of the current character examined from the
# relative position
def replace_macros(user, text, is_input=False):
"""Replaces macros in text output."""
+ # third person pronouns
+ pronouns = {
+ "female": { "obj": "her", "pos": "hers", "sub": "she" },
+ "male": { "obj": "him", "pos": "his", "sub": "he" },
+ "neuter": { "obj": "it", "pos": "its", "sub": "it" }
+ }
+
+ # a dict of replacement macros
+ macros = {
+ "eol": "\r\n",
+ "bld": chr(27) + "[1m",
+ "nrm": chr(27) + "[0m",
+ "blk": chr(27) + "[30m",
+ "blu": chr(27) + "[34m",
+ "cyn": chr(27) + "[36m",
+ "grn": chr(27) + "[32m",
+ "mgt": chr(27) + "[35m",
+ "red": chr(27) + "[31m",
+ "yel": chr(27) + "[33m",
+ }
+
+ # add dynamic macros where possible
+ if user.account:
+ account_name = user.account.get("name")
+ if account_name:
+ macros["account"] = account_name
+ if user.avatar:
+ avatar_gender = user.avatar.get("gender")
+ if avatar_gender:
+ macros["tpop"] = pronouns[avatar_gender]["obj"]
+ macros["tppp"] = pronouns[avatar_gender]["pos"]
+ macros["tpsp"] = pronouns[avatar_gender]["sub"]
+
# loop until broken
while True:
- # third person pronouns
- pronouns = {
- "female": { "obj": "her", "pos": "hers", "sub": "she" },
- "male": { "obj": "him", "pos": "his", "sub": "he" },
- "neuter": { "obj": "it", "pos": "its", "sub": "it" }
- }
-
- # a dict of replacement macros
- macros = {
- "$(eol)": "\r\n",
- "$(bld)": chr(27) + "[1m",
- "$(nrm)": chr(27) + "[0m",
- "$(blk)": chr(27) + "[30m",
- "$(blu)": chr(27) + "[34m",
- "$(cyn)": chr(27) + "[36m",
- "$(grn)": chr(27) + "[32m",
- "$(mgt)": chr(27) + "[35m",
- "$(red)": chr(27) + "[31m",
- "$(yel)": chr(27) + "[33m",
- }
-
- # add dynamic macros where possible
- if user.account:
- account_name = user.account.get("name")
- if account_name:
- macros["$(account)"] = account_name
- if user.avatar:
- avatar_gender = user.avatar.get("gender")
- if avatar_gender:
- macros["$(tpop)"] = pronouns[avatar_gender]["obj"]
- macros["$(tppp)"] = pronouns[avatar_gender]["pos"]
- macros["$(tpsp)"] = pronouns[avatar_gender]["sub"]
-
# find and replace per the macros dict
macro_start = text.find("$(")
if macro_start == -1: break
macro_end = text.find(")", macro_start) + 1
- macro = text[macro_start:macro_end]
+ macro = text[macro_start+2:macro_end-1]
if macro in macros.keys():
- text = text.replace(macro, macros[macro])
+ replacement = macros[macro]
+
+ # this is how we handle local file inclusion (dangerous!)
+ elif macro.startswith("inc:"):
+ incfile = path_join(universe.startdir, macro[4:])
+ if exists(incfile):
+ incfd = file(incfile)
+ replacement = ""
+ for line in incfd:
+ if line.endswith("\n") and not line.endswith("\r\n"):
+ line = line.replace("\n", "\r\n")
+ replacement += line
+ # lose the trailing eol
+ replacement = replacement[:-2]
+ else:
+ replacement = ""
+ log("Couldn't read included " + incfile + " file.", 6)
# if we get here, log and replace it with null
else:
- text = text.replace(macro, "")
+ replacement = ""
if not is_input:
log("Unexpected replacement macro " + macro + " encountered.", 6)
+ # and now we act on the replacement
+ text = text.replace("$(" + macro + ")", replacement)
+
# replace the look-like-a-macro sequence
text = text.replace("$_(", "$(")
# since we got input, flag that the menu/prompt needs to be redisplayed
user.menu_seen = False
+ # update the last_input timestamp while we're at it
+ user.last_input = universe.get_time()
+
def generic_menu_handler(user):
"""A generic menu choice handler."""