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 "
f"remaining, {obj.key} needs $int2str({size}) "
f"$pluralize(slot, {size})).")
raise EquipmentError(
f"Equipment full ($int2str({slots_left}) slots "
f"remaining, {obj.key} needs $int2str({size}) "
f"$pluralize(slot, {size}))."
)
return True
@property
@ -120,11 +122,13 @@ class EquipmentHandler:
"""
slots = self.slots
return sum((
getattr(slots[WieldLocation.BODY], "armor", 0),
getattr(slots[WieldLocation.SHIELD_HAND], "armor", 0),
getattr(slots[WieldLocation.HEAD], "armor", 0),
))
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 "
"on your next action against the same target [range 0-1, one use per combat. "
"Bonus lasts for two turns].")
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]."
)
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,
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
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,37 +247,42 @@ class CombatActionFlee(CombatAction):
# it's safe to do this twice
self.combathandler.flee(combatant)
class CombatActionChase(CombatAction):
"""
Chasing is a way to counter a 'flee' action. It is a maximum movement towards the target
and will mean a DEX contest, if the fleeing target loses, they are moved back from
'disengaging' range and remain in combat at the new distance (likely 2 if max movement
is 2). Advantage/disadvantage are considered.
"""
Chasing is a way to counter a 'flee' action. It is a maximum movement towards the target
and will mean a DEX contest, if the fleeing target loses, they are moved back from
'disengaging' range and remain in combat at the new distance (likely 2 if max movement
is 2). Advantage/disadvantage are considered.
"""
key = "chase"
priority = -5 # checked last
"""
attack_type = Ability.DEX # or is it CON?
defense_type = Ability.DEX
key = "chase"
priority = -5 # checked last
def use(self, combatant, fleeing_target, *args, **kwargs):
attack_type = Ability.DEX # or is it CON?
defense_type = Ability.DEX
advantage = bool(self.advantage_matrix[attacker].pop(fleeing_target, False))
disadvantage = bool(self.disadvantage_matrix[attacker].pop(fleeing_target, False))
def use(self, combatant, fleeing_target, *args, **kwargs):
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
combatant, fleeing_target,
attack_type=self.attack_type, defense_type=self.defense_type,
advantage=advantage, disadvantage=disadvantage
)
advantage = bool(self.advantage_matrix[attacker].pop(fleeing_target, False))
disadvantage = bool(self.disadvantage_matrix[attacker].pop(fleeing_target, False))
if is_success:
# managed to stop the target from fleeing/disengaging
self.combatant.unflee(fleeing_target)
else:
pass # they are getting away!
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
combatant,
fleeing_target,
attack_type=self.attack_type,
defense_type=self.defense_type,
advantage=advantage,
disadvantage=disadvantage,
)
if is_success:
# managed to stop the target from fleeing/disengaging
self.combatant.unflee(fleeing_target)
else:
pass # they are getting away!
class EvAdventureCombatHandler(DefaultScript):
@ -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,
target=defender_defense,
advantage=advantage, disadvantage=disadvantage,
modifier=modifier)
return self.saving_throw(
attacker,
bonus_type=attack_type,
target=defender_defense,
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
@ -596,9 +620,9 @@ class EvAdventureCharacterSheet:
equipment = character.equipment.wielded + character.equipment.worn + character.carried
# divide into chunks of max 10 length (to go into two columns)
equipment_table = EvTable(
table=[equipment[i: i + 10] for i in range(0, len(equipment), 10)]
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

@ -8,7 +8,7 @@ from evennia.utils.test_resources import BaseEvenniaTest
from evennia.utils import create
from .mixins import EvAdventureMixin
from .. import combat_turnbased
from .. charactersd import EvAdventureCharacter
from ..charactersd import EvAdventureCharacter
class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
@ -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")
@ -202,11 +208,11 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
mock_randint.return_value = 5
self.roll_engine.heal_from_rest(character)
self.assertEqual(character.hp, 7) # hp + 1d8 + consititution bonus
self.assertEqual(character.hp, 7) # hp + 1d8 + consititution bonus
mock_randint.assert_called_with(1, 8) # 1d8
self.roll_engine.heal_from_rest(character)
self.assertEqual(character.hp, 8) # can't have more than max hp
self.assertEqual(character.hp, 8) # can't have more than max hp
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
def test_roll_death(self, mock_randint):
@ -246,32 +252,33 @@ 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([
# 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),
(enums.Ability.CHA, enums.Ability.CON, 1, 1, 3),
(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),
])
@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),
(enums.Ability.CHA, enums.Ability.CON, 1, 1, 3),
(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([
# size, pass_validation?
(1, True),
(2, True),
(11, True),
(12, False),
(20, False),
(25, False)
])
@parameterized.expand(
[
# size, pass_validation?
(1, True),
(2, True),
(11, True),
(12, False),
(20, False),
(25, False),
]
)
def test_validate_slot_usage(self, size, is_ok):
obj = MagicMock()
obj.size = size
@ -343,15 +353,17 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
with self.assertRaises(characters.EquipmentError):
self.character.equipment.validate_slot_usage(obj)
@parameterized.expand([
# item, where
("helmet", enums.WieldLocation.HEAD),
("shield", enums.WieldLocation.SHIELD_HAND),
("armor", enums.WieldLocation.BODY),
("weapon", enums.WieldLocation.WEAPON_HAND),
("big_weapon", enums.WieldLocation.TWO_HANDS),
("item", enums.WieldLocation.BACKPACK),
])
@parameterized.expand(
[
# item, where
("helmet", enums.WieldLocation.HEAD),
("shield", enums.WieldLocation.SHIELD_HAND),
("armor", enums.WieldLocation.BODY),
("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.
"""