|
|
@ -6,6 +6,7 @@ class CharacterClass(BaseModel): |
|
|
|
__tablename__ = 'character_class' |
|
|
|
|
|
|
|
name = db.Column(db.String(50), unique=True, nullable=False) |
|
|
|
spellcaster = db.Column(db.String(10)) |
|
|
|
bucket = db.Column(db.String(50)) |
|
|
|
frequency_modifier = db.Column(db.Integer, default=1) |
|
|
|
|
|
|
@ -21,7 +22,15 @@ class CharacterClass(BaseModel): |
|
|
|
ranged_heavy = db.Column(db.Integer) |
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
return '<CharacterClass {0}>'.format(self.name) |
|
|
|
return '<CharacterClass: {0}>'.format(self.name) |
|
|
|
|
|
|
|
@property |
|
|
|
def is_divine_spellcaster(self): |
|
|
|
return self.spellcaster == 'Divine' |
|
|
|
|
|
|
|
@property |
|
|
|
def is_arcane_spellcaster(self): |
|
|
|
return self.spellcaster == 'Arcane' |
|
|
|
|
|
|
|
class ClassLevelProgression(BaseModel): |
|
|
|
__tablename__ = 'class_progression' |
|
|
@ -35,12 +44,85 @@ class ClassLevelProgression(BaseModel): |
|
|
|
save_staffs_wands = db.Column(db.Integer) |
|
|
|
save_spells = db.Column(db.Integer) |
|
|
|
|
|
|
|
spellslots1 = db.Column(db.Integer) |
|
|
|
spellslots2 = db.Column(db.Integer) |
|
|
|
spellslots3 = db.Column(db.Integer) |
|
|
|
spellslots4 = db.Column(db.Integer) |
|
|
|
spellslots5 = db.Column(db.Integer) |
|
|
|
spellslots6 = db.Column(db.Integer) |
|
|
|
|
|
|
|
guild_id = db.Column(db.Integer, db.ForeignKey('character_class.id'), nullable=False) |
|
|
|
guild = db.relationship('CharacterClass', backref=db.backref('progressions', lazy=True)) |
|
|
|
|
|
|
|
def spell_slots(self, level=None): |
|
|
|
if level > self.guild.maximum_level: |
|
|
|
level = self.guild.maximum_level |
|
|
|
|
|
|
|
spellslots = [ |
|
|
|
self.spellslots1, |
|
|
|
self.spellslots2, |
|
|
|
self.spellslots3, |
|
|
|
self.spellslots4, |
|
|
|
self.spellslots5, |
|
|
|
self.spellslots6 |
|
|
|
] |
|
|
|
|
|
|
|
if level: |
|
|
|
return spellslots[level - 1] |
|
|
|
|
|
|
|
return spellslots |
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
return '<LevelProgression {0} {1}>'.format(self.level, self.guild.name) |
|
|
|
return '<LevelProgression: {0} {1}>'.format(self.level, self.guild.name) |
|
|
|
|
|
|
|
|
|
|
|
class Spell(BaseModel): |
|
|
|
__tablename__ = 'spells' |
|
|
|
|
|
|
|
name = db.Column(db.String(50), unique=True, nullable=False) |
|
|
|
range = db.Column(db.String(50)) |
|
|
|
duration = db.Column(db.String(50)) |
|
|
|
arcane = db.Column(db.Integer, nullable=False) |
|
|
|
divine = db.Column(db.Integer, nullable=False) |
|
|
|
description = db.Column(db.Text(1000), nullable=False) |
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
return '<Spell: {0} ({1})>'.format(self.name, self.school) |
|
|
|
|
|
|
|
def level_for(self, npc): |
|
|
|
return self.arcane if npc.is_arcane_spellcaster else self.divine |
|
|
|
|
|
|
|
@property |
|
|
|
def school(self): |
|
|
|
if self.is_arcane and self.is_divine: |
|
|
|
return 'Multi' |
|
|
|
if self.is_arcane: |
|
|
|
return 'Arcane' |
|
|
|
if self.is_divine: |
|
|
|
return 'Divine' |
|
|
|
|
|
|
|
@property |
|
|
|
def is_divine(self): |
|
|
|
return bool(self.divine and self.divine > 0) |
|
|
|
|
|
|
|
@property |
|
|
|
def is_arcane(self): |
|
|
|
return bool(self.arcane and self.arcane > 0) |
|
|
|
|
|
|
|
@property |
|
|
|
def roll20_format(self): |
|
|
|
spell_dict = { |
|
|
|
'id': self.id, |
|
|
|
'name': self.name, |
|
|
|
'range': self.range, |
|
|
|
'duration': self.duration, |
|
|
|
'divine': self.divine, |
|
|
|
'is_divine': self.is_divine, |
|
|
|
'arcane': self.arcane, |
|
|
|
'is_arcane': self.is_arcane, |
|
|
|
'description': self.description #.replace('"', '\\"').replace("'", "\\'") |
|
|
|
} |
|
|
|
return spell_dict |
|
|
|
|
|
|
|
class EquipmentArmour(BaseModel): |
|
|
|
__tablename__ = 'eq_armour' |
|
|
@ -50,7 +132,7 @@ class EquipmentArmour(BaseModel): |
|
|
|
ac_mod = db.Column(db.Integer, nullable=False) |
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
return '<EquipmentArmour {0}>'.format(self.name) |
|
|
|
return '<EquipmentArmour: {0}>'.format(self.name) |
|
|
|
|
|
|
|
class EquipmentRangedWeapon(BaseModel): |
|
|
|
__tablename__ = 'eq_ranged_wep' |
|
|
@ -61,7 +143,7 @@ class EquipmentRangedWeapon(BaseModel): |
|
|
|
damage_die = db.Column(db.String(10), nullable=False) |
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
return '<EquipmentRangedWeapon {0}>'.format(self.name) |
|
|
|
return '<EquipmentRangedWeapon: {0}>'.format(self.name) |
|
|
|
|
|
|
|
class EquipmentMeleeWeapon(BaseModel): |
|
|
|
__tablename__ = 'eq_melee_wep' |
|
|
@ -73,7 +155,7 @@ class EquipmentMeleeWeapon(BaseModel): |
|
|
|
two_handed = db.Column(db.Boolean, nullable=False) |
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
return '<EquipmentMeleeWeapon {0}>'.format(self.name) |
|
|
|
return '<EquipmentMeleeWeapon: {0}>'.format(self.name) |
|
|
|
|
|
|
|
class CharacterNPC(BaseModel): |
|
|
|
__tablename__ = 'npcs' |
|
|
@ -90,6 +172,8 @@ class CharacterNPC(BaseModel): |
|
|
|
constitution = db.Column(db.Integer, nullable=False) |
|
|
|
charisma = db.Column(db.Integer, nullable=False) |
|
|
|
|
|
|
|
spells = db.Column(db.String(200)) |
|
|
|
|
|
|
|
guild_id = db.Column(db.Integer, db.ForeignKey('character_class.id'), nullable=False) |
|
|
|
guild = db.relationship('CharacterClass', backref=db.backref('npcs', lazy=True)) |
|
|
|
|
|
|
@ -103,7 +187,7 @@ class CharacterNPC(BaseModel): |
|
|
|
armour = db.relationship('EquipmentArmour') |
|
|
|
|
|
|
|
def __repr__(self): |
|
|
|
return '<CharacterNPC {0}>'.format(self.name) |
|
|
|
return '<CharacterNPC: {0}>'.format(self.name) |
|
|
|
|
|
|
|
@staticmethod |
|
|
|
def calculate_attr_mod(attr): |
|
|
@ -124,6 +208,35 @@ class CharacterNPC(BaseModel): |
|
|
|
mod = 3 |
|
|
|
return mod |
|
|
|
|
|
|
|
def spell_slots(self, level=None): |
|
|
|
if level > self.guild.maximum_level: |
|
|
|
level = self.guild.maximum_level |
|
|
|
return self.current_progression.spell_slots(level) |
|
|
|
|
|
|
|
def spells_known(self, level=None): |
|
|
|
if level: |
|
|
|
if level > self.guild.maximum_level: |
|
|
|
level = self.guild.maximum_level |
|
|
|
# Return for a specific level |
|
|
|
if self.is_arcane_spellcaster: |
|
|
|
return (self.spell_slots(level) + self.wis_mod) |
|
|
|
return self.spell_slots(level) |
|
|
|
|
|
|
|
# Return for all levels |
|
|
|
if self.is_arcane_spellcaster: |
|
|
|
return [self.spell_slots(x) + self.wis_mod for x in range(1,6)] |
|
|
|
return [self.spell_slots(x) for x in range(1,6)] |
|
|
|
|
|
|
|
def spell_list(self, level=None): |
|
|
|
spell_ids = self.spells.split(',') |
|
|
|
spells = Spell.query.filter(Spell.id.in_(spell_ids)).all() |
|
|
|
|
|
|
|
spells_by_level = {} |
|
|
|
for spell in spells: |
|
|
|
spells_by_level.setdefault(spell.level_for(self), []).append(spell) |
|
|
|
|
|
|
|
return spells_by_level |
|
|
|
|
|
|
|
@property |
|
|
|
def roll20_format(self): |
|
|
|
npc_dict = { |
|
|
@ -260,8 +373,16 @@ class CharacterNPC(BaseModel): |
|
|
|
def hp(self): |
|
|
|
return self.hit_points |
|
|
|
|
|
|
|
@property |
|
|
|
def is_divine_spellcaster(self): |
|
|
|
return self.guild.is_divine_spellcaster |
|
|
|
|
|
|
|
@property |
|
|
|
def is_arcane_spellcaster(self): |
|
|
|
return self.guild.is_arcane_spellcaster |
|
|
|
|
|
|
|
def update(self, kwargs): |
|
|
|
# Allows us to update like a dict, used for inserting attributes zip |
|
|
|
self.__dict__.update(kwargs) |
|
|
|
|
|
|
|
admin_models = [CharacterClass, ClassLevelProgression, EquipmentArmour, EquipmentRangedWeapon, EquipmentMeleeWeapon, CharacterNPC] |
|
|
|
admin_models = [CharacterClass, ClassLevelProgression, EquipmentArmour, EquipmentRangedWeapon, EquipmentMeleeWeapon, CharacterNPC, Spell] |