Integrated rpsystem with rplanguage to a greater degree.

This commit is contained in:
Griatch 2015-09-24 22:55:06 +02:00
parent dc5d8f8130
commit 2442422f9e
3 changed files with 112 additions and 84 deletions

View file

@ -106,8 +106,11 @@ from evennia import DefaultScript
#------------------------------------------------------------
# default language grammar
_PHONEMES = "ea oh ae aa eh ah ao aw ai er ey ow ia ih iy oy ua uh uw y p b t d f v t dh s z sh zh ch jh k ng g m n l r w"
_PHONEMES = "ea oh ae aa eh ah ao aw ai er ey ow ia ih iy oy ua uh uw a e i u y p b t d f v t dh s z sh zh ch jh k ng g m n l r w"
_VOWELS = "eaoiuy"
# these must be able to be constructed from phonemes (so for example,
# if you have v here, there must exixt at least one single-character
# vowel phoneme defined above)
_GRAMMAR = "v cv vc cvv vcc vcv cvcc vccv cvccv cvcvcc cvccvcv vccvccvc cvcvccvv cvcvcvcvv"
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
@ -281,37 +284,36 @@ class LanguageHandler(DefaultScript):
lword = len(word)
if len(word) <= self.level:
# below level. Don't translate
self.lastword = word
return word
elif word.istitle() and not self.lastword.istitle():
# capitalized word inside text - treat as a
# name (don't translate) but don't allow several in a row.
new_word = "%s%s%s" % (self.language["noun_prefix"], word, self.language["noun_postfix"])
self.lastword = word
return new_word
new_word = word
else:
# translate the word
new_word = self.language["translation"].get(word.lower(), "")
if not new_word:
# make up translation on the fly. Length can
# vary from un-translated word.
wlen = max(0, lword + sum(randint(-1,1) for i
in range(self.language["word_length_variance"])))
grammar = self.language["grammar"]
if wlen not in grammar:
# this word has no direct translation!
return ""
structure = choice(grammar[wlen])
grammar2phonemes = self.language["grammar2phonemes"]
for match in _RE_GRAMMAR.finditer(structure):
# there are only four combinations: vv,cc,c,v
new_word += choice(grammar2phonemes[match.group()])
if word.istitle():
# capitalize words correctly
new_word = new_word.capitalize()
if len(word) > 1 and word.isupper():
# keep LOUD words loud also when translated
new_word = new_word.upper()
if word.istitle():
# capitalized word we don't have a translation for -
# treat as a name (don't translate)
print "noun ..."
new_word = "%s%s%s" % (self.language["noun_prefix"], word, self.language["noun_postfix"])
else:
# make up translation on the fly. Length can
# vary from un-translated word.
wlen = max(0, lword + sum(randint(-1,1) for i
in range(self.language["word_length_variance"])))
grammar = self.language["grammar"]
if wlen not in grammar:
# this word has no direct translation!
return ""
structure = choice(grammar[wlen])
grammar2phonemes = self.language["grammar2phonemes"]
for match in _RE_GRAMMAR.finditer(structure):
# there are only four combinations: vv,cc,c,v
new_word += choice(grammar2phonemes[match.group()])
if word.istitle():
# capitalize words the same way
new_word = new_word.capitalize()
if len(word) > 1 and word.isupper():
# keep LOUD words loud also when translated
new_word = new_word.upper()
return new_word
def translate(self, text, level=0.0, language="default"):
@ -340,8 +342,6 @@ class LanguageHandler(DefaultScript):
# configuring the translation
self.level = int(10 * (1.0 - max(0, min(level, 1.0))))
self.lastword = ""
return _RE_WORD.sub(self._translate_sub, text)
@ -355,7 +355,7 @@ def obfuscate_language(text, level=0.0, language="default"):
Args:
text (str): Text to obfuscate.
level (real, optional): A value from 0.0-1.0 determining
the level of obfuscation where 0 means no obfuscation
the level of obfuscation where 0 means no jobfuscation
(string returned unchanged) and 1.0 means the entire
string is obfuscated.
language (str, optional): The identifier of a language
@ -394,6 +394,26 @@ def add_language(**kwargs):
_LANGUAGE_HANDLER.add(**kwargs)
def available_languages():
"""
Returns all available language keys.
Returns:
languages (list): List of key strings of all available
languages.
"""
global _LANGUAGE_HANDLER
if not _LANGUAGE_HANDLER:
try:
_LANGUAGE_HANDLER = LanguageHandler.objects.get(db_key="language_handler")
except LanguageHandler.DoesNotExist:
if not _LANGUAGE_HANDLER:
from evennia import create_script
_LANGUAGE_HANDLER = create_script(LanguageHandler)
return _LANGUAGE_HANDLER.attributes.get("language_storage", {}).keys()
#------------------------------------------------------------
#
# Whisper obscuration

View file

@ -55,7 +55,6 @@ Tall man (assuming his name is Tom) sees:
"""
import re
from re import match as re_match
import itertools
from copy import copy
from evennia import DefaultObject, DefaultCharacter, DefaultRoom
@ -90,9 +89,6 @@ _EMOTE_MULTIMATCH_ERROR = \
"""{{RMultiple possibilities for {ref}:
{{r{reflist}{{n"""
_LANGUAGE_NOMATCH_ERROR = \
"""{{RNo language named {{r{langname}{{n"""
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
_RE_PREFIX = re.compile(r"^%s" % _PREFIX, re.UNICODE)
@ -127,25 +123,6 @@ _RE_REF_LANG = re.compile(r"\{+\##([0-9]+)\}+")
# this regex returns in groups (langname, say), where langname can be empty.
_RE_LANGUAGE = re.compile(r"(?:(\w+))*(\".+?\")")
#TODO
# make this into a pluggable language module for handling
# language errors and translations.
_LANGUAGE_MODULE = None # load code here
#TODO function determining if a given langname exists. Note that
# langname can be None if not specified explicitly.
_LANGUAGE_AVAILABLE = lambda langname: True
#TODO function to translate a string in a given language
_LANGUAGE_TRANSLATE = lambda speaker, listener, language, text: "%s%s" % ("(%s)" % language if language else "", text)
#TODO list available languages
_LANGUAGE_LIST = lambda: []
# color markup to use for coloring sdescs/recog strings
# in emotes and spoken language quotes.
_LANGUAGE_COLOR = lambda obj: "{w"
_RECOG_COLOR = lambda obj: "{b"
# the emote parser works in two steps:
# 1) convert the incoming emote into an intermediary
# form with all object references mapped to ids.
@ -168,6 +145,12 @@ class LanguageError(Exception):
pass
def _dummy_process(text, *args, **kwargs):
"Pass-through processor"
return text
def ordered_permutation_regex(sentence):
"""
Builds a regex that matches 'ordered permutations' of a sentence's
@ -259,10 +242,6 @@ def parse_language(speaker, emote):
# in-place without messing up indexes for future matches
# note that saytext includes surrounding "...".
langname, saytext = say_match.groups()
if not _LANGUAGE_AVAILABLE(langname):
errors.append(_LANGUAGE_NOMATCH_ERROR.format(langname=langname))
continue
istart, iend = say_match.start(), say_match.end()
# the key is simply the running match in the emote
key = "##%i" % imatch
@ -465,17 +444,25 @@ def send_emote(sender, receivers, emote, anonymous_add="first"):
except AttributeError:
pass
# handle the language mapping, which always produce different keys ##nn
try:
process_language = receiver.process_language
except AttributeError:
process_language = _dummy_process
for key, (langname, saytext) in language_mapping.iteritems():
# color says
mapping[key] = "%s%s{n" % (_LANGUAGE_COLOR(receiver),
_LANGUAGE_TRANSLATE(sender, receiver, langname, saytext))
mapping[key] = process_language(saytext, sender, langname)
# make sure receiver always sees their real name
rkey = "#%i" % receiver.id
if rkey in mapping:
mapping[rkey] = receiver.key
# add color to recog strings
mapping = dict((key, "%s%s{n" % (_RECOG_COLOR(receiver), val))
# add color to sdesc strings
try:
process_sdesc = receiver.process_sdesc
except AttributeError:
process_sdesc = _dummy_process
mapping = dict((key, process_sdesc(val, receiver))
for key, val in mapping.iteritems())
# do the template replacement
@ -695,25 +682,6 @@ class CmdRecog(Command): # assign personal alias to object in room
caller.msg("You will now remember {w%s{n as {w%s{n." % (sdesc, alias))
class CmdLanguage(Command): # list available languages
"""
List the available languages.
Usages:
languages
This will display a list of all languages available
and the short names needed to speak a given language in
an emote.
"""
key = "language"
def func(self):
"simple list"
self.caller.msg("Languages available: %s" % ", ".join(_LANGUAGE_LIST))
class RPSystemCmdSet(CmdSet):
"""
Mix-in for adding rp-commands to default cmdset.
@ -723,7 +691,6 @@ class RPSystemCmdSet(CmdSet):
self.add(CmdSdesc())
self.add(CmdPose())
self.add(CmdRecog())
self.add(CmdLanguage())
#------------------------------------------------------------
@ -1133,3 +1100,44 @@ class RPCharacter(DefaultCharacter, RPObject):
# initializing sdesc
self.sdesc.add("A normal person")
def process_sdesc(self, sdesc, obj, **kwargs):
"""
Allows to customize how your sdesc is displayed (primarily by
changing colors).
Args:
sdesc (str): The sdesc to display.
obj (Object): The object to which the adjoining sdesc
belongs (can be yourself).
Returns:
sdesc (str): The processed sdesc ready
for display.
"""
return "{b%s{n" % sdesc
def process_language(self, text, speaker, language, **kwargs):
"""
Allows to process the spoken text, for example
by obfuscating language based on your and the
speaker's language skills. Also a good place to
put coloring.
Args:
text (str): The text to process.
speaker (Object): The object delivering the text.
language (str): An identifier string for the language.
Return:
text (str): The optionally processed text.
Notes:
This is designed to work together with a string obfuscator
such as the `obfuscate_language` or `obfuscate_whisper` in
the evennia.contrib.rplanguage module.
"""
from evennia.contrib import rplanguage
#return "{w%s{n" % text
return "{w%s{n" % rplanguage.obfuscate_language(text, level=1.0)

View file

@ -1404,8 +1404,8 @@ class DefaultCharacter(DefaultObject):
"""
self.msg("\nYou become {c%s{n.\n" % self.name)
self.execute_cmd("look")
if self.location:
self.location.msg_contents("%s has entered the game." % self.name, exclude=[self])
for obj in (obj for obj in self.location.contents if obj != self):
obj.msg("%s has entered the game." % self.get_display_name(obj))
def at_post_unpuppet(self, player, sessid=None):
"""