Apply black to evadventure files

This commit is contained in:
Griatch 2022-07-03 11:40:26 +02:00
parent 6e8e3963dd
commit 7815a06e3a
12 changed files with 653 additions and 327 deletions

View file

@ -27,6 +27,7 @@ class EquipmentHandler:
until you clean them.
"""
save_attribute = "inventory_slots"
def __init__(self, obj):
@ -47,8 +48,8 @@ class EquipmentHandler:
WieldLocation.TWO_HANDS: None,
WieldLocation.BODY: None,
WieldLocation.HEAD: None,
WieldLocation.BACKPACK: []
}
WieldLocation.BACKPACK: [],
},
)
def _count_slots(self):
@ -64,8 +65,7 @@ class EquipmentHandler:
if slot is not WieldLocation.BACKPACK
)
backpack_usage = sum(
getattr(slotobj, "size", 0) or 0
for slotobj in slots[WieldLocation.BACKPACK]
getattr(slotobj, "size", 0) or 0 for slotobj in slots[WieldLocation.BACKPACK]
)
return wield_usage + backpack_usage
@ -101,9 +101,11 @@ class EquipmentHandler:
current_slot_usage = self._count_slots()
if current_slot_usage + size > max_slots:
slots_left = max_slots - current_slot_usage
raise EquipmentError(f"Equipment full ($int2str({slots_left}) slots "
raise EquipmentError(
f"Equipment full ($int2str({slots_left}) slots "
f"remaining, {obj.key} needs $int2str({size}) "
f"$pluralize(slot, {size})).")
f"$pluralize(slot, {size}))."
)
return True
@property
@ -120,11 +122,13 @@ class EquipmentHandler:
"""
slots = self.slots
return sum((
return sum(
(
getattr(slots[WieldLocation.BODY], "armor", 0),
getattr(slots[WieldLocation.SHIELD_HAND], "armor", 0),
getattr(slots[WieldLocation.HEAD], "armor", 0),
))
)
)
@property
def weapon(self):
@ -423,6 +427,7 @@ class EvAdventureNPC(LivingMixin, DefaultCharacter):
EvAdventureCharacter class instead.
"""
hit_dice = AttributeProperty(default=1)
armor = AttributeProperty(default=11)
morale = AttributeProperty(default=9)

View file

@ -42,7 +42,8 @@ class CombatAction:
Inherit from this to make new actions.
"""
key = 'action'
key = "action"
help_text = "Combat action to perform."
# action to echo to everyone.
post_action_text = "{combatant} performed an action."
@ -107,6 +108,7 @@ class CombatActionDoNothing(CombatAction):
Do nothing this turn.
"""
help_text = "Hold you position, doing nothing."
post_action_text = "{combatant} does nothing this turn."
@ -124,24 +126,29 @@ class CombatActionStunt(CombatAction):
spend a use unless they succeed.
"""
give_advantage = True
give_disadvantage = False
max_uses = 1
priority = -1
attack_type = Ability.DEX
defense_type = Ability.DEX
help_text = ("Perform a stunt against a target. This will give you or an ally advantage "
help_text = (
"Perform a stunt against a target. This will give you or an ally advantage "
"on your next action against the same target [range 0-1, one use per combat. "
"Bonus lasts for two turns].")
"Bonus lasts for two turns]."
)
def use(self, attacker, defender, *args, beneficiary=None, **kwargs):
# quality doesn't matter for stunts, they are either successful or not
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
attacker, defender,
attacker,
defender,
attack_type=self.attack_type,
defense_type=self.defense_type,
advantage=False, disadvantage=disadvantage,
advantage=False,
disadvantage=disadvantage,
)
if is_success:
beneficiary = beneficiary if beneficiary else attacker
@ -161,6 +168,7 @@ class CombatActionAttack(CombatAction):
melee attack.
"""
key = "attack"
priority = 1
@ -176,14 +184,17 @@ class CombatActionAttack(CombatAction):
disadvantage = bool(self.combathandler.disadvantage_matrix[attacker].pop(defender, False))
is_hit, quality = rules.EvAdventureRollEngine.opposed_saving_throw(
attacker, defender,
attacker,
defender,
attack_type=attacker.weapon.attack_type,
defense_type=attacker.weapon.defense_type,
advantage=advantage, disadvantage=disadvantage
advantage=advantage,
disadvantage=disadvantage,
)
if is_hit:
self.combathandler.resolve_damage(attacker, defender,
critical=quality == "critical success")
self.combathandler.resolve_damage(
attacker, defender, critical=quality == "critical success"
)
# TODO messaging here
@ -204,6 +215,7 @@ class CombatActionUseItem(CombatAction):
combat_post_use
"""
def get_help(self, item, *args):
return item.combat_get_help(*args)
@ -227,6 +239,7 @@ class CombatActionFlee(CombatAction):
end of the second turn.
"""
key = "flee"
priority = -1
@ -234,6 +247,7 @@ class CombatActionFlee(CombatAction):
# it's safe to do this twice
self.combathandler.flee(combatant)
class CombatActionChase(CombatAction):
"""
@ -243,6 +257,7 @@ class CombatActionChase(CombatAction):
is 2). Advantage/disadvantage are considered.
"""
key = "chase"
priority = -5 # checked last
@ -255,9 +270,12 @@ class CombatActionChase(CombatAction):
disadvantage = bool(self.disadvantage_matrix[attacker].pop(fleeing_target, False))
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
combatant, fleeing_target,
attack_type=self.attack_type, defense_type=self.defense_type,
advantage=advantage, disadvantage=disadvantage
combatant,
fleeing_target,
attack_type=self.attack_type,
defense_type=self.defense_type,
advantage=advantage,
disadvantage=disadvantage,
)
if is_success:
@ -283,7 +301,7 @@ class EvAdventureCombatHandler(DefaultScript):
CombatActionChase,
CombatActionUseItem,
CombatActionStunt,
CombatActionAttack
CombatActionAttack,
]
# attributes
@ -345,7 +363,8 @@ class EvAdventureCombatHandler(DefaultScript):
for combatant in self.combatants:
# read the current action type selected by the player
action, args, kwargs = self.action_queue.get(
combatant, (CombatActionDoNothing(self, combatant), (), {}))
combatant, (CombatActionDoNothing(self, combatant), (), {})
)
# perform the action on the CombatAction instance
action.use(combatant, *args, **kwargs)
@ -380,11 +399,13 @@ class EvAdventureCombatHandler(DefaultScript):
for combatant in self.combatants:
new_advantage_matrix[combatant] = {
target: set_at_turn for target, turn in advantage_matrix.items()
target: set_at_turn
for target, turn in advantage_matrix.items()
if set_at_turn > oldest_stunt_age
}
new_disadvantage_matrix[combatant] = {
target: set_at_turn for target, turn in disadvantage_matrix.items()
target: set_at_turn
for target, turn in disadvantage_matrix.items()
if set_at_turn > oldest_stunt_age
}
@ -500,8 +521,11 @@ class EvAdventureCombatHandler(DefaultScript):
if defender.hp > 0:
# they are weakened, but with hp
self.msg("You are alive, but out of the fight. If you want to press your luck, "
"you need to rejoin the combat.", targets=defender)
self.msg(
"You are alive, but out of the fight. If you want to press your luck, "
"you need to rejoin the combat.",
targets=defender,
)
defender.at_defeat() # note - NPC monsters may still 'die' here
else:
# outright killed
@ -537,19 +561,16 @@ combat_script = """
"""
def _register_action(caller, raw_string, **kwargs):
"""
Register action with handler.
"""
action = kwargs.get['action']
action_args = kwargs['action_args']
action_kwargs = kwargs['action_kwargs']
action = kwargs.get["action"]
action_args = kwargs["action_args"]
action_kwargs = kwargs["action_kwargs"]
combat = caller.scripts.get("combathandler")
combat.register_action(
caller, action=action, *action_args, **action_kwargs
)
combat.register_action(caller, action=action, *action_args, **action_kwargs)
def node_select_target(caller, raw_string, **kwargs):
@ -558,9 +579,9 @@ def node_select_target(caller, raw_string, **kwargs):
with all other actions.
"""
action = kwargs.get('action')
action_args = kwargs.get('action_args')
action_kwargs = kwargs.get('action_kwargs')
action = kwargs.get("action")
action_args = kwargs.get("action_args")
action_kwargs = kwargs.get("action_kwargs")
combat = caller.scripts.get("combathandler")
text = "Select target for |w{action}|n."
@ -568,22 +589,26 @@ def node_select_target(caller, raw_string, **kwargs):
options = [
{
"desc": combatant.key,
"goto": (_register_action, {"action": action,
"args": action_args,
"kwargs": action_kwargs})
"goto": (
_register_action,
{"action": action, "args": action_args, "kwargs": action_kwargs},
),
}
for combatant in combat.combatants]
for combatant in combat.combatants
]
# make the apply-self option always the last one
options.append(
{
"desc": "(yourself)",
"goto": (_register_action, {"action": action,
"args": action_args,
"kwargs": action_kwargs})
"goto": (
_register_action,
{"action": action, "args": action_args, "kwargs": action_kwargs},
),
}
)
return text, options
def node_select_action(caller, raw_string, **kwargs):
"""
Menu node for selecting a combat action.
@ -593,13 +618,14 @@ def node_select_action(caller, raw_string, **kwargs):
text = combat.get_previous_turn_status(caller)
options = combat.get_available_options(caller)
options = {
"desc": action,
"goto": ("node_select_target", {"action": action,
})
"goto": (
"node_select_target",
{
"action": action,
},
),
}
return text, options

View file

@ -16,11 +16,13 @@ To get the `value` of an enum (must always be hashable, useful for Attribute loo
"""
from enum import Enum
class Ability(Enum):
"""
The six base abilities (defense is always bonus + 10)
"""
STR = "strength"
DEX = "dexterity"
CON = "constitution"
@ -45,11 +47,13 @@ class Ability(Enum):
CRITICAL_FAILURE = "critical_failure"
CRITICAL_SUCCESS = "critical_success"
class WieldLocation(Enum):
"""
Wield (or wear) locations.
"""
# wield/wear location
BACKPACK = "backpack"
WEAPON_HAND = "weapon_hand"

View file

@ -13,12 +13,12 @@ from evennia.typeclasses.attributes import AttributeProperty
from .enums import WieldLocation, Ability
class EvAdventureObject(DefaultObject):
"""
Base in-game entity.
"""
# inventory management
inventory_use_slot = AttributeProperty(default=WieldLocation.BACKPACK)
# how many inventory slots it uses (can be a fraction)
@ -41,6 +41,7 @@ class EvAdventureObjectFiller(EvAdventureObject):
meaning it's unusable.
"""
quality = AttributeProperty(default=0)
@ -49,6 +50,7 @@ class EvAdventureWeapon(EvAdventureObject):
Base weapon class for all EvAdventure weapons.
"""
inventory_use_slot = AttributeProperty(WieldLocation.WEAPON_HAND)
attack_type = AttributeProperty(default=Ability.STR)

View file

@ -31,6 +31,7 @@ class EvAdventureQuest:
check_<name> and complete_<name>
"""
# name + category must be globally unique. They are
# queried as name:category or just name, if category is empty.
name = ""
@ -44,11 +45,9 @@ class EvAdventureQuest:
def check():
pass
def progress(self, quester, *args, **kwargs):
"""
""" """
"""
class EvAdventureQuestHandler:
"""
@ -63,15 +62,14 @@ class EvAdventureQuestHandler:
```
"""
quest_storage_attribute = "_quests"
quest_storage_attribute_category = "evadventure"
def __init__(self, obj):
self.obj = obj
self.storage = obj.attributes.get(
self.quest_storage_attribute,
category=self.quest_storage_attribute_category,
default={}
self.quest_storage_attribute, category=self.quest_storage_attribute_category, default={}
)
def quest_storage_key(self, name, category):
@ -116,6 +114,3 @@ class EvAdventureQuestHandler:
start immediately.
"""

View file

@ -227,26 +227,26 @@ character_generation = {
"suspected",
],
"alignment": [
('1-5', "law"),
('6-15', "neutrality"),
('16-20', "chaos"),
("1-5", "law"),
("6-15", "neutrality"),
("16-20", "chaos"),
],
"armor": [
('1-3', "no armor"),
('4-14', "gambeson"),
('15-19', "brigandine"),
('20', "chain"),
("1-3", "no armor"),
("4-14", "gambeson"),
("15-19", "brigandine"),
("20", "chain"),
],
"helmets and shields": [
('1-13', "no helmet or shield"),
('14-16', "helmet"),
('17-19', "shield"),
('20', "helmet and shield"),
("1-13", "no helmet or shield"),
("14-16", "helmet"),
("17-19", "shield"),
("20", "helmet and shield"),
],
"starting weapon": [ # note: these are all d6 dmg weapons
('1-7', "dagger"),
('8-13', "club"),
('14-20', "staff"),
("1-7", "dagger"),
("8-13", "club"),
("14-20", "staff"),
],
"dungeoning gear": [
"rope, 50ft",
@ -315,55 +315,303 @@ character_generation = {
"small bell",
],
"name": [
"Abbo", "Adelaide", "Ellis", "Eleanor", "Lief", "Luanda", "Ablerus", "Agatha",
"Eneto", "Elizabeth", "Luke", "Lyra", "Acot", "Aleida", "Enio", "Elspeth", "Martin",
"Mabel", "Alexander", "Alexia", "Eral", "Emeline", "Merrick", "Maerwynn", "Almanzor",
"Alianor", "Erasmus", "Emma", "Mortimer", "Malkyn", "Althalos", "Aline", "Eustace",
"Emmony", "Ogden", "Margaret", "Ancelot", "Alma", "Everard", "Enna", "Oliver", "Margery",
"Asher", "Alys", "Faustus", "Enndolynn", "Orion", "Maria", "Aster", "Amabel", "Favian",
"Eve", "Oswald", "Marion", "Balan", "Amice", "Fendrel", "Evita", "Pelagon", "Matilda",
"Balthazar", "Anastas", "Finn", "Felice", "Pello", "Millicent", "Barat", "Angmar",
"Florian", "Fern", "Peyton", "Mirabelle", "Bartholomew", "Annabel", "Francis", "Floria",
"Philip", "Muriel", "Basil", "Arabella", "Frederick", "Fredegonde", "Poeas", "Nabarne",
"Benedict", "Ariana", "Gaidon", "Gillian", "Quinn", "Nell", "Berinon", "Ayleth", "Gavin",
"Gloriana", "Ralph", "Nesea", "Bertram", "Barberry", "Geoffrey", "Godeleva", "Randolph",
"Niree", "Beves", "Barsaba", "Gerard", "Godiva", "Reginald", "Odette", "Bilmer",
"Basilia", "Gervase", "Gunnilda", "Reynold", "Odila", "Blanko", "Beatrix", "Gilbert",
"Gussalen", "Richard", "Oria", "Bodo", "Benevolence", "Giles", "Gwendolynn", "Robert",
"Osanna", "Borin", "Bess", "Godfrey", "Hawise", "Robin", "Ostrythe", "Bryce", "Brangian",
"Gregory", "Helena", "Roger", "Ottilia", "Carac", "Brigida", "Gringoire", "Helewise",
"Ronald", "Panope", "Caspar", "Brunhild", "Gunthar", "Hester", "Rowan", "Paternain",
"Cassius", "Camilla", "Guy", "Hildegard", "Rulf", "Pechel", "Cedric", "Canace", "Gyras",
"Idony", "Sabin", "Pepper", "Cephalos", "Cecily", "Hadrian", "Isabella", "Sevrin",
"Petronilla", "Chadwick", "Cedany", "Hedelf", "Iseult", "Silas", "Phrowenia", "Charillos",
"Christina", "Hewelin", "Isolde", "Simon", "Poppy", "Charles", "Claramunda", "Hilderith",
"Jacquelyn", "Solomon", "Quenell", "Chermon", "Clarice", "Humbert", "Jasmine", "Stephen",
"Raisa", "Clement", "Clover", "Hyllus", "Jessamine", "Terrowin", "Reyna", "Clifton",
"Collette", "Ianto", "Josselyn", "Thomas", "Rixende", "Clovis", "Constance", "Ibykos",
"Juliana", "Tristan", "Rosamund", "Cyon", "Damaris", "Inigo", "Karitate", "Tybalt",
"Rose", "Dain", "Daphne", "Itylus", "Katelyn", "Ulric", "Ryia", "Dalmas", "Demona",
"James", "Katja", "Walter", "Sarah", "Danor", "Dimia", "Jasper", "Katrina", "Wander",
"Seraphina", "Destrian", "Dione", "Jiles", "Kaylein", "Warin", "Thea", "Domeka",
"Dorothea", "Joffridus", "Kinna", "Waverly", "Trillby", "Donald", "Douce", "Jordan",
"Krea", "Willahelm", "Wendel", "Doran", "Duraina", "Joris", "Kypris", "William",
"Wilberga", "Dumphey", "Dyota", "Josef", "Landerra", "Wimarc", "Winifred", "Eadmund",
"Eberhild", "Laurence", "Larraza", "Wystan", "Wofled", "Eckardus", "Edelot", "Leofrick",
"Linet", "Xalvador", "Wymarc", "Edward", "Edyva", "Letholdus", "Loreena", "Zane", "Ysmay",
"Abbo",
"Adelaide",
"Ellis",
"Eleanor",
"Lief",
"Luanda",
"Ablerus",
"Agatha",
"Eneto",
"Elizabeth",
"Luke",
"Lyra",
"Acot",
"Aleida",
"Enio",
"Elspeth",
"Martin",
"Mabel",
"Alexander",
"Alexia",
"Eral",
"Emeline",
"Merrick",
"Maerwynn",
"Almanzor",
"Alianor",
"Erasmus",
"Emma",
"Mortimer",
"Malkyn",
"Althalos",
"Aline",
"Eustace",
"Emmony",
"Ogden",
"Margaret",
"Ancelot",
"Alma",
"Everard",
"Enna",
"Oliver",
"Margery",
"Asher",
"Alys",
"Faustus",
"Enndolynn",
"Orion",
"Maria",
"Aster",
"Amabel",
"Favian",
"Eve",
"Oswald",
"Marion",
"Balan",
"Amice",
"Fendrel",
"Evita",
"Pelagon",
"Matilda",
"Balthazar",
"Anastas",
"Finn",
"Felice",
"Pello",
"Millicent",
"Barat",
"Angmar",
"Florian",
"Fern",
"Peyton",
"Mirabelle",
"Bartholomew",
"Annabel",
"Francis",
"Floria",
"Philip",
"Muriel",
"Basil",
"Arabella",
"Frederick",
"Fredegonde",
"Poeas",
"Nabarne",
"Benedict",
"Ariana",
"Gaidon",
"Gillian",
"Quinn",
"Nell",
"Berinon",
"Ayleth",
"Gavin",
"Gloriana",
"Ralph",
"Nesea",
"Bertram",
"Barberry",
"Geoffrey",
"Godeleva",
"Randolph",
"Niree",
"Beves",
"Barsaba",
"Gerard",
"Godiva",
"Reginald",
"Odette",
"Bilmer",
"Basilia",
"Gervase",
"Gunnilda",
"Reynold",
"Odila",
"Blanko",
"Beatrix",
"Gilbert",
"Gussalen",
"Richard",
"Oria",
"Bodo",
"Benevolence",
"Giles",
"Gwendolynn",
"Robert",
"Osanna",
"Borin",
"Bess",
"Godfrey",
"Hawise",
"Robin",
"Ostrythe",
"Bryce",
"Brangian",
"Gregory",
"Helena",
"Roger",
"Ottilia",
"Carac",
"Brigida",
"Gringoire",
"Helewise",
"Ronald",
"Panope",
"Caspar",
"Brunhild",
"Gunthar",
"Hester",
"Rowan",
"Paternain",
"Cassius",
"Camilla",
"Guy",
"Hildegard",
"Rulf",
"Pechel",
"Cedric",
"Canace",
"Gyras",
"Idony",
"Sabin",
"Pepper",
"Cephalos",
"Cecily",
"Hadrian",
"Isabella",
"Sevrin",
"Petronilla",
"Chadwick",
"Cedany",
"Hedelf",
"Iseult",
"Silas",
"Phrowenia",
"Charillos",
"Christina",
"Hewelin",
"Isolde",
"Simon",
"Poppy",
"Charles",
"Claramunda",
"Hilderith",
"Jacquelyn",
"Solomon",
"Quenell",
"Chermon",
"Clarice",
"Humbert",
"Jasmine",
"Stephen",
"Raisa",
"Clement",
"Clover",
"Hyllus",
"Jessamine",
"Terrowin",
"Reyna",
"Clifton",
"Collette",
"Ianto",
"Josselyn",
"Thomas",
"Rixende",
"Clovis",
"Constance",
"Ibykos",
"Juliana",
"Tristan",
"Rosamund",
"Cyon",
"Damaris",
"Inigo",
"Karitate",
"Tybalt",
"Rose",
"Dain",
"Daphne",
"Itylus",
"Katelyn",
"Ulric",
"Ryia",
"Dalmas",
"Demona",
"James",
"Katja",
"Walter",
"Sarah",
"Danor",
"Dimia",
"Jasper",
"Katrina",
"Wander",
"Seraphina",
"Destrian",
"Dione",
"Jiles",
"Kaylein",
"Warin",
"Thea",
"Domeka",
"Dorothea",
"Joffridus",
"Kinna",
"Waverly",
"Trillby",
"Donald",
"Douce",
"Jordan",
"Krea",
"Willahelm",
"Wendel",
"Doran",
"Duraina",
"Joris",
"Kypris",
"William",
"Wilberga",
"Dumphey",
"Dyota",
"Josef",
"Landerra",
"Wimarc",
"Winifred",
"Eadmund",
"Eberhild",
"Laurence",
"Larraza",
"Wystan",
"Wofled",
"Eckardus",
"Edelot",
"Leofrick",
"Linet",
"Xalvador",
"Wymarc",
"Edward",
"Edyva",
"Letholdus",
"Loreena",
"Zane",
"Ysmay",
],
}
reactions = [
('2', "Hostile"),
('3-5', "Unfriendly"),
('6-8', "Unsure"),
('9-11', "Talkative"),
('12', "Helpful"),
("2", "Hostile"),
("3-5", "Unfriendly"),
("6-8", "Unsure"),
("9-11", "Talkative"),
("12", "Helpful"),
]
initiative = [
('1-3', "Enemy acts first"),
('4-6', "PC acts first"),
("1-3", "Enemy acts first"),
("4-6", "PC acts first"),
]
@ -377,4 +625,3 @@ death_and_dismemberment = [
"rattled", # -1d4 WIS
"disfigured", # -1d4 CHA
]

View file

@ -28,12 +28,13 @@ from evennia.utils.evtable import EvTable
from .enums import Ability
from .random_tables import (
character_generation as chargen_table,
death_and_dismemberment as death_table
death_and_dismemberment as death_table,
)
# Basic rolls
class EvAdventureRollEngine:
"""
This groups all dice rolls of EvAdventure. These could all have been normal functions, but we
@ -66,10 +67,11 @@ class EvAdventureRollEngine:
"""
max_diesize = 1000
roll_string = roll_string.lower()
if 'd' not in roll_string:
raise TypeError(f"Dice roll '{roll_string}' was not recognized. "
"Must be `<number>d<dicesize>`.")
number, diesize = roll_string.split('d', 1)
if "d" not in roll_string:
raise TypeError(
f"Dice roll '{roll_string}' was not recognized. " "Must be `<number>d<dicesize>`."
)
number, diesize = roll_string.split("d", 1)
try:
number = int(number)
diesize = int(diesize)
@ -104,8 +106,15 @@ class EvAdventureRollEngine:
else:
return min(self.roll("1d20"), self.roll("1d20"))
def saving_throw(self, character, bonus_type=Ability.STR, target=15,
advantage=False, disadvantage=False, modifier=0):
def saving_throw(
self,
character,
bonus_type=Ability.STR,
target=15,
advantage=False,
disadvantage=False,
modifier=0,
):
"""
A saving throw without a clear enemy to beat. In _Knave_ all unopposed saving
throws always tries to beat 15, so (d20 + bonus + modifier) > 15.
@ -142,9 +151,15 @@ class EvAdventureRollEngine:
return (dice_roll + bonus + modifier) > target, quality
def opposed_saving_throw(
self, attacker, defender,
attack_type=Ability.STR, defense_type=Ability.ARMOR,
advantage=False, disadvantage=False, modifier=0):
self,
attacker,
defender,
attack_type=Ability.STR,
defense_type=Ability.ARMOR,
advantage=False,
disadvantage=False,
modifier=0,
):
"""
An saving throw that tries to beat an active opposing side.
@ -167,10 +182,14 @@ class EvAdventureRollEngine:
"""
defender_defense = getattr(defender, defense_type.value, 1) + 10
return self.saving_throw(attacker, bonus_type=attack_type,
return self.saving_throw(
attacker,
bonus_type=attack_type,
target=defender_defense,
advantage=advantage, disadvantage=disadvantage,
modifier=modifier)
advantage=advantage,
disadvantage=disadvantage,
modifier=modifier,
)
def roll_random_table(self, dieroll, table_choices):
"""
@ -204,7 +223,7 @@ class EvAdventureRollEngine:
min_range = 10**6
for (valrange, choice) in table_choices:
minval, *maxval = valrange.split('-', 1)
minval, *maxval = valrange.split("-", 1)
minval = abs(int(minval))
maxval = abs(int(maxval[0]) if maxval else minval)
@ -240,7 +259,7 @@ class EvAdventureRollEngine:
bool: False if morale roll failed, True otherwise.
"""
return self.roll('2d6') <= defender.morale
return self.roll("2d6") <= defender.morale
def heal(self, character, amount):
"""
@ -265,7 +284,7 @@ class EvAdventureRollEngine:
int: How much HP was healed. This is never more than how damaged we are.
"""
self.heal(character, self.roll('1d8') + character.constitution)
self.heal(character, self.roll("1d8") + character.constitution)
death_map = {
"weakened": "strength",
@ -282,7 +301,7 @@ class EvAdventureRollEngine:
"""
result = self.roll_random_table('1d8', death_table)
result = self.roll_random_table("1d8", death_table)
if result == "dead":
character.handle_death()
else:
@ -304,16 +323,15 @@ class EvAdventureRollEngine:
character.hp = new_hp
character.msg(
"~" * 78 +
"\n|yYou survive your brush with death, "
"~" * 78 + "\n|yYou survive your brush with death, "
f"but are |r{result.upper()}|y and permenently |rlose {loss} {abi}|y.|n\n"
f"|GYou recover |g{new_hp}|G health|.\n"
+ "~" * 78
f"|GYou recover |g{new_hp}|G health|.\n" + "~" * 78
)
# character generation
class EvAdventureCharacterGeneration:
"""
This collects all the rules for generating a new character. An instance of this class can be
@ -341,6 +359,7 @@ class EvAdventureCharacterGeneration:
there is no GM to adjudicate a different choice).
"""
def __init__(self):
"""
Initialize starting values
@ -351,7 +370,7 @@ class EvAdventureCharacterGeneration:
roll_engine = EvAdventureRollEngine()
# name will likely be modified later
self.name = roll_engine.roll_random_table('1d282', chargen_table['name'])
self.name = roll_engine.roll_random_table("1d282", chargen_table["name"])
# base attribute bonuses (flat +1 bonus)
self.strength = 2
@ -362,17 +381,17 @@ class EvAdventureCharacterGeneration:
self.charisma = 2
# physical attributes (only for rp purposes)
self.physique = roll_engine.roll_random_table('1d20', chargen_table['physique'])
self.face = roll_engine.roll_random_table('1d20', chargen_table['face'])
self.skin = roll_engine.roll_random_table('1d20', chargen_table['skin'])
self.hair = roll_engine.roll_random_table('1d20', chargen_table['hair'])
self.clothing = roll_engine.roll_random_table('1d20', chargen_table['clothing'])
self.speech = roll_engine.roll_random_table('1d20', chargen_table['speech'])
self.virtue = roll_engine.roll_random_table('1d20', chargen_table['virtue'])
self.vice = roll_engine.roll_random_table('1d20', chargen_table['vice'])
self.background = roll_engine.roll_random_table('1d20', chargen_table['background'])
self.misfortune = roll_engine.roll_random_table('1d20', chargen_table['misfortune'])
self.alignment = roll_engine.roll_random_table('1d20', chargen_table['alignment'])
self.physique = roll_engine.roll_random_table("1d20", chargen_table["physique"])
self.face = roll_engine.roll_random_table("1d20", chargen_table["face"])
self.skin = roll_engine.roll_random_table("1d20", chargen_table["skin"])
self.hair = roll_engine.roll_random_table("1d20", chargen_table["hair"])
self.clothing = roll_engine.roll_random_table("1d20", chargen_table["clothing"])
self.speech = roll_engine.roll_random_table("1d20", chargen_table["speech"])
self.virtue = roll_engine.roll_random_table("1d20", chargen_table["virtue"])
self.vice = roll_engine.roll_random_table("1d20", chargen_table["vice"])
self.background = roll_engine.roll_random_table("1d20", chargen_table["background"])
self.misfortune = roll_engine.roll_random_table("1d20", chargen_table["misfortune"])
self.alignment = roll_engine.roll_random_table("1d20", chargen_table["alignment"])
# same for all
self.exploration_speed = 120
@ -383,22 +402,23 @@ class EvAdventureCharacterGeneration:
self.level = 1
# random equipment
self.armor = roll_engine.roll_random_table('1d20', chargen_table['armor'])
self.armor = roll_engine.roll_random_table("1d20", chargen_table["armor"])
_helmet_and_shield = roll_engine.roll_random_table(
'1d20', chargen_table["helmets and shields"])
"1d20", chargen_table["helmets and shields"]
)
self.helmet = "helmet" if "helmet" in _helmet_and_shield else "none"
self.shield = "shield" if "shield" in _helmet_and_shield else "none"
self.weapon = roll_engine.roll_random_table('1d20', chargen_table["starting weapon"])
self.weapon = roll_engine.roll_random_table("1d20", chargen_table["starting weapon"])
self.backpack = [
"ration",
"ration",
roll_engine.roll_random_table('1d20', chargen_table["dungeoning gear"]),
roll_engine.roll_random_table('1d20', chargen_table["dungeoning gear"]),
roll_engine.roll_random_table('1d20', chargen_table["general gear 1"]),
roll_engine.roll_random_table('1d20', chargen_table["general gear 2"]),
roll_engine.roll_random_table("1d20", chargen_table["dungeoning gear"]),
roll_engine.roll_random_table("1d20", chargen_table["dungeoning gear"]),
roll_engine.roll_random_table("1d20", chargen_table["general gear 1"]),
roll_engine.roll_random_table("1d20", chargen_table["general gear 2"]),
]
def build_desc(self):
@ -489,12 +509,14 @@ class EvAdventureCharacterGeneration:
# character improvement
class EvAdventureImprovement:
"""
Handle XP gains and level upgrades. Grouped in a class in order to
make it easier to override the mechanism.
"""
xp_per_level = 1000
amount_of_abilities_to_upgrade = 3
max_ability_bonus = 10 # bonus +10, defense 20
@ -546,12 +568,14 @@ class EvAdventureImprovement:
except AttributeError:
pass
character.hp_max = max(character.max_hp + 1,
EvAdventureRollEngine.roll(f"{character.level}d8"))
character.hp_max = max(
character.max_hp + 1, EvAdventureRollEngine.roll(f"{character.level}d8")
)
# character sheet visualization
class EvAdventureCharacterSheet:
"""
Generate a character sheet. This is grouped in a class in order to make
@ -598,7 +622,7 @@ class EvAdventureCharacterSheet:
equipment_table = EvTable(
table=[equipment[i : i + 10] for i in range(0, len(equipment), 10)]
)
form = EvForm({"FORMCHAR": 'x', "TABLECHAR": 'c', "SHEET": sheet})
form = EvForm({"FORMCHAR": "x", "TABLECHAR": "c", "SHEET": sheet})
form.map(
cells={
1: character.key,
@ -610,12 +634,12 @@ class EvAdventureCharacterSheet:
7: f"{character.hp}/{character.hp_max}",
8: character.xp,
9: character.exploration_speed,
'A': character.combat_speed,
'B': character.db.desc,
"A": character.combat_speed,
"B": character.db.desc,
},
tables={
1: equipment_table,
}
},
)
return str(form)

View file

@ -14,25 +14,33 @@ class EvAdventureMixin:
Provides a set of pre-made characters.
"""
def setUp(self):
super().setUp()
self.character = create.create_object(EvAdventureCharacter, key="testchar")
self.helmet = create.create_object(
EvAdventureObject, key="helmet",
attributes=[("inventory_use_slot", enums.WieldLocation.HEAD),
("armor", 1)])
EvAdventureObject,
key="helmet",
attributes=[("inventory_use_slot", enums.WieldLocation.HEAD), ("armor", 1)],
)
self.shield = create.create_object(
EvAdventureObject, key="shield",
attributes=[("inventory_use_slot", enums.WieldLocation.SHIELD_HAND),
("armor", 1)])
EvAdventureObject,
key="shield",
attributes=[("inventory_use_slot", enums.WieldLocation.SHIELD_HAND), ("armor", 1)],
)
self.armor = create.create_object(
EvAdventureObject, key="armor",
attributes=[("inventory_use_slot", enums.WieldLocation.BODY),
("armor", 11)])
EvAdventureObject,
key="armor",
attributes=[("inventory_use_slot", enums.WieldLocation.BODY), ("armor", 11)],
)
self.weapon = create.create_object(
EvAdventureObject, key="weapon",
attributes=[("inventory_use_slot", enums.WieldLocation.WEAPON_HAND)])
EvAdventureObject,
key="weapon",
attributes=[("inventory_use_slot", enums.WieldLocation.WEAPON_HAND)],
)
self.big_weapon = create.create_object(
EvAdventureObject, key="big_weapon",
attributes=[("inventory_use_slot", enums.WieldLocation.TWO_HANDS)])
EvAdventureObject,
key="big_weapon",
attributes=[("inventory_use_slot", enums.WieldLocation.TWO_HANDS)],
)
self.item = create.create_object(EvAdventureObject, key="backpack item")

View file

@ -16,8 +16,12 @@ class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
Test the turn-based combat-handler implementation.
"""
@patch("evennia.contrib.tutorials.evadventure.combat_turnbased"
".EvAdventureCombatHandler.interval", new=-1)
@patch(
"evennia.contrib.tutorials.evadventure.combat_turnbased"
".EvAdventureCombatHandler.interval",
new=-1,
)
def setUp(self):
super().setUp()
self.combathandler = combat_turnbased.EvAdventureCombatHandler.objects.create()
@ -50,8 +54,6 @@ class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
def test_attack(self, mock_randint):
mock_randint = 8
self.combathandler.register_action(
combat_turnbased.CombatActionAttack,
self.combatant, self.target)
combat_turnbased.CombatActionAttack, self.combatant, self.target
)
self.combathandler._end_turn()

View file

@ -19,6 +19,7 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
Test the roll engine in the rules module. This is the core of any RPG.
"""
def setUp(self):
super().setUp()
self.roll_engine = rules.EvAdventureRollEngine()
@ -40,15 +41,15 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
def test_roll_limits(self):
with self.assertRaises(TypeError):
self.roll_engine.roll('100d6', max_number=10) # too many die
self.roll_engine.roll("100d6", max_number=10) # too many die
with self.assertRaises(TypeError):
self.roll_engine.roll('100') # no d
self.roll_engine.roll("100") # no d
with self.assertRaises(TypeError):
self.roll_engine.roll('dummy') # non-numerical
self.roll_engine.roll("dummy") # non-numerical
with self.assertRaises(TypeError):
self.roll_engine.roll('Ad4') # non-numerical
self.roll_engine.roll("Ad4") # non-numerical
with self.assertRaises(TypeError):
self.roll_engine.roll('1d10000') # limit is d1000
self.roll_engine.roll("1d10000") # limit is d1000
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
def test_roll_with_advantage_disadvantage(self, mock_randint):
@ -61,19 +62,18 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
# cancel each other out
self.assertEqual(
self.roll_engine.roll_with_advantage_or_disadvantage(
disadvantage=True, advantage=True), 9)
self.roll_engine.roll_with_advantage_or_disadvantage(disadvantage=True, advantage=True),
9,
)
mock_randint.assert_called_once()
mock_randint.reset_mock()
# run with advantage/disadvantage
self.assertEqual(
self.roll_engine.roll_with_advantage_or_disadvantage(advantage=True), 9)
self.assertEqual(self.roll_engine.roll_with_advantage_or_disadvantage(advantage=True), 9)
mock_randint.assert_has_calls([call(1, 20), call(1, 20)])
mock_randint.reset_mock()
self.assertEqual(
self.roll_engine.roll_with_advantage_or_disadvantage(disadvantage=True), 9)
self.assertEqual(self.roll_engine.roll_with_advantage_or_disadvantage(disadvantage=True), 9)
mock_randint.assert_has_calls([call(1, 20), call(1, 20)])
mock_randint.reset_mock()
@ -86,39 +86,40 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
character.dexterity = 1
self.assertEqual(
self.roll_engine.saving_throw(character, bonus_type=enums.Ability.STR),
(False, None))
self.roll_engine.saving_throw(character, bonus_type=enums.Ability.STR), (False, None)
)
self.assertEqual(
self.roll_engine.saving_throw(character, bonus_type=enums.Ability.DEX, modifier=1),
(False, None))
(False, None),
)
self.assertEqual(
self.roll_engine.saving_throw(
character,
advantage=True,
bonus_type=enums.Ability.DEX, modifier=6),
(False, None))
character, advantage=True, bonus_type=enums.Ability.DEX, modifier=6
),
(False, None),
)
self.assertEqual(
self.roll_engine.saving_throw(
character,
disadvantage=True,
bonus_type=enums.Ability.DEX, modifier=7),
(True, None))
character, disadvantage=True, bonus_type=enums.Ability.DEX, modifier=7
),
(True, None),
)
mock_randint.return_value = 1
self.assertEqual(
self.roll_engine.saving_throw(
character,
disadvantage=True,
bonus_type=enums.Ability.STR, modifier=2),
(False, enums.Ability.CRITICAL_FAILURE))
character, disadvantage=True, bonus_type=enums.Ability.STR, modifier=2
),
(False, enums.Ability.CRITICAL_FAILURE),
)
mock_randint.return_value = 20
self.assertEqual(
self.roll_engine.saving_throw(
character,
disadvantage=True,
bonus_type=enums.Ability.STR, modifier=2),
(True, enums.Ability.CRITICAL_SUCCESS))
character, disadvantage=True, bonus_type=enums.Ability.STR, modifier=2
),
(True, enums.Ability.CRITICAL_SUCCESS),
)
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
def test_opposed_saving_throw(self, mock_randint):
@ -130,18 +131,19 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
self.assertEqual(
self.roll_engine.opposed_saving_throw(
attacker, defender,
attack_type=enums.Ability.STR, defense_type=enums.Ability.ARMOR
attacker, defender, attack_type=enums.Ability.STR, defense_type=enums.Ability.ARMOR
),
(False, None)
(False, None),
)
self.assertEqual(
self.roll_engine.opposed_saving_throw(
attacker, defender,
attack_type=enums.Ability.STR, defense_type=enums.Ability.ARMOR,
modifier=2
attacker,
defender,
attack_type=enums.Ability.STR,
defense_type=enums.Ability.ARMOR,
modifier=2,
),
(True, None)
(True, None),
)
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
@ -150,36 +152,40 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation['physique']),
"scrawny"
"1d20", random_tables.character_generation["physique"]
),
"scrawny",
)
self.assertEqual(
self.roll_engine.roll_random_table("1d20", random_tables.character_generation["vice"]),
"irascible",
)
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation['vice']),
"irascible"
"1d20", random_tables.character_generation["alignment"]
),
"neutrality",
)
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation['alignment']),
"neutrality"
)
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation['helmets and shields']),
"no helmet or shield"
"1d20", random_tables.character_generation["helmets and shields"]
),
"no helmet or shield",
)
# testing faulty rolls outside of the table ranges
mock_randint.return_value = 25
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation['helmets and shields']),
"helmet and shield"
"1d20", random_tables.character_generation["helmets and shields"]
),
"helmet and shield",
)
mock_randint.return_value = -10
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation['helmets and shields']),
"no helmet or shield"
"1d20", random_tables.character_generation["helmets and shields"]
),
"no helmet or shield",
)
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
@ -246,18 +252,20 @@ class EvAdventureCharacterGenerationTest(BaseEvenniaTest):
self.assertEqual(self.chargen.misfortune, "exiled")
self.assertEqual(self.chargen.armor, "gambeson")
self.assertEqual(self.chargen.shield, "shield")
self.assertEqual(self.chargen.backpack, ['ration', 'ration', 'waterskin',
'waterskin', 'drill', 'twine'])
self.assertEqual(
self.chargen.backpack, ["ration", "ration", "waterskin", "waterskin", "drill", "twine"]
)
def test_build_desc(self):
self.assertEqual(
self.chargen.build_desc(),
"Herbalist. Wears stained clothes, and has hoarse speech. Has a scrawny physique, "
"a broken face, pockmarked skin and greased hair. Is honest, but irascible. "
"Has been exiled in the past. Favors neutrality."
"Has been exiled in the past. Favors neutrality.",
)
@parameterized.expand([
@parameterized.expand(
[
# source, target, value, new_source_val, new_target_val
(enums.Ability.CON, enums.Ability.STR, 1, 1, 3),
(enums.Ability.INT, enums.Ability.DEX, 1, 1, 3),
@ -265,13 +273,12 @@ class EvAdventureCharacterGenerationTest(BaseEvenniaTest):
(enums.Ability.STR, enums.Ability.WIS, 1, 1, 3),
(enums.Ability.WIS, enums.Ability.CHA, 1, 1, 3),
(enums.Ability.DEX, enums.Ability.DEX, 1, 2, 2),
])
]
)
def test_adjust_attribute(self, source, target, value, new_source_val, new_target_val):
self.chargen.adjust_attribute(source, target, value)
self.assertEqual(
getattr(self.chargen, source.value), new_source_val, f"{source}->{target}")
self.assertEqual(
getattr(self.chargen, target.value), new_target_val, f"{source}->{target}")
self.assertEqual(getattr(self.chargen, source.value), new_source_val, f"{source}->{target}")
self.assertEqual(getattr(self.chargen, target.value), new_target_val, f"{source}->{target}")
def test_adjust_consecutive(self):
# gradually shift all to STR (starts at 2)
@ -311,6 +318,7 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
Test the equipment mechanism.
"""
def _get_empty_slots(self):
return {
enums.WieldLocation.BACKPACK: [],
@ -324,15 +332,17 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
def test_equipmenthandler_max_slots(self):
self.assertEqual(self.character.equipment.max_slots, 11)
@parameterized.expand([
@parameterized.expand(
[
# size, pass_validation?
(1, True),
(2, True),
(11, True),
(12, False),
(20, False),
(25, False)
])
(25, False),
]
)
def test_validate_slot_usage(self, size, is_ok):
obj = MagicMock()
obj.size = size
@ -343,7 +353,8 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
with self.assertRaises(characters.EquipmentError):
self.character.equipment.validate_slot_usage(obj)
@parameterized.expand([
@parameterized.expand(
[
# item, where
("helmet", enums.WieldLocation.HEAD),
("shield", enums.WieldLocation.SHIELD_HAND),
@ -351,7 +362,8 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
("weapon", enums.WieldLocation.WEAPON_HAND),
("big_weapon", enums.WieldLocation.TWO_HANDS),
("item", enums.WieldLocation.BACKPACK),
])
]
)
def test_use(self, itemname, where):
self.assertEqual(self.character.equipment.slots, self._get_empty_slots())
@ -366,32 +378,32 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
def test_store(self):
self.character.equipment.store(self.weapon)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], None)
self.assertTrue(
self.weapon in self.character.equipment.slots[enums.WieldLocation.BACKPACK])
self.assertTrue(self.weapon in self.character.equipment.slots[enums.WieldLocation.BACKPACK])
def test_two_handed_exclusive(self):
"""Two-handed weapons can't be used together with weapon+shield"""
self.character.equipment.use(self.big_weapon)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], self.big_weapon)
self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], self.big_weapon
)
# equipping sword or shield removes two-hander
self.character.equipment.use(self.shield)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], None)
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield
)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], None)
self.character.equipment.use(self.weapon)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], self.weapon)
self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], self.weapon
)
# the two-hander removes the two weapons
self.character.equipment.use(self.big_weapon)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], self.big_weapon)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], None)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], None)
self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], self.big_weapon
)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], None)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], None)
def test_remove__with_obj(self):
self.character.equipment.use(self.shield)
@ -399,16 +411,19 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
self.character.equipment.store(self.weapon)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.BACKPACK],
[self.item, self.weapon])
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield
)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.BACKPACK], [self.item, self.weapon]
)
self.assertEqual(self.character.equipment.remove(self.shield), [self.shield])
self.assertEqual(self.character.equipment.remove(self.item), [self.item])
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], None)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.BACKPACK],
[self.weapon])
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.BACKPACK], [self.weapon]
)
def test_remove__with_slot(self):
self.character.equipment.use(self.shield)
@ -416,17 +431,20 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
self.character.equipment.store(self.helmet)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.BACKPACK],
[self.item, self.helmet])
self.assertEqual(self.character.equipment.remove(enums.WieldLocation.SHIELD_HAND),
[self.shield])
self.assertEqual(self.character.equipment.remove(enums.WieldLocation.BACKPACK),
[self.item, self.helmet])
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield
)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.BACKPACK], [self.item, self.helmet]
)
self.assertEqual(
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], None)
self.character.equipment.remove(enums.WieldLocation.SHIELD_HAND), [self.shield]
)
self.assertEqual(
self.character.equipment.remove(enums.WieldLocation.BACKPACK), [self.item, self.helmet]
)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], None)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.BACKPACK], [])
def test_properties(self):

View file

@ -13,6 +13,3 @@ from . import enums
from . import combat_turnbased
from . import rules
from . import random_tables

View file

@ -2,5 +2,3 @@
Various utilities.
"""