Integrated rpsystem with rplanguage to a greater degree.
This commit is contained in:
parent
dc5d8f8130
commit
2442422f9e
3 changed files with 112 additions and 84 deletions
|
|
@ -106,8 +106,11 @@ from evennia import DefaultScript
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
# default language grammar
|
# 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"
|
_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"
|
_GRAMMAR = "v cv vc cvv vcc vcv cvcc vccv cvccv cvcvcc cvccvcv vccvccvc cvcvccvv cvcvcvcvv"
|
||||||
|
|
||||||
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
|
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
|
||||||
|
|
@ -281,37 +284,36 @@ class LanguageHandler(DefaultScript):
|
||||||
lword = len(word)
|
lword = len(word)
|
||||||
if len(word) <= self.level:
|
if len(word) <= self.level:
|
||||||
# below level. Don't translate
|
# below level. Don't translate
|
||||||
self.lastword = word
|
new_word = 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
|
|
||||||
else:
|
else:
|
||||||
# translate the word
|
# translate the word
|
||||||
new_word = self.language["translation"].get(word.lower(), "")
|
new_word = self.language["translation"].get(word.lower(), "")
|
||||||
if not new_word:
|
if not new_word:
|
||||||
# make up translation on the fly. Length can
|
if word.istitle():
|
||||||
# vary from un-translated word.
|
# capitalized word we don't have a translation for -
|
||||||
wlen = max(0, lword + sum(randint(-1,1) for i
|
# treat as a name (don't translate)
|
||||||
in range(self.language["word_length_variance"])))
|
print "noun ..."
|
||||||
grammar = self.language["grammar"]
|
new_word = "%s%s%s" % (self.language["noun_prefix"], word, self.language["noun_postfix"])
|
||||||
if wlen not in grammar:
|
else:
|
||||||
# this word has no direct translation!
|
# make up translation on the fly. Length can
|
||||||
return ""
|
# vary from un-translated word.
|
||||||
structure = choice(grammar[wlen])
|
wlen = max(0, lword + sum(randint(-1,1) for i
|
||||||
grammar2phonemes = self.language["grammar2phonemes"]
|
in range(self.language["word_length_variance"])))
|
||||||
for match in _RE_GRAMMAR.finditer(structure):
|
grammar = self.language["grammar"]
|
||||||
# there are only four combinations: vv,cc,c,v
|
if wlen not in grammar:
|
||||||
new_word += choice(grammar2phonemes[match.group()])
|
# this word has no direct translation!
|
||||||
if word.istitle():
|
return ""
|
||||||
# capitalize words correctly
|
structure = choice(grammar[wlen])
|
||||||
new_word = new_word.capitalize()
|
grammar2phonemes = self.language["grammar2phonemes"]
|
||||||
if len(word) > 1 and word.isupper():
|
for match in _RE_GRAMMAR.finditer(structure):
|
||||||
# keep LOUD words loud also when translated
|
# there are only four combinations: vv,cc,c,v
|
||||||
new_word = new_word.upper()
|
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
|
return new_word
|
||||||
|
|
||||||
def translate(self, text, level=0.0, language="default"):
|
def translate(self, text, level=0.0, language="default"):
|
||||||
|
|
@ -340,8 +342,6 @@ class LanguageHandler(DefaultScript):
|
||||||
|
|
||||||
# configuring the translation
|
# configuring the translation
|
||||||
self.level = int(10 * (1.0 - max(0, min(level, 1.0))))
|
self.level = int(10 * (1.0 - max(0, min(level, 1.0))))
|
||||||
self.lastword = ""
|
|
||||||
|
|
||||||
return _RE_WORD.sub(self._translate_sub, text)
|
return _RE_WORD.sub(self._translate_sub, text)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -355,7 +355,7 @@ def obfuscate_language(text, level=0.0, language="default"):
|
||||||
Args:
|
Args:
|
||||||
text (str): Text to obfuscate.
|
text (str): Text to obfuscate.
|
||||||
level (real, optional): A value from 0.0-1.0 determining
|
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 returned unchanged) and 1.0 means the entire
|
||||||
string is obfuscated.
|
string is obfuscated.
|
||||||
language (str, optional): The identifier of a language
|
language (str, optional): The identifier of a language
|
||||||
|
|
@ -394,6 +394,26 @@ def add_language(**kwargs):
|
||||||
_LANGUAGE_HANDLER.add(**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
|
# Whisper obscuration
|
||||||
|
|
@ -55,7 +55,6 @@ Tall man (assuming his name is Tom) sees:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from re import match as re_match
|
|
||||||
import itertools
|
import itertools
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from evennia import DefaultObject, DefaultCharacter, DefaultRoom
|
from evennia import DefaultObject, DefaultCharacter, DefaultRoom
|
||||||
|
|
@ -90,9 +89,6 @@ _EMOTE_MULTIMATCH_ERROR = \
|
||||||
"""{{RMultiple possibilities for {ref}:
|
"""{{RMultiple possibilities for {ref}:
|
||||||
{{r{reflist}{{n"""
|
{{r{reflist}{{n"""
|
||||||
|
|
||||||
_LANGUAGE_NOMATCH_ERROR = \
|
|
||||||
"""{{RNo language named {{r{langname}{{n"""
|
|
||||||
|
|
||||||
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
|
_RE_FLAGS = re.MULTILINE + re.IGNORECASE + re.UNICODE
|
||||||
|
|
||||||
_RE_PREFIX = re.compile(r"^%s" % _PREFIX, 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.
|
# this regex returns in groups (langname, say), where langname can be empty.
|
||||||
_RE_LANGUAGE = re.compile(r"(?:(\w+))*(\".+?\")")
|
_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:
|
# the emote parser works in two steps:
|
||||||
# 1) convert the incoming emote into an intermediary
|
# 1) convert the incoming emote into an intermediary
|
||||||
# form with all object references mapped to ids.
|
# form with all object references mapped to ids.
|
||||||
|
|
@ -168,6 +145,12 @@ class LanguageError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _dummy_process(text, *args, **kwargs):
|
||||||
|
"Pass-through processor"
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def ordered_permutation_regex(sentence):
|
def ordered_permutation_regex(sentence):
|
||||||
"""
|
"""
|
||||||
Builds a regex that matches 'ordered permutations' of a sentence's
|
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
|
# in-place without messing up indexes for future matches
|
||||||
# note that saytext includes surrounding "...".
|
# note that saytext includes surrounding "...".
|
||||||
langname, saytext = say_match.groups()
|
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()
|
istart, iend = say_match.start(), say_match.end()
|
||||||
# the key is simply the running match in the emote
|
# the key is simply the running match in the emote
|
||||||
key = "##%i" % imatch
|
key = "##%i" % imatch
|
||||||
|
|
@ -465,17 +444,25 @@ def send_emote(sender, receivers, emote, anonymous_add="first"):
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
# handle the language mapping, which always produce different keys ##nn
|
# 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():
|
for key, (langname, saytext) in language_mapping.iteritems():
|
||||||
# color says
|
# color says
|
||||||
mapping[key] = "%s%s{n" % (_LANGUAGE_COLOR(receiver),
|
mapping[key] = process_language(saytext, sender, langname)
|
||||||
_LANGUAGE_TRANSLATE(sender, receiver, langname, saytext))
|
|
||||||
# make sure receiver always sees their real name
|
# make sure receiver always sees their real name
|
||||||
rkey = "#%i" % receiver.id
|
rkey = "#%i" % receiver.id
|
||||||
if rkey in mapping:
|
if rkey in mapping:
|
||||||
mapping[rkey] = receiver.key
|
mapping[rkey] = receiver.key
|
||||||
|
|
||||||
# add color to recog strings
|
# add color to sdesc strings
|
||||||
mapping = dict((key, "%s%s{n" % (_RECOG_COLOR(receiver), val))
|
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())
|
for key, val in mapping.iteritems())
|
||||||
|
|
||||||
# do the template replacement
|
# 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))
|
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):
|
class RPSystemCmdSet(CmdSet):
|
||||||
"""
|
"""
|
||||||
Mix-in for adding rp-commands to default cmdset.
|
Mix-in for adding rp-commands to default cmdset.
|
||||||
|
|
@ -723,7 +691,6 @@ class RPSystemCmdSet(CmdSet):
|
||||||
self.add(CmdSdesc())
|
self.add(CmdSdesc())
|
||||||
self.add(CmdPose())
|
self.add(CmdPose())
|
||||||
self.add(CmdRecog())
|
self.add(CmdRecog())
|
||||||
self.add(CmdLanguage())
|
|
||||||
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
@ -1133,3 +1100,44 @@ class RPCharacter(DefaultCharacter, RPObject):
|
||||||
# initializing sdesc
|
# initializing sdesc
|
||||||
self.sdesc.add("A normal person")
|
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)
|
||||||
|
|
|
||||||
|
|
@ -1404,8 +1404,8 @@ class DefaultCharacter(DefaultObject):
|
||||||
"""
|
"""
|
||||||
self.msg("\nYou become {c%s{n.\n" % self.name)
|
self.msg("\nYou become {c%s{n.\n" % self.name)
|
||||||
self.execute_cmd("look")
|
self.execute_cmd("look")
|
||||||
if self.location:
|
for obj in (obj for obj in self.location.contents if obj != self):
|
||||||
self.location.msg_contents("%s has entered the game." % self.name, exclude=[self])
|
obj.msg("%s has entered the game." % self.get_display_name(obj))
|
||||||
|
|
||||||
def at_post_unpuppet(self, player, sessid=None):
|
def at_post_unpuppet(self, player, sessid=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue