django-exalted/app/models.py

1285 lines
44 KiB
Python
Raw Normal View History

from django.db import models
2020-04-13 00:31:12 +01:00
from polymorphic.models import PolymorphicModel
2020-04-11 14:01:52 +01:00
import multiselectfield
2020-04-11 14:55:45 +01:00
from random import randint
from math import ceil
#==============================================================================#
#-------------------------------- OPTION LISTS --------------------------------#
#==============================================================================#
2020-04-11 13:50:56 +01:00
ATTRIBUTES = [
(
2020-04-11 13:56:12 +01:00
"Physical", (
2020-04-13 00:31:12 +01:00
("Strength", "Strength"),
("Dexterity", "Dexterity"),
("Stamina", "Stamina"),
2020-04-11 13:50:56 +01:00
),
),
(
2020-04-11 13:56:12 +01:00
"Social", (
2020-04-13 00:31:12 +01:00
("Charisma", "Charisma"),
("Manipulation", "Manipulation"),
("Appearance", "Appearance"),
2020-04-11 13:50:56 +01:00
),
),
(
2020-04-11 13:56:12 +01:00
"Mental", (
2020-04-13 00:31:12 +01:00
("Perception", "Perception"),
("Intelligence", "Intelligence"),
("Wits", "Wits"),
2020-04-11 13:50:56 +01:00
),
),
]
ABILITIES = [
(
2020-04-11 13:56:12 +01:00
"War", (
2020-04-13 00:31:12 +01:00
("Archery", "Archery"),
("Athletics", "Athletics"),
("Awareness", "Awareness"),
("Brawl", "Brawl"),
("Dodge", "Dodge"),
("Integrity", "Integrity"),
("Melee", "Melee"),
("Resistance", "Resistance"),
("Thrown", "Thrown"),
("War", "War"),
2020-04-11 13:50:56 +01:00
),
),
(
2020-04-11 13:56:12 +01:00
"Life", (
2020-04-13 00:31:12 +01:00
("Craft", "Craft"),
("Larceny", "Larceny"),
("Linguistics", "Linguistics"),
("Performance", "Performance"),
("Presence", "Presence"),
("Ride", "Ride"),
("Sail", "Sail"),
("Socialise", "Socialise"),
("Stealth", "Stealth"),
("Survival", "Survival"),
2020-04-11 13:50:56 +01:00
),
),
(
2020-04-11 13:56:12 +01:00
"Wisdom", (
2020-04-13 00:31:12 +01:00
("Bureaucracy", "Bureaucracy"),
("Investigation", "Investigation"),
("Lore", "Lore"),
("Medicine", "Medicine"),
("Occult", "Occult"),
2020-04-11 13:50:56 +01:00
),
),
]
STATICS = [
2020-04-13 00:31:12 +01:00
("Natural Soak", "Natural Soak"),
("Armored Soak", "Armored Soak"),
("Total Soak", "Total Soak"),
("Hardness", "Hardness"),
("Parry", "Parry"),
("Evasion", "Evasion"),
("Resolve", "Resolve"),
("Guile", "Guile"),
("Rush", "Rush"),
("Disengage", "Disengage"),
("Join Battle", "Join Battle"),
2020-04-11 13:50:56 +01:00
]
CATEGORIES = [
2020-04-13 00:31:12 +01:00
("Light", "Light"),
("Medium", "Medium"),
("Heavy", "Heavy"),
2020-04-11 13:50:56 +01:00
]
2020-04-11 14:01:52 +01:00
TAGS_WEAPONS = [
2020-04-11 13:50:56 +01:00
(
2020-04-11 13:56:12 +01:00
"General", (
2020-04-13 00:31:12 +01:00
("One Handed", "One Handed"),
("Two Handed", "Two Handed"),
("Bashing", "Bashing"),
("Concealable", "Concealable"),
("Lethal", "Lethal"),
("Mounted", "Mounted"),
("Piercing", "Piercing"),
("Special", "Special"),
2020-04-11 13:50:56 +01:00
),
),
(
2020-04-11 13:56:12 +01:00
"Melee", (
2020-04-13 00:31:12 +01:00
("Melee", "Melee"),
("Balanced", "Balanced"),
("Brawl", "Brawl"),
("Chopping", "Chopping"),
("Disarming", "Disarming"),
("Flexible", "Flexible"),
("Improvised", "Improvised"),
("Grappling", "Grappling"),
("Martial Arts", "Martial Arts"),
("Natural", "Natural"),
("Reaching", "Reaching"),
("Shield", "Shield"),
("Smashing", "Smashing"),
("Worn", "Worn"),
2020-04-11 13:50:56 +01:00
),
),
(
2020-04-11 13:56:12 +01:00
"Thrown", (
2020-04-16 00:07:58 +01:00
("Thrown", "Thrown"),
2020-04-13 00:31:12 +01:00
("Occult", "Occult"),
("Cutting", "Cutting"),
("Poisonable", "Poisonable"),
("Subtle", "Subtle"),
2020-04-11 13:50:56 +01:00
),
),
(
2020-04-11 13:56:12 +01:00
"Archery", (
2020-04-13 00:31:12 +01:00
("Archery", "Archery"),
("Crossbow", "Crossbow"),
("Flame", "Flame"),
("Powerful", "Powerful"),
("Slow", "Slow"),
2020-04-11 13:50:56 +01:00
),
),
]
TAGS_ARMOR = [
2020-04-13 00:31:12 +01:00
("Buoyant", "Buoyant"),
("Concealable", "Concealable"),
("Silent", "Silent"),
2020-04-11 13:50:56 +01:00
]
INTENSITIES = [
2020-04-13 00:31:12 +01:00
("Minor", "Minor"),
("Major", "Major"),
("Defining", "Defining"),
]
2020-04-11 14:55:45 +01:00
DIE_TYPES = [
2020-04-13 00:31:12 +01:00
("None", "None"),
("Success", "Success"),
("Double", "Double"),
("Exploding / Disappearing", "Exploding / Disappearing"),
("Subtracting", "Subtracting")
]
CHARM_TYPES = [
("Permanent", "Permanent"),
("Simple", "Simple"),
("Reflexive", "Reflexive"),
("Suplemental", "Suplemental"),
]
CHARM_DURATIONS = [
("", ""),
("One Round", "One Round"),
("One Scene", "One Scene"),
("Indefinite", "Indefinite"),
]
CHARM_KEYWORDS = [
(
"Charms", (
("Advantage", "Advantage"),
("Attack-Action", "Attack-Action"),
("Counterattack", "Counterattack"),
("Form", "Form"),
("Group", "Group"),
("Mute", "Mute"),
("Perilous", "Perilous"),
("Once Per Scene", "Once Per Scene"),
("Once Per Day", "Once Per Day"),
("Once Per Story", "Once Per Story"),
("Once Per Season", "Once Per Season"),
("Pilot", "Pilot"),
("Post-Roll", "Post-Roll"),
("Psyche", "Psyche"),
("Quickshot", "Quickshot"),
)
),
(
"Evocations", (
("Dissonant", "Dissonant"),
("Resonant", "Resonant"),
)
),
]
CASTES_SOLAR = [
("Dawn", "Dawn"),
("Zenith", "Zenith"),
("Twilight", "Twilight"),
("Night", "Night"),
("Eclipse", "Eclipse"),
]
CASTES_LUNAR = [
("Full Moon", "Full Moon"),
("Changing Moon", "Changing Moon"),
("No Moon", "No Moon"),
("Castless", "Castless")
2020-04-11 14:55:45 +01:00
]
2020-04-16 00:07:58 +01:00
SHAPE_SIZES = [
("Normal", "Normal"),
]
SHAPE_TYPES = [
("Human", "Human"),
("Animal", "Animal"),
]
#==============================================================================#
#------------------------------- CUSTOM MODELS --------------------------------#
#==============================================================================#
class NameField(models.CharField):
def __init__(self, *args, **kwargs):
kwargs['verbose_name'] = "Name"
kwargs['blank'] = False
kwargs['max_length'] = 100
super().__init__(*args, **kwargs)
class DescriptionField(models.TextField):
def __init__(self, *args, **kwargs):
kwargs['verbose_name'] = "Description"
kwargs['blank'] = True
kwargs['max_length'] = 1000
super().__init__(*args, **kwargs)
class DotField(models.IntegerField):
def __init__(self, verbose_name, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['blank'] = False
kwargs['default'] = 0
super().__init__(*args, **kwargs)
class SingleChoiceField(models.CharField):
def __init__(self, verbose_name, choices, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['choices'] = choices
kwargs['blank'] = True
kwargs['max_length'] = 100
super().__init__(*args, **kwargs)
2020-04-11 14:01:52 +01:00
class MultiChoiceField(multiselectfield.MultiSelectField):
def __init__(self, verbose_name, choices, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['choices'] = choices
kwargs['blank'] = True
kwargs['max_length'] = 100
super().__init__(*args, **kwargs)
class NamedIntegerField(models.IntegerField):
def __init__(self, verbose_name, desc=None, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['help_text'] = desc
kwargs['blank'] = False
kwargs['default'] = 0
super().__init__(*args, **kwargs)
class NamedCharField(models.CharField):
def __init__(self, verbose_name, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['blank'] = False
kwargs['max_length'] = 100
super().__init__(*args, **kwargs)
2020-04-11 15:15:05 +01:00
class DieField(multiselectfield.MultiSelectField):
2020-04-11 14:55:45 +01:00
def __init__(self, verbose_name, number, default, *args, **kwargs):
self.number = number
kwargs['verbose_name'] = verbose_name
kwargs['default'] = default
kwargs['choices'] = DIE_TYPES
kwargs['blank'] = False
kwargs['max_length'] = 100
super().__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs['number'] = self.number
return name, path, args, kwargs
class NamedBooleanField(models.BooleanField):
def __init__(self, verbose_name, default=False, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['default'] = default
kwargs['blank'] = False
super().__init__(*args, **kwargs)
class NamedForeignKeyField(models.ForeignKey):
2020-04-11 15:29:21 +01:00
def __init__(self, verbose_name, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['on_delete'] = models.CASCADE
kwargs['blank'] = True
kwargs['null'] = True
super().__init__(*args, **kwargs)
class NamedManyToManyField(models.ManyToManyField):
def __init__(self, verbose_name, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['blank'] = True
super().__init__(*args, **kwargs)
class NamedOneToOneField(models.OneToOneField):
def __init__(self, verbose_name, *args, **kwargs):
kwargs['verbose_name'] = verbose_name
kwargs['on_delete'] = models.CASCADE
kwargs['blank'] = True
kwargs['null'] = True
super().__init__(*args, **kwargs)
2020-04-11 14:55:45 +01:00
#==============================================================================#
#-------------------------------- DICE ROLLING --------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class RollConfiguration(PolymorphicModel):
def __str__(self):
return self.name
name = NameField()
successesAuto = NamedIntegerField("Auto-Successes")
2020-04-11 15:15:05 +01:00
r01 = DieField("1s", 1, ["NONE"])
r02 = DieField("2s", 2, ["NONE"])
r03 = DieField("3s", 3, ["NONE"])
r04 = DieField("4s", 4, ["NONE"])
r05 = DieField("5s", 5, ["NONE"])
r06 = DieField("6s", 6, ["NONE"])
r07 = DieField("7s", 7, ["SUCCESS"])
r08 = DieField("8s", 8, ["SUCCESS"])
r09 = DieField("9s", 9, ["SUCCESS"])
r10 = DieField("10s", 10, ["SUCCESS", "DOUBLE"])
2020-04-11 14:55:45 +01:00
def roll(self, pool=1, successesStunt=0):
2020-04-11 14:55:45 +01:00
listDice = [
self.r01,
self.r02,
self.r03,
self.r04,
self.r05,
self.r06,
self.r07,
self.r08,
self.r09,
self.r10,
]
2020-04-11 15:18:32 +01:00
listSuccess, listDouble, listExplodingDisappearing, listSubtracting = [], [], [], []
2020-04-11 14:55:45 +01:00
for die in listDice:
2020-04-11 15:15:05 +01:00
if "SUCCESS" in die:
2020-04-11 14:55:45 +01:00
listSuccess.append(die.number)
2020-04-11 15:15:05 +01:00
if "DOUBLE" in die:
2020-04-11 14:55:45 +01:00
listDouble.append(die.number)
2020-04-11 15:15:05 +01:00
if "EXPLODING_DISAPPEARING" in die:
listExplodingDisappearing.append(die.number)
if "SUBTRACTING" in die:
2020-04-11 14:55:45 +01:00
listSubtracting.append(die.number)
successes = self.successesAuto + successesStunt
2020-04-11 14:55:45 +01:00
listExploded, listDisappeared = [], []
listRoll = [0 for die in range(pool)]
while 0 in listRoll:
for die in listRoll:
if die == 0:
die = randint(1, 10)
2020-04-11 15:15:05 +01:00
if die in listExplodingDisappearing:
if die in listSuccess:
listExploded.append(die)
else:
listDisappeared.append(die)
2020-04-11 14:55:45 +01:00
die = 0
for die in listRoll + listExploded:
if die in listSuccess:
successes += 1
2020-04-11 15:15:05 +01:00
if die in listDouble:
successes += 1
if die in listSubtracting:
2020-04-11 14:55:45 +01:00
successes -= 1
if successes < 0:
successes = 0
botch = (successes == 0) and (1 in listRoll)
return successes, botch, listRoll, listExploded, listDisappeared
#==============================================================================#
#--------------------------------- MODIFIERS ----------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class ModifierBase(PolymorphicModel):
value = NamedIntegerField("Modifier Value")
2020-04-16 20:12:02 +01:00
class ModifierAttribute(ModifierBase):
def __str__(self):
2020-04-13 00:31:12 +01:00
return "{} [{}]".format(self.keyword, self.value)
2020-04-13 00:31:12 +01:00
keyword = SingleChoiceField("Attribute", ATTRIBUTES)
2020-04-16 20:12:02 +01:00
class ModifierAbility(ModifierBase):
def __str__(self):
2020-04-13 00:31:12 +01:00
return "{} [{}]".format(self.keyword, self.value)
2020-04-13 00:31:12 +01:00
keyword = SingleChoiceField("Ability", ABILITIES)
2020-04-16 20:12:02 +01:00
class ModifierStatic(ModifierBase):
def __str__(self):
2020-04-13 00:31:12 +01:00
return "{} [{}]".format(self.keyword, self.value)
2020-04-13 00:31:12 +01:00
keyword = SingleChoiceField("Static", STATICS)
#==============================================================================#
#--------------------------------- CHARACTERS ---------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class CharacterBase(PolymorphicModel):
def __str__(self):
return self.name
#======== MODIFIER METHODS ========#
2020-04-13 00:31:12 +01:00
def effectModifier(self, keyword):
modifier = 0
try:
2020-04-15 20:35:45 +01:00
ownerships = [ownership for ownership in ownershipBase.objects.all() if (ownership.owner == self) and (ownership.active)]
2020-04-13 00:31:12 +01:00
for ownership in ownerships:
try:
modifier += ownership.target.modifier(keyword)
except:
pass
except:
pass
return modifier
#============ GENERAL =============#
name = NameField()
2020-04-13 00:31:12 +01:00
player = models.CharField(verbose_name="Player", max_length=100, blank=True)
concept = models.TextField(blank=True)
#=========== ATTRIBUTES ===========#
strength = DotField("Strength")
def attributeStrength(self):
2020-04-15 20:35:45 +01:00
return self.strength + self.effectModifier("Strength")
2020-04-13 00:31:12 +01:00
def dotsStrength(self):
output = []
for i in range(self.strength):
output.append(True)
for i in range(5 - self.strength):
output.append(False)
return output
dexterity = DotField("Dexterity")
def attributeDexterity(self):
2020-04-15 20:35:45 +01:00
return self.dexterity + self.effectModifier("Dexterity")
2020-04-13 00:31:12 +01:00
def dotsDexterity(self):
output = []
for i in range(self.dexterity):
output.append(True)
for i in range(5 - self.dexterity):
output.append(False)
return output
stamina = DotField("Stamina")
def attributeStamina(self):
2020-04-15 20:35:45 +01:00
return self.stamina + self.effectModifier("Stamina")
2020-04-13 00:31:12 +01:00
def dotsStamina(self):
output = []
for i in range(self.stamina):
output.append(True)
for i in range(5 - self.stamina):
output.append(False)
return output
charisma = DotField("Charisma")
def attributeCharisma(self):
2020-04-15 20:35:45 +01:00
return self.charisma + self.effectModifier("Charisma")
2020-04-13 00:31:12 +01:00
def dotsCharisma(self):
output = []
for i in range(self.charisma):
output.append(True)
for i in range(5 - self.charisma):
output.append(False)
return output
manipulation = DotField("Manipulation")
def attributeManipulation(self):
2020-04-15 20:35:45 +01:00
return self.manipulation + self.effectModifier("Manipulation")
2020-04-13 00:31:12 +01:00
def dotsManipulation(self):
output = []
for i in range(self.manipulation):
output.append(True)
for i in range(5 - self.manipulation):
output.append(False)
return output
appearance = DotField("Apperance")
def attributeAppearance(self):
2020-04-15 20:35:45 +01:00
return self.appearance + self.effectModifier("Appearance")
2020-04-13 00:31:12 +01:00
def dotsAppearance(self):
output = []
for i in range(self.appearance):
output.append(True)
for i in range(5 - self.appearance):
output.append(False)
return output
perception = DotField("Perception")
def attributePerception(self):
2020-04-15 20:35:45 +01:00
return self.perception + self.effectModifier("Perception")
2020-04-13 00:31:12 +01:00
def dotsPerception(self):
output = []
for i in range(self.perception):
output.append(True)
for i in range(5 - self.perception):
output.append(False)
return output
intelligence = DotField("Intelligence")
def attributeIntelligence(self):
2020-04-15 20:35:45 +01:00
return self.intelligence + self.effectModifier("Intelligence")
2020-04-13 00:31:12 +01:00
def dotsIntelligence(self):
output = []
for i in range(self.intelligence):
output.append(True)
for i in range(5 - self.intelligence):
output.append(False)
return output
wits = DotField("Wits")
def attributeWits(self):
2020-04-15 20:35:45 +01:00
return self.wits + self.effectModifier("Wits")
2020-04-13 00:31:12 +01:00
def dotsWits(self):
output = []
for i in range(self.wits):
output.append(True)
for i in range(5 - self.wits):
output.append(False)
return output
#=========== ABILITIES ============#
archery = DotField("Archery")
def abilityArchery(self):
2020-04-15 20:35:45 +01:00
return self.archery + self.effectModifier("Archery")
2020-04-13 00:31:12 +01:00
def dotsArchery(self):
output = []
for i in range(self.archery):
output.append(True)
for i in range(5 - self.archery):
output.append(False)
return output
athletics = DotField("Athletics")
def abilityAthletics(self):
2020-04-15 20:35:45 +01:00
return self.athletics + self.effectModifier("Athletics")
2020-04-13 00:31:12 +01:00
def dotsAthletics(self):
output = []
for i in range(self.athletics):
output.append(True)
for i in range(5 - self.athletics):
output.append(False)
return output
awareness = DotField("Awareness")
def abilityAwareness(self):
2020-04-15 20:35:45 +01:00
return self.awareness + self.effectModifier("Awareness")
2020-04-13 00:31:12 +01:00
def dotsAwareness(self):
output = []
for i in range(self.awareness):
output.append(True)
for i in range(5 - self.awareness):
output.append(False)
return output
brawl = DotField("Brawl")
def abilityBrawl(self):
2020-04-15 20:35:45 +01:00
return self.brawl + self.effectModifier("Brawl")
2020-04-13 00:31:12 +01:00
def dotsBrawl(self):
output = []
for i in range(self.brawl):
output.append(True)
for i in range(5 - self.brawl):
output.append(False)
return output
bureaucracy = DotField("Bureaucracy")
def abilityBureaucracy(self):
2020-04-15 20:35:45 +01:00
return self.bureaucracy + self.effectModifier("Bureaucracy")
2020-04-13 00:31:12 +01:00
def dotsBureaucracy(self):
output = []
for i in range(self.bureaucracy):
output.append(True)
for i in range(5 - self.bureaucracy):
output.append(False)
return output
craft = DotField("Craft")
def abilityCraft(self):
2020-04-15 20:35:45 +01:00
return self.craft + self.effectModifier("Craft")
2020-04-13 00:31:12 +01:00
def dotsCraft(self):
output = []
for i in range(self.craft):
output.append(True)
for i in range(5 - self.craft):
output.append(False)
return output
dodge = DotField("Dodge")
def abilityDodge(self):
2020-04-15 20:35:45 +01:00
return self.dodge + self.effectModifier("Dodge")
2020-04-13 00:31:12 +01:00
def dotsDodge(self):
output = []
for i in range(self.dodge):
output.append(True)
for i in range(5 - self.dodge):
output.append(False)
return output
integrity = DotField("Integrity")
def abilityIntegrity(self):
2020-04-15 20:35:45 +01:00
return self.integrity + self.effectModifier("Integrity")
2020-04-13 00:31:12 +01:00
def dotsIntegrity(self):
output = []
for i in range(self.integrity):
output.append(True)
for i in range(5 - self.integrity):
output.append(False)
return output
investigation = DotField("Investigation")
def abilityInvestigation(self):
2020-04-15 20:35:45 +01:00
return self.investigation + self.effectModifier("Investigation")
2020-04-13 00:31:12 +01:00
def dotsInvestigation(self):
output = []
for i in range(self.investigation):
output.append(True)
for i in range(5 - self.investigation):
output.append(False)
return output
larceny = DotField("Larceny")
def abilityLarceny(self):
2020-04-15 20:35:45 +01:00
return self.larceny + self.effectModifier("Larceny")
2020-04-13 00:31:12 +01:00
def dotsLarceny(self):
output = []
for i in range(self.larceny):
output.append(True)
for i in range(5 - self.larceny):
output.append(False)
return output
linguistics = DotField("Linguistics")
def abilityLinguistics(self):
2020-04-15 20:35:45 +01:00
return self.linguistics + self.effectModifier("Linguistics")
2020-04-13 00:31:12 +01:00
def dotsLinguistics(self):
output = []
for i in range(self.linguistics):
output.append(True)
for i in range(5 - self.linguistics):
output.append(False)
return output
lore = DotField("Lore")
def abilityLore(self):
2020-04-15 20:35:45 +01:00
return self.lore + self.effectModifier("Lore")
2020-04-13 00:31:12 +01:00
def dotsLore(self):
output = []
for i in range(self.lore):
output.append(True)
for i in range(5 - self.lore):
output.append(False)
return output
martialArts = DotField("MartialArts")
def abilityMartialArts(self):
2020-04-15 20:35:45 +01:00
return self.martialArts + self.effectModifier("Martial Arts")
2020-04-13 00:31:12 +01:00
def dotsMartialArts(self):
output = []
for i in range(self.martialArts):
output.append(True)
for i in range(5 - self.martialArts):
output.append(False)
return output
medicine = DotField("Medicine")
def abilityMedicine(self):
2020-04-15 20:35:45 +01:00
return self.medicine + self.effectModifier("Medicine")
2020-04-13 00:31:12 +01:00
def dotsMedicine(self):
output = []
for i in range(self.medicine):
output.append(True)
for i in range(5 - self.medicine):
output.append(False)
return output
melee = DotField("Melee")
def abilityMelee(self):
2020-04-15 20:35:45 +01:00
return self.melee + self.effectModifier("Melee")
2020-04-13 00:31:12 +01:00
def dotsMelee(self):
output = []
for i in range(self.melee):
output.append(True)
for i in range(5 - self.melee):
output.append(False)
return output
occult = DotField("Occult")
def abilityOccult(self):
2020-04-15 20:35:45 +01:00
return self.occult + self.effectModifier("Occult")
2020-04-13 00:31:12 +01:00
def dotsOccult(self):
output = []
for i in range(self.occult):
output.append(True)
for i in range(5 - self.occult):
output.append(False)
return output
performance = DotField("Performance")
def abilityPerformance(self):
2020-04-15 20:35:45 +01:00
return self.performance + self.effectModifier("Performance")
2020-04-13 00:31:12 +01:00
def dotsPerformance(self):
output = []
for i in range(self.performance):
output.append(True)
for i in range(5 - self.performance):
output.append(False)
return output
presence = DotField("Presence")
def abilityPresence(self):
2020-04-15 20:35:45 +01:00
return self.presence + self.effectModifier("Presence")
2020-04-13 00:31:12 +01:00
def dotsPresence(self):
output = []
for i in range(self.presence):
output.append(True)
for i in range(5 - self.presence):
output.append(False)
return output
resistance = DotField("Resistance")
def abilityResistance(self):
2020-04-15 20:35:45 +01:00
return self.resistance + self.effectModifier("Resistance")
2020-04-13 00:31:12 +01:00
def dotsResistance(self):
output = []
for i in range(self.resistance):
output.append(True)
for i in range(5 - self.resistance):
output.append(False)
return output
ride = DotField("Ride")
def abilityRide(self):
2020-04-15 20:35:45 +01:00
return self.ride + self.effectModifier("Ride")
2020-04-13 00:31:12 +01:00
def dotsRide(self):
output = []
for i in range(self.ride):
output.append(True)
for i in range(5 - self.ride):
output.append(False)
return output
sail = DotField("Sail")
def abilitySail(self):
2020-04-15 20:35:45 +01:00
return self.sail + self.effectModifier("Sail")
2020-04-13 00:31:12 +01:00
def dotsSail(self):
output = []
for i in range(self.sail):
output.append(True)
for i in range(5 - self.sail):
output.append(False)
return output
socialize = DotField("Socialize")
def abilitySocialize(self):
2020-04-15 20:35:45 +01:00
return self.socialize + self.effectModifier("Socialize")
2020-04-13 00:31:12 +01:00
def dotsSocialize(self):
output = []
for i in range(self.socialize):
output.append(True)
for i in range(5 - self.socialize):
output.append(False)
return output
stealth = DotField("Stealth")
def abilityStealth(self):
2020-04-15 20:35:45 +01:00
return self.stealth + self.effectModifier("Stealth")
2020-04-13 00:31:12 +01:00
def dotsStealth(self):
output = []
for i in range(self.stealth):
output.append(True)
for i in range(5 - self.stealth):
output.append(False)
return output
survival = DotField("Survival")
def abilitySurvival(self):
2020-04-15 20:35:45 +01:00
return self.survival + self.effectModifier("Survival")
2020-04-13 00:31:12 +01:00
def dotsSurvival(self):
output = []
for i in range(self.survival):
output.append(True)
for i in range(5 - self.survival):
output.append(False)
return output
thrown = DotField("Thrown")
def abilityThrown(self):
2020-04-15 20:35:45 +01:00
return self.thrown + self.effectModifier("Thrown")
2020-04-13 00:31:12 +01:00
def dotsThrown(self):
output = []
for i in range(self.thrown):
output.append(True)
for i in range(5 - self.thrown):
output.append(False)
return output
war = DotField("War")
def abilityWar(self):
2020-04-15 20:35:45 +01:00
return self.war + self.effectModifier("War")
2020-04-13 00:31:12 +01:00
def dotsWar(self):
output = []
for i in range(self.war):
output.append(True)
for i in range(5 - self.war):
output.append(False)
return output
#============= MERITS =============#
# Reverse relation
2020-04-13 00:31:12 +01:00
def meritSet(self):
output = []
try:
ownerships = self.ownershipMerit_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#========== SPECIALITIES ==========#
# Reverse relation
def specialitySet(self):
output = []
try:
ownerships = self.ownershipSpeciality_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#=========== INTIMACIES ===========#
# Reverse relation
2020-04-15 20:35:45 +01:00
# character.intimactBase_set.all()
# character.intimacyTie_set.object.all()
# character.intimacyPrincipal_set.all()
#=========== WILLPOWER ============#
willpowerMax = NamedIntegerField("Maximum Willpower")
willpower = NamedIntegerField("Current Willpower")
def dotsTriWillpower(self):
output = [0 for i in range(10)]
for i in range(10):
if i < self.willpowerMax and i >= self.willpower:
output[i] = 1
elif i < self.willpower:
output[i] = 2
return output
#=========== EXPERIENCE ===========#
experienceTotal = NamedIntegerField("Total Experience")
experience = NamedIntegerField("Current Experience")
#============ WEAPONS =============#
# Reverse relation
2020-04-13 00:31:12 +01:00
def itemWeaponSet(self):
output = []
try:
ownerships = self.ownershipItemWeapon_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#============= ARMOR ==============#
# Reverse relation
2020-04-13 00:31:12 +01:00
def itemArmorSet(self):
output = []
try:
ownerships = self.ownershipItemArmor_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
def armorSoak(self):
armor = None
modifier = 0
try:
2020-04-13 00:31:12 +01:00
armor = self.itemArmorSet().filter(equipped=True)
except:
pass
if armor:
for item in armor:
modifier += item.soak
return modifier
def armorHardness(self):
armor = None
modifier = 0
try:
2020-04-13 00:31:12 +01:00
armor = self.itemArmorSet().filter(equipped=True)
except:
pass
if armor:
for item in armor:
modifier += item.hardness
return modifier
def armorMobilityPenalty(self):
armor = None
modifier = 0
try:
2020-04-13 00:31:12 +01:00
armor = self.itemArmorSet().filter(equipped=True)
except:
pass
if armor:
for item in armor:
modifier += item.mobilityPenalty
return modifier
#============= ITEMS ==============#
# Reverse relation
2020-04-13 00:31:12 +01:00
def itemSet(self):
output = []
try:
ownerships = self.ownershipItem_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#============ ESSENCE =============#
essence = NamedIntegerField("Essence")
def dotsEssence(self):
output = []
for i in range(self.essence):
output.append(True)
for i in range(5 - self.essence):
output.append(False)
return output
#============= HEALTH =============#
health0 = NamedIntegerField("'-0' Health Levels")
health1 = NamedIntegerField("'-1' Health Levels")
health2 = NamedIntegerField("'-2' Health Levels")
healthIndex = NamedIntegerField("Health Track Index")
def healthTrack(self):
return ["Healthy"] + ["-0" for i in range(self.health0)] + ["-1" for i in range(self.health1)] + ["-1" for i in range(self.health1)] + ["-4", "i"]
def healthLevel(self):
return self.healthTrack()[self.healthIndex]
2020-04-16 00:07:58 +01:00
def healthDots(self):
output = []
for i in range(len(self.healthTrack()) - 1):
output.append((self.healthTrack()[i+1], i < self.healthIndex))
return output
#============ STATICS =============#
def resolve(self, speciality=None, mod=0):
2020-04-13 00:31:12 +01:00
return mod + ceil((self.attributeWits() + self.abilityIntegrity()) / 2) + self.effectModifier("RESOLVE")
def guile(self, speciality=None, mod=0):
2020-04-13 00:31:12 +01:00
return mod + ceil((self.attributeManipulation() + self.abilitySocialize()) / 2) + self.effectModifier("GUILE")
def soakNatural(self, mod=0):
2020-04-13 00:31:12 +01:00
return mod + self.attributeStamina() + self.effectModifier("SOAK NATURAL")
def soakArmored(self, mod=0):
return mod + self.armorSoak()
def soakTotal(self, mod=0):
return mod + self.soakNatural() + self.soakArmored()
def hardness(self, mod=0):
2020-04-13 00:31:12 +01:00
return mod + self.armorHardness() + self.effectModifier("HARDNESS")
def joinBattle(self, mod=0):
2020-04-13 00:31:12 +01:00
return mod + self.attributeWits() + self.abilityAwareness() + 3 + self.effectModifier("JOIN BATTLE")
def evasion(self, mod=0):
2020-04-13 00:31:12 +01:00
return mod + ceil((self.attributeDexterity() + self.abilityDodge()) / 2) - self.armorMobilityPenalty() + self.effectModifier("EVASION")
def rush(self, mod=0):
2020-04-13 00:31:12 +01:00
return mod + self.attributeDexterity() + self.abilityAthletics() + self.effectModifier("RUSH")
def disengage(self, mod=0):
2020-04-13 00:31:12 +01:00
return mod + self.attributeDexterity() + self.abilityDodge() + self.effectModifier("DISENGAGE")
2020-04-16 20:12:02 +01:00
class CharacterMortal(CharacterBase):
def type(self):
return "Mortal"
class CharacterExaltBase(CharacterBase):
2020-04-13 00:31:12 +01:00
anima = models.CharField(verbose_name="Anima", max_length=100)
#============= MOTES ==============#
motesPersonalMax = NamedIntegerField("Maximum Personal Motes")
motesPersonal = NamedIntegerField("Current Personal Motes")
motesPeripheralMax = NamedIntegerField("Maximum Peripheral Motes")
motesPeripheral = NamedIntegerField("Current Peripheral Motes")
motesCommitted = NamedIntegerField("Committed Motes")
#============= LIMIT ==============#
limitTrigger = models.TextField(verbose_name="Limit Trigger", blank="False", max_length=1000)
limitBreak = NamedIntegerField("Limit Break")
def dotsLimit(self):
output = [False for i in range(10)]
for i in range(10):
output[i] = i < self.limitBreak
return output
#======= EXALTED EXPERIENCE =======#
2020-04-13 00:31:12 +01:00
experienceExaltedTotal = NamedIntegerField("Total Exalted Experience")
experienceExalted = NamedIntegerField("Current Exalted Experience")
#========== MARTIAL ARTS ==========#
# Reverse relation
def martialArtSet(self):
output = []
try:
ownerships = self.ownershipCharmMartialArt_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#=========== EVOCATIONS ===========#
# Reverse relation
def evocationSet(self):
output = []
try:
ownerships = self.ownershipCharmEvocation_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
2020-04-16 20:12:02 +01:00
class CharacterExaltSolar(CharacterExaltBase):
2020-04-13 00:31:12 +01:00
def type(self):
return "Solar Exalt"
caste = SingleChoiceField("Solar Caste", CASTES_SOLAR)
#============= CHARMS =============#
# Reverse relation
def charmSet(self):
output = []
try:
ownerships = self.ownershipCharmSolar_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#======= SUPERNAL & FAVORED =======#
abilitySupernal = SingleChoiceField("Supernal Ability", ABILITIES)
abilityFavored = MultiChoiceField("Favoured Abilities", ABILITIES)
2020-04-16 20:12:02 +01:00
class CharacterExaltLunar(CharacterExaltBase):
2020-04-13 00:31:12 +01:00
def type(self):
return "Lunar Exalt"
2020-04-13 00:31:12 +01:00
caste = SingleChoiceField("Lunar Caste", CASTES_LUNAR)
#========= SHAPESHIFTING ==========#
2020-04-13 00:31:12 +01:00
spiritShape = models.CharField(verbose_name="Spirit Shape", max_length=100)
# Reverse relation
2020-04-16 00:07:58 +01:00
def lunarShapeSet(self):
2020-04-13 00:31:12 +01:00
output = []
try:
ownerships = self.ownershipCharmLunarShape_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#============= CHARMS =============#
# Reverse relation
2020-04-13 00:31:12 +01:00
def charmSet(self):
output = []
try:
ownerships = self.ownershipCharmLunar_set.all()
for ownership in ownerships:
output.append(ownership.target)
except:
pass
return output
#============ FAVORED =============#
attributeFavored = MultiChoiceField("Favoured Attributes", ATTRIBUTES)
#==============================================================================#
#----------------------------------- ITEMS ------------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class ItemBase(PolymorphicModel):
def __str__(self):
return self.name
name = NameField()
description = DescriptionField()
2020-04-16 20:12:02 +01:00
class Item(ItemBase):
pass
#==============================================================================#
#---------------------------------- WEAPONS -----------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class ItemWeaponBase(ItemBase):
2020-04-11 14:01:52 +01:00
category = SingleChoiceField("Category", CATEGORIES)
tags = MultiChoiceField("Tags", TAGS_WEAPONS)
accuracy = NamedIntegerField("Accuracy")
damage = NamedIntegerField("Damage")
defense = NamedIntegerField("Defense")
overwhelming = NamedIntegerField("Overwhelming")
attunement = NamedIntegerField("Attunement")
2020-04-16 20:12:02 +01:00
class ItemWeaponMelee(ItemWeaponBase):
def attack(self, ability, mod=0, withering=True):
if withering:
return mod + ability + self.dexterity + weapon.accuracy
else:
return mod + ability + self.dexterity
def parry(self, ability, mod=0):
if self.character.charmsActive():
mod += sum([])
return mod + ceil((self.dexterity + ability) / 2) + weapon.defense
2020-04-16 20:12:02 +01:00
class ItemWeaponRanged(ItemWeaponBase):
rangeClose = NamedIntegerField("Close Range")
rangeShort = NamedIntegerField("Short Range")
rangeMedium = NamedIntegerField("Medium Range")
rangeLong = NamedIntegerField("Long Range")
rangeExtreme = NamedIntegerField("Extreme Range")
def attack(self, ability, rangeBand, mod=0, withering=True):
rangeBand = rangeBand.lower()
if rangeBand == "close" or rangeBand == "c":
rangeModifier = self.rangeClose
elif rangeBand == "short" or rangeBand == "s":
rangeModifier = self.rangeShort
elif rangeBand == "medium" or rangeBand == "m":
rangeModifier = self.rangeMedium
elif rangeBand == "long" or rangeBand == "l":
rangeModifier = self.rangeLong
elif rangeBand == "extreme" or rangeBand == "e":
rangeModifier = self.rangeExtreme
else:
rangeModifier = 0
if withering:
return mod + rangeModifier + ability + self.dexterity + weapon.accuracy
else:
return mod + rangeModifier + ability + self.dexterity
#==============================================================================#
#----------------------------------- ARMOR ------------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class ItemArmor(ItemBase):
2020-04-11 14:03:04 +01:00
category = SingleChoiceField("Category", CATEGORIES)
tags = MultiChoiceField("Tags", TAGS_ARMOR)
soak = NamedIntegerField("Soak")
hardness = NamedIntegerField("Hardness")
mobilityPenalty = NamedIntegerField("Mobility Penalty")
attunement = NamedIntegerField("Attunement")
#==============================================================================#
2020-04-13 00:31:12 +01:00
#---------------------------------- EFFECTS -----------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class EffectBase(PolymorphicModel):
def __str__(self):
return self.name
name = NameField()
description = DescriptionField()
2020-04-16 20:12:02 +01:00
rollConfiguration = NamedManyToManyField("Roll Configurations", RollConfiguration)
modifiers = NamedManyToManyField("Modifiers", ModifierBase)
def modifier(self, keyword):
output = 0
2020-04-13 00:31:12 +01:00
for modifier in self.modifiers.all():
if keyword == modifier.keyword:
output += modifier.value
return output
2020-04-13 00:31:12 +01:00
#==============================================================================#
#----------------------------------- CHARMS -----------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class CharmBase(EffectBase):
2020-04-13 00:31:12 +01:00
levelEssence = NamedIntegerField("Essence Level")
charmType = SingleChoiceField("Charm Type", CHARM_TYPES)
duration = SingleChoiceField("Charm Duration", CHARM_DURATIONS)
keywords = MultiChoiceField("Charm Keywords", CHARM_KEYWORDS)
2020-04-16 20:12:02 +01:00
class CharmMartialArt(CharmBase):
2020-04-16 00:07:58 +01:00
def type(self):
return "Martial Art"
2020-04-13 00:31:12 +01:00
levelKey = NamedIntegerField("Martial Arts Level")
key = None
2020-04-16 20:12:02 +01:00
class CharmEvocation(CharmBase):
2020-04-16 00:07:58 +01:00
def type(self):
return "Evocation"
2020-04-13 00:31:12 +01:00
levelKey = 0
2020-04-16 20:12:02 +01:00
key = NamedForeignKeyField("Artifact", ItemBase)
2020-04-13 00:31:12 +01:00
2020-04-16 20:12:02 +01:00
class CharmSolar(CharmBase):
2020-04-16 00:07:58 +01:00
def type(self):
return "Solar"
2020-04-13 00:31:12 +01:00
levelKey = NamedIntegerField("Ability Level")
key = SingleChoiceField("Key Ability", ABILITIES)
2020-04-16 20:12:02 +01:00
class CharmLunar(CharmBase):
2020-04-16 00:07:58 +01:00
def type(self):
return "Lunar"
2020-04-13 00:31:12 +01:00
levelKey = NamedIntegerField("Attribute Level")
key = SingleChoiceField("Key Attribute", ATTRIBUTES)
2020-04-16 20:12:02 +01:00
class CharmLunarShape(CharmBase):
2020-04-13 00:31:12 +01:00
levelKey = 0
2020-04-16 00:07:58 +01:00
def type(self):
return "Lunar Shape"
2020-04-13 00:31:12 +01:00
key = None
2020-04-16 00:07:58 +01:00
size = SingleChoiceField("Size", SHAPE_SIZES)
shapeType = SingleChoiceField("Shape Type", SHAPE_TYPES)
#==============================================================================#
#----------------------------------- MERITS -----------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class Merit(EffectBase):
dots = DotField("Dots")
2020-04-16 00:07:58 +01:00
def dotsDisplay(self):
output = []
for i in range(self.dots):
output.append(True)
for i in range(5 - self.dots):
output.append(False)
return output
#==============================================================================#
#-------------------------------- SPECIALITIES --------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class Speciality(EffectBase):
2020-04-13 00:31:12 +01:00
pass
#==============================================================================#
#--------------------------------- INTIMACIES ---------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class IntimacyBase(PolymorphicModel):
def __str__(self):
return "[{}] {}".format(self.description, self.intensity)
description = DescriptionField()
intensity = SingleChoiceField("Intensity", INTENSITIES)
2020-04-16 20:12:02 +01:00
character = NamedForeignKeyField("Character", CharacterBase, related_name="intimacy_set")
2020-04-16 20:12:02 +01:00
class IntimacyTie(IntimacyBase):
target = NamedCharField("Target")
2020-04-16 20:12:02 +01:00
class IntimacyPrincipal(IntimacyBase):
pass
2020-04-13 00:31:12 +01:00
#==============================================================================#
#--------------------------------- OWNERSHIP ----------------------------------#
#==============================================================================#
2020-04-16 20:12:02 +01:00
class OwnershipBase(PolymorphicModel):
2020-04-13 00:31:12 +01:00
notes = models.TextField(verbose_name="Notes", blank=True)
active = NamedBooleanField("Active/Equipped?")
2020-04-16 20:12:02 +01:00
class OwnershipItem(OwnershipBase):
target = NamedForeignKeyField("Item", Item, related_name="ownershipItemTarget_set")
owner = NamedForeignKeyField("Owner", CharacterBase, related_name="ownershipItem_set")
class OwnershipItemWeapon(OwnershipBase):
target = NamedForeignKeyField("Weapon", ItemWeaponBase, related_name="ownershipItemWeaponTarget_set")
owner = NamedForeignKeyField("Owner", CharacterBase, related_name="ownershipItemWeapon_set")
class OwnershipItemArmor(OwnershipBase):
target = NamedForeignKeyField("Armor", ItemArmor, related_name="ownershipItemArmorTarget_set")
owner = NamedForeignKeyField("Owner", CharacterBase, related_name="ownershipItemArmor_set")
class OwnershipCharmMartialArt(OwnershipBase):
target = NamedForeignKeyField("Martial Arts Charm", CharmMartialArt, related_name="ownershipCharmMartialArtTarget_set")
owner = NamedForeignKeyField("Exalted Owner", CharacterExaltBase, related_name="ownershipCharmMartialArt_set")
class OwnershipCharmEvocation(OwnershipBase):
target = NamedForeignKeyField("Evocation", CharmEvocation, related_name="ownershipCharmEvocationTarget_set")
owner = NamedForeignKeyField("Exalted Owner", CharacterExaltBase, related_name="ownershipCharmEvocation_set")
class OwnershipCharmSolar(OwnershipBase):
target = NamedForeignKeyField("Solar Charm", CharmSolar, related_name="ownershipCharmSolarTarget_set")
owner = NamedForeignKeyField("Solar Exalted Owner", CharacterExaltSolar, related_name="ownershipCharmSolar_set")
class OwnershipCharmLunar(OwnershipBase):
target = NamedForeignKeyField("Lunar Charm", CharmLunar, related_name="ownershipCharmLunarTarget_set")
owner = NamedForeignKeyField("Lunar Exalted Owner", CharacterExaltLunar, related_name="ownershipCharmLunar_set")
class OwnershipCharmLunarShape(OwnershipBase):
target = NamedForeignKeyField("Lunar Shape", CharmLunarShape, related_name="ownershipCharmLunarShapeTarget_set")
owner = NamedForeignKeyField("Lunar Exalted Owner", CharacterExaltLunar, related_name="ownershipCharmLunarShape_set")
class OwnershipMerit(OwnershipBase):
target = NamedForeignKeyField("Merit", Merit, related_name="ownershipMeritTarget_set")
owner = NamedForeignKeyField("Owner", CharacterBase, related_name="ownershipMerit_set")
class OwnershipSpeciality(OwnershipBase):
target = NamedForeignKeyField("Speciality", Speciality, related_name="ownershipSpecialityTarget_set")
owner = NamedForeignKeyField("Owner", CharacterBase, related_name="ownershipSpeciality_set")