update character_creator contrib

This commit is contained in:
Cal 2023-12-22 12:23:06 -07:00
parent 7a7416b084
commit 4628d86056
2 changed files with 111 additions and 111 deletions

View file

@ -23,10 +23,11 @@ from django.conf import settings
from evennia import DefaultAccount from evennia import DefaultAccount
from evennia.commands.default.muxcommand import MuxAccountCommand from evennia.commands.default.muxcommand import MuxAccountCommand
from evennia.objects.models import ObjectDB from evennia.objects.models import ObjectDB
from evennia.utils import create, search
from evennia.utils.evmenu import EvMenu from evennia.utils.evmenu import EvMenu
from evennia.utils.utils import is_iter
_MAX_NR_CHARACTERS = settings.MAX_NR_CHARACTERS
_CHARACTER_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
try: try:
_CHARGEN_MENU = settings.CHARGEN_MENU _CHARGEN_MENU = settings.CHARGEN_MENU
except AttributeError: except AttributeError:
@ -60,37 +61,20 @@ class ContribCmdCharCreate(MuxAccountCommand):
# we're continuing chargen for a WIP character # we're continuing chargen for a WIP character
new_character = in_progress[0] new_character = in_progress[0]
else: else:
# we're making a new character
charmax = settings.MAX_NR_CHARACTERS
if not account.is_superuser and (
account.characters and len(account.characters) >= charmax
):
plural = "" if charmax == 1 else "s"
self.msg(f"You may only create a maximum of {charmax} character{plural}.")
return
# create the new character object, with default settings
# start_location = ObjectDB.objects.get_id(settings.START_LOCATION)
default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
permissions = settings.PERMISSION_ACCOUNT_DEFAULT
# generate a randomized key so the player can choose a character name later # generate a randomized key so the player can choose a character name later
key = "".join(choices(string.ascii_letters + string.digits, k=10)) key = "".join(choices(string.ascii_letters + string.digits, k=10))
new_character = create.create_object( new_character, errors = account.create_character(
_CHARACTER_TYPECLASS, key=key, location=None, ip=session.address
key=key,
location=None,
home=default_home,
permissions=permissions,
)
# only allow creator (and developers) to puppet this char
new_character.locks.add(
f"puppet:pid({account.id}) or perm(Developer) or"
f" pperm(Developer);delete:id({account.id}) or perm(Admin)"
) )
if errors:
self.msg(errors)
if not new_character:
return
# initalize the new character to the beginning of the chargen menu # initalize the new character to the beginning of the chargen menu
new_character.db.chargen_step = "menunode_welcome" new_character.db.chargen_step = "menunode_welcome"
account.characters.add(new_character) # make sure the character first logs in at the settings-defined start location
new_character.db.prelogout_location = ObjectDB.objects.get_id(settings.START_LOCATION)
# set the menu node to start at to the character's last saved step # set the menu node to start at to the character's last saved step
startnode = new_character.db.chargen_step startnode = new_character.db.chargen_step
@ -111,17 +95,17 @@ class ContribCmdCharCreate(MuxAccountCommand):
class ContribChargenAccount(DefaultAccount): class ContribChargenAccount(DefaultAccount):
""" """
A modified Account class that makes minor changes to the OOC look A modified Account class that makes minor changes to the OOC look
output, to incorporate in-progress characters. output to incorporate in-progress characters.
""" """
def at_look(self, target=None, session=None, **kwargs): def at_look(self, target=None, session=None, **kwargs):
""" """
Called by the OOC look command. It displays a list of playable Called when this object executes a look. It allows to customize
characters and should be mostly identical to the core method. just what this means.
Args: Args:
target (Object or list, optional): An object or a list target (Object or list, optional): An object or a list
objects to inspect. objects to inspect. This is normally a list of characters.
session (Session, optional): The session doing this look. session (Session, optional): The session doing this look.
**kwargs (dict): Arbitrary, optional arguments for users **kwargs (dict): Arbitrary, optional arguments for users
overriding the call (unused by default). overriding the call (unused by default).
@ -129,73 +113,85 @@ class ContribChargenAccount(DefaultAccount):
Returns: Returns:
look_string (str): A prepared look string, ready to send look_string (str): A prepared look string, ready to send
off to any recipient (usually to ourselves) off to any recipient (usually to ourselves)
""" """
# list of targets - make list to disconnect from db if target and not is_iter(target):
# single target - just show it
if hasattr(target, "return_appearance"):
return target.return_appearance(self)
else:
return f"{target} has no in-game appearance."
# multiple targets - this is a list of characters
characters = list(tar for tar in target if tar) if target else [] characters = list(tar for tar in target if tar) if target else []
ncars = len(characters)
sessions = self.sessions.all() sessions = self.sessions.all()
is_su = self.is_superuser
# text shown when looking in the ooc area
result = [f"Account |g{self.key}|n (you are Out-of-Character)"]
nsess = len(sessions) nsess = len(sessions)
if nsess == 1:
result.append("\n\n|wConnected session:|n") if not nsess:
elif nsess > 1: # no sessions, nothing to report
result.append(f"\n\n|wConnected sessions ({nsess}):|n") return ""
# header text
txt_header = f"Account |g{self.name}|n (you are Out-of-Character)"
# sessions
sess_strings = []
for isess, sess in enumerate(sessions): for isess, sess in enumerate(sessions):
csessid = sess.sessid ip_addr = sess.address[0] if isinstance(sess.address, tuple) else sess.address
addr = "{protocol} ({address})".format( addr = f"{sess.protocol_key} ({ip_addr})"
protocol=sess.protocol_key, sess_str = (
address=isinstance(sess.address, tuple) f"|w* {isess + 1}|n"
and str(sess.address[0]) if session and session.sessid == sess.sessid
or str(sess.address), else f" {isess + 1}"
) )
if session.sessid == csessid:
result.append(f"\n |w* {isess+1}|n {addr}") sess_strings.append(f"{sess_str} {addr}")
txt_sessions = "|wConnected session(s):|n\n" + "\n".join(sess_strings)
if not characters:
txt_characters = "You don't have a character yet. Use |wcharcreate|n."
else: else:
result.append(f"\n {isess+1} {addr}") max_chars = (
"unlimited"
result.append("\n\n |whelp|n - more commands") if self.is_superuser or _MAX_NR_CHARACTERS is None
result.append("\n |wpublic <Text>|n - talk on public channel") else _MAX_NR_CHARACTERS
)
charmax = settings.MAX_NR_CHARACTERS
if is_su or len(characters) < charmax:
result.append("\n |wcharcreate|n - create a new character")
if characters:
result.append("\n |wchardelete <name>|n - delete a character (cannot be undone!)")
plural = "" if len(characters) == 1 else "s"
result.append("\n |wic <character>|n - enter the game (|wooc|n to return here)")
if is_su:
result.append(f"\n\nAvailable character{plural} ({len(characters)}/unlimited):")
else:
result.append(f"\n\nAvailable character{plural} ({len(characters)}/{charmax}):")
char_strings = []
for char in characters: for char in characters:
if char.db.chargen_step:
# currently in-progress character; don't display placeholder names
result.append("\n - |Yin progress|n (|wcharcreate|n to continue)")
continue
csessions = char.sessions.all() csessions = char.sessions.all()
if csessions: if csessions:
for sess in csessions: for sess in csessions:
# character is already puppeted # character is already puppeted
sid = sess in sessions and sessions.index(sess) + 1 sid = sess in sessions and sessions.index(sess) + 1
if sess and sid: if sess and sid:
result.append( char_strings.append(
f"\n - |G{char.key}|n [{', '.join(char.permissions.all())}] (played by" f" - |G{char.name}|n [{', '.join(char.permissions.all())}] "
f" you in session {sid})" f"(played by you in session {sid})"
) )
else: else:
result.append( char_strings.append(
f"\n - |R{char.key}|n [{', '.join(char.permissions.all())}] (played by" f" - |R{char.name}|n [{', '.join(char.permissions.all())}] "
" someone else)" "(played by someone else)"
) )
elif char.db.chargen_step:
# currently in-progress character; don't display placeholder names
char_strings.append("\n - |Yin progress|n (|wcharcreate|n to continue)")
continue
else: else:
# character is available # character is "free to puppet"
result.append(f"\n - {char.key} [{', '.join(char.permissions.all())}]") char_strings.append(f" - {char.name} [{', '.join(char.permissions.all())}]")
look_string = ("-" * 68) + "\n" + "".join(result) + "\n" + ("-" * 68)
return look_string txt_characters = (
f"Available character(s) ({ncars}/{max_chars}, |wic <name>|n to play):|n\n"
+ "\n".join(char_strings)
)
return self.ooc_appearance_template.format(
header=txt_header,
sessions=txt_sessions,
characters=txt_characters,
footer="",
)

View file

@ -1,10 +1,4 @@
from unittest.mock import patch
from django.conf import settings
from django.test import override_settings
from evennia import DefaultCharacter from evennia import DefaultCharacter
from evennia.commands.default import account
from evennia.utils import inherits_from from evennia.utils import inherits_from
from evennia.utils.test_resources import BaseEvenniaCommandTest from evennia.utils.test_resources import BaseEvenniaCommandTest
@ -15,31 +9,41 @@ class TestCharacterCreator(BaseEvenniaCommandTest):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.account.swap_typeclass(character_creator.ContribChargenAccount) self.account.swap_typeclass(character_creator.ContribChargenAccount)
def test_ooc_look(self):
self.account.characters.add(self.char1)
self.account.unpuppet_all() self.account.unpuppet_all()
def test_account_look(self):
self.account.characters.add(self.char1)
self.char1.db.chargen_step = "start" self.char1.db.chargen_step = "start"
with patch("evennia.commands.default.account._AUTO_PUPPET_ON_LOGIN", new=False):
# check that correct output is returning # check that correct output is returning
output = self.call( output = self.account.at_look(target=self.account.characters.all(), session=self.session)
account.CmdOOCLook(),
"",
"Account TestAccount (you are Out-of-Character)",
caller=self.account,
)
# check that char1 is recognized as in progress # check that char1 is recognized as in progress
self.assertIn("in progress", output) self.assertIn("in progress", output)
@override_settings(CHARGEN_MENU="evennia.contrib.rpg.character_creator.example_menu")
def test_char_create(self): def test_char_create(self):
with self.settings(START_LOCATION=f"#{self.room1.id}"):
self.call( self.call(
character_creator.ContribCmdCharCreate(), character_creator.ContribCmdCharCreate(),
"", "",
caller=self.account, caller=self.account,
) )
# verify menu was initialized
menu = self.session.ndb._menutree menu = self.session.ndb._menutree
self.assertNotEqual(menu, None) self.assertNotEqual(menu, None)
self.assertTrue(inherits_from(self.session.new_char, DefaultCharacter)) # verify character was created
new_char = self.session.new_char
self.assertTrue(inherits_from(new_char, DefaultCharacter))
# verify character's "start location" was set
self.assertEqual(self.session.new_char.db.prelogout_location, self.room1)
# exit the menu, verify it resumes
menu.parse_input("q")
del self.session.new_char
self.assertEqual(self.session.ndb._menutree, None)
self.call(
character_creator.ContribCmdCharCreate(),
"",
caller=self.account,
)
# should be the same new char
self.assertEqual(new_char, self.session.new_char)