More refactoring of combat
This commit is contained in:
parent
b1c765b50f
commit
7715ac84b6
3 changed files with 66 additions and 14 deletions
|
|
@ -3,13 +3,14 @@ EvAdventure Base combat utilities.
|
||||||
|
|
||||||
This establishes the basic building blocks for combat:
|
This establishes the basic building blocks for combat:
|
||||||
|
|
||||||
- `CombatAction` - classes encompassing all the working around an action. They are initialized
|
- `CombatFailure` - exception for combat-specific errors.
|
||||||
from 'action-dicts` - dictionaries with all the relevant data for the particular invocation
|
- `CombatAction` (and subclasses) - classes encompassing all the working around an action.
|
||||||
|
They are initialized from 'action-dicts` - dictionaries with all the relevant data for the
|
||||||
|
particular invocation
|
||||||
- `CombatHandler` - base class for running a combat. Exactly how this is used depends on the
|
- `CombatHandler` - base class for running a combat. Exactly how this is used depends on the
|
||||||
type of combat intended (twitch- or turn-based) so many details of this will be implemented
|
type of combat intended (twitch- or turn-based) so many details of this will be implemented
|
||||||
in child classes.
|
in child classes.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia import Command, create_script
|
from evennia import Command, create_script
|
||||||
|
|
@ -318,7 +319,7 @@ class EvAdventureCombatHandlerBase(DefaultScript):
|
||||||
obj.ndb.combathandler = combathandler
|
obj.ndb.combathandler = combathandler
|
||||||
return combathandler
|
return combathandler
|
||||||
|
|
||||||
def msg(self, message, combatant=None, broadcast=True):
|
def msg(self, message, combatant=None, broadcast=True, location=None):
|
||||||
"""
|
"""
|
||||||
Central place for sending messages to combatants. This allows
|
Central place for sending messages to combatants. This allows
|
||||||
for adding any combat-specific text-decoration in one place.
|
for adding any combat-specific text-decoration in one place.
|
||||||
|
|
@ -329,6 +330,9 @@ class EvAdventureCombatHandlerBase(DefaultScript):
|
||||||
broadcast (bool): If `False`, `combatant` must be included and
|
broadcast (bool): If `False`, `combatant` must be included and
|
||||||
will be the only one to see the message. If `True`, send to
|
will be the only one to see the message. If `True`, send to
|
||||||
everyone in the location.
|
everyone in the location.
|
||||||
|
location (Object, optional): If given, use this as the location to
|
||||||
|
send broadcast messages to. If not, use `self.obj` as that
|
||||||
|
location.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
If `combatant` is given, use `$You/you()` markup to create
|
If `combatant` is given, use `$You/you()` markup to create
|
||||||
|
|
@ -336,7 +340,9 @@ class EvAdventureCombatHandlerBase(DefaultScript):
|
||||||
`$You(combatant_key)` to refer to other combatants.
|
`$You(combatant_key)` to refer to other combatants.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
location = self.obj
|
if not location:
|
||||||
|
location = self.obj
|
||||||
|
|
||||||
location_objs = location.contents
|
location_objs = location.contents
|
||||||
|
|
||||||
exclude = []
|
exclude = []
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,28 @@ class EvAdventureCombatTwitchHandler(EvAdventureCombatHandlerBase):
|
||||||
# stores the current ticker reference, so we can manipulate it later
|
# stores the current ticker reference, so we can manipulate it later
|
||||||
current_ticker_ref = AttributeProperty(None)
|
current_ticker_ref = AttributeProperty(None)
|
||||||
|
|
||||||
|
def msg(self, message, broadcast=True):
|
||||||
|
"""
|
||||||
|
Central place for sending messages to combatants. This allows
|
||||||
|
for adding any combat-specific text-decoration in one place.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message (str): The message to send.
|
||||||
|
combatant (Object): The 'You' in the message, if any.
|
||||||
|
broadcast (bool): If `False`, `combatant` must be included and
|
||||||
|
will be the only one to see the message. If `True`, send to
|
||||||
|
everyone in the location.
|
||||||
|
location (Object, optional): If given, use this as the location to
|
||||||
|
send broadcast messages to. If not, use `self.obj` as that
|
||||||
|
location.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
If `combatant` is given, use `$You/you()` markup to create
|
||||||
|
a message that looks different depending on who sees it. Use
|
||||||
|
`$You(combatant_key)` to refer to other combatants.
|
||||||
|
"""
|
||||||
|
super().msg(message, broadcast=broadcast, location=self.obj.location)
|
||||||
|
|
||||||
def get_sides(self, combatant):
|
def get_sides(self, combatant):
|
||||||
"""
|
"""
|
||||||
Get a listing of the two 'sides' of this combat, from the perspective of the provided
|
Get a listing of the two 'sides' of this combat, from the perspective of the provided
|
||||||
|
|
@ -181,7 +203,9 @@ class EvAdventureCombatTwitchHandler(EvAdventureCombatHandlerBase):
|
||||||
self.queue_action(self.fallback_action_dict)
|
self.queue_action(self.fallback_action_dict)
|
||||||
|
|
||||||
def check_stop_combat(self):
|
def check_stop_combat(self):
|
||||||
# check if one side won the battle.
|
"""
|
||||||
|
Check if the combat is over.
|
||||||
|
"""
|
||||||
|
|
||||||
allies, enemies = self.get_sides()
|
allies, enemies = self.get_sides()
|
||||||
allies.append(self.obj)
|
allies.append(self.obj)
|
||||||
|
|
@ -191,15 +215,19 @@ class EvAdventureCombatTwitchHandler(EvAdventureCombatHandlerBase):
|
||||||
enemies = [comb for comb in enemies if comb.hp > 0]
|
enemies = [comb for comb in enemies if comb.hp > 0]
|
||||||
|
|
||||||
if not allies and not enemies:
|
if not allies and not enemies:
|
||||||
self.msg("Noone stands after the dust settles.")
|
self.msg("Noone stands after the dust settles.", broadcast=False)
|
||||||
self.stop_combat()
|
self.stop_combat()
|
||||||
return
|
return
|
||||||
|
|
||||||
if not allies or not enemies:
|
if not allies or not enemies:
|
||||||
still_standing = list_to_string(
|
still_standing = list_to_string(f"$You({comb.key})" for comb in allies + enemies)
|
||||||
f"$You({comb.key})" for comb in allies + enemies if comb.hp > 0
|
self.msg(
|
||||||
|
(
|
||||||
|
f"The combat is over. {still_standing} $pluralize(is, {len(allies + enemies)})"
|
||||||
|
" are) still standing."
|
||||||
|
),
|
||||||
|
broadcast=False,
|
||||||
)
|
)
|
||||||
self.msg(f"The combat is over. {still_standing} are still standing.")
|
|
||||||
self.stop_combat()
|
self.stop_combat()
|
||||||
|
|
||||||
def stop_combat(self):
|
def stop_combat(self):
|
||||||
|
|
@ -268,7 +296,7 @@ class CmdAttack(_BaseTwitchCombatCommand):
|
||||||
help_category = "combat"
|
help_category = "combat"
|
||||||
|
|
||||||
def func(self):
|
def func(self):
|
||||||
target = self.search(self.lhs)
|
target = self.caller.search(self.lhs)
|
||||||
if not target:
|
if not target:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from unittest.mock import Mock, call, patch
|
||||||
|
|
||||||
from evennia.utils import create
|
from evennia.utils import create
|
||||||
from evennia.utils.ansi import strip_ansi
|
from evennia.utils.ansi import strip_ansi
|
||||||
from evennia.utils.test_resources import EvenniaCommandTestMixin, EvenniaTestCase
|
from evennia.utils.test_resources import BaseEvenniaTest, EvenniaCommandTestMixin, EvenniaTestCase
|
||||||
|
|
||||||
from .. import combat_base, combat_turnbased, combat_twitch
|
from .. import combat_base, combat_turnbased, combat_twitch
|
||||||
from ..characters import EvAdventureCharacter
|
from ..characters import EvAdventureCharacter
|
||||||
|
|
@ -531,6 +531,10 @@ class TestEvAdventureTwitchCombatHandler(EvenniaCommandTestMixin, _CombatTestBas
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
|
# in order to use the EvenniaCommandTestMixin we need these variables defined
|
||||||
|
self.char1 = self.combatant
|
||||||
|
self.account = None
|
||||||
|
|
||||||
self.combatant_combathandler = (
|
self.combatant_combathandler = (
|
||||||
combat_twitch.EvAdventureCombatTwitchHandler.get_or_create_combathandler(
|
combat_twitch.EvAdventureCombatTwitchHandler.get_or_create_combathandler(
|
||||||
self.combatant, key="combathandler"
|
self.combatant, key="combathandler"
|
||||||
|
|
@ -578,17 +582,31 @@ class TestEvAdventureTwitchCombatHandler(EvenniaCommandTestMixin, _CombatTestBas
|
||||||
|
|
||||||
@patch("evennia.contrib.tutorials.evadventure.combat_twitch.unrepeat", new=Mock())
|
@patch("evennia.contrib.tutorials.evadventure.combat_twitch.unrepeat", new=Mock())
|
||||||
def test_check_stop_combat(self):
|
def test_check_stop_combat(self):
|
||||||
"""Test if combat should stop"""
|
"""Test combat-stop functionality"""
|
||||||
|
|
||||||
# noone remains
|
# noone remains
|
||||||
self.combatant_combathandler.get_sides = Mock(return_value=([], []))
|
self.combatant_combathandler.get_sides = Mock(return_value=([], []))
|
||||||
self.combatant_combathandler.stop_combat = Mock()
|
self.combatant_combathandler.stop_combat = Mock()
|
||||||
|
|
||||||
|
self.combatant.hp = -1
|
||||||
|
self.target.hp = -1
|
||||||
|
|
||||||
self.combatant_combathandler.check_stop_combat()
|
self.combatant_combathandler.check_stop_combat()
|
||||||
self.combatant.msg.assert_called_with()
|
self.combatant.msg.assert_called_with()
|
||||||
self.combatant_combathandler.stop_combat.assert_called()
|
self.combatant_combathandler.stop_combat.assert_called()
|
||||||
|
|
||||||
# one side wiped out
|
# only one side wiped out
|
||||||
|
self.combatant = 10
|
||||||
self.combatant_combathandler.get_sides = Mock(return_value=([], []))
|
self.combatant_combathandler.get_sides = Mock(return_value=([], []))
|
||||||
self.combatant_combathandler.check_stop_combat()
|
self.combatant_combathandler.check_stop_combat()
|
||||||
self.combatant.msg.assert_called_with()
|
self.combatant.msg.assert_called_with()
|
||||||
|
|
||||||
|
@patch("evennia.contrib.tutorials.evadventure.combat_twitch.unrepeat", new=Mock())
|
||||||
|
@patch("evennia.contrib.tutorials.evadventure.combat_twitch.repeat", new=Mock())
|
||||||
|
def test_attack(self):
|
||||||
|
"""Test attack action in the twitch combathandler"""
|
||||||
|
self.call(combat_twitch.CmdAttack(), f"{self.target.key}", "")
|
||||||
|
self.assertEqual(
|
||||||
|
self.combatant_combathandler.action_dict,
|
||||||
|
{"key": "attack", "target": self.target, "dt": 3},
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue