More fixes to evadventure
This commit is contained in:
parent
ab2e84a40f
commit
39bf20c8f2
3 changed files with 114 additions and 22 deletions
|
|
@ -328,6 +328,29 @@ class EvAdventureCharacter(DefaultCharacter):
|
|||
"""
|
||||
# TODO
|
||||
|
||||
@property
|
||||
def hurt_level(self):
|
||||
"""
|
||||
String describing how hurt this character is.
|
||||
"""
|
||||
percent = max(0, min(100, 100 * (self.hp / self.hp_max)))
|
||||
if 95 < percent <= 100:
|
||||
return "|gPerfect|n"
|
||||
elif 80 < percent <= 95:
|
||||
return "|gScraped|n"
|
||||
elif 60 < percent <= 80:
|
||||
return "|GBruised|n"
|
||||
elif 45 < percent <= 60:
|
||||
return "|yHurt|n"
|
||||
elif 30 < percent <= 45:
|
||||
return "|yWounded|n"
|
||||
elif 15 < percent <= 30:
|
||||
return "|rBadly wounded|n"
|
||||
elif 1 < percent <= 15:
|
||||
return "|rBarely hanging on|n"
|
||||
elif percent == 0:
|
||||
return "|RCollapsed!|n"
|
||||
|
||||
def heal(self, hp, healer=None):
|
||||
"""
|
||||
Heal the character by a certain amount of HP.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from collections import defaultdict
|
|||
from evennia.scripts.scripts import DefaultScript
|
||||
from evennia.typeclasses.attributes import AttributeProperty
|
||||
from evennia.utils.utils import make_iter
|
||||
from evennia.utils import evmenu
|
||||
from evennia.utils import evmenu, evtable
|
||||
from . import rules
|
||||
|
||||
MIN_RANGE = 0
|
||||
|
|
@ -48,26 +48,37 @@ class CombatAction:
|
|||
|
||||
"""
|
||||
key = 'action'
|
||||
status_text = "{combatant} performs an action."
|
||||
post_action_text = "{combatant} performed an action."
|
||||
|
||||
# move actions can be combined with other actions
|
||||
is_move_action = False
|
||||
|
||||
def __init__(self, combathandler):
|
||||
def __init__(self, combathandler, combatant):
|
||||
self.combathandler = combathandler
|
||||
self.combatant = combatant
|
||||
|
||||
def can_use(self, combatant, *args, **kwargs):
|
||||
"""
|
||||
Determine if combatant can use this action.
|
||||
|
||||
Args:
|
||||
combatant (Object): The one performing the action.
|
||||
*args: Any optional arguments.
|
||||
**kwargs: Any optional keyword arguments.
|
||||
|
||||
Returns:
|
||||
tuple: (bool, motivation) - if not available, will describe why,
|
||||
if available, should describe what the action does.
|
||||
|
||||
"""
|
||||
return True
|
||||
|
||||
def use(self, combatant, *args, **kwargs):
|
||||
def use(self, *args, **kwargs):
|
||||
"""
|
||||
Use action
|
||||
|
||||
"""
|
||||
self.combathandler.msg(self.status_text.format(combatant=combatant))
|
||||
self.combathandler.msg(self.post_action_text.format(combatant=combatant))
|
||||
|
||||
|
||||
class CombatActionDoNothing(CombatAction):
|
||||
|
|
@ -75,7 +86,7 @@ class CombatActionDoNothing(CombatAction):
|
|||
Do nothing this turn.
|
||||
|
||||
"""
|
||||
status_text = "{combatant} does nothing this turn."
|
||||
post_action_text = "{combatant} does nothing this turn."
|
||||
|
||||
|
||||
class CombatActionStunt(CombatAction):
|
||||
|
|
@ -83,6 +94,28 @@ class CombatActionStunt(CombatAction):
|
|||
Perform a stunt.
|
||||
|
||||
"""
|
||||
optimal_distance = 0
|
||||
suboptimal_distance = 1
|
||||
advantage = True
|
||||
attack_type = "dexterity"
|
||||
defense_type = "dexterity"
|
||||
|
||||
def can_use(self, combatant, defender, *args, **kwargs):
|
||||
distance = self.combathandler.distance_matrix[attacker][defender]
|
||||
|
||||
disadvantage = False
|
||||
if self.suboptimal_distance == distance:
|
||||
# stunts need to be within range
|
||||
disadvantage = True
|
||||
elif self.optimal_distance != distance:
|
||||
# if we are neither at optimal nor suboptimal distance, we can't do the stunt
|
||||
# from here.
|
||||
return False, (f"you can't perform this stunt "
|
||||
f"from {range_names[distance]} distance (must be "
|
||||
f"{range_names[suboptimal_distance]} or, even better, "
|
||||
f"{range_names[optimal_distance]}).")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -111,6 +144,12 @@ class EvAdventureCombatHandler(DefaultScript):
|
|||
# actions that will be performed before a normal action
|
||||
move_actions = ("approach", "withdraw")
|
||||
|
||||
def at_init(self):
|
||||
self.ndb.actions = {
|
||||
"do_nothing": CombatActionDoNothing,
|
||||
}
|
||||
|
||||
|
||||
def _refresh_distance_matrix(self):
|
||||
"""
|
||||
Refresh the distance matrix, either after movement or when a
|
||||
|
|
@ -248,6 +287,37 @@ class EvAdventureCombatHandler(DefaultScript):
|
|||
self.combatants.remove(combatant)
|
||||
self._refresh_distance_matrix()
|
||||
|
||||
def get_combat_summary(self, combatant):
|
||||
"""
|
||||
Get a summary of the current combat state.
|
||||
|
||||
You (5/10 health)
|
||||
Foo (Hurt) distance: You__0__1___X____3_____4 (medium)
|
||||
Bar (Perfect health): You__X__1___2____3_____4 (close)
|
||||
|
||||
"""
|
||||
table = evtable.EvTable(border_width=0)
|
||||
|
||||
table.add_row(f"You ({combatant.hp} / {combatant.hp_max} health)")
|
||||
|
||||
dist_template = "|x(You)__{0}|x__{1}|x___{2}|x____{3}|x_____{4} |x({distname})"
|
||||
|
||||
for comb in self.combatants:
|
||||
|
||||
if comb is combatant:
|
||||
continue
|
||||
|
||||
name = combatant.key
|
||||
distance = self.distance_matrix[combatant][comb]
|
||||
dist_map = {i: '|wX' if i == distance else i for i in range(MAX_RANGE)}
|
||||
dist_map["distname"] = RANGE_NAMES[distance]
|
||||
health = f"{comb.hurt_level}"
|
||||
distance_string = dist_template.format(**dist_map)
|
||||
|
||||
table.add_row(f"{name} ({health})", distance_string)
|
||||
|
||||
return str(table)
|
||||
|
||||
def msg(self, message, targets=None):
|
||||
"""
|
||||
Central place for sending messages to combatants. This allows
|
||||
|
|
@ -399,10 +469,10 @@ class EvAdventureCombatHandler(DefaultScript):
|
|||
elif self._get_optimal_distance(attacker) != distance:
|
||||
# if we are neither at optimal nor suboptimal distance, we can't do the stunt
|
||||
# from here.
|
||||
raise CombatFailure(f"You can't perform this stunt "
|
||||
f"from {RANGE_NAMES[distance]} distance (must be "
|
||||
f"{RANGE_NAMES[suboptimal_distance]} or, even better, "
|
||||
f"{RANGE_NAMES[optimal_distance]}).")
|
||||
raise combatfailure(f"you can't perform this stunt "
|
||||
f"from {range_names[distance]} distance (must be "
|
||||
f"{range_names[suboptimal_distance]} or, even better, "
|
||||
f"{range_names[optimal_distance]}).")
|
||||
# quality doesn't matter for stunts, they are either successful or not
|
||||
is_success, _ = rules.EvAdventureRollEngine.opposed_saving_throw(
|
||||
attacker, defender,
|
||||
|
|
@ -582,7 +652,6 @@ def node_select_action(caller, raw_string, **kwargs):
|
|||
text = combat.get_previous_turn_status(caller)
|
||||
options = combat.get_available_options(caller)
|
||||
|
||||
# TODO - reshuffle options
|
||||
|
||||
options = {
|
||||
"desc": action,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue