Apply black to evadventure files
This commit is contained in:
parent
6e8e3963dd
commit
7815a06e3a
12 changed files with 653 additions and 327 deletions
|
|
@ -27,6 +27,7 @@ class EquipmentHandler:
|
||||||
until you clean them.
|
until you clean them.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
save_attribute = "inventory_slots"
|
save_attribute = "inventory_slots"
|
||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
|
|
@ -47,8 +48,8 @@ class EquipmentHandler:
|
||||||
WieldLocation.TWO_HANDS: None,
|
WieldLocation.TWO_HANDS: None,
|
||||||
WieldLocation.BODY: None,
|
WieldLocation.BODY: None,
|
||||||
WieldLocation.HEAD: None,
|
WieldLocation.HEAD: None,
|
||||||
WieldLocation.BACKPACK: []
|
WieldLocation.BACKPACK: [],
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def _count_slots(self):
|
def _count_slots(self):
|
||||||
|
|
@ -64,8 +65,7 @@ class EquipmentHandler:
|
||||||
if slot is not WieldLocation.BACKPACK
|
if slot is not WieldLocation.BACKPACK
|
||||||
)
|
)
|
||||||
backpack_usage = sum(
|
backpack_usage = sum(
|
||||||
getattr(slotobj, "size", 0) or 0
|
getattr(slotobj, "size", 0) or 0 for slotobj in slots[WieldLocation.BACKPACK]
|
||||||
for slotobj in slots[WieldLocation.BACKPACK]
|
|
||||||
)
|
)
|
||||||
return wield_usage + backpack_usage
|
return wield_usage + backpack_usage
|
||||||
|
|
||||||
|
|
@ -101,9 +101,11 @@ class EquipmentHandler:
|
||||||
current_slot_usage = self._count_slots()
|
current_slot_usage = self._count_slots()
|
||||||
if current_slot_usage + size > max_slots:
|
if current_slot_usage + size > max_slots:
|
||||||
slots_left = max_slots - current_slot_usage
|
slots_left = max_slots - current_slot_usage
|
||||||
raise EquipmentError(f"Equipment full ($int2str({slots_left}) slots "
|
raise EquipmentError(
|
||||||
f"remaining, {obj.key} needs $int2str({size}) "
|
f"Equipment full ($int2str({slots_left}) slots "
|
||||||
f"$pluralize(slot, {size})).")
|
f"remaining, {obj.key} needs $int2str({size}) "
|
||||||
|
f"$pluralize(slot, {size}))."
|
||||||
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -120,11 +122,13 @@ class EquipmentHandler:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
slots = self.slots
|
slots = self.slots
|
||||||
return sum((
|
return sum(
|
||||||
getattr(slots[WieldLocation.BODY], "armor", 0),
|
(
|
||||||
getattr(slots[WieldLocation.SHIELD_HAND], "armor", 0),
|
getattr(slots[WieldLocation.BODY], "armor", 0),
|
||||||
getattr(slots[WieldLocation.HEAD], "armor", 0),
|
getattr(slots[WieldLocation.SHIELD_HAND], "armor", 0),
|
||||||
))
|
getattr(slots[WieldLocation.HEAD], "armor", 0),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def weapon(self):
|
def weapon(self):
|
||||||
|
|
@ -423,6 +427,7 @@ class EvAdventureNPC(LivingMixin, DefaultCharacter):
|
||||||
EvAdventureCharacter class instead.
|
EvAdventureCharacter class instead.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
hit_dice = AttributeProperty(default=1)
|
hit_dice = AttributeProperty(default=1)
|
||||||
armor = AttributeProperty(default=11)
|
armor = AttributeProperty(default=11)
|
||||||
morale = AttributeProperty(default=9)
|
morale = AttributeProperty(default=9)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ class CombatAction:
|
||||||
Inherit from this to make new actions.
|
Inherit from this to make new actions.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
key = 'action'
|
|
||||||
|
key = "action"
|
||||||
help_text = "Combat action to perform."
|
help_text = "Combat action to perform."
|
||||||
# action to echo to everyone.
|
# action to echo to everyone.
|
||||||
post_action_text = "{combatant} performed an action."
|
post_action_text = "{combatant} performed an action."
|
||||||
|
|
@ -107,6 +108,7 @@ class CombatActionDoNothing(CombatAction):
|
||||||
Do nothing this turn.
|
Do nothing this turn.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
help_text = "Hold you position, doing nothing."
|
help_text = "Hold you position, doing nothing."
|
||||||
post_action_text = "{combatant} does nothing this turn."
|
post_action_text = "{combatant} does nothing this turn."
|
||||||
|
|
||||||
|
|
@ -124,24 +126,29 @@ class CombatActionStunt(CombatAction):
|
||||||
spend a use unless they succeed.
|
spend a use unless they succeed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
give_advantage = True
|
give_advantage = True
|
||||||
give_disadvantage = False
|
give_disadvantage = False
|
||||||
max_uses = 1
|
max_uses = 1
|
||||||
priority = -1
|
priority = -1
|
||||||
attack_type = Ability.DEX
|
attack_type = Ability.DEX
|
||||||
defense_type = Ability.DEX
|
defense_type = Ability.DEX
|
||||||
help_text = ("Perform a stunt against a target. This will give you or an ally advantage "
|
help_text = (
|
||||||
"on your next action against the same target [range 0-1, one use per combat. "
|
"Perform a stunt against a target. This will give you or an ally advantage "
|
||||||
"Bonus lasts for two turns].")
|
"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):
|
def use(self, attacker, defender, *args, beneficiary=None, **kwargs):
|
||||||
# quality doesn't matter for stunts, they are either successful or not
|
# quality doesn't matter for stunts, they are either successful or not
|
||||||
|
|
||||||
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
|
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
|
||||||
attacker, defender,
|
attacker,
|
||||||
|
defender,
|
||||||
attack_type=self.attack_type,
|
attack_type=self.attack_type,
|
||||||
defense_type=self.defense_type,
|
defense_type=self.defense_type,
|
||||||
advantage=False, disadvantage=disadvantage,
|
advantage=False,
|
||||||
|
disadvantage=disadvantage,
|
||||||
)
|
)
|
||||||
if is_success:
|
if is_success:
|
||||||
beneficiary = beneficiary if beneficiary else attacker
|
beneficiary = beneficiary if beneficiary else attacker
|
||||||
|
|
@ -161,6 +168,7 @@ class CombatActionAttack(CombatAction):
|
||||||
melee attack.
|
melee attack.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "attack"
|
key = "attack"
|
||||||
priority = 1
|
priority = 1
|
||||||
|
|
||||||
|
|
@ -176,14 +184,17 @@ class CombatActionAttack(CombatAction):
|
||||||
disadvantage = bool(self.combathandler.disadvantage_matrix[attacker].pop(defender, False))
|
disadvantage = bool(self.combathandler.disadvantage_matrix[attacker].pop(defender, False))
|
||||||
|
|
||||||
is_hit, quality = rules.EvAdventureRollEngine.opposed_saving_throw(
|
is_hit, quality = rules.EvAdventureRollEngine.opposed_saving_throw(
|
||||||
attacker, defender,
|
attacker,
|
||||||
|
defender,
|
||||||
attack_type=attacker.weapon.attack_type,
|
attack_type=attacker.weapon.attack_type,
|
||||||
defense_type=attacker.weapon.defense_type,
|
defense_type=attacker.weapon.defense_type,
|
||||||
advantage=advantage, disadvantage=disadvantage
|
advantage=advantage,
|
||||||
|
disadvantage=disadvantage,
|
||||||
)
|
)
|
||||||
if is_hit:
|
if is_hit:
|
||||||
self.combathandler.resolve_damage(attacker, defender,
|
self.combathandler.resolve_damage(
|
||||||
critical=quality == "critical success")
|
attacker, defender, critical=quality == "critical success"
|
||||||
|
)
|
||||||
|
|
||||||
# TODO messaging here
|
# TODO messaging here
|
||||||
|
|
||||||
|
|
@ -204,6 +215,7 @@ class CombatActionUseItem(CombatAction):
|
||||||
combat_post_use
|
combat_post_use
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_help(self, item, *args):
|
def get_help(self, item, *args):
|
||||||
return item.combat_get_help(*args)
|
return item.combat_get_help(*args)
|
||||||
|
|
||||||
|
|
@ -227,6 +239,7 @@ class CombatActionFlee(CombatAction):
|
||||||
end of the second turn.
|
end of the second turn.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
key = "flee"
|
key = "flee"
|
||||||
priority = -1
|
priority = -1
|
||||||
|
|
||||||
|
|
@ -234,37 +247,42 @@ class CombatActionFlee(CombatAction):
|
||||||
# it's safe to do this twice
|
# it's safe to do this twice
|
||||||
self.combathandler.flee(combatant)
|
self.combathandler.flee(combatant)
|
||||||
|
|
||||||
|
|
||||||
class CombatActionChase(CombatAction):
|
class CombatActionChase(CombatAction):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Chasing is a way to counter a 'flee' action. It is a maximum movement towards the target
|
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
|
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
|
'disengaging' range and remain in combat at the new distance (likely 2 if max movement
|
||||||
is 2). Advantage/disadvantage are considered.
|
is 2). Advantage/disadvantage are considered.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
key = "chase"
|
|
||||||
priority = -5 # checked last
|
|
||||||
|
|
||||||
attack_type = Ability.DEX # or is it CON?
|
key = "chase"
|
||||||
defense_type = Ability.DEX
|
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))
|
def use(self, combatant, fleeing_target, *args, **kwargs):
|
||||||
disadvantage = bool(self.disadvantage_matrix[attacker].pop(fleeing_target, False))
|
|
||||||
|
|
||||||
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
|
advantage = bool(self.advantage_matrix[attacker].pop(fleeing_target, False))
|
||||||
combatant, fleeing_target,
|
disadvantage = bool(self.disadvantage_matrix[attacker].pop(fleeing_target, False))
|
||||||
attack_type=self.attack_type, defense_type=self.defense_type,
|
|
||||||
advantage=advantage, disadvantage=disadvantage
|
|
||||||
)
|
|
||||||
|
|
||||||
if is_success:
|
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
|
||||||
# managed to stop the target from fleeing/disengaging
|
combatant,
|
||||||
self.combatant.unflee(fleeing_target)
|
fleeing_target,
|
||||||
else:
|
attack_type=self.attack_type,
|
||||||
pass # they are getting away!
|
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):
|
class EvAdventureCombatHandler(DefaultScript):
|
||||||
|
|
@ -283,7 +301,7 @@ class EvAdventureCombatHandler(DefaultScript):
|
||||||
CombatActionChase,
|
CombatActionChase,
|
||||||
CombatActionUseItem,
|
CombatActionUseItem,
|
||||||
CombatActionStunt,
|
CombatActionStunt,
|
||||||
CombatActionAttack
|
CombatActionAttack,
|
||||||
]
|
]
|
||||||
|
|
||||||
# attributes
|
# attributes
|
||||||
|
|
@ -345,7 +363,8 @@ class EvAdventureCombatHandler(DefaultScript):
|
||||||
for combatant in self.combatants:
|
for combatant in self.combatants:
|
||||||
# read the current action type selected by the player
|
# read the current action type selected by the player
|
||||||
action, args, kwargs = self.action_queue.get(
|
action, args, kwargs = self.action_queue.get(
|
||||||
combatant, (CombatActionDoNothing(self, combatant), (), {}))
|
combatant, (CombatActionDoNothing(self, combatant), (), {})
|
||||||
|
)
|
||||||
# perform the action on the CombatAction instance
|
# perform the action on the CombatAction instance
|
||||||
action.use(combatant, *args, **kwargs)
|
action.use(combatant, *args, **kwargs)
|
||||||
|
|
||||||
|
|
@ -380,11 +399,13 @@ class EvAdventureCombatHandler(DefaultScript):
|
||||||
|
|
||||||
for combatant in self.combatants:
|
for combatant in self.combatants:
|
||||||
new_advantage_matrix[combatant] = {
|
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
|
if set_at_turn > oldest_stunt_age
|
||||||
}
|
}
|
||||||
new_disadvantage_matrix[combatant] = {
|
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
|
if set_at_turn > oldest_stunt_age
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,8 +521,11 @@ class EvAdventureCombatHandler(DefaultScript):
|
||||||
|
|
||||||
if defender.hp > 0:
|
if defender.hp > 0:
|
||||||
# they are weakened, but with hp
|
# they are weakened, but with hp
|
||||||
self.msg("You are alive, but out of the fight. If you want to press your luck, "
|
self.msg(
|
||||||
"you need to rejoin the combat.", targets=defender)
|
"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
|
defender.at_defeat() # note - NPC monsters may still 'die' here
|
||||||
else:
|
else:
|
||||||
# outright killed
|
# outright killed
|
||||||
|
|
@ -537,19 +561,16 @@ combat_script = """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _register_action(caller, raw_string, **kwargs):
|
def _register_action(caller, raw_string, **kwargs):
|
||||||
"""
|
"""
|
||||||
Register action with handler.
|
Register action with handler.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
action = kwargs.get['action']
|
action = kwargs.get["action"]
|
||||||
action_args = kwargs['action_args']
|
action_args = kwargs["action_args"]
|
||||||
action_kwargs = kwargs['action_kwargs']
|
action_kwargs = kwargs["action_kwargs"]
|
||||||
combat = caller.scripts.get("combathandler")
|
combat = caller.scripts.get("combathandler")
|
||||||
combat.register_action(
|
combat.register_action(caller, action=action, *action_args, **action_kwargs)
|
||||||
caller, action=action, *action_args, **action_kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def node_select_target(caller, raw_string, **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.
|
with all other actions.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
action = kwargs.get('action')
|
action = kwargs.get("action")
|
||||||
action_args = kwargs.get('action_args')
|
action_args = kwargs.get("action_args")
|
||||||
action_kwargs = kwargs.get('action_kwargs')
|
action_kwargs = kwargs.get("action_kwargs")
|
||||||
combat = caller.scripts.get("combathandler")
|
combat = caller.scripts.get("combathandler")
|
||||||
text = "Select target for |w{action}|n."
|
text = "Select target for |w{action}|n."
|
||||||
|
|
||||||
|
|
@ -568,22 +589,26 @@ def node_select_target(caller, raw_string, **kwargs):
|
||||||
options = [
|
options = [
|
||||||
{
|
{
|
||||||
"desc": combatant.key,
|
"desc": combatant.key,
|
||||||
"goto": (_register_action, {"action": action,
|
"goto": (
|
||||||
"args": action_args,
|
_register_action,
|
||||||
"kwargs": action_kwargs})
|
{"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
|
# make the apply-self option always the last one
|
||||||
options.append(
|
options.append(
|
||||||
{
|
{
|
||||||
"desc": "(yourself)",
|
"desc": "(yourself)",
|
||||||
"goto": (_register_action, {"action": action,
|
"goto": (
|
||||||
"args": action_args,
|
_register_action,
|
||||||
"kwargs": action_kwargs})
|
{"action": action, "args": action_args, "kwargs": action_kwargs},
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return text, options
|
return text, options
|
||||||
|
|
||||||
|
|
||||||
def node_select_action(caller, raw_string, **kwargs):
|
def node_select_action(caller, raw_string, **kwargs):
|
||||||
"""
|
"""
|
||||||
Menu node for selecting a combat action.
|
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)
|
text = combat.get_previous_turn_status(caller)
|
||||||
options = combat.get_available_options(caller)
|
options = combat.get_available_options(caller)
|
||||||
|
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
"desc": action,
|
"desc": action,
|
||||||
"goto": ("node_select_target", {"action": action,
|
"goto": (
|
||||||
})
|
"node_select_target",
|
||||||
|
{
|
||||||
|
"action": action,
|
||||||
|
},
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return text, options
|
return text, options
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,13 @@ To get the `value` of an enum (must always be hashable, useful for Attribute loo
|
||||||
"""
|
"""
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class Ability(Enum):
|
class Ability(Enum):
|
||||||
"""
|
"""
|
||||||
The six base abilities (defense is always bonus + 10)
|
The six base abilities (defense is always bonus + 10)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
STR = "strength"
|
STR = "strength"
|
||||||
DEX = "dexterity"
|
DEX = "dexterity"
|
||||||
CON = "constitution"
|
CON = "constitution"
|
||||||
|
|
@ -45,11 +47,13 @@ class Ability(Enum):
|
||||||
CRITICAL_FAILURE = "critical_failure"
|
CRITICAL_FAILURE = "critical_failure"
|
||||||
CRITICAL_SUCCESS = "critical_success"
|
CRITICAL_SUCCESS = "critical_success"
|
||||||
|
|
||||||
|
|
||||||
class WieldLocation(Enum):
|
class WieldLocation(Enum):
|
||||||
"""
|
"""
|
||||||
Wield (or wear) locations.
|
Wield (or wear) locations.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# wield/wear location
|
# wield/wear location
|
||||||
BACKPACK = "backpack"
|
BACKPACK = "backpack"
|
||||||
WEAPON_HAND = "weapon_hand"
|
WEAPON_HAND = "weapon_hand"
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,12 @@ from evennia.typeclasses.attributes import AttributeProperty
|
||||||
from .enums import WieldLocation, Ability
|
from .enums import WieldLocation, Ability
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class EvAdventureObject(DefaultObject):
|
class EvAdventureObject(DefaultObject):
|
||||||
"""
|
"""
|
||||||
Base in-game entity.
|
Base in-game entity.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# inventory management
|
# inventory management
|
||||||
inventory_use_slot = AttributeProperty(default=WieldLocation.BACKPACK)
|
inventory_use_slot = AttributeProperty(default=WieldLocation.BACKPACK)
|
||||||
# how many inventory slots it uses (can be a fraction)
|
# how many inventory slots it uses (can be a fraction)
|
||||||
|
|
@ -41,6 +41,7 @@ class EvAdventureObjectFiller(EvAdventureObject):
|
||||||
meaning it's unusable.
|
meaning it's unusable.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
quality = AttributeProperty(default=0)
|
quality = AttributeProperty(default=0)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -49,6 +50,7 @@ class EvAdventureWeapon(EvAdventureObject):
|
||||||
Base weapon class for all EvAdventure weapons.
|
Base weapon class for all EvAdventure weapons.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
inventory_use_slot = AttributeProperty(WieldLocation.WEAPON_HAND)
|
inventory_use_slot = AttributeProperty(WieldLocation.WEAPON_HAND)
|
||||||
|
|
||||||
attack_type = AttributeProperty(default=Ability.STR)
|
attack_type = AttributeProperty(default=Ability.STR)
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ class EvAdventureQuest:
|
||||||
check_<name> and complete_<name>
|
check_<name> and complete_<name>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# name + category must be globally unique. They are
|
# name + category must be globally unique. They are
|
||||||
# queried as name:category or just name, if category is empty.
|
# queried as name:category or just name, if category is empty.
|
||||||
name = ""
|
name = ""
|
||||||
|
|
@ -44,11 +45,9 @@ class EvAdventureQuest:
|
||||||
def check():
|
def check():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def progress(self, quester, *args, **kwargs):
|
def progress(self, quester, *args, **kwargs):
|
||||||
"""
|
""" """
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
class EvAdventureQuestHandler:
|
class EvAdventureQuestHandler:
|
||||||
"""
|
"""
|
||||||
|
|
@ -63,15 +62,14 @@ class EvAdventureQuestHandler:
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
quest_storage_attribute = "_quests"
|
quest_storage_attribute = "_quests"
|
||||||
quest_storage_attribute_category = "evadventure"
|
quest_storage_attribute_category = "evadventure"
|
||||||
|
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
self.obj = obj
|
self.obj = obj
|
||||||
self.storage = obj.attributes.get(
|
self.storage = obj.attributes.get(
|
||||||
self.quest_storage_attribute,
|
self.quest_storage_attribute, category=self.quest_storage_attribute_category, default={}
|
||||||
category=self.quest_storage_attribute_category,
|
|
||||||
default={}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def quest_storage_key(self, name, category):
|
def quest_storage_key(self, name, category):
|
||||||
|
|
@ -116,6 +114,3 @@ class EvAdventureQuestHandler:
|
||||||
start immediately.
|
start immediately.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -227,26 +227,26 @@ character_generation = {
|
||||||
"suspected",
|
"suspected",
|
||||||
],
|
],
|
||||||
"alignment": [
|
"alignment": [
|
||||||
('1-5', "law"),
|
("1-5", "law"),
|
||||||
('6-15', "neutrality"),
|
("6-15", "neutrality"),
|
||||||
('16-20', "chaos"),
|
("16-20", "chaos"),
|
||||||
],
|
],
|
||||||
"armor": [
|
"armor": [
|
||||||
('1-3', "no armor"),
|
("1-3", "no armor"),
|
||||||
('4-14', "gambeson"),
|
("4-14", "gambeson"),
|
||||||
('15-19', "brigandine"),
|
("15-19", "brigandine"),
|
||||||
('20', "chain"),
|
("20", "chain"),
|
||||||
],
|
],
|
||||||
"helmets and shields": [
|
"helmets and shields": [
|
||||||
('1-13', "no helmet or shield"),
|
("1-13", "no helmet or shield"),
|
||||||
('14-16', "helmet"),
|
("14-16", "helmet"),
|
||||||
('17-19', "shield"),
|
("17-19", "shield"),
|
||||||
('20', "helmet and shield"),
|
("20", "helmet and shield"),
|
||||||
],
|
],
|
||||||
"starting weapon": [ # note: these are all d6 dmg weapons
|
"starting weapon": [ # note: these are all d6 dmg weapons
|
||||||
('1-7', "dagger"),
|
("1-7", "dagger"),
|
||||||
('8-13', "club"),
|
("8-13", "club"),
|
||||||
('14-20', "staff"),
|
("14-20", "staff"),
|
||||||
],
|
],
|
||||||
"dungeoning gear": [
|
"dungeoning gear": [
|
||||||
"rope, 50ft",
|
"rope, 50ft",
|
||||||
|
|
@ -315,55 +315,303 @@ character_generation = {
|
||||||
"small bell",
|
"small bell",
|
||||||
],
|
],
|
||||||
"name": [
|
"name": [
|
||||||
"Abbo", "Adelaide", "Ellis", "Eleanor", "Lief", "Luanda", "Ablerus", "Agatha",
|
"Abbo",
|
||||||
"Eneto", "Elizabeth", "Luke", "Lyra", "Acot", "Aleida", "Enio", "Elspeth", "Martin",
|
"Adelaide",
|
||||||
"Mabel", "Alexander", "Alexia", "Eral", "Emeline", "Merrick", "Maerwynn", "Almanzor",
|
"Ellis",
|
||||||
"Alianor", "Erasmus", "Emma", "Mortimer", "Malkyn", "Althalos", "Aline", "Eustace",
|
"Eleanor",
|
||||||
"Emmony", "Ogden", "Margaret", "Ancelot", "Alma", "Everard", "Enna", "Oliver", "Margery",
|
"Lief",
|
||||||
"Asher", "Alys", "Faustus", "Enndolynn", "Orion", "Maria", "Aster", "Amabel", "Favian",
|
"Luanda",
|
||||||
"Eve", "Oswald", "Marion", "Balan", "Amice", "Fendrel", "Evita", "Pelagon", "Matilda",
|
"Ablerus",
|
||||||
"Balthazar", "Anastas", "Finn", "Felice", "Pello", "Millicent", "Barat", "Angmar",
|
"Agatha",
|
||||||
"Florian", "Fern", "Peyton", "Mirabelle", "Bartholomew", "Annabel", "Francis", "Floria",
|
"Eneto",
|
||||||
"Philip", "Muriel", "Basil", "Arabella", "Frederick", "Fredegonde", "Poeas", "Nabarne",
|
"Elizabeth",
|
||||||
"Benedict", "Ariana", "Gaidon", "Gillian", "Quinn", "Nell", "Berinon", "Ayleth", "Gavin",
|
"Luke",
|
||||||
"Gloriana", "Ralph", "Nesea", "Bertram", "Barberry", "Geoffrey", "Godeleva", "Randolph",
|
"Lyra",
|
||||||
"Niree", "Beves", "Barsaba", "Gerard", "Godiva", "Reginald", "Odette", "Bilmer",
|
"Acot",
|
||||||
"Basilia", "Gervase", "Gunnilda", "Reynold", "Odila", "Blanko", "Beatrix", "Gilbert",
|
"Aleida",
|
||||||
"Gussalen", "Richard", "Oria", "Bodo", "Benevolence", "Giles", "Gwendolynn", "Robert",
|
"Enio",
|
||||||
"Osanna", "Borin", "Bess", "Godfrey", "Hawise", "Robin", "Ostrythe", "Bryce", "Brangian",
|
"Elspeth",
|
||||||
"Gregory", "Helena", "Roger", "Ottilia", "Carac", "Brigida", "Gringoire", "Helewise",
|
"Martin",
|
||||||
"Ronald", "Panope", "Caspar", "Brunhild", "Gunthar", "Hester", "Rowan", "Paternain",
|
"Mabel",
|
||||||
"Cassius", "Camilla", "Guy", "Hildegard", "Rulf", "Pechel", "Cedric", "Canace", "Gyras",
|
"Alexander",
|
||||||
"Idony", "Sabin", "Pepper", "Cephalos", "Cecily", "Hadrian", "Isabella", "Sevrin",
|
"Alexia",
|
||||||
"Petronilla", "Chadwick", "Cedany", "Hedelf", "Iseult", "Silas", "Phrowenia", "Charillos",
|
"Eral",
|
||||||
"Christina", "Hewelin", "Isolde", "Simon", "Poppy", "Charles", "Claramunda", "Hilderith",
|
"Emeline",
|
||||||
"Jacquelyn", "Solomon", "Quenell", "Chermon", "Clarice", "Humbert", "Jasmine", "Stephen",
|
"Merrick",
|
||||||
"Raisa", "Clement", "Clover", "Hyllus", "Jessamine", "Terrowin", "Reyna", "Clifton",
|
"Maerwynn",
|
||||||
"Collette", "Ianto", "Josselyn", "Thomas", "Rixende", "Clovis", "Constance", "Ibykos",
|
"Almanzor",
|
||||||
"Juliana", "Tristan", "Rosamund", "Cyon", "Damaris", "Inigo", "Karitate", "Tybalt",
|
"Alianor",
|
||||||
"Rose", "Dain", "Daphne", "Itylus", "Katelyn", "Ulric", "Ryia", "Dalmas", "Demona",
|
"Erasmus",
|
||||||
"James", "Katja", "Walter", "Sarah", "Danor", "Dimia", "Jasper", "Katrina", "Wander",
|
"Emma",
|
||||||
"Seraphina", "Destrian", "Dione", "Jiles", "Kaylein", "Warin", "Thea", "Domeka",
|
"Mortimer",
|
||||||
"Dorothea", "Joffridus", "Kinna", "Waverly", "Trillby", "Donald", "Douce", "Jordan",
|
"Malkyn",
|
||||||
"Krea", "Willahelm", "Wendel", "Doran", "Duraina", "Joris", "Kypris", "William",
|
"Althalos",
|
||||||
"Wilberga", "Dumphey", "Dyota", "Josef", "Landerra", "Wimarc", "Winifred", "Eadmund",
|
"Aline",
|
||||||
"Eberhild", "Laurence", "Larraza", "Wystan", "Wofled", "Eckardus", "Edelot", "Leofrick",
|
"Eustace",
|
||||||
"Linet", "Xalvador", "Wymarc", "Edward", "Edyva", "Letholdus", "Loreena", "Zane", "Ysmay",
|
"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 = [
|
reactions = [
|
||||||
('2', "Hostile"),
|
("2", "Hostile"),
|
||||||
('3-5', "Unfriendly"),
|
("3-5", "Unfriendly"),
|
||||||
('6-8', "Unsure"),
|
("6-8", "Unsure"),
|
||||||
('9-11', "Talkative"),
|
("9-11", "Talkative"),
|
||||||
('12', "Helpful"),
|
("12", "Helpful"),
|
||||||
]
|
]
|
||||||
|
|
||||||
initiative = [
|
initiative = [
|
||||||
('1-3', "Enemy acts first"),
|
("1-3", "Enemy acts first"),
|
||||||
('4-6', "PC acts first"),
|
("4-6", "PC acts first"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -377,4 +625,3 @@ death_and_dismemberment = [
|
||||||
"rattled", # -1d4 WIS
|
"rattled", # -1d4 WIS
|
||||||
"disfigured", # -1d4 CHA
|
"disfigured", # -1d4 CHA
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,13 @@ from evennia.utils.evtable import EvTable
|
||||||
from .enums import Ability
|
from .enums import Ability
|
||||||
from .random_tables import (
|
from .random_tables import (
|
||||||
character_generation as chargen_table,
|
character_generation as chargen_table,
|
||||||
death_and_dismemberment as death_table
|
death_and_dismemberment as death_table,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Basic rolls
|
# Basic rolls
|
||||||
|
|
||||||
|
|
||||||
class EvAdventureRollEngine:
|
class EvAdventureRollEngine:
|
||||||
"""
|
"""
|
||||||
This groups all dice rolls of EvAdventure. These could all have been normal functions, but we
|
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
|
max_diesize = 1000
|
||||||
roll_string = roll_string.lower()
|
roll_string = roll_string.lower()
|
||||||
if 'd' not in roll_string:
|
if "d" not in roll_string:
|
||||||
raise TypeError(f"Dice roll '{roll_string}' was not recognized. "
|
raise TypeError(
|
||||||
"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)
|
)
|
||||||
|
number, diesize = roll_string.split("d", 1)
|
||||||
try:
|
try:
|
||||||
number = int(number)
|
number = int(number)
|
||||||
diesize = int(diesize)
|
diesize = int(diesize)
|
||||||
|
|
@ -104,8 +106,15 @@ class EvAdventureRollEngine:
|
||||||
else:
|
else:
|
||||||
return min(self.roll("1d20"), self.roll("1d20"))
|
return min(self.roll("1d20"), self.roll("1d20"))
|
||||||
|
|
||||||
def saving_throw(self, character, bonus_type=Ability.STR, target=15,
|
def saving_throw(
|
||||||
advantage=False, disadvantage=False, modifier=0):
|
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
|
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.
|
throws always tries to beat 15, so (d20 + bonus + modifier) > 15.
|
||||||
|
|
@ -142,9 +151,15 @@ class EvAdventureRollEngine:
|
||||||
return (dice_roll + bonus + modifier) > target, quality
|
return (dice_roll + bonus + modifier) > target, quality
|
||||||
|
|
||||||
def opposed_saving_throw(
|
def opposed_saving_throw(
|
||||||
self, attacker, defender,
|
self,
|
||||||
attack_type=Ability.STR, defense_type=Ability.ARMOR,
|
attacker,
|
||||||
advantage=False, disadvantage=False, modifier=0):
|
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.
|
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
|
defender_defense = getattr(defender, defense_type.value, 1) + 10
|
||||||
return self.saving_throw(attacker, bonus_type=attack_type,
|
return self.saving_throw(
|
||||||
target=defender_defense,
|
attacker,
|
||||||
advantage=advantage, disadvantage=disadvantage,
|
bonus_type=attack_type,
|
||||||
modifier=modifier)
|
target=defender_defense,
|
||||||
|
advantage=advantage,
|
||||||
|
disadvantage=disadvantage,
|
||||||
|
modifier=modifier,
|
||||||
|
)
|
||||||
|
|
||||||
def roll_random_table(self, dieroll, table_choices):
|
def roll_random_table(self, dieroll, table_choices):
|
||||||
"""
|
"""
|
||||||
|
|
@ -204,7 +223,7 @@ class EvAdventureRollEngine:
|
||||||
min_range = 10**6
|
min_range = 10**6
|
||||||
for (valrange, choice) in table_choices:
|
for (valrange, choice) in table_choices:
|
||||||
|
|
||||||
minval, *maxval = valrange.split('-', 1)
|
minval, *maxval = valrange.split("-", 1)
|
||||||
minval = abs(int(minval))
|
minval = abs(int(minval))
|
||||||
maxval = abs(int(maxval[0]) if maxval else minval)
|
maxval = abs(int(maxval[0]) if maxval else minval)
|
||||||
|
|
||||||
|
|
@ -240,7 +259,7 @@ class EvAdventureRollEngine:
|
||||||
bool: False if morale roll failed, True otherwise.
|
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):
|
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.
|
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 = {
|
death_map = {
|
||||||
"weakened": "strength",
|
"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":
|
if result == "dead":
|
||||||
character.handle_death()
|
character.handle_death()
|
||||||
else:
|
else:
|
||||||
|
|
@ -304,16 +323,15 @@ class EvAdventureRollEngine:
|
||||||
character.hp = new_hp
|
character.hp = new_hp
|
||||||
|
|
||||||
character.msg(
|
character.msg(
|
||||||
"~" * 78 +
|
"~" * 78 + "\n|yYou survive your brush with death, "
|
||||||
"\n|yYou survive your brush with death, "
|
|
||||||
f"but are |r{result.upper()}|y and permenently |rlose {loss} {abi}|y.|n\n"
|
f"but are |r{result.upper()}|y and permenently |rlose {loss} {abi}|y.|n\n"
|
||||||
f"|GYou recover |g{new_hp}|G health|.\n"
|
f"|GYou recover |g{new_hp}|G health|.\n" + "~" * 78
|
||||||
+ "~" * 78
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# character generation
|
# character generation
|
||||||
|
|
||||||
|
|
||||||
class EvAdventureCharacterGeneration:
|
class EvAdventureCharacterGeneration:
|
||||||
"""
|
"""
|
||||||
This collects all the rules for generating a new character. An instance of this class can be
|
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).
|
there is no GM to adjudicate a different choice).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
Initialize starting values
|
Initialize starting values
|
||||||
|
|
@ -351,7 +370,7 @@ class EvAdventureCharacterGeneration:
|
||||||
roll_engine = EvAdventureRollEngine()
|
roll_engine = EvAdventureRollEngine()
|
||||||
|
|
||||||
# name will likely be modified later
|
# 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)
|
# base attribute bonuses (flat +1 bonus)
|
||||||
self.strength = 2
|
self.strength = 2
|
||||||
|
|
@ -362,17 +381,17 @@ class EvAdventureCharacterGeneration:
|
||||||
self.charisma = 2
|
self.charisma = 2
|
||||||
|
|
||||||
# physical attributes (only for rp purposes)
|
# physical attributes (only for rp purposes)
|
||||||
self.physique = roll_engine.roll_random_table('1d20', chargen_table['physique'])
|
self.physique = roll_engine.roll_random_table("1d20", chargen_table["physique"])
|
||||||
self.face = roll_engine.roll_random_table('1d20', chargen_table['face'])
|
self.face = roll_engine.roll_random_table("1d20", chargen_table["face"])
|
||||||
self.skin = roll_engine.roll_random_table('1d20', chargen_table['skin'])
|
self.skin = roll_engine.roll_random_table("1d20", chargen_table["skin"])
|
||||||
self.hair = roll_engine.roll_random_table('1d20', chargen_table['hair'])
|
self.hair = roll_engine.roll_random_table("1d20", chargen_table["hair"])
|
||||||
self.clothing = roll_engine.roll_random_table('1d20', chargen_table['clothing'])
|
self.clothing = roll_engine.roll_random_table("1d20", chargen_table["clothing"])
|
||||||
self.speech = roll_engine.roll_random_table('1d20', chargen_table['speech'])
|
self.speech = roll_engine.roll_random_table("1d20", chargen_table["speech"])
|
||||||
self.virtue = roll_engine.roll_random_table('1d20', chargen_table['virtue'])
|
self.virtue = roll_engine.roll_random_table("1d20", chargen_table["virtue"])
|
||||||
self.vice = roll_engine.roll_random_table('1d20', chargen_table['vice'])
|
self.vice = roll_engine.roll_random_table("1d20", chargen_table["vice"])
|
||||||
self.background = roll_engine.roll_random_table('1d20', chargen_table['background'])
|
self.background = roll_engine.roll_random_table("1d20", chargen_table["background"])
|
||||||
self.misfortune = roll_engine.roll_random_table('1d20', chargen_table['misfortune'])
|
self.misfortune = roll_engine.roll_random_table("1d20", chargen_table["misfortune"])
|
||||||
self.alignment = roll_engine.roll_random_table('1d20', chargen_table['alignment'])
|
self.alignment = roll_engine.roll_random_table("1d20", chargen_table["alignment"])
|
||||||
|
|
||||||
# same for all
|
# same for all
|
||||||
self.exploration_speed = 120
|
self.exploration_speed = 120
|
||||||
|
|
@ -383,22 +402,23 @@ class EvAdventureCharacterGeneration:
|
||||||
self.level = 1
|
self.level = 1
|
||||||
|
|
||||||
# random equipment
|
# 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(
|
_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.helmet = "helmet" if "helmet" in _helmet_and_shield else "none"
|
||||||
self.shield = "shield" if "shield" 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 = [
|
self.backpack = [
|
||||||
"ration",
|
"ration",
|
||||||
"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["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 1"]),
|
||||||
roll_engine.roll_random_table('1d20', chargen_table["general gear 2"]),
|
roll_engine.roll_random_table("1d20", chargen_table["general gear 2"]),
|
||||||
]
|
]
|
||||||
|
|
||||||
def build_desc(self):
|
def build_desc(self):
|
||||||
|
|
@ -489,12 +509,14 @@ class EvAdventureCharacterGeneration:
|
||||||
|
|
||||||
# character improvement
|
# character improvement
|
||||||
|
|
||||||
|
|
||||||
class EvAdventureImprovement:
|
class EvAdventureImprovement:
|
||||||
"""
|
"""
|
||||||
Handle XP gains and level upgrades. Grouped in a class in order to
|
Handle XP gains and level upgrades. Grouped in a class in order to
|
||||||
make it easier to override the mechanism.
|
make it easier to override the mechanism.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
xp_per_level = 1000
|
xp_per_level = 1000
|
||||||
amount_of_abilities_to_upgrade = 3
|
amount_of_abilities_to_upgrade = 3
|
||||||
max_ability_bonus = 10 # bonus +10, defense 20
|
max_ability_bonus = 10 # bonus +10, defense 20
|
||||||
|
|
@ -546,12 +568,14 @@ class EvAdventureImprovement:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
character.hp_max = max(character.max_hp + 1,
|
character.hp_max = max(
|
||||||
EvAdventureRollEngine.roll(f"{character.level}d8"))
|
character.max_hp + 1, EvAdventureRollEngine.roll(f"{character.level}d8")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# character sheet visualization
|
# character sheet visualization
|
||||||
|
|
||||||
|
|
||||||
class EvAdventureCharacterSheet:
|
class EvAdventureCharacterSheet:
|
||||||
"""
|
"""
|
||||||
Generate a character sheet. This is grouped in a class in order to make
|
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
|
equipment = character.equipment.wielded + character.equipment.worn + character.carried
|
||||||
# divide into chunks of max 10 length (to go into two columns)
|
# divide into chunks of max 10 length (to go into two columns)
|
||||||
equipment_table = EvTable(
|
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(
|
form.map(
|
||||||
cells={
|
cells={
|
||||||
1: character.key,
|
1: character.key,
|
||||||
|
|
@ -610,12 +634,12 @@ class EvAdventureCharacterSheet:
|
||||||
7: f"{character.hp}/{character.hp_max}",
|
7: f"{character.hp}/{character.hp_max}",
|
||||||
8: character.xp,
|
8: character.xp,
|
||||||
9: character.exploration_speed,
|
9: character.exploration_speed,
|
||||||
'A': character.combat_speed,
|
"A": character.combat_speed,
|
||||||
'B': character.db.desc,
|
"B": character.db.desc,
|
||||||
},
|
},
|
||||||
tables={
|
tables={
|
||||||
1: equipment_table,
|
1: equipment_table,
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
return str(form)
|
return str(form)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,33 @@ class EvAdventureMixin:
|
||||||
Provides a set of pre-made characters.
|
Provides a set of pre-made characters.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.character = create.create_object(EvAdventureCharacter, key="testchar")
|
self.character = create.create_object(EvAdventureCharacter, key="testchar")
|
||||||
self.helmet = create.create_object(
|
self.helmet = create.create_object(
|
||||||
EvAdventureObject, key="helmet",
|
EvAdventureObject,
|
||||||
attributes=[("inventory_use_slot", enums.WieldLocation.HEAD),
|
key="helmet",
|
||||||
("armor", 1)])
|
attributes=[("inventory_use_slot", enums.WieldLocation.HEAD), ("armor", 1)],
|
||||||
|
)
|
||||||
self.shield = create.create_object(
|
self.shield = create.create_object(
|
||||||
EvAdventureObject, key="shield",
|
EvAdventureObject,
|
||||||
attributes=[("inventory_use_slot", enums.WieldLocation.SHIELD_HAND),
|
key="shield",
|
||||||
("armor", 1)])
|
attributes=[("inventory_use_slot", enums.WieldLocation.SHIELD_HAND), ("armor", 1)],
|
||||||
|
)
|
||||||
self.armor = create.create_object(
|
self.armor = create.create_object(
|
||||||
EvAdventureObject, key="armor",
|
EvAdventureObject,
|
||||||
attributes=[("inventory_use_slot", enums.WieldLocation.BODY),
|
key="armor",
|
||||||
("armor", 11)])
|
attributes=[("inventory_use_slot", enums.WieldLocation.BODY), ("armor", 11)],
|
||||||
|
)
|
||||||
self.weapon = create.create_object(
|
self.weapon = create.create_object(
|
||||||
EvAdventureObject, key="weapon",
|
EvAdventureObject,
|
||||||
attributes=[("inventory_use_slot", enums.WieldLocation.WEAPON_HAND)])
|
key="weapon",
|
||||||
|
attributes=[("inventory_use_slot", enums.WieldLocation.WEAPON_HAND)],
|
||||||
|
)
|
||||||
self.big_weapon = create.create_object(
|
self.big_weapon = create.create_object(
|
||||||
EvAdventureObject, key="big_weapon",
|
EvAdventureObject,
|
||||||
attributes=[("inventory_use_slot", enums.WieldLocation.TWO_HANDS)])
|
key="big_weapon",
|
||||||
|
attributes=[("inventory_use_slot", enums.WieldLocation.TWO_HANDS)],
|
||||||
|
)
|
||||||
self.item = create.create_object(EvAdventureObject, key="backpack item")
|
self.item = create.create_object(EvAdventureObject, key="backpack item")
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from evennia.utils.test_resources import BaseEvenniaTest
|
||||||
from evennia.utils import create
|
from evennia.utils import create
|
||||||
from .mixins import EvAdventureMixin
|
from .mixins import EvAdventureMixin
|
||||||
from .. import combat_turnbased
|
from .. import combat_turnbased
|
||||||
from .. charactersd import EvAdventureCharacter
|
from ..charactersd import EvAdventureCharacter
|
||||||
|
|
||||||
|
|
||||||
class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
|
class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
|
|
@ -16,8 +16,12 @@ class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
Test the turn-based combat-handler implementation.
|
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):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.combathandler = combat_turnbased.EvAdventureCombatHandler.objects.create()
|
self.combathandler = combat_turnbased.EvAdventureCombatHandler.objects.create()
|
||||||
|
|
@ -50,8 +54,6 @@ class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
def test_attack(self, mock_randint):
|
def test_attack(self, mock_randint):
|
||||||
mock_randint = 8
|
mock_randint = 8
|
||||||
self.combathandler.register_action(
|
self.combathandler.register_action(
|
||||||
combat_turnbased.CombatActionAttack,
|
combat_turnbased.CombatActionAttack, self.combatant, self.target
|
||||||
self.combatant, self.target)
|
)
|
||||||
self.combathandler._end_turn()
|
self.combathandler._end_turn()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
|
||||||
Test the roll engine in the rules module. This is the core of any RPG.
|
Test the roll engine in the rules module. This is the core of any RPG.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.roll_engine = rules.EvAdventureRollEngine()
|
self.roll_engine = rules.EvAdventureRollEngine()
|
||||||
|
|
@ -40,15 +41,15 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
|
||||||
|
|
||||||
def test_roll_limits(self):
|
def test_roll_limits(self):
|
||||||
with self.assertRaises(TypeError):
|
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):
|
with self.assertRaises(TypeError):
|
||||||
self.roll_engine.roll('100') # no d
|
self.roll_engine.roll("100") # no d
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
self.roll_engine.roll('dummy') # non-numerical
|
self.roll_engine.roll("dummy") # non-numerical
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
self.roll_engine.roll('Ad4') # non-numerical
|
self.roll_engine.roll("Ad4") # non-numerical
|
||||||
with self.assertRaises(TypeError):
|
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")
|
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
||||||
def test_roll_with_advantage_disadvantage(self, mock_randint):
|
def test_roll_with_advantage_disadvantage(self, mock_randint):
|
||||||
|
|
@ -61,19 +62,18 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
|
||||||
|
|
||||||
# cancel each other out
|
# cancel each other out
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.roll_with_advantage_or_disadvantage(
|
self.roll_engine.roll_with_advantage_or_disadvantage(disadvantage=True, advantage=True),
|
||||||
disadvantage=True, advantage=True), 9)
|
9,
|
||||||
|
)
|
||||||
mock_randint.assert_called_once()
|
mock_randint.assert_called_once()
|
||||||
mock_randint.reset_mock()
|
mock_randint.reset_mock()
|
||||||
|
|
||||||
# run with advantage/disadvantage
|
# run with advantage/disadvantage
|
||||||
self.assertEqual(
|
self.assertEqual(self.roll_engine.roll_with_advantage_or_disadvantage(advantage=True), 9)
|
||||||
self.roll_engine.roll_with_advantage_or_disadvantage(advantage=True), 9)
|
|
||||||
mock_randint.assert_has_calls([call(1, 20), call(1, 20)])
|
mock_randint.assert_has_calls([call(1, 20), call(1, 20)])
|
||||||
mock_randint.reset_mock()
|
mock_randint.reset_mock()
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(self.roll_engine.roll_with_advantage_or_disadvantage(disadvantage=True), 9)
|
||||||
self.roll_engine.roll_with_advantage_or_disadvantage(disadvantage=True), 9)
|
|
||||||
mock_randint.assert_has_calls([call(1, 20), call(1, 20)])
|
mock_randint.assert_has_calls([call(1, 20), call(1, 20)])
|
||||||
mock_randint.reset_mock()
|
mock_randint.reset_mock()
|
||||||
|
|
||||||
|
|
@ -86,39 +86,40 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
|
||||||
character.dexterity = 1
|
character.dexterity = 1
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.saving_throw(character, bonus_type=enums.Ability.STR),
|
self.roll_engine.saving_throw(character, bonus_type=enums.Ability.STR), (False, None)
|
||||||
(False, None))
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.saving_throw(character, bonus_type=enums.Ability.DEX, modifier=1),
|
self.roll_engine.saving_throw(character, bonus_type=enums.Ability.DEX, modifier=1),
|
||||||
(False, None))
|
(False, None),
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.saving_throw(
|
self.roll_engine.saving_throw(
|
||||||
character,
|
character, advantage=True, bonus_type=enums.Ability.DEX, modifier=6
|
||||||
advantage=True,
|
),
|
||||||
bonus_type=enums.Ability.DEX, modifier=6),
|
(False, None),
|
||||||
(False, None))
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.saving_throw(
|
self.roll_engine.saving_throw(
|
||||||
character,
|
character, disadvantage=True, bonus_type=enums.Ability.DEX, modifier=7
|
||||||
disadvantage=True,
|
),
|
||||||
bonus_type=enums.Ability.DEX, modifier=7),
|
(True, None),
|
||||||
(True, None))
|
)
|
||||||
|
|
||||||
mock_randint.return_value = 1
|
mock_randint.return_value = 1
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.saving_throw(
|
self.roll_engine.saving_throw(
|
||||||
character,
|
character, disadvantage=True, bonus_type=enums.Ability.STR, modifier=2
|
||||||
disadvantage=True,
|
),
|
||||||
bonus_type=enums.Ability.STR, modifier=2),
|
(False, enums.Ability.CRITICAL_FAILURE),
|
||||||
(False, enums.Ability.CRITICAL_FAILURE))
|
)
|
||||||
|
|
||||||
mock_randint.return_value = 20
|
mock_randint.return_value = 20
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.saving_throw(
|
self.roll_engine.saving_throw(
|
||||||
character,
|
character, disadvantage=True, bonus_type=enums.Ability.STR, modifier=2
|
||||||
disadvantage=True,
|
),
|
||||||
bonus_type=enums.Ability.STR, modifier=2),
|
(True, enums.Ability.CRITICAL_SUCCESS),
|
||||||
(True, enums.Ability.CRITICAL_SUCCESS))
|
)
|
||||||
|
|
||||||
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
||||||
def test_opposed_saving_throw(self, mock_randint):
|
def test_opposed_saving_throw(self, mock_randint):
|
||||||
|
|
@ -130,18 +131,19 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.opposed_saving_throw(
|
self.roll_engine.opposed_saving_throw(
|
||||||
attacker, defender,
|
attacker, defender, attack_type=enums.Ability.STR, defense_type=enums.Ability.ARMOR
|
||||||
attack_type=enums.Ability.STR, defense_type=enums.Ability.ARMOR
|
|
||||||
),
|
),
|
||||||
(False, None)
|
(False, None),
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.opposed_saving_throw(
|
self.roll_engine.opposed_saving_throw(
|
||||||
attacker, defender,
|
attacker,
|
||||||
attack_type=enums.Ability.STR, defense_type=enums.Ability.ARMOR,
|
defender,
|
||||||
modifier=2
|
attack_type=enums.Ability.STR,
|
||||||
|
defense_type=enums.Ability.ARMOR,
|
||||||
|
modifier=2,
|
||||||
),
|
),
|
||||||
(True, None)
|
(True, None),
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
||||||
|
|
@ -150,36 +152,40 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.roll_random_table(
|
self.roll_engine.roll_random_table(
|
||||||
"1d20", random_tables.character_generation['physique']),
|
"1d20", random_tables.character_generation["physique"]
|
||||||
"scrawny"
|
),
|
||||||
|
"scrawny",
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.roll_engine.roll_random_table("1d20", random_tables.character_generation["vice"]),
|
||||||
|
"irascible",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.roll_random_table(
|
self.roll_engine.roll_random_table(
|
||||||
"1d20", random_tables.character_generation['vice']),
|
"1d20", random_tables.character_generation["alignment"]
|
||||||
"irascible"
|
),
|
||||||
|
"neutrality",
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.roll_random_table(
|
self.roll_engine.roll_random_table(
|
||||||
"1d20", random_tables.character_generation['alignment']),
|
"1d20", random_tables.character_generation["helmets and shields"]
|
||||||
"neutrality"
|
),
|
||||||
)
|
"no helmet or shield",
|
||||||
self.assertEqual(
|
|
||||||
self.roll_engine.roll_random_table(
|
|
||||||
"1d20", random_tables.character_generation['helmets and shields']),
|
|
||||||
"no helmet or shield"
|
|
||||||
)
|
)
|
||||||
# testing faulty rolls outside of the table ranges
|
# testing faulty rolls outside of the table ranges
|
||||||
mock_randint.return_value = 25
|
mock_randint.return_value = 25
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.roll_random_table(
|
self.roll_engine.roll_random_table(
|
||||||
"1d20", random_tables.character_generation['helmets and shields']),
|
"1d20", random_tables.character_generation["helmets and shields"]
|
||||||
"helmet and shield"
|
),
|
||||||
|
"helmet and shield",
|
||||||
)
|
)
|
||||||
mock_randint.return_value = -10
|
mock_randint.return_value = -10
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.roll_engine.roll_random_table(
|
self.roll_engine.roll_random_table(
|
||||||
"1d20", random_tables.character_generation['helmets and shields']),
|
"1d20", random_tables.character_generation["helmets and shields"]
|
||||||
"no helmet or shield"
|
),
|
||||||
|
"no helmet or shield",
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
||||||
|
|
@ -202,11 +208,11 @@ class EvAdventureRollEngineTest(BaseEvenniaTest):
|
||||||
|
|
||||||
mock_randint.return_value = 5
|
mock_randint.return_value = 5
|
||||||
self.roll_engine.heal_from_rest(character)
|
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
|
mock_randint.assert_called_with(1, 8) # 1d8
|
||||||
|
|
||||||
self.roll_engine.heal_from_rest(character)
|
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")
|
@patch("evennia.contrib.tutorials.evadventure.rules.randint")
|
||||||
def test_roll_death(self, mock_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.misfortune, "exiled")
|
||||||
self.assertEqual(self.chargen.armor, "gambeson")
|
self.assertEqual(self.chargen.armor, "gambeson")
|
||||||
self.assertEqual(self.chargen.shield, "shield")
|
self.assertEqual(self.chargen.shield, "shield")
|
||||||
self.assertEqual(self.chargen.backpack, ['ration', 'ration', 'waterskin',
|
self.assertEqual(
|
||||||
'waterskin', 'drill', 'twine'])
|
self.chargen.backpack, ["ration", "ration", "waterskin", "waterskin", "drill", "twine"]
|
||||||
|
)
|
||||||
|
|
||||||
def test_build_desc(self):
|
def test_build_desc(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.chargen.build_desc(),
|
self.chargen.build_desc(),
|
||||||
"Herbalist. Wears stained clothes, and has hoarse speech. Has a scrawny physique, "
|
"Herbalist. Wears stained clothes, and has hoarse speech. Has a scrawny physique, "
|
||||||
"a broken face, pockmarked skin and greased hair. Is honest, but irascible. "
|
"a broken face, pockmarked skin and greased hair. Is honest, but irascible. "
|
||||||
"Has been exiled in the past. Favors neutrality."
|
"Has been exiled in the past. Favors neutrality.",
|
||||||
)
|
)
|
||||||
|
|
||||||
@parameterized.expand([
|
@parameterized.expand(
|
||||||
# source, target, value, new_source_val, new_target_val
|
[
|
||||||
(enums.Ability.CON, enums.Ability.STR, 1, 1, 3),
|
# source, target, value, new_source_val, new_target_val
|
||||||
(enums.Ability.INT, enums.Ability.DEX, 1, 1, 3),
|
(enums.Ability.CON, enums.Ability.STR, 1, 1, 3),
|
||||||
(enums.Ability.CHA, enums.Ability.CON, 1, 1, 3),
|
(enums.Ability.INT, enums.Ability.DEX, 1, 1, 3),
|
||||||
(enums.Ability.STR, enums.Ability.WIS, 1, 1, 3),
|
(enums.Ability.CHA, enums.Ability.CON, 1, 1, 3),
|
||||||
(enums.Ability.WIS, enums.Ability.CHA, 1, 1, 3),
|
(enums.Ability.STR, enums.Ability.WIS, 1, 1, 3),
|
||||||
(enums.Ability.DEX, enums.Ability.DEX, 1, 2, 2),
|
(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):
|
def test_adjust_attribute(self, source, target, value, new_source_val, new_target_val):
|
||||||
self.chargen.adjust_attribute(source, target, value)
|
self.chargen.adjust_attribute(source, target, value)
|
||||||
self.assertEqual(
|
self.assertEqual(getattr(self.chargen, source.value), new_source_val, f"{source}->{target}")
|
||||||
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, target.value), new_target_val, f"{source}->{target}")
|
|
||||||
|
|
||||||
def test_adjust_consecutive(self):
|
def test_adjust_consecutive(self):
|
||||||
# gradually shift all to STR (starts at 2)
|
# gradually shift all to STR (starts at 2)
|
||||||
|
|
@ -311,6 +318,7 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
Test the equipment mechanism.
|
Test the equipment mechanism.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _get_empty_slots(self):
|
def _get_empty_slots(self):
|
||||||
return {
|
return {
|
||||||
enums.WieldLocation.BACKPACK: [],
|
enums.WieldLocation.BACKPACK: [],
|
||||||
|
|
@ -324,15 +332,17 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
def test_equipmenthandler_max_slots(self):
|
def test_equipmenthandler_max_slots(self):
|
||||||
self.assertEqual(self.character.equipment.max_slots, 11)
|
self.assertEqual(self.character.equipment.max_slots, 11)
|
||||||
|
|
||||||
@parameterized.expand([
|
@parameterized.expand(
|
||||||
# size, pass_validation?
|
[
|
||||||
(1, True),
|
# size, pass_validation?
|
||||||
(2, True),
|
(1, True),
|
||||||
(11, True),
|
(2, True),
|
||||||
(12, False),
|
(11, True),
|
||||||
(20, False),
|
(12, False),
|
||||||
(25, False)
|
(20, False),
|
||||||
])
|
(25, False),
|
||||||
|
]
|
||||||
|
)
|
||||||
def test_validate_slot_usage(self, size, is_ok):
|
def test_validate_slot_usage(self, size, is_ok):
|
||||||
obj = MagicMock()
|
obj = MagicMock()
|
||||||
obj.size = size
|
obj.size = size
|
||||||
|
|
@ -343,15 +353,17 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
with self.assertRaises(characters.EquipmentError):
|
with self.assertRaises(characters.EquipmentError):
|
||||||
self.character.equipment.validate_slot_usage(obj)
|
self.character.equipment.validate_slot_usage(obj)
|
||||||
|
|
||||||
@parameterized.expand([
|
@parameterized.expand(
|
||||||
# item, where
|
[
|
||||||
("helmet", enums.WieldLocation.HEAD),
|
# item, where
|
||||||
("shield", enums.WieldLocation.SHIELD_HAND),
|
("helmet", enums.WieldLocation.HEAD),
|
||||||
("armor", enums.WieldLocation.BODY),
|
("shield", enums.WieldLocation.SHIELD_HAND),
|
||||||
("weapon", enums.WieldLocation.WEAPON_HAND),
|
("armor", enums.WieldLocation.BODY),
|
||||||
("big_weapon", enums.WieldLocation.TWO_HANDS),
|
("weapon", enums.WieldLocation.WEAPON_HAND),
|
||||||
("item", enums.WieldLocation.BACKPACK),
|
("big_weapon", enums.WieldLocation.TWO_HANDS),
|
||||||
])
|
("item", enums.WieldLocation.BACKPACK),
|
||||||
|
]
|
||||||
|
)
|
||||||
def test_use(self, itemname, where):
|
def test_use(self, itemname, where):
|
||||||
self.assertEqual(self.character.equipment.slots, self._get_empty_slots())
|
self.assertEqual(self.character.equipment.slots, self._get_empty_slots())
|
||||||
|
|
||||||
|
|
@ -366,32 +378,32 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
def test_store(self):
|
def test_store(self):
|
||||||
self.character.equipment.store(self.weapon)
|
self.character.equipment.store(self.weapon)
|
||||||
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], None)
|
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], None)
|
||||||
self.assertTrue(
|
self.assertTrue(self.weapon in self.character.equipment.slots[enums.WieldLocation.BACKPACK])
|
||||||
self.weapon in self.character.equipment.slots[enums.WieldLocation.BACKPACK])
|
|
||||||
|
|
||||||
def test_two_handed_exclusive(self):
|
def test_two_handed_exclusive(self):
|
||||||
"""Two-handed weapons can't be used together with weapon+shield"""
|
"""Two-handed weapons can't be used together with weapon+shield"""
|
||||||
self.character.equipment.use(self.big_weapon)
|
self.character.equipment.use(self.big_weapon)
|
||||||
self.assertEqual(
|
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
|
# equipping sword or shield removes two-hander
|
||||||
self.character.equipment.use(self.shield)
|
self.character.equipment.use(self.shield)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield)
|
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield
|
||||||
self.assertEqual(
|
)
|
||||||
self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], None)
|
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], None)
|
||||||
self.character.equipment.use(self.weapon)
|
self.character.equipment.use(self.weapon)
|
||||||
self.assertEqual(
|
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
|
# the two-hander removes the two weapons
|
||||||
self.character.equipment.use(self.big_weapon)
|
self.character.equipment.use(self.big_weapon)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.character.equipment.slots[enums.WieldLocation.TWO_HANDS], self.big_weapon)
|
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.SHIELD_HAND], None)
|
||||||
self.assertEqual(
|
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], None)
|
||||||
self.character.equipment.slots[enums.WieldLocation.WEAPON_HAND], None)
|
|
||||||
|
|
||||||
def test_remove__with_obj(self):
|
def test_remove__with_obj(self):
|
||||||
self.character.equipment.use(self.shield)
|
self.character.equipment.use(self.shield)
|
||||||
|
|
@ -399,16 +411,19 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
self.character.equipment.store(self.weapon)
|
self.character.equipment.store(self.weapon)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield)
|
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.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.shield), [self.shield])
|
||||||
self.assertEqual(self.character.equipment.remove(self.item), [self.item])
|
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.SHIELD_HAND], None)
|
||||||
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.BACKPACK],
|
self.assertEqual(
|
||||||
[self.weapon])
|
self.character.equipment.slots[enums.WieldLocation.BACKPACK], [self.weapon]
|
||||||
|
)
|
||||||
|
|
||||||
def test_remove__with_slot(self):
|
def test_remove__with_slot(self):
|
||||||
self.character.equipment.use(self.shield)
|
self.character.equipment.use(self.shield)
|
||||||
|
|
@ -416,17 +431,20 @@ class EvAdventureEquipmentTest(EvAdventureMixin, BaseEvenniaTest):
|
||||||
self.character.equipment.store(self.helmet)
|
self.character.equipment.store(self.helmet)
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.character.equipment.slots[enums.WieldLocation.SHIELD_HAND], self.shield)
|
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.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.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], [])
|
self.assertEqual(self.character.equipment.slots[enums.WieldLocation.BACKPACK], [])
|
||||||
|
|
||||||
def test_properties(self):
|
def test_properties(self):
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,3 @@ from . import enums
|
||||||
from . import combat_turnbased
|
from . import combat_turnbased
|
||||||
from . import rules
|
from . import rules
|
||||||
from . import random_tables
|
from . import random_tables
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,3 @@
|
||||||
Various utilities.
|
Various utilities.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue