diff --git a/dungeonsheets/character.py b/dungeonsheets/character.py index 3c91f21..aca6027 100644 --- a/dungeonsheets/character.py +++ b/dungeonsheets/character.py @@ -20,10 +20,10 @@ from dungeonsheets import ( spells, weapons, ) -from dungeonsheets.stats import Ability, ArmorClass, Initiative, Skill, Speed, findattr +from dungeonsheets.stats import findattr from dungeonsheets.weapons import Weapon from dungeonsheets.readers import read_character_file -from dungeonsheets.agent import Agent +from dungeonsheets.encounter.agent import Agent def read(fname): diff --git a/dungeonsheets/encounter/actions.py b/dungeonsheets/encounter/actions.py new file mode 100644 index 0000000..143bc53 --- /dev/null +++ b/dungeonsheets/encounter/actions.py @@ -0,0 +1,61 @@ +from abc import ABC, abstractmethod + +class Event: + """An event between one and possibly more entities""" + + subj = None + obj = None + + def __init__(self, action, subj, obj): + self.action = action + self.subj = subj + self.obj = obj + + +class Executable(ABC): + """Something (like an action) that can be executed. + + Executing an action results in an event that is stored + """ + + @abstractmethod + def execute(self, subj, obj=None): + return Event(self, subj, obj) + + +class Action(Executable): + pass + + +class BonusAction(Executable): + pass + + +class Reaction(Executable): + pass + + +class Movement(Executable): + pass + + +class LairAction(Executable): + pass + + +class LegendaryAction(Executable): + pass + + +class Attack(Action): + + def __init__(self, subj, obj): + self.subj = subj + self.obj = obj + + def execute(self): + # Subject makes an attack roll + # Compare attack roll to object's AC + # Store the results to look into the event later + + pass # TODO: Write how to do this diff --git a/dungeonsheets/agent.py b/dungeonsheets/encounter/agent.py similarity index 81% rename from dungeonsheets/agent.py rename to dungeonsheets/encounter/agent.py index b4fd79e..5f5192a 100644 --- a/dungeonsheets/agent.py +++ b/dungeonsheets/encounter/agent.py @@ -1,6 +1,8 @@ from dungeonsheets.conditions.conditions import Blinded, Charmed -from dungeonsheets.stats import Ability, ArmorClass, Initiative, Speed, Skill, CurrentInitiative, CurrentHP +from dungeonsheets.stats import Ability, ArmorClass, Initiative, Speed, Skill, CurrentInitiative, CurrentHP, \ + NumericalInitiative from abc import ABC +from dungeonsheets.utils import roll class Agent(ABC): @@ -81,8 +83,9 @@ class Agent(ABC): feature_choices = list() # Current Status: - initiative_roll = CurrentInitiative() - current_hp = CurrentHP() + numerical_initiative = NumericalInitiative() + _initiative_roll = False + _current_hp = None statuses = list() # TODO: Pull in the monster class-variables here too @@ -90,6 +93,26 @@ class Agent(ABC): def __init__(self): pass + def roll_initiative(self): + init_mod, adv = self.numerical_initiative + val = roll(20) + if adv: + val = max(val, roll(20)) + self._initiative_roll = val + init_mod + + @property + def current_hp(self): + if self._current_hp is None: + self._current_hp = self.hp_max + return self._current_hp + + @property + def initiative_roll(self): + if self._initiative_roll is False: + self.roll_initiative() + return self._initiative_roll + + # TODO: Perhaps these are better stored like the skills are as objects with a __get__? @property diff --git a/dungeonsheets/encounter/encounter.py b/dungeonsheets/encounter/encounter.py index 74c7d68..e54d559 100644 --- a/dungeonsheets/encounter/encounter.py +++ b/dungeonsheets/encounter/encounter.py @@ -18,7 +18,6 @@ class Encounter: self.all_agents = sorted(self.all_agents, key=lambda a: a.initiative_roll) - raise NotImplementedError() # Apparently the mind flayers win for now def analyze(self): """So, really... how deadly *is* it?""" diff --git a/dungeonsheets/monsters.py b/dungeonsheets/monsters.py index 0ff11e1..6af52f0 100644 --- a/dungeonsheets/monsters.py +++ b/dungeonsheets/monsters.py @@ -3,7 +3,7 @@ shape forms.""" from dungeonsheets.stats import Ability -from dungeonsheets.agent import Agent +from dungeonsheets.encounter.agent import Agent class Monster(Agent): diff --git a/dungeonsheets/stats.py b/dungeonsheets/stats.py index 7b570bb..8555ff4 100644 --- a/dungeonsheets/stats.py +++ b/dungeonsheets/stats.py @@ -240,23 +240,3 @@ class Initiative(NumericalInitiative): if has_advantage: ini += "(A)" return ini - - -########################### -# STATUS -########################### - -class CurrentHP: - """A Numerical Representation of Current HP""" - - def __get__(self, char, Character): - if not char.hp_max: - char.__set_hp_max() - return char.hp_max - - -class CurrentInitiative(NumericalInitiative): - """A Numerical Representation of a Character's Rolled Initiative""" - - def __get__(self, char, Character): - ini, has_advantage = super(CurrentInitiative, self).__get__(char, Character) \ No newline at end of file diff --git a/tests/test_encounter.py b/tests/test_encounter.py index 24fa6b9..9e5c6fa 100644 --- a/tests/test_encounter.py +++ b/tests/test_encounter.py @@ -12,7 +12,7 @@ class TestEncounter(TestCase): """Tests for features and feature-related activities.""" def test_simulation(self): - """Can I run an encounter against Schlangdedrosa Magentawrath?""" + """Can I run an encounter against Langdedrosa Cyanwrath?""" char = Character() char.set_attrs(name="Stravajiaxen") char.set_attrs(weapons=["greataxe"]) @@ -22,7 +22,7 @@ class TestEncounter(TestCase): char.set_attrs(race="half orc") char.set_attrs(inspiration=False) - class SchlangdedrosaMagentawrath(Monster): + class LangdedrosaCyanwrath(Monster): """ **Action Surge (Recharges on a Short or Long Rest).** On his turn, Langdedrosa can take one additional action. @@ -46,7 +46,7 @@ class TestEncounter(TestCase): **Climbing speed:** 30 ft. """ - name = "Schlangdedrosa Magentawrath" + name = "Langdedrosa Cyanwrath" description = "Medium humanoid (half-dragon), lawful evil" challenge_rating = 4 armor_class = 17 @@ -64,7 +64,7 @@ class TestEncounter(TestCase): hp_max = 57 hit_dice = "6d12+18" - schlang = SchlangdedrosaMagentawrath() + lang = LangdedrosaCyanwrath() - battle = Encounter([char], [schlang]) + battle = Encounter([char], [lang]) results = battle.simulate() \ No newline at end of file