update clothing contrib

This commit is contained in:
InspectorCaracal 2022-11-21 22:55:30 -07:00
parent 796bf543c5
commit 0f93b7b136
2 changed files with 276 additions and 359 deletions

View file

@ -72,14 +72,15 @@ with which to test the system:
wear shirt
"""
from collections import defaultdict
from django.conf import settings
from evennia import DefaultCharacter, DefaultObject, default_cmds
from evennia.commands.default.muxcommand import MuxCommand
from evennia.utils import evtable, list_to_string
from evennia.utils import at_search_result, evtable, inherits_from, iter_to_str
# Options start here.
# Maximum character length of 'wear style' strings, or None for unlimited.
WEARSTYLE_MAXLENGTH = 50
WEARSTYLE_MAXLENGTH = getattr(settings, 'CLOTHING_WEARSTYLE_MAXLENGTH', 50)
# The rest of these options have to do with clothing types. ContribClothing types are optional,
# but can be used to give better control over how different items of clothing behave. You
@ -88,7 +89,7 @@ WEARSTYLE_MAXLENGTH = 50
# The order in which clothing types appear on the description. Untyped clothing or clothing
# with a type not given in this list goes last.
CLOTHING_TYPE_ORDER = [
CLOTHING_TYPE_ORDER = getattr(settings, 'CLOTHING_TYPE_ORDERED', [
"hat",
"jewelry",
"top",
@ -100,28 +101,26 @@ CLOTHING_TYPE_ORDER = [
"socks",
"shoes",
"accessory",
]
])
# The maximum number of each type of clothes that can be worn. Unlimited if untyped or not specified.
CLOTHING_TYPE_LIMIT = {"hat": 1, "gloves": 1, "socks": 1, "shoes": 1}
CLOTHING_TYPE_LIMIT = getattr(settings, 'CLOTHING_TYPE_LIMIT', {"hat": 1, "gloves": 1, "socks": 1, "shoes": 1})
# The maximum number of clothing items that can be worn, or None for unlimited.
CLOTHING_OVERALL_LIMIT = 20
CLOTHING_OVERALL_LIMIT = getattr(settings, 'CLOTHING_OVERALL_LIMIT', 20)
# What types of clothes will automatically cover what other types of clothes when worn.
# Note that clothing only gets auto-covered if it's already worn when you put something
# on that auto-covers it - for example, it's perfectly possible to have your underpants
# showing if you put them on after your pants!
CLOTHING_TYPE_AUTOCOVER = {
CLOTHING_TYPE_AUTOCOVER = getattr(settings, 'CLOTHING_TYPE_AUTOCOVER', {
"top": ["undershirt"],
"bottom": ["underpants"],
"fullbody": ["undershirt", "underpants"],
"shoes": ["socks"],
}
})
# Types of clothes that can't be used to cover other clothes.
CLOTHING_TYPE_CANT_COVER_WITH = ["jewelry"]
CLOTHING_TYPE_CANT_COVER_WITH = getattr(settings, 'CLOTHING_TYPE_AUTOCOVER', ["jewelry"])
# HELPER FUNCTIONS START HERE
def order_clothes_list(clothes_list):
"""
Orders a given clothes list by the order specified in CLOTHING_TYPE_ORDER.
@ -245,26 +244,23 @@ class ContribClothing(DefaultObject):
"""
# Set clothing as worn
self.db.worn = wearstyle
# Auto-cover appropirate clothing types, as specified above
# Auto-cover appropriate clothing types
to_cover = []
if self.db.clothing_type and self.db.clothing_type in CLOTHING_TYPE_AUTOCOVER:
for garment in get_worn_clothes(wearer):
if (
garment.db.clothing_type
and garment.db.clothing_type in CLOTHING_TYPE_AUTOCOVER[self.db.clothing_type]
):
to_cover.append(garment)
garment.db.covered_by = self
# Return if quiet
if quiet:
return
if clothing_type := self.db.clothing_type:
if autocover_types := CLOTHING_TYPE_AUTOCOVER.get(clothing_type):
to_cover.extend( [ garment for garment in get_worn_clothes(wearer) if garment.db.clothing_type in autocover_types ] )
for garment in to_cover:
garment.db.covered_by = self
# Echo a message to the room
message = "%s puts on %s" % (wearer, self.name)
if wearstyle is not True:
message = "%s wears %s %s" % (wearer, self.name, wearstyle)
if to_cover:
message = message + ", covering %s" % list_to_string(to_cover)
wearer.location.msg_contents(message + ".")
if not quiet:
if type(wearstyle) is str:
message = f"$You() $conj(wear) {self.name} {wearstyle}"
else:
message = f"$You() $conj(put) on {self.name}"
if to_cover:
message += ", covering {iter_to_str(to_cover)}"
wearer.location.msg_contents(message + ".", from_obj=wearer)
def remove(self, wearer, quiet=False):
"""
@ -277,24 +273,19 @@ class ContribClothing(DefaultObject):
quiet (bool): If false, does not message the room
"""
self.db.worn = False
remove_message = "%s removes %s." % (wearer, self.name)
uncovered_list = []
# Check to see if any other clothes are covered by this object.
for thing in wearer.contents:
# If anything is covered by
if thing.db.covered_by == self:
thing.db.covered_by = False
uncovered_list.append(thing.name)
if len(uncovered_list) > 0:
remove_message = "%s removes %s, revealing %s." % (
wearer,
self.name,
list_to_string(uncovered_list),
)
# Echo a message to the room
if not quiet:
wearer.location.msg_contents(remove_message)
remove_message = f"$You() $conj(remove) {self.name}"
if len(uncovered_list) > 0:
remove_message += f", revealing {iter_to_str(uncovered_list)}"
wearer.location.msg_contents(remove_message + ".", from_obj=wearer)
def at_get(self, getter):
"""
@ -304,6 +295,19 @@ class ContribClothing(DefaultObject):
"""
self.db.worn = False
def at_pre_move(self, destination, **kwargs):
"""
Called just before starting to move this object to
destination. Return False to abort move.
Notes:
If this method returns False/None, the move is cancelled
before it is even started.
"""
# Covered clothing cannot be removed, dropped, or otherwise relocated
if self.db.covered_by:
return False
return True
class ClothedCharacter(DefaultCharacter):
"""
@ -312,45 +316,69 @@ class ClothedCharacter(DefaultCharacter):
character typeclass.
"""
def return_appearance(self, looker):
def get_display_desc(self, looker, **kwargs):
"""
This formats a description. It is the hook a 'look' command
should call.
Get the 'desc' component of the object description. Called by `return_appearance`.
Args:
looker (Object): Object doing the looking.
Notes:
The name of every clothing item carried and worn by the character
is appended to their description. If the clothing's db.worn value
is set to True, only the name is appended, but if the value is a
string, the string is appended to the end of the name, to allow
characters to specify how clothing is worn.
**kwargs: Arbitrary data for use when overriding.
Returns:
str: The desc display string.
"""
if not looker:
return ""
# get description, build string
string = "|c%s|n\n" % self.get_display_name(looker)
desc = self.db.desc
worn_string_list = []
clothes_list = get_worn_clothes(self, exclude_covered=True)
outfit_list = []
# Append worn, uncovered clothing to the description
for garment in clothes_list:
# If 'worn' is True, just append the name
if garment.db.worn is True:
worn_string_list.append(garment.name)
# Otherwise, append the name and the string value of 'worn'
elif garment.db.worn:
worn_string_list.append("%s %s" % (garment.name, garment.db.worn))
if desc:
string += "%s" % desc
# Append worn clothes.
if worn_string_list:
string += "|/|/%s is wearing %s." % (self, list_to_string(worn_string_list))
else:
string += "|/|/%s is not wearing anything." % self
return string
for garment in get_worn_clothes(self, exclude_covered=True):
wearstyle = garment.db.worn
if type(wearstyle) is str:
outfit_list.append(f"{garment.name} {wearstyle}")
else:
outfit_list.append(garment.name)
# Create outfit string
if outfit_list:
outfit = f"{self.get_display_name(looker, **kwargs)} is wearing {iter_to_str(outfit_list)}."
else:
outfit = f"{self.get_display_name(looker, **kwargs)} is wearing nothing."
# Add on to base description
if desc:
desc += f"\n\n{outfit}"
else:
desc = outfit
return desc
def get_display_things(self, looker, **kwargs):
"""
Get the 'things' component of the object's contents. Called by `return_appearance`.
Args:
looker (Object): Object doing the looking.
**kwargs: Arbitrary data for use when overriding.
Returns:
str: A string describing the things in object.
"""
def _filter_visible(obj_list):
return (obj for obj in obj_list if obj != looker and obj.access(looker, "view") and not obj.db.worn)
# sort and handle same-named things
things = _filter_visible(self.contents_get(content_type="object"))
grouped_things = defaultdict(list)
for thing in things:
grouped_things[thing.get_display_name(looker, **kwargs)].append(thing)
thing_names = []
for thingname, thinglist in sorted(grouped_things.items()):
nthings = len(thinglist)
thing = thinglist[0]
singular, plural = thing.get_numbered_name(nthings, looker, key=thingname)
thing_names.append(singular if nthings == 1 else plural)
thing_names = iter_to_str(thing_names)
return f"\n{self.get_display_name(looker, **kwargs)} is carrying {thing_names}" if thing_names else ""
# COMMANDS START HERE
@ -360,11 +388,12 @@ class CmdWear(MuxCommand):
Puts on an item of clothing you are holding.
Usage:
wear <obj> [wear style]
wear <obj> [=] [wear style]
Examples:
wear shirt
wear red shirt
wear scarf wrapped loosely about the shoulders
wear blue hat = at a jaunty angle
All the clothes you are wearing are appended to your description.
If you provide a 'wear style' after the command, the message you
@ -375,55 +404,66 @@ class CmdWear(MuxCommand):
help_category = "clothing"
def func(self):
"""
This performs the actual command.
"""
if not self.args:
self.caller.msg("Usage: wear <obj> [wear style]")
return
clothing = self.caller.search(self.arglist[0], candidates=self.caller.contents)
wearstyle = True
if not clothing:
self.caller.msg("Thing to wear must be in your inventory.")
return
if not clothing.is_typeclass(ContribClothing, exact=False):
self.caller.msg("That's not clothes!")
self.caller.msg("Usage: wear <obj> [=] [wear style]")
return
if not self.rhs:
# check if the whole string is an object
clothing = self.caller.search(self.lhs, candidates=self.caller.contents, quiet=True)
if not clothing:
# split out the first word as the object and the rest as the wearstyle
argslist = self.lhs.split()
self.lhs = argslist[0]
self.rhs = " ".join(argslist[1:])
clothing = self.caller.search(self.lhs, candidates=self.caller.contents)
else:
# pass the result through the search-result hook
clothing = at_search_result(clothing, self.caller, self.lhs)
else:
# it had an explicit separator - just do a normal search for the lhs
clothing = self.caller.search(self.lhs, candidates=self.caller.contents)
if not clothing:
return
if not inherits_from(clothing, ContribClothing):
self.caller.msg(f"{clothing.name} isn't something you can wear.")
return
if clothing.db.worn:
if not self.rhs:
# If no wearstyle was provided and the clothing is already being worn, do nothing
self.caller.msg(f"You're already wearing your {clothing.name}.")
return
elif len(self.rhs) > WEARSTYLE_MAXLENGTH:
self.caller.msg(
f"Please keep your wear style message to less than {WEARSTYLE_MAXLENGTH} characters."
)
return
else:
# Adjust the wearstyle
clothing.db.worn = self.rhs
self.caller.location.msg_contents(f"$You() $conj(wear) {clothing.name} {self.rhs}.", from_obj=self.caller)
return
already_worn = get_worn_clothes(self.caller)
# Enforce overall clothing limit.
if CLOTHING_OVERALL_LIMIT and len(get_worn_clothes(self.caller)) >= CLOTHING_OVERALL_LIMIT:
if CLOTHING_OVERALL_LIMIT and len(already_worn) >= CLOTHING_OVERALL_LIMIT:
self.caller.msg("You can't wear any more clothes.")
return
# Apply individual clothing type limits.
if clothing.db.clothing_type and not clothing.db.worn:
type_count = single_type_count(get_worn_clothes(self.caller), clothing.db.clothing_type)
if clothing.db.clothing_type in list(CLOTHING_TYPE_LIMIT.keys()):
if type_count >= CLOTHING_TYPE_LIMIT[clothing.db.clothing_type]:
if clothing_type := clothing.db.type:
if clothing_type in CLOTHING_TYPE_LIMIT:
type_count = single_type_count(already_worn, clothing_type)
if type_count >= CLOTHING_TYPE_LIMIT[clothing_type]:
self.caller.msg(
"You can't wear any more clothes of the type '%s'."
% clothing.db.clothing_type
"You can't wear any more clothes of the type '{clothing_type}'."
)
return
if clothing.db.worn and len(self.arglist) == 1:
self.caller.msg("You're already wearing %s!" % clothing.name)
return
if len(self.arglist) > 1: # If wearstyle arguments given
wearstyle_list = self.arglist # Split arguments into a list of words
del wearstyle_list[0] # Leave first argument (the clothing item) out of the wearstyle
wearstring = " ".join(
str(e) for e in wearstyle_list
) # Join list of args back into one string
if (
WEARSTYLE_MAXLENGTH and len(wearstring) > WEARSTYLE_MAXLENGTH
): # If length of wearstyle exceeds limit
self.caller.msg(
"Please keep your wear style message to less than %i characters."
% WEARSTYLE_MAXLENGTH
)
else:
wearstyle = wearstring
wearstyle = self.rhs or True
clothing.wear(self.caller, wearstyle)
@ -443,18 +483,15 @@ class CmdRemove(MuxCommand):
help_category = "clothing"
def func(self):
"""
This performs the actual command.
"""
clothing = self.caller.search(self.args, candidates=self.caller.contents)
if not clothing:
self.caller.msg("Thing to remove must be carried or worn.")
self.caller.msg("You don't have anything like that.")
return
if not clothing.db.worn:
self.caller.msg("You're not wearing that!")
return
if clothing.db.covered_by:
self.caller.msg("You have to take off %s first." % clothing.db.covered_by.name)
if covered := clothing.db.covered_by:
self.caller.msg(f"You have to take off {covered} first.")
return
clothing.remove(self.caller)
@ -464,7 +501,7 @@ class CmdCover(MuxCommand):
Covers a worn item of clothing with another you're holding or wearing.
Usage:
cover <obj> [with] <obj>
cover <worn obj> with <obj>
When you cover a clothing item, it is hidden and no longer appears in
your description until it's uncovered or the item covering it is removed.
@ -473,55 +510,45 @@ class CmdCover(MuxCommand):
key = "cover"
help_category = "clothing"
rhs_split = (" with ","=")
def func(self):
"""
This performs the actual command.
"""
if not len(self.args) or not self.rhs:
self.caller.msg("Usage: cover <worn clothing> with <clothing object>")
return
if len(self.arglist) < 2:
self.caller.msg("Usage: cover <worn clothing> [with] <clothing object>")
return
# Get rid of optional 'with' syntax
if self.arglist[1].lower() == "with" and len(self.arglist) > 2:
del self.arglist[1]
to_cover = self.caller.search(self.arglist[0], candidates=self.caller.contents)
cover_with = self.caller.search(self.arglist[1], candidates=self.caller.contents)
to_cover = self.caller.search(self.lhs, candidates = get_worn_clothes(self.caller))
cover_with = self.caller.search(self.rhs, candidates=self.caller.contents)
if not to_cover or not cover_with:
return
if not to_cover.is_typeclass(ContribClothing, exact=False):
self.caller.msg("%s isn't clothes!" % to_cover.name)
return
if not cover_with.is_typeclass(ContribClothing, exact=False):
self.caller.msg("%s isn't clothes!" % cover_with.name)
return
if cover_with.db.clothing_type:
if cover_with.db.clothing_type in CLOTHING_TYPE_CANT_COVER_WITH:
self.caller.msg("You can't cover anything with that!")
return
if not to_cover.db.worn:
self.caller.msg("You're not wearing %s!" % to_cover.name)
return
if to_cover == cover_with:
self.caller.msg("You can't cover an item with itself!")
return
if cover_with.db.covered_by:
self.caller.msg("%s is covered by something else!" % cover_with.name)
if not inherits_from(cover_with, ContribClothing):
self.caller.msg(f"{cover_with.name} isn't something you can wear.")
rturn
if cover_with.db.clothing_type in CLOTHING_TYPE_CANT_COVER_WITH:
self.caller.msg(f"You can't cover anything with {cover_with.name}.")
return
if to_cover.db.covered_by:
if covered_by := cover_with.db.covered_by:
self.caller.msg(f"{cover_with.name} is already covered by {covered_by.name}.")
return
if covered_by := to_cover.db.covered_by:
self.caller.msg(
"%s is already covered by %s." % (cover_with.name, to_cover.db.covered_by.name)
f"{to_cover.name} is already covered by {covered_by.name}."
)
return
# Put on the item to cover with if it's not on already
if not cover_with.db.worn:
cover_with.wear(
self.caller, True
) # Put on the item to cover with if it's not on already
self.caller.location.msg_contents(
"%s covers %s with %s." % (self.caller, to_cover.name, cover_with.name)
)
cover_with.wear(self.caller, True)
to_cover.db.covered_by = cover_with
self.caller.location.msg_contents(f"$You() $conj(cover) {to_cover.name} with {cover_with.name}.", from_obj=self.caller)
class CmdUncover(MuxCommand):
"""
@ -548,126 +575,19 @@ class CmdUncover(MuxCommand):
self.caller.msg("Usage: uncover <worn clothing object>")
return
to_uncover = self.caller.search(self.args, candidates=self.caller.contents)
if not to_uncover:
clothing = self.caller.search(self.args, candidates=get_worn_clothes(self.caller))
if not clothing:
return
if not to_uncover.db.worn:
self.caller.msg("You're not wearing %s!" % to_uncover.name)
if covered_by := clothing.db.covered_by:
if covered_by.db.covered_by:
self.caller.msg(f"{clothing.name} is under too many layers to uncover.")
return
clothing.db.covered_by = None
self.caller.location.msg_contents(f"$You() $conj(uncover) {clothing.name}.", from_obj=self.caller)
else:
self.caller.msg(f"{clothing.name} isn't covered by anything.")
return
if not to_uncover.db.covered_by:
self.caller.msg("%s isn't covered by anything!" % to_uncover.name)
return
covered_by = to_uncover.db.covered_by
if covered_by.db.covered_by:
self.caller.msg("%s is under too many layers to uncover." % (to_uncover.name))
return
self.caller.location.msg_contents("%s uncovers %s." % (self.caller, to_uncover.name))
to_uncover.db.covered_by = None
class CmdDrop(MuxCommand):
"""
drop something
Usage:
drop <obj>
Lets you drop an object from your inventory into the
location you are currently in.
"""
key = "drop"
locks = "cmd:all()"
arg_regex = r"\s|$"
def func(self):
"""Implement command"""
caller = self.caller
if not self.args:
caller.msg("Drop what?")
return
# Because the DROP command by definition looks for items
# in inventory, call the search function using location = caller
obj = caller.search(
self.args,
location=caller,
nofound_string="You aren't carrying %s." % self.args,
multimatch_string="You carry more than one %s:" % self.args,
)
if not obj:
return
# This part is new!
# You can't drop clothing items that are covered.
if obj.db.covered_by:
caller.msg("You can't drop that because it's covered by %s." % obj.db.covered_by)
return
# Remove clothes if they're dropped.
if obj.db.worn:
obj.remove(caller, quiet=True)
obj.move_to(caller.location, quiet=True, move_type="drop")
caller.msg("You drop %s." % (obj.name,))
caller.location.msg_contents("%s drops %s." % (caller.name, obj.name), exclude=caller)
# Call the object script's at_drop() method.
obj.at_drop(caller)
class CmdGive(MuxCommand):
"""
give away something to someone
Usage:
give <inventory obj> = <target>
Gives an items from your inventory to another character,
placing it in their inventory.
"""
key = "give"
locks = "cmd:all()"
arg_regex = r"\s|$"
def func(self):
"""Implement give"""
caller = self.caller
if not self.args or not self.rhs:
caller.msg("Usage: give <inventory object> = <target>")
return
to_give = caller.search(
self.lhs,
location=caller,
nofound_string="You aren't carrying %s." % self.lhs,
multimatch_string="You carry more than one %s:" % self.lhs,
)
target = caller.search(self.rhs)
if not (to_give and target):
return
if target == caller:
caller.msg("You keep %s to yourself." % to_give.key)
return
if not to_give.location == caller:
caller.msg("You are not holding %s." % to_give.key)
return
# This is new! Can't give away something that's worn.
if to_give.db.covered_by:
caller.msg(
"You can't give that away because it's covered by %s." % to_give.db.covered_by
)
return
# Remove clothes if they're given.
if to_give.db.worn:
to_give.remove(caller)
to_give.move_to(caller.location, quiet=True, move_type="remove")
# give object
caller.msg("You give %s to %s." % (to_give.key, target.key))
to_give.move_to(target, quiet=True, move_type="give")
target.msg("%s gives you %s." % (caller.key, to_give.key))
# Call the object script's at_give() method.
to_give.at_give(caller, target)
class CmdInventory(MuxCommand):
@ -695,23 +615,34 @@ class CmdInventory(MuxCommand):
self.caller.msg("You are not carrying or wearing anything.")
return
message_list = []
items = self.caller.contents
carry_table = evtable.EvTable(border="header")
wear_table = evtable.EvTable(border="header")
for item in items:
if not item.db.worn:
carry_table.add_row("|C%s|n" % item.name, item.db.desc or "")
carried = [ obj for obj in items if not obj.db.worn ]
worn = [ obj for obj in items if obj.db.worn ]
message_list.append("|wYou are carrying:|n")
for item in carried:
carry_table.add_row(item.get_display_name(self.caller), item.get_display_desc(self.caller))
if carry_table.nrows == 0:
carry_table.add_row("|CNothing.|n", "")
string = "|wYou are carrying:\n%s" % carry_table
for item in items:
if item.db.worn:
wear_table.add_row("|C%s|n" % item.name, item.db.desc or "")
carry_table.add_row("Nothing.", "")
message_list.append(str(carry_table))
message_list.append("|wYou are wearing:|n")
for item in worn:
item_name = item.get_display_name(self.caller)
if item.db.covered_by:
item_name += " (hidden)"
wear_table.add_row(item_name, item.get_display_desc(self.caller))
if wear_table.nrows == 0:
wear_table.add_row("|CNothing.|n", "")
string += "|/|wYou are wearing:\n%s" % wear_table
self.caller.msg(string)
wear_table.add_row("Nothing.", "")
message_list.append(str(wear_table))
self.caller.msg("\n".join(message_list))
class ClothedCharacterCmdSet(default_cmds.CharacterCmdSet):
@ -736,6 +667,4 @@ class ClothedCharacterCmdSet(default_cmds.CharacterCmdSet):
self.add(CmdRemove())
self.add(CmdCover())
self.add(CmdUncover())
self.add(CmdGive())
self.add(CmdDrop())
self.add(CmdInventory())

View file

@ -12,120 +12,108 @@ from . import clothing
class TestClothingCmd(BaseEvenniaCommandTest):
def test_clothingcommands(self):
wearer = create_object(clothing.ClothedCharacter, key="Wearer")
friend = create_object(clothing.ClothedCharacter, key="Friend")
room = create_object(DefaultRoom, key="room")
wearer.location = room
friend.location = room
def setUp(self):
super().setUp()
self.room = create_object(DefaultRoom, key="Room")
self.wearer = create_object(clothing.ClothedCharacter, key="Wearer")
self.wearer.location = self.room
# Make a test hat
test_hat = create_object(clothing.ContribClothing, key="test hat")
test_hat.db.clothing_type = "hat"
test_hat.location = wearer
self.test_hat = create_object(clothing.ContribClothing, key="test hat")
self.test_hat.db.clothing_type = "hat"
# Make a test scarf
test_scarf = create_object(clothing.ContribClothing, key="test scarf")
test_scarf.db.clothing_type = "accessory"
test_scarf.location = wearer
self.test_scarf = create_object(clothing.ContribClothing, key="test scarf")
self.test_scarf.db.clothing_type = "accessory"
def test_clothingcommands(self):
# Test inventory command.
self.call(
clothing.CmdInventory(), "", "You are not carrying or wearing anything.", caller=self.wearer
)
# Test wear command
self.call(clothing.CmdWear(), "", "Usage: wear <obj> [wear style]", caller=wearer)
self.call(clothing.CmdWear(), "hat", "Wearer puts on test hat.", caller=wearer)
self.test_scarf.location = self.wearer
self.test_hat.location = self.wearer
self.call(clothing.CmdWear(), "", "Usage: wear <obj> [=] [wear style]", caller=self.wearer)
self.call(clothing.CmdWear(), "hat", "You put on test hat.", caller=self.wearer)
self.call(
clothing.CmdWear(),
"scarf stylishly",
"Wearer wears test scarf stylishly.",
caller=wearer,
"You wear test scarf stylishly.",
caller=self.wearer,
)
# Test cover command.
self.call(
clothing.CmdCover(),
"",
"Usage: cover <worn clothing> [with] <clothing object>",
caller=wearer,
"Usage: cover <worn clothing> with <clothing object>",
caller=self.wearer,
)
self.call(
clothing.CmdCover(),
"hat with scarf",
"Wearer covers test hat with test scarf.",
caller=wearer,
"You cover test hat with test scarf.",
caller=self.wearer,
)
# Test remove command.
self.call(clothing.CmdRemove(), "", "Could not find ''.", caller=wearer)
self.call(clothing.CmdRemove(), "", "Could not find ''.", caller=self.wearer)
self.call(
clothing.CmdRemove(), "hat", "You have to take off test scarf first.", caller=wearer
clothing.CmdRemove(), "hat", "You have to take off test scarf first.", caller=self.wearer
)
self.call(
clothing.CmdRemove(),
"scarf",
"Wearer removes test scarf, revealing test hat.",
caller=wearer,
"You remove test scarf, revealing test hat.",
caller=self.wearer,
)
# Test uncover command.
test_scarf.wear(wearer, True)
test_hat.db.covered_by = test_scarf
self.call(clothing.CmdUncover(), "", "Usage: uncover <worn clothing object>", caller=wearer)
self.call(clothing.CmdUncover(), "hat", "Wearer uncovers test hat.", caller=wearer)
# Test drop command.
test_hat.db.covered_by = test_scarf
self.call(clothing.CmdDrop(), "", "Drop what?", caller=wearer)
self.call(
clothing.CmdDrop(),
"hat",
"You can't drop that because it's covered by test scarf.",
caller=wearer,
)
self.call(clothing.CmdDrop(), "scarf", "You drop test scarf.", caller=wearer)
# Test give command.
self.call(
clothing.CmdGive(), "", "Usage: give <inventory object> = <target>", caller=wearer
)
self.call(
clothing.CmdGive(),
"hat = Friend",
"Wearer removes test hat.|You give test hat to Friend.",
caller=wearer,
)
# Test inventory command.
self.call(
clothing.CmdInventory(), "", "You are not carrying or wearing anything.", caller=wearer
)
self.test_scarf.wear(self.wearer, True)
self.test_hat.db.covered_by = self.test_scarf
self.call(clothing.CmdUncover(), "", "Usage: uncover <worn clothing object>", caller=self.wearer)
self.call(clothing.CmdUncover(), "hat", "You uncover test hat.", caller=self.wearer)
class TestClothingFunc(BaseEvenniaTest):
def test_clothingfunctions(self):
wearer = create_object(clothing.ClothedCharacter, key="Wearer")
room = create_object(DefaultRoom, key="room")
wearer.location = room
def setUp(self):
super().setUp()
self.room = create_object(DefaultRoom, key="Room")
self.wearer = create_object(clothing.ClothedCharacter, key="Wearer")
self.wearer.location = self.room
# Make a test hat
test_hat = create_object(clothing.ContribClothing, key="test hat")
test_hat.db.clothing_type = "hat"
test_hat.location = wearer
self.test_hat = create_object(clothing.ContribClothing, key="test hat")
self.test_hat.db.clothing_type = "hat"
self.test_hat.location = self.wearer
# Make a test shirt
test_shirt = create_object(clothing.ContribClothing, key="test shirt")
test_shirt.db.clothing_type = "top"
test_shirt.location = wearer
# Make a test pants
test_pants = create_object(clothing.ContribClothing, key="test pants")
test_pants.db.clothing_type = "bottom"
test_pants.location = wearer
self.test_shirt = create_object(clothing.ContribClothing, key="test shirt")
self.test_shirt.db.clothing_type = "top"
self.test_shirt.location = self.wearer
# Make test pants
self.test_pants = create_object(clothing.ContribClothing, key="test pants")
self.test_pants.db.clothing_type = "bottom"
self.test_pants.location = self.wearer
def test_clothingfunctions(self):
self.test_hat.wear(self.wearer, "on the head")
self.assertEqual(self.test_hat.db.worn, "on the head")
test_hat.wear(wearer, "on the head")
self.assertEqual(test_hat.db.worn, "on the head")
self.test_hat.remove(self.wearer)
self.assertFalse(self.test_hat.db.worn)
test_hat.remove(wearer)
self.assertEqual(test_hat.db.worn, False)
self.test_hat.db.worn = True
self.test_hat.at_get(self.wearer)
self.assertFalse(self.test_hat.db.worn)
test_hat.worn = True
test_hat.at_get(wearer)
self.assertEqual(test_hat.db.worn, False)
self.test_hat.db.covered_by = self.test_shirt
can_move = self.test_hat.at_pre_move(self.room)
self.assertFalse(can_move)
clothes_list = [test_shirt, test_hat, test_pants]
clothes_list = [self.test_shirt, self.test_hat, self.test_pants]
self.assertEqual(
clothing.order_clothes_list(clothes_list), [test_hat, test_shirt, test_pants]
clothing.order_clothes_list(clothes_list), [self.test_hat, self.test_shirt, self.test_pants]
)
test_hat.wear(wearer, True)
test_pants.wear(wearer, True)
self.assertEqual(clothing.get_worn_clothes(wearer), [test_hat, test_pants])
self.test_hat.wear(self.wearer, True)
self.test_pants.wear(self.wearer, True)
self.assertEqual(clothing.get_worn_clothes(self.wearer), [self.test_hat, self.test_pants])
self.assertEqual(
clothing.clothing_type_count(clothes_list), {"hat": 1, "top": 1, "bottom": 1}