forked from vantablack/vantaMOO
implement pronounsub
This commit is contained in:
parent
488595e2b8
commit
8daecbf9fc
|
@ -18,11 +18,12 @@ from evennia import default_cmds
|
||||||
|
|
||||||
from evennia.contrib.base_systems.building_menu import GenericBuildingCmd
|
from evennia.contrib.base_systems.building_menu import GenericBuildingCmd
|
||||||
from evennia.contrib.game_systems import mail
|
from evennia.contrib.game_systems import mail
|
||||||
from evennia.contrib.game_systems.multidescer import CmdMultiDesc
|
|
||||||
from evennia.contrib.grid.ingame_map_display import MapDisplayCmdSet
|
|
||||||
from evennia.contrib.grid import simpledoor
|
|
||||||
from lib.rpsystem.rpsystem import RPSystemCmdSet
|
|
||||||
from evennia.contrib.game_systems.clothing import ClothedCharacterCmdSet
|
from evennia.contrib.game_systems.clothing import ClothedCharacterCmdSet
|
||||||
|
from evennia.contrib.game_systems.multidescer import CmdMultiDesc
|
||||||
|
from evennia.contrib.grid import simpledoor
|
||||||
|
from evennia.contrib.grid.ingame_map_display import MapDisplayCmdSet
|
||||||
|
from lib.pronounsub import SetPronouns
|
||||||
|
from lib.rpsystem.rpsystem import RPSystemCmdSet
|
||||||
|
|
||||||
|
|
||||||
class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
||||||
|
@ -65,6 +66,9 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
||||||
# Clothing: wear
|
# Clothing: wear
|
||||||
self.add(ClothedCharacterCmdSet())
|
self.add(ClothedCharacterCmdSet())
|
||||||
|
|
||||||
|
# gendersub
|
||||||
|
self.add(SetPronouns())
|
||||||
|
|
||||||
class AccountCmdSet(default_cmds.AccountCmdSet):
|
class AccountCmdSet(default_cmds.AccountCmdSet):
|
||||||
"""
|
"""
|
||||||
This is the cmdset available to the Account at all times. It is
|
This is the cmdset available to the Account at all times. It is
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .pronounsub import PronounCharacter
|
||||||
|
from .pronounsub import SetPronouns
|
|
@ -0,0 +1,262 @@
|
||||||
|
"""
|
||||||
|
Pronounsub
|
||||||
|
|
||||||
|
Griatch 2015
|
||||||
|
Copyright (c) 2023 lunacb <lunacb@disroot.org>
|
||||||
|
|
||||||
|
This is a gender-aware Character class that allows people to set pronouns and
|
||||||
|
use them in text.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
|
||||||
|
When in use, messages can contain special tags to indicate pronouns gendered
|
||||||
|
based on the one being addressed. Capitalization will be retained.
|
||||||
|
|
||||||
|
- `|s`, `|S`: Subjective form, like They
|
||||||
|
- `|o`, `|O`: Objective form, like Them
|
||||||
|
- `|p`, `|P`: Possessive form, like Their
|
||||||
|
- `|a`, `|A`: Absolute Possessive form, like Theirs
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
```
|
||||||
|
char.msg("%s falls on |p face with a thud." % char.key)
|
||||||
|
"Tom falls on their face with a thud"
|
||||||
|
```
|
||||||
|
|
||||||
|
To use, have DefaultCharacter inherit from this, or change
|
||||||
|
setting.DEFAULT_CHARACTER to point to this class.
|
||||||
|
|
||||||
|
The `pronouns` command is used to set pronouns. It needs to be added to the
|
||||||
|
default cmdset before it becomes available.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
|
||||||
|
from evennia import Command, DefaultCharacter
|
||||||
|
from evennia.utils import logger
|
||||||
|
|
||||||
|
# gender maps
|
||||||
|
|
||||||
|
# TODO: Don't make this hardcoded.
|
||||||
|
_PRONOUN_LIST = [
|
||||||
|
{"s": "he", "o": "him", "p": "his", "a": "his"},
|
||||||
|
{"s": "she", "o": "her", "p": "her", "a": "hers"},
|
||||||
|
{"s": "it", "o": "it", "p": "its", "a": "its"},
|
||||||
|
{"s": "they", "o": "them", "p": "their", "a": "theirs"},
|
||||||
|
]
|
||||||
|
|
||||||
|
_PRONOUN_FORMS = [ "s", "o", "p", "a" ]
|
||||||
|
|
||||||
|
_RE_GENDER_PRONOUN = re.compile(r"(?<!\|)\|(?!\|)[sSoOpPaA]")
|
||||||
|
|
||||||
|
# in-game command for setting the gender
|
||||||
|
|
||||||
|
|
||||||
|
class SetPronouns(Command):
|
||||||
|
"""
|
||||||
|
Sets your pronouns.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@gender
|
||||||
|
@gender <pronoun1>[;pronoun2 ...]
|
||||||
|
|
||||||
|
With no arguments, this command prints your current pronouns.
|
||||||
|
|
||||||
|
Pronouns can be specified either in a general form, like "she/they", or a
|
||||||
|
specific form, like "they,them,their,theirs".
|
||||||
|
|
||||||
|
For the general form, each in the list must match up to a grammatical form
|
||||||
|
of a specific pronoun in a known database, and that specific pronoun will
|
||||||
|
be used.
|
||||||
|
|
||||||
|
The specific format is: <subjective>,<objective>,<possessive>,<absolute>
|
||||||
|
subjective: *They* went to the store.
|
||||||
|
objective: You took *them* to the store.
|
||||||
|
possessive: You took *their* friend to the store.
|
||||||
|
absolute: The sandwich in the fridge was *theirs*.
|
||||||
|
|
||||||
|
When multiple pronouns are given, a random one will be used in each text
|
||||||
|
substitution.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
@pronouns he/him
|
||||||
|
|
||||||
|
@pronouns she/they/it
|
||||||
|
|
||||||
|
@pronouns they,them,their,thers
|
||||||
|
|
||||||
|
@pronouns she/they;fae,faer,faer,faers
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = "pronouns"
|
||||||
|
locks = "call:all()"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.cmd_type = "set"
|
||||||
|
self.syntax_error = False
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
|
||||||
|
self.cmd_type = "set"
|
||||||
|
self.syntax_error = True
|
||||||
|
|
||||||
|
generals = []
|
||||||
|
specifics = []
|
||||||
|
|
||||||
|
if self.args == '':
|
||||||
|
self.cmd_type = "get"
|
||||||
|
self.syntax_error = False
|
||||||
|
return
|
||||||
|
|
||||||
|
pronouns = self.args.strip().lower().split(";")
|
||||||
|
|
||||||
|
for pronoun in pronouns:
|
||||||
|
slash = ('/' in pronoun)
|
||||||
|
comma = (',' in pronoun)
|
||||||
|
if slash and comma:
|
||||||
|
return
|
||||||
|
|
||||||
|
if comma:
|
||||||
|
specific = [ p.strip() for p in pronoun.split(",") ]
|
||||||
|
if len(specific) != len(_PRONOUN_FORMS):
|
||||||
|
return
|
||||||
|
|
||||||
|
new = {}
|
||||||
|
for i in range(len(specific)):
|
||||||
|
new[_PRONOUN_FORMS[i]] = specific[i]
|
||||||
|
specifics.append(new)
|
||||||
|
else:
|
||||||
|
generals += [ p.strip() for p in pronoun.split("/") ]
|
||||||
|
|
||||||
|
self.args = (generals, specifics)
|
||||||
|
self.syntax_error = False
|
||||||
|
|
||||||
|
def func(self):
|
||||||
|
caller = self.caller
|
||||||
|
|
||||||
|
if self.syntax_error:
|
||||||
|
caller.msg(self.get_help(caller, self.cmdset))
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.cmd_type == "get":
|
||||||
|
caller.msg(f"Your pronouns are \"{caller._print_pronouns()}\"")
|
||||||
|
return
|
||||||
|
|
||||||
|
generals, specifics = self.args
|
||||||
|
|
||||||
|
for general in generals:
|
||||||
|
if not caller._specific_pronoun_from_general(general):
|
||||||
|
caller.msg(f"Warning: The general pronoun \"{general}\" is not"
|
||||||
|
"in the server's list of pronouns. It will be"
|
||||||
|
"ignored.")
|
||||||
|
|
||||||
|
caller.db.pronoun_generals = generals
|
||||||
|
caller.db.pronoun_specifics = specifics
|
||||||
|
caller.msg(f"Your pronouns have been set to \"{caller._print_pronouns()}\".")
|
||||||
|
|
||||||
|
class PronounCharacter(DefaultCharacter):
|
||||||
|
"""
|
||||||
|
This is a Character class aware of gender.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def at_object_creation(self):
|
||||||
|
"""
|
||||||
|
Called once when the object is created.
|
||||||
|
"""
|
||||||
|
super().at_object_creation()
|
||||||
|
self.db.pronoun_generals = [ "they", "them" ]
|
||||||
|
self.db.pronoun_specifics = []
|
||||||
|
|
||||||
|
def _specific_pronoun_from_general(self, general):
|
||||||
|
for pronoun in _PRONOUN_LIST:
|
||||||
|
if general in pronoun.values():
|
||||||
|
return pronoun
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _print_pronouns(self):
|
||||||
|
generals = self.attributes.get("pronoun_generals", default=[ "they", "them" ])
|
||||||
|
specifics = self.attributes.get("pronoun_specifics", default=[])
|
||||||
|
res = [ "/".join(generals) ] if len(generals) else []
|
||||||
|
for specific in specifics:
|
||||||
|
res.append(",".join([ specific[form] for form in _PRONOUN_FORMS ]))
|
||||||
|
return ";".join(res)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_pronoun(self, regex_match):
|
||||||
|
logger.log_info("hereee " + str(regex_match))
|
||||||
|
"""
|
||||||
|
Get pronoun from the pronoun marker in the text. This is used as
|
||||||
|
the callable for the re.sub function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
regex_match (MatchObject): the regular expression match.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- `|s`, `|S`: Subjective form, like They
|
||||||
|
- `|o`, `|O`: Objective form, like Them
|
||||||
|
- `|p`, `|P`: Possessive form, like Their
|
||||||
|
- `|a`, `|A`: Absolute Possessive form, like Theirs
|
||||||
|
|
||||||
|
"""
|
||||||
|
typ = regex_match.group()[1] # "s", "O" etc
|
||||||
|
logger.log_info("hereee " + typ)
|
||||||
|
dup_specifics = self.attributes.get("pronoun_specifics", default=[])
|
||||||
|
for general in self.attributes.get("pronoun_generals", default=[ "they", "them" ]):
|
||||||
|
specific = self._specific_pronoun_from_general(general)
|
||||||
|
if specific != None:
|
||||||
|
dup_specifics.append(specific)
|
||||||
|
|
||||||
|
specifics = []
|
||||||
|
for s in dup_specifics:
|
||||||
|
if not s in specifics:
|
||||||
|
specifics.append(s)
|
||||||
|
|
||||||
|
choice = random.choice(specifics)
|
||||||
|
|
||||||
|
gender = self.attributes.get("gender", default="ambiguous")
|
||||||
|
gender = gender if gender in ("male", "female", "neutral") else "ambiguous"
|
||||||
|
|
||||||
|
pronoun = choice[typ.lower()]
|
||||||
|
logger.log_info("hereee " + pronoun)
|
||||||
|
return pronoun.capitalize() if typ.isupper() else pronoun
|
||||||
|
|
||||||
|
def msg(self, text=None, from_obj=None, session=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Emits something to a session attached to the object.
|
||||||
|
Overloads the default msg() implementation to include
|
||||||
|
gender-aware markers in output.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
text (str or tuple, optional): The message to send. This
|
||||||
|
is treated internally like any send-command, so its
|
||||||
|
value can be a tuple if sending multiple arguments to
|
||||||
|
the `text` oob command.
|
||||||
|
from_obj (obj, optional): object that is sending. If
|
||||||
|
given, at_msg_send will be called
|
||||||
|
session (Session or list, optional): session or list of
|
||||||
|
sessions to relay to, if any. If set, will
|
||||||
|
force send regardless of MULTISESSION_MODE.
|
||||||
|
Notes:
|
||||||
|
`at_msg_receive` will be called on this Object.
|
||||||
|
All extra kwargs will be passed on to the protocol.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if text is None:
|
||||||
|
super().msg(from_obj=from_obj, session=session, **kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
if text and isinstance(text, tuple):
|
||||||
|
text = (_RE_GENDER_PRONOUN.sub(self._get_pronoun, text[0]), *text[1:])
|
||||||
|
else:
|
||||||
|
text = _RE_GENDER_PRONOUN.sub(self._get_pronoun, text)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
logger.log_trace(e)
|
||||||
|
super().msg(text, from_obj=from_obj, session=session, **kwargs)
|
|
@ -8,8 +8,16 @@ creation commands.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from lib.rpsystem import ContribRPCharacter
|
from lib.rpsystem import ContribRPCharacter
|
||||||
|
from lib.pronounsub import PronounCharacter
|
||||||
from evennia.contrib.game_systems.clothing import ClothedCharacter
|
from evennia.contrib.game_systems.clothing import ClothedCharacter
|
||||||
|
|
||||||
# rpsystem
|
# rpsystem
|
||||||
class Character(ContribRPCharacter, ClothedCharacter):
|
class Character(ContribRPCharacter, ClothedCharacter, PronounCharacter):
|
||||||
pass
|
def at_object_creation(self):
|
||||||
|
super(PronounCharacter, self).at_object_creation()
|
||||||
|
super(ContribRPCharacter, self).at_object_creation()
|
||||||
|
|
||||||
|
def msg(self, text=None, from_obj=None, session=None, **kwargs):
|
||||||
|
# TODO: Don't do this. See https://git.disroot.org/vantablack/vantaMOO/issues/29
|
||||||
|
super(PronounCharacter, self).msg(text, from_obj, session, **kwargs)
|
||||||
|
#super(ContribRPCharacter, self).msg(text, from_obj, session, **kwargs)
|
||||||
|
|
Loading…
Reference in New Issue