Files
dungeon-sheets/dungeonsheets/encounter/agent.py
T
2021-05-23 15:52:50 -04:00

185 lines
5.4 KiB
Python

from dungeonsheets.conditions.conditions import Blinded, Charmed
from dungeonsheets.encounter.actions import Attack
from dungeonsheets.stats import Ability, ArmorClass, Initiative, Speed, Skill, \
NumericalInitiative
from abc import ABC
from dungeonsheets.dice import roll
class Agent(ABC):
"""An actor in an encounter. Use Monster or Character, not this class directly!"""
# General attributes
name = ""
alignment = "Neutral"
# Hit points
hp_max = None
# Base stats (ability scores)
strength = Ability()
dexterity = Ability()
constitution = Ability()
intelligence = Ability()
wisdom = Ability()
charisma = Ability()
# Numerical things
armor_class = ArmorClass()
initiative = Initiative()
speed = Speed()
# Proficiencies and Languages
_saving_throw_proficiencies = tuple() # use to overwrite class proficiencies
other_weapon_proficiencies = tuple() # add to class/race proficiencies
skill_proficiencies = list()
skill_expertise = list()
languages = ""
# Skills
acrobatics = Skill(ability="dexterity")
animal_handling = Skill(ability="wisdom")
arcana = Skill(ability="intelligence")
athletics = Skill(ability="strength")
deception = Skill(ability="charisma")
history = Skill(ability="intelligence")
insight = Skill(ability="wisdom")
intimidation = Skill(ability="charisma")
investigation = Skill(ability="intelligence")
medicine = Skill(ability="wisdom")
nature = Skill(ability="intelligence")
perception = Skill(ability="wisdom")
performance = Skill(ability="charisma")
persuasion = Skill(ability="charisma")
religion = Skill(ability="intelligence")
sleight_of_hand = Skill(ability="dexterity")
stealth = Skill(ability="dexterity")
survival = Skill(ability="wisdom")
# Conditions
blinded = Blinded()
charmed = Charmed()
# TODO finish me!
# Inventory
cp = 0
sp = 0
ep = 0
gp = 0
pp = 0
equipment = ""
weapons = list()
magic_items = list()
armor = None
shield = None
# Magic
spellcasting_ability = None
_spells = list()
_spells_prepared = list()
infusions = list()
# Features IN MAJOR DEVELOPMENT
custom_features = list()
feature_choices = list()
# Current Status:
numerical_initiative = NumericalInitiative()
_initiative_roll = False
_current_hp = None
statuses = list()
# TODO: Pull in the monster class-variables here too
def __init__(self):
self.default_actions = list()
self.default_bonus_actions = list()
self.default_reactions = list()
self.default_legendary_actions = list()
self.default_lair_actions = list()
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
@current_hp.setter
def current_hp(self, val):
if val < 0:
self._current_hp = 0
else:
self._current_hp = val
@property
def initiative_roll(self):
if self._initiative_roll is False:
self.roll_initiative()
return self._initiative_roll
def make_actions(self, encounter):
"""Return a series of actions"""
# TODO: Dramatically improve logic, consider healing,
# consider encounter state, consider strategy etc.
best_opponent = encounter.opponents(self)[0] # TODO: Choose opponent cleverly
action = self.actions[0](self, best_opponent)
event = action.execute()
encounter.events.append(event)
return [event] # TODO: Also allow bonus actions, etc.
def long_rest(self):
self.current_hp = self.hp_max
# TODO: Support spell slots
self.new_turn()
def new_turn(self):
self._actions = self.default_actions
self._bonus_actions = self.default_bonus_actions
self._reactions = self.default_reactions
self._legendary_actions = self.default_legendary_actions
self._lair_actions = self.default_lair_actions
def has_feature(self, *args, **kwargs):
return False # TODO: Save list of monster features as a list to check
# TODO: Consider having a single list of actions and gain or lose them each
# turn based on interrogating their sub-type instead, using isinstance or
# another method.
@property
def actions(self):
"""All the remaining things I can do in a turn"""
return self._actions
@property
def movement(self):
"""The rest of where I can go in a turn"""
return self._movement
@property
def bonus_actions(self):
"""The rest of the things I can do once in addition to an action"""
return self._bonus_actions
@property
def reactions(self):
"""The remaining things I can do in response to an action"""
return self._reactions
@property
def lair_actions(self):
"""Remaining things I can do at initiative count 20"""
return self._lair_actions
@property
def legendary_actions(self):
"""Remaining things I can do only so many times in a turn after another agent acts"""
return self._legendary_actions