mirror of
https://github.com/Threnklyn/dungeon-sheets.git
synced 2026-05-18 20:23:27 +02:00
185 lines
5.4 KiB
Python
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 |