|
|
|
from dataclasses import dataclass
|
|
|
|
from typing import Union
|
|
|
|
|
|
|
|
from effects import DamageEffect
|
|
|
|
from enums import CombatSide
|
|
|
|
from jsonable import JsonableDataclassArgs
|
|
|
|
from model import Action, Target, Effect, Character, Clock, CombatStatus, log_substitute
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class RoleplayAction(Action):
|
|
|
|
text: str
|
|
|
|
user: Target | None
|
|
|
|
effects: tuple[Effect, ...]
|
|
|
|
|
|
|
|
def do(self, combat: "CombatStatus", source: Union["Action", "Effect", None] = None) -> "CombatStatus":
|
|
|
|
for effect in self.effects:
|
|
|
|
combat = effect.do(combat, self)
|
|
|
|
return combat
|
|
|
|
|
|
|
|
def undo(self, combat: "CombatStatus", source: Union["Action", "Effect", None] = None) -> "CombatStatus":
|
|
|
|
for effect in reversed(self.effects):
|
|
|
|
combat = effect.undo(combat, self)
|
|
|
|
return combat
|
|
|
|
|
|
|
|
def log_message(self, user: Target | None = None) -> str | None:
|
|
|
|
return "\n ".join(
|
|
|
|
[log_substitute(self.text, user=self.user, target=self.user)] +
|
|
|
|
[log_substitute(t, user=self.user, target=self.user)
|
|
|
|
for t in [v.log_message(self.user) for v in self.effects]
|
|
|
|
if t is not None]
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class AbilityAction(Action):
|
|
|
|
name: str
|
|
|
|
user: Target | None
|
|
|
|
costs: tuple[DamageEffect, ...]
|
|
|
|
effects: tuple[Effect, ...]
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class ModifyCharacterAction(Action):
|
|
|
|
index: int
|
|
|
|
old_character_data: Character | None
|
|
|
|
new_character_data: Character | None
|
|
|
|
|
|
|
|
def __post_init__(self):
|
|
|
|
if self.old_character_data is None and self.new_character_data is None:
|
|
|
|
raise ValueError("At least one of old_character_data or new_character_data must be non-None")
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class ModifyClockAction(Action):
|
|
|
|
index: int
|
|
|
|
old_clock_data: Clock | None
|
|
|
|
new_clock_data: Clock | None
|
|
|
|
|
|
|
|
def __post_init__(self):
|
|
|
|
if self.old_clock_data is None and self.new_clock_data is None:
|
|
|
|
raise ValueError("At least one of old_clock_data or new_clock_data must be non-None")
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class EndTurnAction(Action):
|
|
|
|
turn_ending_index: int
|
|
|
|
activating_side: CombatSide
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class StartTurnAction(Action):
|
|
|
|
turn_starting_index: int
|
|
|
|
old_active_side: CombatSide
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class StartRoundAction(Action):
|
|
|
|
last_round: int
|
|
|
|
old_active_side: CombatSide
|
|
|
|
old_turns_remaining: tuple[int, ...]
|
|
|
|
next_round: int
|
|
|
|
activating_side: CombatSide
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class StartBattleAction(Action):
|
|
|
|
starting_side: CombatSide
|
|
|
|
starting_round: int
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass(**JsonableDataclassArgs)
|
|
|
|
class EndBattleAction(Action):
|
|
|
|
old_round_number: int
|
|
|
|
old_active_side: CombatSide
|
|
|
|
old_starting_side: CombatSide
|
|
|
|
old_turns_remaining: tuple[int, ...]
|