diff --git a/evennia/contrib/tutorials/evadventure/characters.py b/evennia/contrib/tutorials/evadventure/characters.py index d0f3d14333..3c2d4a5ea5 100644 --- a/evennia/contrib/tutorials/evadventure/characters.py +++ b/evennia/contrib/tutorials/evadventure/characters.py @@ -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) diff --git a/evennia/contrib/tutorials/evadventure/combat_turnbased.py b/evennia/contrib/tutorials/evadventure/combat_turnbased.py index 44845693fe..1f9ed504ad 100644 --- a/evennia/contrib/tutorials/evadventure/combat_turnbased.py +++ b/evennia/contrib/tutorials/evadventure/combat_turnbased.py @@ -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 diff --git a/evennia/contrib/tutorials/evadventure/enums.py b/evennia/contrib/tutorials/evadventure/enums.py index c6c24d7b97..8cd934fec1 100644 --- a/evennia/contrib/tutorials/evadventure/enums.py +++ b/evennia/contrib/tutorials/evadventure/enums.py @@ -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" diff --git a/evennia/contrib/tutorials/evadventure/objects.py b/evennia/contrib/tutorials/evadventure/objects.py index 499571d9a6..b08ffe1e54 100644 --- a/evennia/contrib/tutorials/evadventure/objects.py +++ b/evennia/contrib/tutorials/evadventure/objects.py @@ -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) diff --git a/evennia/contrib/tutorials/evadventure/quests.py b/evennia/contrib/tutorials/evadventure/quests.py index 0eefba39d1..54fcb52423 100644 --- a/evennia/contrib/tutorials/evadventure/quests.py +++ b/evennia/contrib/tutorials/evadventure/quests.py @@ -31,6 +31,7 @@ class EvAdventureQuest: check_ and complete_ """ + # 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. """ - - - diff --git a/evennia/contrib/tutorials/evadventure/random_tables.py b/evennia/contrib/tutorials/evadventure/random_tables.py index cac6566369..12a81dd167 100644 --- a/evennia/contrib/tutorials/evadventure/random_tables.py +++ b/evennia/contrib/tutorials/evadventure/random_tables.py @@ -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 ] - diff --git a/evennia/contrib/tutorials/evadventure/rules.py b/evennia/contrib/tutorials/evadventure/rules.py index 150458d035..595e572c06 100644 --- a/evennia/contrib/tutorials/evadventure/rules.py +++ b/evennia/contrib/tutorials/evadventure/rules.py @@ -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 `d`.") - 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 `d`." + ) + 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) diff --git a/evennia/contrib/tutorials/evadventure/tests/mixins.py b/evennia/contrib/tutorials/evadventure/tests/mixins.py index 39e687c706..04746a1734 100644 --- a/evennia/contrib/tutorials/evadventure/tests/mixins.py +++ b/evennia/contrib/tutorials/evadventure/tests/mixins.py @@ -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") diff --git a/evennia/contrib/tutorials/evadventure/tests/test_combat.py b/evennia/contrib/tutorials/evadventure/tests/test_combat.py index 4629fd2063..abff04ff81 100644 --- a/evennia/contrib/tutorials/evadventure/tests/test_combat.py +++ b/evennia/contrib/tutorials/evadventure/tests/test_combat.py @@ -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() - - diff --git a/evennia/contrib/tutorials/evadventure/tests/test_rules.py b/evennia/contrib/tutorials/evadventure/tests/test_rules.py index 65dee75289..6db9781444 100644 --- a/evennia/contrib/tutorials/evadventure/tests/test_rules.py +++ b/evennia/contrib/tutorials/evadventure/tests/test_rules.py @@ -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): diff --git a/evennia/contrib/tutorials/evadventure/tests/tests.py b/evennia/contrib/tutorials/evadventure/tests/tests.py index 2be289d10c..5fb5a6fbaa 100644 --- a/evennia/contrib/tutorials/evadventure/tests/tests.py +++ b/evennia/contrib/tutorials/evadventure/tests/tests.py @@ -13,6 +13,3 @@ from . import enums from . import combat_turnbased from . import rules from . import random_tables - - - diff --git a/evennia/contrib/tutorials/evadventure/utils.py b/evennia/contrib/tutorials/evadventure/utils.py index fc7da8fb52..070f252ad5 100644 --- a/evennia/contrib/tutorials/evadventure/utils.py +++ b/evennia/contrib/tutorials/evadventure/utils.py @@ -2,5 +2,3 @@ Various utilities. """ - -