Resolve unit tests

This commit is contained in:
Griatch 2022-09-17 23:37:08 +02:00
parent a4eff902cc
commit 705d47fe47
14 changed files with 291 additions and 350 deletions

View file

@ -103,7 +103,7 @@ from the _Knave_ rulebook. While we added the ability to roll on a random table
```
# in mygame/evadventure/random_tables.py
character_generation = {
chargen_tables = {
"physique": [
"athletic", "brawny", "corpulent", "delicate", "gaunt", "hulking", "lanky",
"ripped", "rugged", "scrawny", "short", "sinewy", "slender", "flabby",
@ -135,20 +135,19 @@ During character generation we will need an entity to store/retain the changes,
```python
# in mygame/evadventure/chargen.py
from .random_tables import chargen_table
from .random_tables import chargen_tables
from .rules import dice
class TemporaryCharacterSheet:
def __init__(self):
self.ability_changes = 0 # how many times we tried swap abilities
def _random_ability(self):
return min(dice.roll("1d6"), dice.roll("1d6"), dice.roll("1d6"))
def generate(self):
def __init__(self):
self.ability_changes = 0 # how many times we tried swap abilities
# name will likely be modified later
self.name = dice.roll_random_table("1d282", chargen_table["name"])
self.name = dice.roll_random_table("1d282", chargen_tables["name"])
# base attribute values
self.strength = self._random_ability()
@ -159,17 +158,17 @@ class TemporaryCharacterSheet:
self.charisma = self._random_ability()
# physical attributes (only for rp purposes)
physique = dice.roll_random_table("1d20", chargen_table["physique"])
face = dice.roll_random_table("1d20", chargen_table["face"])
skin = dice.roll_random_table("1d20", chargen_table["skin"])
hair = dice.roll_random_table("1d20", chargen_table["hair"])
clothing = dice.roll_random_table("1d20", chargen_table["clothing"])
speech = dice.roll_random_table("1d20", chargen_table["speech"])
virtue = dice.roll_random_table("1d20", chargen_table["virtue"])
vice = dice.roll_random_table("1d20", chargen_table["vice"])
background = dice.roll_random_table("1d20", chargen_table["background"])
misfortune = dice.roll_random_table("1d20", chargen_table["misfortune"])
alignment = dice.roll_random_table("1d20", chargen_table["alignment"])
physique = dice.roll_random_table("1d20", chargen_tables["physique"])
face = dice.roll_random_table("1d20", chargen_tables["face"])
skin = dice.roll_random_table("1d20", chargen_tables["skin"])
hair = dice.roll_random_table("1d20", chargen_tables["hair"])
clothing = dice.roll_random_table("1d20", chargen_tables["clothing"])
speech = dice.roll_random_table("1d20", chargen_tables["speech"])
virtue = dice.roll_random_table("1d20", chargen_tables["virtue"])
vice = dice.roll_random_table("1d20", chargen_tables["vice"])
background = dice.roll_random_table("1d20", chargen_tables["background"])
misfortune = dice.roll_random_table("1d20", chargen_tables["misfortune"])
alignment = dice.roll_random_table("1d20", chargen_tables["alignment"])
self.desc = (
f"You are {physique} with a {face} face, {skin} skin, {hair} hair, {speech} speech,"
@ -185,21 +184,21 @@ class TemporaryCharacterSheet:
self.level = 1
# random equipment
self.armor = dice.roll_random_table("1d20", chargen_table["armor"])
self.armor = dice.roll_random_table("1d20", chargen_tables["armor"])
_helmet_and_shield = dice.roll_random_table("1d20", chargen_table["helmets and shields"])
_helmet_and_shield = dice.roll_random_table("1d20", chargen_tables["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 = dice.roll_random_table("1d20", chargen_table["starting weapon"])
self.weapon = dice.roll_random_table("1d20", chargen_tables["starting weapon"])
self.backpack = [
"ration",
"ration",
dice.roll_random_table("1d20", chargen_table["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_table["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_table["general gear 1"]),
dice.roll_random_table("1d20", chargen_table["general gear 2"]),
dice.roll_random_table("1d20", chargen_tables["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_tables["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_tables["general gear 1"]),
dice.roll_random_table("1d20", chargen_tables["general gear 2"]),
]
```
@ -367,7 +366,6 @@ def start_chargen(caller, session=None):
# this generates all random components of the character
tmp_character = TemporaryCharacterSheet()
tmp_character.generate()
EvMenu(caller, menutree, session=session, tmp_character=tmp_character)

View file

@ -3,12 +3,13 @@ Turnbattle tests.
"""
from mock import patch, MagicMock
from evennia.commands.default.tests import BaseEvenniaCommandTest
from evennia.objects.objects import DefaultRoom
from evennia.utils.create import create_object
from evennia.utils.test_resources import BaseEvenniaTest
from evennia.objects.objects import DefaultRoom
from . import tb_basic, tb_equip, tb_range, tb_items, tb_magic
from mock import MagicMock, patch
from . import tb_basic, tb_equip, tb_items, tb_magic, tb_range
class TestTurnBattleBasicCmd(BaseEvenniaCommandTest):

View file

@ -7,7 +7,7 @@ from evennia.prototypes.spawner import spawn
from evennia.utils.evmenu import EvMenu
from .characters import EvAdventureCharacter
from .random_tables import chargen_table
from .random_tables import chargen_tables
from .rules import dice
_ABILITIES = {
@ -56,21 +56,12 @@ class TemporaryCharacterSheet:
"""
def __init__(self):
# you are only allowed to tweak abilities once
self.ability_changes = 0
def _random_ability(self):
return min(dice.roll("1d6"), dice.roll("1d6"), dice.roll("1d6"))
def generate(self):
"""
Generate random values for character.
"""
def __init__(self):
# name will likely be modified later
self.name = dice.roll_random_table("1d282", chargen_table["name"])
self.name = dice.roll_random_table("1d282", chargen_tables["name"])
# base attribute values
self.strength = self._random_ability()
@ -81,23 +72,22 @@ class TemporaryCharacterSheet:
self.charisma = self._random_ability()
# physical attributes (only for rp purposes)
physique = dice.roll_random_table("1d20", chargen_table["physique"])
face = dice.roll_random_table("1d20", chargen_table["face"])
skin = dice.roll_random_table("1d20", chargen_table["skin"])
hair = dice.roll_random_table("1d20", chargen_table["hair"])
clothing = dice.roll_random_table("1d20", chargen_table["clothing"])
speech = dice.roll_random_table("1d20", chargen_table["speech"])
virtue = dice.roll_random_table("1d20", chargen_table["virtue"])
vice = dice.roll_random_table("1d20", chargen_table["vice"])
background = dice.roll_random_table("1d20", chargen_table["background"])
misfortune = dice.roll_random_table("1d20", chargen_table["misfortune"])
alignment = dice.roll_random_table("1d20", chargen_table["alignment"])
physique = dice.roll_random_table("1d20", chargen_tables["physique"])
face = dice.roll_random_table("1d20", chargen_tables["face"])
skin = dice.roll_random_table("1d20", chargen_tables["skin"])
hair = dice.roll_random_table("1d20", chargen_tables["hair"])
clothing = dice.roll_random_table("1d20", chargen_tables["clothing"])
speech = dice.roll_random_table("1d20", chargen_tables["speech"])
virtue = dice.roll_random_table("1d20", chargen_tables["virtue"])
vice = dice.roll_random_table("1d20", chargen_tables["vice"])
background = dice.roll_random_table("1d20", chargen_tables["background"])
misfortune = dice.roll_random_table("1d20", chargen_tables["misfortune"])
alignment = dice.roll_random_table("1d20", chargen_tables["alignment"])
self.desc = (
f"You are {physique} with a {face} face, {skin} skin, {hair} hair, {speech} speech,"
f" and {clothing} clothing. You were a {background.title()}, but you were"
f" {misfortune} and ended up a knave. You are {virtue} but also {vice}. You are of the"
f" {alignment} alignment."
f"You are {physique} with a {face} face, {skin} skin, {hair} hair, {speech} speech, and"
f" {clothing} clothing. You were a {background.title()}, but you were {misfortune} and"
f" ended up a knave. You are {virtue} but also {vice}. You tend towards {alignment}."
)
# same for all
@ -105,21 +95,21 @@ class TemporaryCharacterSheet:
self.hp = self.hp_max
# random equipment
self.armor = dice.roll_random_table("1d20", chargen_table["armor"])
self.armor = dice.roll_random_table("1d20", chargen_tables["armor"])
_helmet_and_shield = dice.roll_random_table("1d20", chargen_table["helmets and shields"])
_helmet_and_shield = dice.roll_random_table("1d20", chargen_tables["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 = dice.roll_random_table("1d20", chargen_table["starting weapon"])
self.weapon = dice.roll_random_table("1d20", chargen_tables["starting weapon"])
self.backpack = [
"ration",
"ration",
dice.roll_random_table("1d20", chargen_table["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_table["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_table["general gear 1"]),
dice.roll_random_table("1d20", chargen_table["general gear 2"]),
dice.roll_random_table("1d20", chargen_tables["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_tables["dungeoning gear"]),
dice.roll_random_table("1d20", chargen_tables["general gear 1"]),
dice.roll_random_table("1d20", chargen_tables["general gear 2"]),
]
def show_sheet(self):
@ -155,7 +145,7 @@ class TemporaryCharacterSheet:
new_character = create_object(
EvAdventureCharacter,
key=self.name,
attrs=(
attributes=(
("strength", self.strength),
("dexterity", self.dexterity),
("constitution", self.constitution),
@ -183,7 +173,7 @@ class TemporaryCharacterSheet:
for item in self.backpack:
item = spawn(item)
new_character.equipment.store(item)
new_character.equipment.move(item)
return new_character

View file

@ -357,7 +357,7 @@ class CombatActionStunt(CombatAction):
if self.give_advantage:
self.combathandler.gain_advantage(attacker, defender)
self.msg(
f"%You() $conj(gain) advantage against $You(defender.key! "
"%You() $conj(gain) advantage against $You(defender.key! "
f"You must use it within {stunt_duration} turns."
)
else:
@ -398,15 +398,6 @@ class CombatActionUseItem(CombatAction):
def get_help(self, item, *args):
return item.get_help(*args)
def pre_use(self, item, *args, **kwargs):
"""
We tie into the `item.at_pre_use` hook here, which returns False if
the item is not usable (that is, has .uses > 0).
"""
if item.at_pre_use(self.combatant, *args, **kwargs):
item.at_use(self.combatant, *args, **kwargs)
def use(self, item, target, *args, **kwargs):
item.at_use(self.combatant, target, *args, **kwargs)
@ -442,7 +433,7 @@ class CombatActionSwapWieldedWeaponOrSpell(CombatAction):
def use(self, _, item, *args, **kwargs):
# this will make use of the item
self.combatant.equipment.use(item)
self.combatant.equipment.move(item)
class CombatActionFlee(CombatAction):

View file

@ -465,7 +465,7 @@ class EvAdventureDungeonStartRoom(EvAdventureDungeonRoom):
branch_max_life = 60 * 60 * 24 * 7 # 1 week
# allow for a custom room_generator function
room_generator = AttributeProperty(room_generator, autocreate=False)
room_generator = AttributeProperty(lambda: room_generator, autocreate=False)
def get_display_footer(self, looker, **kwargs):
return (

View file

@ -270,13 +270,15 @@ class EquipmentHandler:
# it belongs in backpack, so goes back to it
to_backpack = [obj]
else:
# for others (body, head), just replace whatever's there
replaced = [obj]
# for others (body, head), just replace whatever's there and put the old
# thing in the backpack
to_backpack = [slots[use_slot]]
slots[use_slot] = obj
for to_backpack_obj in to_backpack:
# put stuff in backpack
slots[use_slot].append(to_backpack_obj)
if to_backpack_obj:
slots[WieldLocation.BACKPACK].append(to_backpack_obj)
# store new state
self._save()

View file

@ -5,7 +5,7 @@ Random tables - adopted from _Knave_.
# Character generation tables
character_generation = {
chargen_tables = {
"physique": [
"athletic",
"brawny",

View file

@ -24,11 +24,7 @@ This module presents several singletons to import
"""
from random import randint
from evennia.utils.evform import EvForm
from evennia.utils.evtable import EvTable
from .enums import Ability
from .random_tables import character_generation as chargen_table
from .random_tables import death_and_dismemberment as death_table
# Basic rolls
@ -68,7 +64,7 @@ class EvAdventureRollEngine:
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>`."
f"Dice roll '{roll_string}' was not recognized. Must be `<number>d<dicesize>`."
)
number, diesize = roll_string.split("d", 1)
try:
@ -296,9 +292,6 @@ class EvAdventureRollEngine:
Args:
character (Character): The one resting.
Returns:
int: How much HP was healed. This is never more than how damaged we are.
"""
character.heal(self.roll("1d8") + character.constitution)
@ -334,13 +327,16 @@ class EvAdventureRollEngine:
character.at_death()
else:
# refresh health, but get permanent ability loss
self.heal(character, self.roll("1d4"))
new_hp = self.roll("1d4")
character.heal(new_hp)
setattr(character, abi, current_abi)
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 permanently |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
)

View file

@ -43,4 +43,4 @@ class TestCharacters(BaseEvenniaTest):
# can't get more coins than we have
result = self.character.at_pay(100)
self.assertEqual(result, 40)
self.assertEqual(self.characer.coins, 0)
self.assertEqual(self.character.coins, 0)

View file

@ -0,0 +1,64 @@
"""
Test chargen.
"""
from unittest.mock import MagicMock, patch
from evennia import create_object
from evennia.utils.test_resources import BaseEvenniaTest
from parameterized import parameterized
from .. import chargen, enums, objects
class EvAdventureCharacterGenerationTest(BaseEvenniaTest):
"""
Test the Character generator in the rule engine.
"""
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
def setUp(self, mock_randint):
super().setUp()
mock_randint.return_value = 10
self.chargen = chargen.TemporaryCharacterSheet()
def test_base_chargen(self):
self.assertEqual(self.chargen.strength, 10) # not realistic, due to mock
self.assertEqual(self.chargen.armor, "gambeson")
self.assertEqual(self.chargen.shield, "shield")
self.assertEqual(
self.chargen.backpack, ["ration", "ration", "waterskin", "waterskin", "drill", "twine"]
)
def test_build_desc(self):
self.assertEqual(
self.chargen.desc,
"You are scrawny with a broken face, pockmarked skin, greased hair, hoarse speech, and "
"stained clothing. You were a Herbalist, but you were exiled and ended up a knave. You "
"are honest but also irascible. You tend towards neutrality.",
)
@patch("evennia.contrib.tutorials.evadventure.chargen.spawn")
def test_apply(self, mock_spawn):
gambeson = create_object(objects.EvAdventureArmor, key="gambeson")
mock_spawn.return_value = gambeson
character = self.chargen.apply()
self.assertIn("Herbalist", character.db.desc)
self.assertEqual(
character.equipment.all(),
[
(None, enums.WieldLocation.WEAPON_HAND),
(None, enums.WieldLocation.SHIELD_HAND),
(None, enums.WieldLocation.TWO_HANDS),
(gambeson, enums.WieldLocation.BODY),
(None, enums.WieldLocation.HEAD),
],
)
gambeson.delete()
character.delete()

View file

@ -4,7 +4,10 @@ Test the EvAdventure equipment handler.
"""
from unittest.mock import MagicMock, patch
from evennia.utils.test_resources import BaseEvenniaTest
from parameterized import parameterized
from ..enums import Ability, WieldLocation
from ..equipment import EquipmentError
@ -20,13 +23,6 @@ class TestEquipment(EvAdventureMixin, BaseEvenniaTest):
setattr(self.character, Ability.CON.value, 3)
self.assertEqual(self.character.equipment.max_slots, 13)
def test_validate_slot_usage(self):
helmet = self.helmet
self.assertTrue(self.character.equipment.validate_slot_usage(helmet))
helmet.size = 20 # a very large helmet
with self.assertRaises(EquipmentError):
self.assertFalse(self.character.equipment.validate_slot_usage(helmet))
def test_add__remove(self):
self.character.equipment.add(self.helmet)
self.assertEqual(self.character.equipment.slots[WieldLocation.BACKPACK], [self.helmet])
@ -53,6 +49,141 @@ class TestEquipment(EvAdventureMixin, BaseEvenniaTest):
)
self.assertEqual(
self.character.equipment.get_all(),
[(self.helmet, WieldLocation.BACKPACK), (self.weapon, WieldLocation.BACKPACK)],
self.character.equipment.all(),
[
(None, WieldLocation.WEAPON_HAND),
(None, WieldLocation.SHIELD_HAND),
(None, WieldLocation.TWO_HANDS),
(None, WieldLocation.BODY),
(None, WieldLocation.HEAD),
(self.helmet, WieldLocation.BACKPACK),
(self.weapon, WieldLocation.BACKPACK),
],
)
def _get_empty_slots(self):
return {
WieldLocation.BACKPACK: [],
WieldLocation.WEAPON_HAND: None,
WieldLocation.SHIELD_HAND: None,
WieldLocation.TWO_HANDS: None,
WieldLocation.BODY: None,
WieldLocation.HEAD: None,
}
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),
]
)
def test_validate_slot_usage(self, size, is_ok):
obj = MagicMock()
obj.size = size
with patch("evennia.contrib.tutorials.evadventure.equipment.inherits_from") as mock_inherit:
mock_inherit.return_value = True
if is_ok:
self.assertTrue(self.character.equipment.validate_slot_usage(obj))
else:
with self.assertRaises(EquipmentError):
self.character.equipment.validate_slot_usage(obj)
@parameterized.expand(
[
# item, where
("helmet", WieldLocation.HEAD),
("shield", WieldLocation.SHIELD_HAND),
("armor", WieldLocation.BODY),
("weapon", WieldLocation.WEAPON_HAND),
("big_weapon", WieldLocation.TWO_HANDS),
("item", WieldLocation.BACKPACK),
]
)
def test_move(self, itemname, where):
self.assertEqual(self.character.equipment.slots, self._get_empty_slots())
obj = getattr(self, itemname)
self.character.equipment.move(obj)
# check that item ended up in the right place
if where is WieldLocation.BACKPACK:
self.assertTrue(obj in self.character.equipment.slots[where])
else:
self.assertEqual(self.character.equipment.slots[where], obj)
def test_add(self):
self.character.equipment.add(self.weapon)
self.assertEqual(self.character.equipment.slots[WieldLocation.WEAPON_HAND], None)
self.assertTrue(self.weapon in self.character.equipment.slots[WieldLocation.BACKPACK])
def test_two_handed_exclusive(self):
"""Two-handed weapons can't be used together with weapon+shield"""
self.character.equipment.move(self.big_weapon)
self.assertEqual(self.character.equipment.slots[WieldLocation.TWO_HANDS], self.big_weapon)
# equipping sword or shield removes two-hander
self.character.equipment.move(self.shield)
self.assertEqual(self.character.equipment.slots[WieldLocation.SHIELD_HAND], self.shield)
self.assertEqual(self.character.equipment.slots[WieldLocation.TWO_HANDS], None)
self.character.equipment.move(self.weapon)
self.assertEqual(self.character.equipment.slots[WieldLocation.WEAPON_HAND], self.weapon)
# the two-hander removes the two weapons
self.character.equipment.move(self.big_weapon)
self.assertEqual(self.character.equipment.slots[WieldLocation.TWO_HANDS], self.big_weapon)
self.assertEqual(self.character.equipment.slots[WieldLocation.SHIELD_HAND], None)
self.assertEqual(self.character.equipment.slots[WieldLocation.WEAPON_HAND], None)
def test_remove__with_obj(self):
self.character.equipment.move(self.shield)
self.character.equipment.move(self.item)
self.character.equipment.add(self.weapon)
self.assertEqual(self.character.equipment.slots[WieldLocation.SHIELD_HAND], self.shield)
self.assertEqual(
self.character.equipment.slots[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[WieldLocation.SHIELD_HAND], None)
self.assertEqual(self.character.equipment.slots[WieldLocation.BACKPACK], [self.weapon])
def test_remove__with_slot(self):
self.character.equipment.move(self.shield)
self.character.equipment.move(self.item)
self.character.equipment.add(self.helmet)
self.assertEqual(self.character.equipment.slots[WieldLocation.SHIELD_HAND], self.shield)
self.assertEqual(
self.character.equipment.slots[WieldLocation.BACKPACK], [self.item, self.helmet]
)
self.assertEqual(self.character.equipment.remove(WieldLocation.SHIELD_HAND), [self.shield])
self.assertEqual(
self.character.equipment.remove(WieldLocation.BACKPACK), [self.item, self.helmet]
)
self.assertEqual(self.character.equipment.slots[WieldLocation.SHIELD_HAND], None)
self.assertEqual(self.character.equipment.slots[WieldLocation.BACKPACK], [])
def test_properties(self):
self.character.equipment.move(self.armor)
self.assertEqual(self.character.equipment.armor, 1)
self.character.equipment.move(self.shield)
self.assertEqual(self.character.equipment.armor, 2)
self.character.equipment.move(self.helmet)
self.assertEqual(self.character.equipment.armor, 3)
self.character.equipment.move(self.weapon)
self.assertEqual(self.character.equipment.weapon, self.weapon)
self.character.equipment.move(self.big_weapon)
self.assertEqual(self.character.equipment.weapon, self.big_weapon)

View file

@ -151,24 +151,20 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
mock_randint.return_value = 10
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation["physique"]
),
self.roll_engine.roll_random_table("1d20", random_tables.chargen_tables["physique"]),
"scrawny",
)
self.assertEqual(
self.roll_engine.roll_random_table("1d20", random_tables.character_generation["vice"]),
self.roll_engine.roll_random_table("1d20", random_tables.chargen_tables["vice"]),
"irascible",
)
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation["alignment"]
),
self.roll_engine.roll_random_table("1d20", random_tables.chargen_tables["alignment"]),
"neutrality",
)
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation["helmets and shields"]
"1d20", random_tables.chargen_tables["helmets and shields"]
),
"no helmet or shield",
)
@ -176,14 +172,14 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
mock_randint.return_value = 25
self.assertEqual(
self.roll_engine.roll_random_table(
"1d20", random_tables.character_generation["helmets and shields"]
"1d20", random_tables.chargen_tables["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"]
"1d20", random_tables.chargen_tables["helmets and shields"]
),
"no helmet or shield",
)
@ -202,17 +198,15 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
def test_heal_from_rest(self, mock_randint):
character = MagicMock()
character.heal = MagicMock()
character.hp_max = 8
character.hp = 1
character.constitution = 1
mock_randint.return_value = 5
self.roll_engine.heal_from_rest(character)
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
character.heal.assert_called_with(6) # roll + constitution bonus
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
def test_roll_death(self, mock_randint):
@ -229,233 +223,3 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
mock_randint.return_value = 3
self.roll_engine.roll_death(character)
self.assertEqual(character.strength, 10)
class EvAdventureCharacterGenerationTest(BaseEvenniaTest):
"""
Test the Character generator in the rule engine.
"""
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
def setUp(self, mock_randint):
super().setUp()
mock_randint.return_value = 10
self.chargen = rules.EvAdventureCharacterGeneration()
def test_base_chargen(self):
self.assertEqual(self.chargen.strength, 2)
self.assertEqual(self.chargen.physique, "scrawny")
self.assertEqual(self.chargen.skin, "pockmarked")
self.assertEqual(self.chargen.hair, "greased")
self.assertEqual(self.chargen.clothing, "stained")
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"]
)
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.",
)
@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}")
def test_adjust_consecutive(self):
# gradually shift all to STR (starts at 2)
self.chargen.adjust_attribute(enums.Ability.CON, enums.Ability.STR, 1)
self.chargen.adjust_attribute(enums.Ability.CHA, enums.Ability.STR, 1)
self.chargen.adjust_attribute(enums.Ability.DEX, enums.Ability.STR, 1)
self.chargen.adjust_attribute(enums.Ability.WIS, enums.Ability.STR, 1)
self.assertEqual(self.chargen.constitution, 1)
self.assertEqual(self.chargen.strength, 6)
# max is 6
with self.assertRaises(ValueError):
self.chargen.adjust_attribute(enums.Ability.INT, enums.Ability.STR, 1)
# minimum is 1
with self.assertRaises(ValueError):
self.chargen.adjust_attribute(enums.Ability.DEX, enums.Ability.WIS, 1)
# move all from str to wis
self.chargen.adjust_attribute(enums.Ability.STR, enums.Ability.WIS, 5)
self.assertEqual(self.chargen.strength, 1)
self.assertEqual(self.chargen.wisdom, 6)
def test_apply(self):
character = MagicMock()
self.chargen.apply(character)
self.assertTrue(character.db.desc.startswith("Herbalist"))
self.assertEqual(character.armor, "gambeson")
character.equipment.add.assert_called()
class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
"""
Test the equipment mechanism.
"""
def _get_empty_slots(self):
return {
enums.WieldLocation.BACKPACK: [],
enums.WieldLocation.WEAPON_HAND: None,
enums.WieldLocation.SHIELD_HAND: None,
enums.WieldLocation.TWO_HANDS: None,
enums.WieldLocation.BODY: None,
enums.WieldLocation.HEAD: None,
}
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),
]
)
def test_validate_slot_usage(self, size, is_ok):
obj = MagicMock()
obj.size = size
if is_ok:
self.assertTrue(self.character.equipment.validate_slot_usage(obj))
else:
with self.assertRaises(equipment.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),
]
)
def test_use(self, itemname, where):
self.assertEqual(self.character.equipment.slots, self._get_empty_slots())
obj = getattr(self, itemname)
self.character.equipment.use(obj)
# check that item ended up in the right place
if where is enums.WieldLocation.BACKPACK:
self.assertTrue(obj in self.character.equipment.slots[where])
else:
self.assertEqual(self.character.equipment.slots[where], obj)
def test_add(self):
self.character.equipment.add(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])
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
)
# 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.use(self.weapon)
self.assertEqual(
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)
def test_remove__with_obj(self):
self.character.equipment.use(self.shield)
self.character.equipment.use(self.item)
self.character.equipment.add(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.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]
)
def test_remove__with_slot(self):
self.character.equipment.use(self.shield)
self.character.equipment.use(self.item)
self.character.equipment.add(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.assertEqual(self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], None)
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.BACKPACK], [])
def test_properties(self):
self.character.equipment.use(self.armor)
self.assertEqual(self.character.equipment.armor, 1)
self.character.equipment.use(self.shield)
self.assertEqual(self.character.equipment.armor, 2)
self.character.equipment.use(self.helmet)
self.assertEqual(self.character.equipment.armor, 3)
self.character.equipment.use(self.weapon)
self.assertEqual(self.character.equipment.weapon, self.weapon)
self.character.equipment.use(self.big_weapon)
self.assertEqual(self.character.equipment.weapon, self.big_weapon)

View file

@ -882,14 +882,18 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
return False
# check if source location lets us go
try:
if not source_location.at_pre_object_leave(self, destination, **kwargs):
if source_location and not source_location.at_pre_object_leave(
self, destination, **kwargs
):
return False
except Exception as err:
logerr(errtxt.format(err="at_pre_object_leave()"), err)
return False
# check if destination accepts us
try:
if not self.at_pre_object_receive(self, source_location, **kwargs):
if destination and not destination.at_pre_object_receive(
self, source_location, **kwargs
):
return False
except Exception as err:
logerr(errtxt.format(err="at_pre_object_receive()"), err)

View file

@ -2732,7 +2732,7 @@ _INT2STR_MAP_NOUN = {
_INT2STR_MAP_ADJ = {1: "1st", 2: "2nd", 3: "3rd"} # rest is Xth.
def int2str(self, number, adjective=False):
def int2str(number, adjective=False):
"""
Convert a number to an English string for better display; so 1 -> one, 2 -> two etc
up until 12, after which it will be '13', '14' etc.