More work on tech demo area

This commit is contained in:
Griatch 2022-07-12 11:51:05 +02:00
parent 1ed7ffa095
commit afadb1001e
16 changed files with 275 additions and 252 deletions

View file

@ -172,6 +172,8 @@ Up requirements to Django 4.0+, Twisted 22+, Python 3.9 or 3.10
now return `None` instead of `.db.desc` if no sdesc is set; fallback in hook (inspectorCaracal)
- Reworked text2html parser to avoid problems with stateful color tags (inspectorCaracal)
- Simplified `EvMenu.options_formatter` hook to use `EvColumn` and f-strings (inspectorcaracal)
- Allow `# CODE`, `# HEADER` etc as well as `#CODE`/`#HEADER` in batchcode
files - this works better with black linting.
## Evennia 0.9.5

View file

@ -4,19 +4,17 @@ The base Command class.
All commands in Evennia inherit from the 'Command' class in this module.
"""
import re
import math
import inspect
import math
import re
from django.conf import settings
from django.urls import reverse
from django.utils.text import slugify
from evennia.locks.lockhandler import LockHandler
from evennia.utils.utils import is_iter, fill, lazy_property, make_iter
from evennia.utils.evtable import EvTable
from evennia.utils.ansi import ANSIString
from evennia.utils.evtable import EvTable
from evennia.utils.utils import fill, is_iter, lazy_property, make_iter
CMD_IGNORE_PREFIXES = settings.CMD_IGNORE_PREFIXES

View file

@ -0,0 +1,7 @@
"""
EvAdventure - a complete game in Evennia.
This is an implementation of, and reference code to, the game created in the
documentation's beginner tutorial.
"""

View file

@ -15,45 +15,69 @@ You can also build/rebuild individiaul #CODE blocks in the `batchcode/interactiv
"""
#HEADER
# HEADER
# this is loaded at the top of every #CODE block
from evennia import create_object, search_object
from evennia import DefaultExit
from evennia import DefaultExit, create_object, search_object
from evennia.contrib.tutorials import evadventure
from evennia.contrib.tutorials.evadventure.objects import (
EvAdventureObject, EvAdventureRunestone, EvAdventureRunestone, EvAdventureConsumable,
EvAdventureObjectFiller)
from evennia.contrib.tutorials.evadventure.rooms import EvAdventureRoom
from evennia.contrib.tutorials.evadventure.combat_turnbasedA import EvAdventureCombatHandler
from evennia.contrib.tutorials.evadventure import npcs
from evennia.contrib.tutorials.evadventure.combat_turnbased import EvAdventureCombatHandler
from evennia.contrib.tutorials.evadventure.objects import (
EvAdventureConsumable,
EvAdventureObject,
EvAdventureObjectFiller,
EvAdventureRunestone,
)
from evennia.contrib.tutorials.evadventure.rooms import EvAdventureRoom
#CODE
# CODE
# Hub room evtechdemo#00
# for other test areas to link back to. Connects in turn back to Limbo.
limbo = search_object("Limbo")
hub_room = create_object(EvAdventureRoom, key="Techdemo Hub", aliases=("evtechdemo#00",),
attributes=[("desc", "Central hub for EvAdventure tech demo.")])
create_object(DefaultExit, key="EvAdventure Techdemo", aliases=("techdemo",),
location=limbo, destination=hub_room)
create_object(DefaultExit, key="Back to Limbo", aliases=("limbo", "back"),
location=hub_room, destination=limbo)
limbo = search_object("Limbo")[0]
hub_room = create_object(
EvAdventureRoom,
key="Techdemo Hub",
aliases=("evtechdemo#00",),
attributes=[("desc", "Central hub for EvAdventure tech demo.")],
)
create_object(
DefaultExit,
key="EvAdventure Techdemo",
aliases=("techdemo", "demo", "evadventure"),
location=limbo,
destination=hub_room,
)
create_object(
DefaultExit,
key="Back to Limbo",
aliases=("limbo", "back"),
location=hub_room,
destination=limbo,
)
#CODE
# CODE
# A combat room evtechdemo#01
# with a static enemy
combat_room = create_object(EvAdventureRoom, key="Combat Arena", aliases=("evtechdemo#01",))
combat_room_enemy = create_object(npcs.EvadventureMob, key="Training Dummy")
combat_room_enemy = create_object(
npcs.EvadventureMob, key="Training Dummy", aliases=("dummy",), location=combat_room
)
# link to/back to hub
hub_room = search_object("evtechdemo#00")
create_object(DefaultExit, key="Back to Hub", aliases=("back", "hub"),
location=combat_room, destination=hub_room)
create_object(DefaultExit, key="combat test", aliases=("combat"),
location=combat_room, destination=hub_room)
hub_room = search_object("evtechdemo#00")[0]
create_object(
DefaultExit, key="combat test", aliases=("combat",), location=hub_room, destination=combat_room
)
create_object(
DefaultExit,
key="Back to Hub",
aliases=("back", "hub"),
location=combat_room,
destination=hub_room,
)

View file

@ -5,10 +5,11 @@ Base Character and NPCs.
from evennia.objects.objects import DefaultCharacter, DefaultObject
from evennia.typeclasses.attributes import AttributeProperty
from evennia.utils.utils import lazy_property, int2str
from .objects import EvAdventureObject
from evennia.utils.utils import int2str, lazy_property
from . import rules
from .enums import Ability, WieldLocation
from .objects import EvAdventureObject
class EquipmentError(TypeError):
@ -290,11 +291,12 @@ class EquipmentHandler:
in the list after all).
"""
return [obj for obj in slots[WieldLocation.BACKPACK]
if obj.inventory_use_slot in (
WieldLocation.WEAPON_HAND,
WieldLocation.TWO_HANDS,
WieldLocation.SHIELD_HAND)]
return [
obj
for obj in slots[WieldLocation.BACKPACK]
if obj.inventory_use_slot
in (WieldLocation.WEAPON_HAND, WieldLocation.TWO_HANDS, WieldLocation.SHIELD_HAND)
]
def get_wearable_objects_from_backpack(self):
"""
@ -307,11 +309,11 @@ class EquipmentHandler:
in the list after all).
"""
return [obj for obj in slots[WieldLocation.BACKPACK]
if obj.inventory_use_slot in (
WieldLocation.BODY,
WieldLocation.HEAD
)]
return [
obj
for obj in slots[WieldLocation.BACKPACK]
if obj.inventory_use_slot in (WieldLocation.BODY, WieldLocation.HEAD)
]
def get_usable_objects_from_backpack(self):
"""
@ -327,7 +329,7 @@ class EquipmentHandler:
class LivingMixin:
"""
Helpers shared between all living things.
Mixin class to use for all living things.
"""
@ -488,64 +490,3 @@ class EvAdventureCharacter(LivingMixin, DefaultCharacter):
Called when character dies.
"""
class EvAdventureNPC(LivingMixin, DefaultCharacter):
"""
This is the base class for all non-player entities, including monsters. These
generally don't advance in level but uses a simplified, abstract measure of how
dangerous or competent they are - the 'hit dice' (HD).
HD indicates how much health they have and how hard they hit. In _Knave_, HD also
defaults to being the bonus for all abilities. HP is 4 x Hit die (this can then be
customized per-entity of course).
Morale is set explicitly per-NPC, usually between 7 and 9.
Monsters don't use equipment in the way PCs do, instead they have a fixed armor
value, and their Abilities are dynamically generated from the HD (hit_dice).
If wanting monsters or NPCs that can level and work the same as PCs, base them off the
EvAdventureCharacter class instead.
"""
hit_dice = AttributeProperty(default=1)
armor = AttributeProperty(default=11)
morale = AttributeProperty(default=9)
hp = AttributeProperty(default=8)
@property
def strength(self):
return self.hit_dice
@property
def dexterity(self):
return self.hit_dice
@property
def constitution(self):
return self.hit_dice
@property
def intelligence(self):
return self.hit_dice
@property
def wisdom(self):
return self.hit_dice
@property
def charisma(self):
return self.hit_dice
@property
def hp_max(self):
return self.hit_dice * 4
def at_object_creation(self):
"""
Start with max health.
"""
self.hp = self.hp_max

View file

@ -99,15 +99,16 @@ Choose who to block:
"""
from datetime import datetime
from collections import defaultdict
from datetime import datetime
from evennia.scripts.scripts import DefaultScript
from evennia.typeclasses.attributes import AttributeProperty
from evennia.utils import dbserialize, delay, evmenu, evtable
from evennia.utils.utils import make_iter
from evennia.utils import evtable, dbserialize, delay, evmenu
from .enums import Ability
from . import rules
from . import rules
from .enums import Ability
COMBAT_HANDLER_KEY = "evadventure_turnbased_combathandler"
COMBAT_HANDLER_INTERVAL = 60
@ -242,7 +243,7 @@ class CombatActionAttack(CombatAction):
# figure out disadvantage (gained by enemy stunts/actions)
disadvantage = bool(self.combathandler.disadvantage_matrix[attacker].pop(defender, False))
is_hit, quality = rules.EvAdventureRollEngine.opposed_saving_throw(
is_hit, quality = rules.dice.opposed_saving_throw(
attacker,
defender,
attack_type=attacker.weapon.attack_type,
@ -295,9 +296,9 @@ class CombatActionStunt(CombatAction):
# quality doesn't matter for stunts, they are either successful or not
attacker = self.combatant
advantage, disadvantage = False
advantage, disadvantage = False, False
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
is_success, _ = rules.dice.opposed_saving_throw(
attacker,
defender,
attack_type=self.attack_type,
@ -333,6 +334,7 @@ class CombatActionUseItem(CombatAction):
combat_post_use
"""
key = "Use Item"
desc = "[U]se item"
aliases = ("u", "item", "use item")
@ -406,7 +408,7 @@ class CombatActionBlock(CombatAction):
advantage = bool(self.advantage_matrix[combatant].pop(fleeing_target, False))
disadvantage = bool(self.disadvantage_matrix[combatant].pop(fleeing_target, False))
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
is_success, _ = rules.dice.opposed_saving_throw(
combatant,
fleeing_target,
attack_type=self.attack_type,
@ -427,12 +429,23 @@ class CombatActionSwapWieldedWeaponOrSpell(CombatAction):
Swap Wielded weapon or spell.
"""
key = "Swap weapon/rune/shield"
desc = "Swap currently wielded weapon, shield or spell-rune."
aliases = ("s", "swap", "draw", "swap weapon", "draw weapon",
"swap rune", "draw rune", "swap spell", "draw spell")
help_text = ("Draw a new weapon or spell-rune from your inventory, "
"replacing your current loadout")
aliases = (
"s",
"swap",
"draw",
"swap weapon",
"draw weapon",
"swap rune",
"draw rune",
"swap spell",
"draw spell",
)
help_text = (
"Draw a new weapon or spell-rune from your inventory, replacing your current loadout"
)
next_menu_node = "node_select_wield_from_inventory"
@ -448,6 +461,7 @@ class CombatActionUseItem(CombatAction):
Use an item from inventory.
"""
key = "Use an item from backpack"
desc = "Use an item from your inventory."
aliases = ("u", "use", "use item")
@ -543,6 +557,29 @@ class EvAdventureCombatHandler(DefaultScript):
self._end_turn()
self._start_turn()
def _init_menu(self, combatant, session=None):
"""
Make sure combatant is in the menu. This is safe to call on a combatant already in a menu.
"""
if not combatant.ndb._evmenu:
# re-joining the menu is useful during testing
evmenu.EvMenu(
combatant,
{
"node_wait_start": node_wait_start,
"node_select_target": node_select_target,
"node_select_action": node_select_action,
"node_wait_turn": node_wait_turn,
},
startnode="node_wait_turn",
auto_quit=True,
persistent=True,
cmdset_mergetype="Union",
session=session,
combathandler=self, # makes this available as combatant.ndb._evmenu.combathandler
)
def _reset_menu(self):
"""
Move menu to the action-selection node.
@ -577,10 +614,12 @@ class EvAdventureCombatHandler(DefaultScript):
# set -1 for unit tests
warning_time = 15
self._warn_time_task = delay(
self.interval - warning_time, self._warn_time, warning_time)
self.interval - warning_time, self._warn_time, warning_time
)
for combatant in self.combatants:
# cycle combat menu
self._init_menu(combatant)
combatant.ndb._evmenu.goto("node_select_action", "")
def _end_turn(self):
@ -633,12 +672,12 @@ class EvAdventureCombatHandler(DefaultScript):
for combatant in self.combatants:
new_advantage_matrix[combatant] = {
target: set_at_turn
for target, set_at_turn in advantage_matrix.items()
for target, set_at_turn in advantage_matrix[combatant].items()
if set_at_turn > oldest_stunt_age
}
new_disadvantage_matrix[combatant] = {
target: set_at_turn
for target, set_at_turn in disadvantage_matrix.items()
for target, set_at_turn in disadvantage_matrix[combatant].items()
if set_at_turn > oldest_stunt_age
}
@ -676,23 +715,7 @@ class EvAdventureCombatHandler(DefaultScript):
action_class.key: action_class(self, combatant)
for action_class in self.default_action_classes + custom_action_classes
}
# start evmenu (menu node definitions at the end of this module)
evmenu.EvMenu(
combatant,
{
"node_wait_start": node_wait_start,
"node_select_target": node_select_target,
"node_select_action": node_select_action,
"node_wait_turn": node_wait_turn,
},
startnode="node_wait_turn",
auto_quit=False,
persistent=True,
session=session,
combathandler=self # makes this available as combatant.ndb._evmenu.combathandler
)
self._init_menu(combatant, session=session)
def remove_combatant(self, combatant):
"""
@ -823,9 +846,9 @@ class EvAdventureCombatHandler(DefaultScript):
"""
weapon_dmg_roll = attacker.weapon.damage_roll
dmg = rules.EvAdventureRollEngine.roll(weapon_dmg_roll)
dmg = rules.dice.roll(weapon_dmg_roll)
if critical:
dmg += rules.EvAdventureRollEngine.roll(weapon_dmg_roll)
dmg += rules.dice.roll(weapon_dmg_roll)
defender.hp -= dmg
@ -834,7 +857,7 @@ class EvAdventureCombatHandler(DefaultScript):
if defender.hp <= 0:
# roll on death table. This may or may not kill you
rules.EvAdventureRollEngine.roll_death(self)
rules.dice.roll_death(self)
# tell everyone
self.msg(defender.defeat_message(attacker, dmg))
@ -870,8 +893,7 @@ class EvAdventureCombatHandler(DefaultScript):
"""
# get the instantiated action for this combatant
action = self.combatant_actions[combatant].get(
action_key,
CombatActionDoNothing(self, combatant)
action_key, CombatActionDoNothing(self, combatant)
)
# store the action in the queue
@ -912,13 +934,13 @@ def _register_action(caller, raw_string, **kwargs):
Register action with handler.
"""
action_key = kwargs.get["action_key"]
action_key = kwargs.pop("action_key")
action_args = kwargs["action_args"]
action_kwargs = kwargs["action_kwargs"]
action_target = kwargs.get("action_target")
combat_handler = caller._evmenu.combathandler
combat_handler.register_action(
caller, action_key, action_target, *action_args, **action_kwargs)
action_target = kwargs.pop("action_target", None)
combat_handler = caller.ndb._evmenu.combathandler
print("action_args", action_args, "action_kwargs", action_kwargs)
combat_handler.register_action(caller, action_key, action_target, *action_args, **action_kwargs)
# move into waiting
return "node_wait_turn"
@ -930,41 +952,22 @@ def node_select_target(caller, raw_string, **kwargs):
with all other actions.
"""
action_key = kwargs.get("action_key")
action_args = kwargs.get("action_args")
action_kwargs = kwargs.get("action_kwargs")
combat = caller.ndb._evmenu.combathandler
text = "Select target for |w{action_key}|n."
# make the apply-self option always the first one, give it key 0
kwargs["action_target"] = caller
options = [
{
"key": "0",
"desc": "(yourself)",
"goto": (_register_action, kwargs)
}
]
options = [{"key": "0", "desc": "(yourself)", "goto": (_register_action, kwargs)}]
# filter out ourselves and then make options for everyone else
combatants = [combatant for combatant in combat.combatants if combatant is not caller]
for combatant in combatants:
# automatic menu numbering starts from 1
for inum, combatant in enumerate(combatants):
kwargs["action_target"] = combatant
options.append(
{
"desc": combatant.key,
"goto": (_register_action, kwargs)
}
{"key": str(inum + 1), "desc": combatant.key, "goto": (_register_action, kwargs)}
)
# add ability to cancel
options.append(
{
"key": "_default",
"desc": "(No input to Abort and go back)",
"goto": "node_select_action"
}
)
options.append({"key": "_default", "goto": "node_select_action"})
return text, options
@ -981,8 +984,10 @@ def node_select_wield_from_inventory(caller, raw_string, **kwargs):
"""
combat = caller.ndb._evmenu.combathandler
loadout = caller.inventory.display_loadout()
text = (f"{loadout}\nSelect weapon, spell or shield to draw. It will swap out "
"anything already in the same hand (you can't change armor or helmet in combat).")
text = (
f"{loadout}\nSelect weapon, spell or shield to draw. It will swap out "
"anything already in the same hand (you can't change armor or helmet in combat)."
)
# get a list of all suitable weapons/spells/shields
options = []
@ -997,21 +1002,12 @@ def node_select_wield_from_inventory(caller, raw_string, **kwargs):
)
else:
# normally working item
kwargs['action_args'] = (obj,)
options.append(
{
"desc": str(obj),
"goto": (_register_action, kwargs)
}
)
kwargs["action_args"] = (obj,)
options.append({"desc": str(obj), "goto": (_register_action, kwargs)})
# add ability to cancel
options.append(
{
"key": "_default",
"desc": "(No input to Abort and go back)",
"goto": "node_select_action"
}
{"key": "_default", "desc": "(No input to Abort and go back)", "goto": "node_select_action"}
)
return text, options
@ -1038,21 +1034,12 @@ def node_select_use_item_from_inventory(caller, raw_string, **kwargs):
)
else:
# normally working item
kwargs['action_args'] = (obj,)
options.append(
{
"desc": str(obj),
"goto": (_register_action, kwargs)
}
)
kwargs["action_args"] = (obj,)
options.append({"desc": str(obj), "goto": (_register_action, kwargs)})
# add ability to cancel
options.append(
{
"key": "_default",
"desc": "(No input to Abort and go back)",
"goto": "node_select_action"
}
{"key": "_default", "desc": "(No input to Abort and go back)", "goto": "node_select_action"}
)
return text, options
@ -1063,8 +1050,8 @@ def _action_unavailable(caller, raw_string, **kwargs):
Selecting an unavailable action.
"""
action_key = kwargs.get["action_key"]
caller.msg(f"Action '{action_key}' is currently not available.")
action_key = kwargs["action_key"]
caller.msg(f"|rAction |w{action_key}|r is currently not available.|n")
# go back to previous node
return
@ -1093,12 +1080,7 @@ def node_select_action(caller, raw_string, **kwargs):
{
"key": key,
"desc": desc,
"goto": (
_action_unavailable,
{
"action_key": action.key
}
)
"goto": (_action_unavailable, {"action_key": action.key}),
}
)
elif action.next_menu_node is None:
@ -1113,7 +1095,7 @@ def node_select_action(caller, raw_string, **kwargs):
{
"action_key": action.key,
"action_args": (),
"action_kwargs": kwargs,
"action_kwargs": {},
"action_target": None,
},
),
@ -1130,7 +1112,8 @@ def node_select_action(caller, raw_string, **kwargs):
{
"action_key": action.key,
"action_args": (),
"action_kwargs": kwargs,
"action_kwargs": {},
"action_target": None,
},
),
}
@ -1139,8 +1122,7 @@ def node_select_action(caller, raw_string, **kwargs):
options.append(
{
"key": "_default",
"desc": "(No input to Abort and go back)",
"goto": "node_select_action"
"goto": "node_select_action",
}
)
@ -1160,7 +1142,7 @@ def node_wait_turn(caller, raw_string, **kwargs):
options = {
"key": "_default",
"desc": "(next round will start automatically)",
"goto": "node_wait_turn"
"goto": "node_wait_turn",
}
return text, options
@ -1177,7 +1159,7 @@ def node_wait_start(caller, raw_string, **kwargs):
options = {
"key": "_default",
"desc": "(combat will start automatically)",
"goto": "node_wait_start"
"goto": "node_wait_start",
}
return text, options
@ -1218,10 +1200,13 @@ def join_combat(caller, *targets, session=None):
combathandler = location.scripts.add(EvAdventureCombatHandler, autostart=False)
created = True
if not hasattr(caller, "hp"):
raise CombatFailure("You have no hp and so can't attack anyone.")
# it's safe to add a combatant to the same combat more than once
combathandler.add_combatant(caller, session=session)
for target in targets:
combathandler.add_combatant(target, session=session)
combathandler.add_combatant(target)
if created:
combathandler.start_combat()

View file

@ -1,11 +1,11 @@
"""
EvAdventure commands and cmdsets.
nextEvAdventure commands and cmdsets.
"""
from evennia import Command, default_cmds
from . combat_turnbased import join_combat
from .combat_turnbased import CombatFailure, join_combat
class EvAdventureCommand(Command):
@ -17,6 +17,7 @@ class EvAdventureCommand(Command):
where whitespace around the argument(s) are stripped.
"""
def parse(self):
self.args = self.args.strip()
@ -38,6 +39,9 @@ class CmdAttackTurnBased(EvAdventureCommand):
"""
key = "attack"
aliases = ("hit",)
def parse(self):
super().parse()
self.targets = [name.strip() for name in self.args.split(",")]
@ -49,10 +53,15 @@ class CmdAttackTurnBased(EvAdventureCommand):
target_objs = []
for target in self.targets:
target_obj = self.caller.search(target)
if target_obj:
if not target_obj:
# show a warning but don't abort
continue
target_objs.append(target_obj)
if target_objs:
join_combat(self.caller, *target_objs, session=self.session)
try:
join_combat(self.caller, *target_objs, session=self.session)
except CombatFailure as err:
self.caller.msg(f"|r{err}|n")
else:
self.caller.msg("|rFound noone to attack.|n")

View file

@ -3,15 +3,72 @@ EvAdventure NPCs. This includes both friends and enemies, only separated by thei
"""
from .characters import EvAdventureCharacter
from evennia import DefaultCharacter
from evennia.typeclasses.attributes import AttributeProperty
class EvAdventureNPC(EvAdventureCharacter):
from .characters import LivingMixin
class EvAdventureNPC(LivingMixin, DefaultCharacter):
"""
Base typeclass for NPCs. They have the features of a Character except
they have tooling for AI and for acting as quest-gives and shop-keepers.
This is the base class for all non-player entities, including monsters. These
generally don't advance in level but uses a simplified, abstract measure of how
dangerous or competent they are - the 'hit dice' (HD).
HD indicates how much health they have and how hard they hit. In _Knave_, HD also
defaults to being the bonus for all abilities. HP is 4 x Hit die (this can then be
customized per-entity of course).
Morale is set explicitly per-NPC, usually between 7 and 9.
Monsters don't use equipment in the way PCs do, instead they have a fixed armor
value, and their Abilities are dynamically generated from the HD (hit_dice).
If wanting monsters or NPCs that can level and work the same as PCs, base them off the
EvAdventureCharacter class instead.
"""
hit_dice = AttributeProperty(default=1)
armor = AttributeProperty(default=11)
morale = AttributeProperty(default=9)
hp = AttributeProperty(default=8)
@property
def strength(self):
return self.hit_dice
@property
def dexterity(self):
return self.hit_dice
@property
def constitution(self):
return self.hit_dice
@property
def intelligence(self):
return self.hit_dice
@property
def wisdom(self):
return self.hit_dice
@property
def charisma(self):
return self.hit_dice
@property
def hp_max(self):
return self.hit_dice * 4
def at_object_creation(self):
"""
Start with max health.
"""
self.hp = self.hp_max
class EvAdventureShopKeeper(EvAdventureNPC):
"""

View file

@ -10,7 +10,7 @@ Tags.
from evennia.objects.objects import DefaultObject
from evennia.typeclasses.attributes import AttributeProperty
from .enums import WieldLocation, Ability
from .enums import Ability, WieldLocation
class EvAdventureObject(DefaultObject):
@ -44,6 +44,7 @@ class EvAdventureObjectFiller(EvAdventureObject):
meaning it's unusable.
"""
quality = AttributeProperty(0)
@ -53,6 +54,7 @@ class EvAdventureConsumable(EvAdventureObject):
have a limited usage in this way.
"""
inventory_use_slot = AttributeProperty(WieldLocation.BACKPACK)
size = AttributeProperty(0.25)
uses = AttributeProperty(1)
@ -91,6 +93,7 @@ class EvAdventureRunestone(EvAdventureWeapon):
they are quite powerful (and scales with caster level).
"""
inventory_use_slot = AttributeProperty(WieldLocation.TWO_HANDS)
attack_type = AttributeProperty(Ability.INT)

View file

@ -23,14 +23,13 @@ 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,
death_and_dismemberment as death_table,
)
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

View file

@ -19,8 +19,9 @@ class EvAdventureMixin:
def setUp(self):
super().setUp()
self.location = create.create_object(EvAdventureRoom, key="testroom")
self.character = create.create_object(EvAdventureCharacter, key="testchar",
location=self.location)
self.character = create.create_object(
EvAdventureCharacter, key="testchar", location=self.location
)
self.helmet = create.create_object(
EvAdventureObject,
key="helmet",

View file

@ -16,6 +16,7 @@ class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
Test the turn-based combat-handler implementation.
"""
maxDiff = None
@patch(
@ -52,10 +53,7 @@ class EvAdventureTurnbasedCombatHandlerTest(EvAdventureMixin, BaseEvenniaTest):
self.combathandler.register_action(self.combatant, action.key)
self.assertEqual(
self.combathandler.action_queue[self.combatant],
(action, (), {})
)
self.assertEqual(self.combathandler.action_queue[self.combatant], (action, (), {}))
action.use = MagicMock()

View file

@ -13,7 +13,6 @@ from collections import defaultdict
import inflect
from django.conf import settings
from django.utils.translation import gettext as _
from evennia.commands import cmdset
from evennia.commands.cmdsethandler import CmdSetHandler
from evennia.objects.manager import ObjectManager
@ -22,15 +21,9 @@ from evennia.scripts.scripthandler import ScriptHandler
from evennia.typeclasses.attributes import ModelAttributeBackend, NickHandler
from evennia.typeclasses.models import TypeclassBase
from evennia.utils import ansi, create, funcparser, logger, search
from evennia.utils.utils import (
class_from_module,
is_iter,
lazy_property,
list_to_string,
make_iter,
to_str,
variable_from_module,
)
from evennia.utils.utils import (class_from_module, is_iter, lazy_property,
list_to_string, make_iter, to_str,
variable_from_module)
_INFLECT = inflect.engine()
_MULTISESSION_MODE = settings.MULTISESSION_MODE

View file

@ -1,10 +1,11 @@
from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTestCase
from evennia import DefaultObject, DefaultCharacter, DefaultRoom, DefaultExit
from evennia.typeclasses.attributes import AttributeProperty
from evennia.typeclasses.tags import TagProperty, AliasProperty, PermissionProperty
from evennia import DefaultCharacter, DefaultExit, DefaultObject, DefaultRoom
from evennia.objects.models import ObjectDB
from evennia.objects.objects import DefaultObject
from evennia.typeclasses.attributes import AttributeProperty
from evennia.typeclasses.tags import (AliasProperty, PermissionProperty,
TagProperty)
from evennia.utils import create
from evennia.utils.test_resources import BaseEvenniaTest, EvenniaTestCase
class DefaultObjectTest(BaseEvenniaTest):

View file

@ -126,7 +126,7 @@ class ScriptHandler(object):
"""
return ScriptDB.objects.get_all_scripts_on_obj(self.obj, key=key)
def delete(self, key=None):
def remove(self, key=None):
"""
Forcibly delete a script from this object.
@ -149,7 +149,8 @@ class ScriptHandler(object):
num += 1
return num
# alias to delete
# legacy aliases to remove
delete = remove
stop = delete
def all(self):

View file

@ -5,13 +5,13 @@ ability to run timers.
"""
from django.utils.translation import gettext as _
from evennia.scripts.manager import ScriptManager
from evennia.scripts.models import ScriptDB
from evennia.typeclasses.models import TypeclassBase
from evennia.utils import create, logger
from twisted.internet.defer import Deferred, maybeDeferred
from twisted.internet.task import LoopingCall
from django.utils.translation import gettext as _
from evennia.typeclasses.models import TypeclassBase
from evennia.scripts.models import ScriptDB
from evennia.scripts.manager import ScriptManager
from evennia.utils import create, logger
__all__ = ["DefaultScript", "DoNothing", "Store"]
@ -366,7 +366,11 @@ class ScriptBase(ScriptDB, metaclass=TypeclassBase):
return
# call hook
self.at_repeat()
try:
self.at_repeat()
except Exception:
logger.log_trace()
raise
# check repeats
if self.ndb._task: