Skip to content

Commit

Permalink
Merge pull request #615 from open5e/staging
Browse files Browse the repository at this point in the history
1.9.0
  • Loading branch information
augustjohnson authored Dec 20, 2024
2 parents b1dc102 + 779d62e commit 667e94f
Show file tree
Hide file tree
Showing 16 changed files with 21,024 additions and 1,684 deletions.
10 changes: 9 additions & 1 deletion api_v2/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ class RaceAdmin(admin.ModelAdmin):
RaceTraitInline,
]

class ClassFeatureItemInline(admin.TabularInline):
model = ClassFeatureItem

class ClassFeatureAdmin(admin.ModelAdmin):
inlines = [
ClassFeatureItemInline
]


class BackgroundBenefitInline(admin.TabularInline):
model = BackgroundBenefit
Expand Down Expand Up @@ -93,7 +101,7 @@ class LanguageAdmin(admin.ModelAdmin):
admin.site.register(Condition)

admin.site.register(ClassFeatureItem)
admin.site.register(ClassFeature)
admin.site.register(ClassFeature, admin_class=ClassFeatureAdmin)
admin.site.register(CharacterClass)

admin.site.register(Environment)
Expand Down
18 changes: 18 additions & 0 deletions api_v2/migrations/0017_characterclass_saving_throws.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-11-25 19:36

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api_v2', '0016_alter_creaturetrait_parent'),
]

operations = [
migrations.AddField(
model_name='characterclass',
name='saving_throws',
field=models.ManyToManyField(help_text='Saving throw proficiencies for this class.', related_name='characterclass_saving_throws', to='api_v2.ability'),
),
]
18 changes: 18 additions & 0 deletions api_v2/migrations/0018_characterclass_caster_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2024-11-26 22:05

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api_v2', '0017_characterclass_saving_throws'),
]

operations = [
migrations.AddField(
model_name='characterclass',
name='caster_type',
field=models.CharField(blank=True, choices=[('FULL', 'Full'), ('HALF', 'Half'), ('NONE', 'None')], default=None, help_text='Type of caster. Options are full, half, none.', max_length=100, null=True),
),
]
19 changes: 19 additions & 0 deletions api_v2/migrations/0019_classfeatureitem_column.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.1.2 on 2024-12-01 15:06

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api_v2', '0018_characterclass_caster_type'),
]

operations = [
migrations.AddField(
model_name='classfeatureitem',
name='column',
field=models.BooleanField(default=False, help_text='Whether or not the field should be displayed as a column.'),
preserve_default=False,
),
]
22 changes: 22 additions & 0 deletions api_v2/migrations/0020_remove_classfeatureitem_column_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.1.2 on 2024-12-01 15:11

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api_v2', '0019_classfeatureitem_column'),
]

operations = [
migrations.RemoveField(
model_name='classfeatureitem',
name='column',
),
migrations.AddField(
model_name='classfeatureitem',
name='column_value',
field=models.CharField(blank=True, help_text='The value that should be displayed in the table column (where applicable).', max_length=20, null=True),
),
]
115 changes: 95 additions & 20 deletions api_v2/models/characterclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@

from .abstracts import HasName, HasDescription, Modification
from .abstracts import key_field
from .abilities import Ability
from .document import FromDocument
from .enums import DIE_TYPES
from .enums import DIE_TYPES, CASTER_TYPES
from drf_spectacular.utils import extend_schema_field, inline_serializer
from drf_spectacular.types import OpenApiTypes
from rest_framework import serializers



class ClassFeatureItem(models.Model):
"""This is the class for an individual class feature item, a subset of a class
feature. The name field is unused."""
feature."""

key = key_field()

Expand All @@ -23,6 +26,14 @@ class ClassFeatureItem(models.Model):
parent = models.ForeignKey('ClassFeature', on_delete=models.CASCADE)
level = models.IntegerField(validators=[MinValueValidator(0),MaxValueValidator(20)])

column_value = models.CharField(
# The value displayed in a column, or null if no value.
null=True,
blank=True,
max_length=20,
help_text='The value that should be displayed in the table column (where applicable).'
)

def __str__(self):
return "{} {} ({})".format(
self.parent.parent.name,
Expand All @@ -37,18 +48,25 @@ class ClassFeature(HasName, HasDescription, FromDocument):
parent = models.ForeignKey('CharacterClass',
on_delete=models.CASCADE)

def featureitems(self):
return self.classfeatureitem_set.exclude(column_value__isnull=False)

def columnitems(self):
return self.classfeatureitem_set.exclude(column_value__isnull=True)

def __str__(self):
return "{} ({})".format(self.name,self.parent.name)


class CharacterClass(HasName, FromDocument):
"""The model for a character class or subclass."""

subclass_of = models.ForeignKey('self',
default=None,
blank=True,
null=True,
on_delete=models.CASCADE)

hit_dice = models.CharField(
max_length=100,
default=None,
Expand All @@ -57,6 +75,18 @@ class CharacterClass(HasName, FromDocument):
choices=DIE_TYPES,
help_text='Dice notation hit dice option.')

saving_throws = models.ManyToManyField(Ability,
related_name="characterclass_saving_throws",
help_text='Saving throw proficiencies for this class.')

caster_type = models.CharField(
max_length=100,
default=None,
blank=True,
null=True,
choices=CASTER_TYPES,
help_text='Type of caster. Options are full, half, none.')

@property
@extend_schema_field(inline_serializer(
name="hit_points",
Expand Down Expand Up @@ -104,21 +134,68 @@ def features(self):
}
)
))
def levels(self):
"""Returns an array of level information for the given class."""
by_level = {}

for classfeature in self.classfeature_set.all():
for fl in classfeature.classfeatureitem_set.all():
if (str(fl.level)) not in by_level.keys():
by_level[str(fl.level)] = {}
by_level[str(fl.level)]['features'] = []

by_level[str(fl.level)]['features'].append(fl.parent.key)
by_level[str(fl.level)]['proficiency-bonus'] = self.proficiency_bonus(player_level=fl.level)
by_level[str(fl.level)]['level'] = fl.level

return by_level


def get_slots_by_player_level(self,level,caster_type):
# full is for a full caster, not including cantrips.
# full=False is for a half caster.
if level<0: # Invalid player level.
return None
if level>20: # Invalid player level.
return None

full = [[],
[0,2,0,0,0,0,0,0,0,0],
[0,3,0,0,0,0,0,0,0,0],
[0,4,2,0,0,0,0,0,0,0],
[0,4,3,0,0,0,0,0,0,0],
[0,4,3,2,0,0,0,0,0,0],
[0,4,3,3,0,0,0,0,0,0],
[0,4,3,3,1,0,0,0,0,0],
[0,4,3,3,2,0,0,0,0,0],
[0,4,3,3,3,1,0,0,0,0],
[0,4,3,3,3,2,0,0,0,0],
[0,4,3,3,3,2,1,0,0,0],
[0,4,3,3,3,2,1,0,0,0],
[0,4,3,3,3,2,1,1,0,0],
[0,4,3,3,3,2,1,1,0,0],
[0,4,3,3,3,2,1,1,1,0],
[0,4,3,3,3,2,1,1,1,0],
[0,4,3,3,3,2,1,1,1,1],
[0,4,3,3,3,3,1,1,1,1],
[0,4,3,3,3,3,2,1,1,1],
[0,4,3,3,3,3,2,2,1,1]
]

half = [[],
[0,0,0,0,0,0],
[0,2,0,0,0,0],
[0,3,0,0,0,0],
[0,3,0,0,0,0],
[0,4,2,0,0,0],
[0,4,2,0,0,0],
[0,4,3,0,0,0],
[0,4,3,0,0,0],
[0,4,3,2,0,0],
[0,4,3,2,0,0],
[0,4,3,3,0,0],
[0,4,3,3,0,0],
[0,4,3,3,1,0],
[0,4,3,3,1,0],
[0,4,3,3,2,0],
[0,4,3,3,2,0],
[0,4,3,3,3,1],
[0,4,3,3,3,1],
[0,4,3,3,3,2],
[0,4,3,3,3,2]
]

if caster_type=='FULL':
return full[level]
if caster_type=='HALF':
return half[level]
else:
return []

def proficiency_bonus(self, player_level):
# Consider as part of enums
Expand Down Expand Up @@ -146,5 +223,3 @@ def search_result_extra_fields(self):
"key": self.subclass_of.key
} if self.subclass_of else None
}

#TODO add verbose name plural
6 changes: 6 additions & 0 deletions api_v2/models/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
("WEAPON", "Weapon"),
]

CASTER_TYPES = [
("FULL","Full"),
("HALF","Half"),
("NONE","None")
]

ACTION_TYPES = [
("ACTION", "Action"),
("REACTION","Reaction"),
Expand Down
19 changes: 16 additions & 3 deletions api_v2/serializers/characterclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,36 @@
from .abstracts import GameContentSerializer
from .document import DocumentSerializer


class ClassFeatureItemSerializer(GameContentSerializer):

class Meta:
model = models.ClassFeatureItem
fields = ['name','desc','type']
fields = ['level']

class ClassFeatureColumnItemSerializer(GameContentSerializer):
class Meta:
model = models.ClassFeatureItem
fields = ['level','column_value']

class ClassFeatureSerializer(GameContentSerializer):
key = serializers.ReadOnlyField()
featureitems = ClassFeatureItemSerializer(
many=True
)

columnitems = ClassFeatureColumnItemSerializer(
many=True
)

class Meta:
model = models.ClassFeature
fields = ['key', 'name', 'desc']
fields = ['key', 'name', 'desc','featureitems','columnitems']

class CharacterClassSerializer(GameContentSerializer):
key = serializers.ReadOnlyField()
features = ClassFeatureSerializer(
many=True, context={'request': {}})
levels = serializers.ReadOnlyField()
hit_points = serializers.ReadOnlyField()
document = DocumentSerializer()

Expand Down
Loading

0 comments on commit 667e94f

Please sign in to comment.