From 08facf7d00fe6b621c40d5103df910b2f5a4b1a0 Mon Sep 17 00:00:00 2001 From: lunacb Date: Tue, 17 Jan 2023 17:51:04 -0500 Subject: [PATCH] refactor character code structure --- commands/default_cmdsets.py | 3 +- lib/__init__.py | 0 lib/pronounsub/__init__.py | 4 - lib/pronounsub/character.py | 49 +++++ lib/pronounsub/{pronounsub.py => commands.py} | 186 +----------------- lib/pronounsub/common.py | 137 +++++++++++++ lib/pronounsub/consts.py | 16 -- lib/pronounsub/db.py | 8 - lib/rpsystem/rpsystem.py | 5 +- typeclasses/characters.py | 11 +- 10 files changed, 203 insertions(+), 216 deletions(-) create mode 100644 lib/__init__.py create mode 100644 lib/pronounsub/character.py rename lib/pronounsub/{pronounsub.py => commands.py} (57%) create mode 100644 lib/pronounsub/common.py delete mode 100644 lib/pronounsub/consts.py delete mode 100644 lib/pronounsub/db.py diff --git a/commands/default_cmdsets.py b/commands/default_cmdsets.py index ef2a515..96c8bcc 100644 --- a/commands/default_cmdsets.py +++ b/commands/default_cmdsets.py @@ -23,8 +23,7 @@ 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 PronounAdminCommand -from lib.pronounsub import PronounsCommand +from lib.pronounsub.commands import * from lib.rpsystem.rpsystem import RPSystemCmdSet diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/pronounsub/__init__.py b/lib/pronounsub/__init__.py index 596d19c..e69de29 100644 --- a/lib/pronounsub/__init__.py +++ b/lib/pronounsub/__init__.py @@ -1,4 +0,0 @@ -from .pronounsub import PronounCharacter -from .pronounsub import PronounsCommand -from .pronounsub import PronounAdminCommand -from .db import PronounDbScript diff --git a/lib/pronounsub/character.py b/lib/pronounsub/character.py new file mode 100644 index 0000000..f3f5fff --- /dev/null +++ b/lib/pronounsub/character.py @@ -0,0 +1,49 @@ +from .common import * + +# This should be called before every use of a Character to make sure it's +# initialized right. +def object_init(character): + if character.db.pronouns == None: + character.db.pronouns = DEFAULT_CHARACTER_PRONOUNS[:] + if character.db.pronoun_specs == None: + character.db.pronoun_specs = [] + +def msg(character, text=None, from_obj=None, session=None, **kwargs): + object_init(character) + + """ + 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. + Note: + `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: + repl = lambda a: pronoun_repl(character, a) + + if text and isinstance(text, tuple): + text = (RE_GENDER_PRONOUN.sub(repl, text[0]), *text[1:]) + else: + text = RE_GENDER_PRONOUN.sub(repl, text) + except TypeError: + pass + except Exception as e: + logger.log_trace(e) + return (text, from_obj, session, kwargs) diff --git a/lib/pronounsub/pronounsub.py b/lib/pronounsub/commands.py similarity index 57% rename from lib/pronounsub/pronounsub.py rename to lib/pronounsub/commands.py index c490666..4b65ff0 100644 --- a/lib/pronounsub/pronounsub.py +++ b/lib/pronounsub/commands.py @@ -1,81 +1,5 @@ -""" -Pronounsub - -Griatch 2015 -Copyright (c) 2023 lunacb - -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 - -from evennia import Command, DefaultCharacter -from evennia import InterruptCommand -from evennia.utils import logger -from evennia.utils.create import create_script -from evennia.utils.search import search_script -from .consts import * - -# in-game command for setting the gender - -def parse_specific_pronoun(pronoun): - specific = [ p.strip() for p in pronoun.split(",") ] - if len(specific) != len(PRONOUN_FORMS): - return None - - new = {} - for i in range(len(specific)): - new[PRONOUN_FORMS[i]] = specific[i] - - return new - -def get_pronoun_list(): - search = search_script("pronoun_db") - if not any(search): - script = create_script("lib.pronounsub.PronounDbScript", key="pronoun_db") - else: - script = search[0] - - return script.db.pronouns - -def specific_pronoun_from_character(character, caller=None): - pronoun_list = get_pronoun_list()[:] - if caller != None: - # TODO: reorder - pronoun_list += caller.db.pronoun_specs - for pronoun in pronoun_list: - if character in pronoun.values(): - return pronoun - - return None - -def stringify_specific_pronoun(spec): - return ",".join([ spec[form] for form in PRONOUN_FORMS ]) +from .common import * +from .character import object_init class PronounAdminCommand(Command): """ @@ -221,7 +145,7 @@ class PronounsCommand(Command): def parse(self): caller = self.caller - caller.pronoun_object_init() + object_init(caller) args = self.args.strip().lower().split() if len(args) == 1: @@ -254,7 +178,7 @@ class PronounsCommand(Command): def func(self): caller = self.caller - caller.pronoun_object_init() + object_init(caller) command = self.args[0] @@ -275,10 +199,10 @@ class PronounsCommand(Command): "details. |/") caller.db.pronouns = pronouns - caller.msg(f"Your pronouns have been set to {caller._stringify_pronouns()}.") + caller.msg(f"Your pronouns have been set to {stringify_pronouns(caller)}.") case "get": - caller.msg(f"Your pronouns are {caller._stringify_pronouns()}.") + caller.msg(f"Your pronouns are {stringify_pronouns(caller)}.") case "list_known": caller.msg("Known user-defined pronouns:") @@ -299,101 +223,3 @@ class PronounsCommand(Command): if pronoun in caller.db.pronoun_specs: caller.db.pronoun_specs.remove(pronoun) self.caller.msg(f"Remobed the pronoun {stringify_specific_pronoun(pronoun)}.") - -class PronounCharacter(DefaultCharacter): - """ - This is a Character class aware of gender. - - """ - - # This should be called before every use of a Character to make sure it's - # initialized right. - def pronoun_object_init(self): - if self.db.pronouns == None: - self.db.pronouns = DEFAULT_CHARACTER_PRONOUNS[:] - if self.db.pronoun_specs == None: - self.db.pronoun_specs = [] - - def at_object_creation(self): - """ - Called once when the object is created. - """ - super().at_object_creation() - self.pronoun_object_init() - - def _stringify_pronouns(self): - pronouns = self.attributes.get("pronouns", default=DEFAULT_CHARACTER_PRONOUNS[:]) - return "/".join(pronouns) - - def _get_pronoun(self, 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 - dup_specifics = [] - for pronoun in self.attributes.get("pronouns", default=DEFAULT_CHARACTER_PRONOUNS[:]): - specific = specific_pronoun_from_character(pronoun, self) - if specific != None: - dup_specifics.append(specific) - - specifics = [] - for s in dup_specifics: - if not s in specifics: - specifics.append(s) - - if len(specifics) == 0: - choice = DEFAULT_SPECIFIC_NEUTRAL_PRONOUNS - else: - choice = random.choice(specifics) - - pronoun = choice[typ.lower()] - return pronoun.capitalize() if typ.isupper() else pronoun - - def msg(self, text=None, from_obj=None, session=None, **kwargs): - self.pronoun_object_init() - - """ - 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) diff --git a/lib/pronounsub/common.py b/lib/pronounsub/common.py new file mode 100644 index 0000000..5ef3aa6 --- /dev/null +++ b/lib/pronounsub/common.py @@ -0,0 +1,137 @@ +""" +Pronounsub + +Griatch 2015 +Copyright (c) 2023 lunacb + +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 copy +import random +import re + +from evennia import Command, DefaultCharacter +from evennia import DefaultScript +from evennia import InterruptCommand +from evennia.utils import logger +from evennia.utils.create import create_script +from evennia.utils.search import search_script + +class PronounDbScript(DefaultScript): + def at_script_creation(self): + self.db.pronouns = copy.deepcopy(DEFAULT_SPECIFIC_PRONOUNS) + +DEFAULT_SPECIFIC_NEUTRAL_PRONOUNS = {"s": "they", "o": "them", "p": "their", "a": "theirs"} + +DEFAULT_SPECIFIC_PRONOUNS = [ + {"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"} +] + +DEFAULT_CHARACTER_PRONOUNS = [ "they", "them" ] + +PRONOUN_FORMS = [ "s", "o", "p", "a" ] + +RE_GENDER_PRONOUN = re.compile(r"(?