Skip to content

Commit 2b29152

Browse files
Merge pull request #500 from open5e/499-v2-challenge-rating-missing-from-creatures
499 v2 challenge rating missing from creatures
2 parents 514d2ee + c737fb0 commit 2b29152

13 files changed

Lines changed: 5811 additions & 2 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 3.2.20 on 2024-08-04 13:31
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('api_v2', '0109_alter_creature_passive_perception'),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name='creature',
16+
name='challenge_rating_decimal',
17+
field=models.DecimalField(decimal_places=3, default=0, help_text='Challenge Rating field as a decimal number.', max_digits=10, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(30)]),
18+
preserve_default=False,
19+
),
20+
migrations.AddField(
21+
model_name='creature',
22+
name='experience_points_integer',
23+
field=models.IntegerField(help_text='Optional override for calculated XP based on CR.', null=True, validators=[django.core.validators.MinValueValidator(0)]),
24+
),
25+
]

api_v2/models/creature.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""The model for a creature."""
2+
from fractions import Fraction
23

34
from django.db import models
45
from django.core.validators import MaxValueValidator, MinValueValidator
@@ -57,6 +58,21 @@ class Creature(Object, Abilities, Senses, HasLanguage, HasSpeed, FromDocument):
5758
help_text="Conditions that this creature is immune to."
5859
)
5960

61+
challenge_rating_decimal = models.DecimalField(
62+
null=False,
63+
max_digits=10,
64+
decimal_places=3,
65+
validators=[MinValueValidator(0),MaxValueValidator(30)],
66+
help_text="Challenge Rating field as a decimal number."
67+
)
68+
69+
experience_points_integer = models.IntegerField(
70+
null=True,
71+
blank=True,
72+
validators=[MinValueValidator(0)],
73+
help_text="Optional override for calculated XP based on CR."
74+
)
75+
6076
def as_text(self):
6177
text = self.name + '\n'
6278
for action in self.creatureaction_set.all():
@@ -76,6 +92,58 @@ def creatureset(self):
7692
'''Helper method to rename and return creaturesets.'''
7793
return self.creaturesets.all()
7894

95+
@property
96+
def challenge_rating_text(self):
97+
'''Challenge rating as text string representation of a fraction or integer. '''
98+
return str(Fraction(self.challenge_rating_decimal))
99+
100+
@property
101+
def experience_points(self):
102+
if self.experience_points_integer is not None:
103+
return self.experience_points_integer
104+
else:
105+
xp_by_cr_lookup = {
106+
"0":0,
107+
"1/8":25,
108+
"1/4":50,
109+
"1/2":100,
110+
"1":200,
111+
"2":450,
112+
"3":700,
113+
"4":1100,
114+
"5":1800,
115+
"6":2300,
116+
"7":2900,
117+
"8":3900,
118+
"9":5000,
119+
"10":5900,
120+
"11":7200,
121+
"12":8400,
122+
"13":10000,
123+
"14":11500,
124+
"15":13000,
125+
"16":15000,
126+
"17":18000,
127+
"18":20000,
128+
"19":22000,
129+
"20":25000,
130+
"21":33000,
131+
"22":41000,
132+
"23":50000,
133+
"24":62000,
134+
"25":75000,
135+
"26":90000,
136+
"27":105000,
137+
"28":120000,
138+
"29":135000,
139+
"30":155000,
140+
}
141+
142+
try:
143+
return xp_by_cr_lookup[str(Fraction(self.challenge_rating_decimal))]
144+
except:
145+
return None
146+
79147

80148
class CreatureAction(HasName, HasDescription):
81149
"""Describes an action available to a creature."""

api_v2/serializers/creature.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ class CreatureSerializer(GameContentSerializer):
111111
size = SizeSerializer(read_only=True, context={'request': {}})
112112
speed = serializers.SerializerMethodField()
113113
all_speed = serializers.SerializerMethodField()
114+
challenge_rating_text = serializers.SerializerMethodField()
115+
experience_points = serializers.SerializerMethodField()
116+
114117

115118
class Meta:
116119
'''Serializer meta options.'''
@@ -130,6 +133,9 @@ class Meta:
130133
'armor_class',
131134
'hit_points',
132135
'hit_dice',
136+
'challenge_rating_decimal',
137+
'challenge_rating_text',
138+
'experience_points',
133139
'ability_scores',
134140
'modifiers',
135141
'saving_throws',
@@ -206,7 +212,6 @@ def get_speed(self, creature):
206212
entries = creature.get_speed().items()
207213
return { key: value for key, value in entries if value is not None }
208214

209-
210215
def get_all_speed(self, creature):
211216
'''Implicit speed helper method.'''
212217
return creature.get_all_speed()
@@ -219,6 +224,11 @@ def get_actions(self, creature):
219224
result.append(action_obj)
220225
return result
221226

227+
def get_challenge_rating_text(self, creature):
228+
return creature.challenge_rating_text
229+
230+
def get_experience_points(self, creature):
231+
return creature.experience_points
222232

223233
class CreatureTypeSerializer(GameContentSerializer):
224234
'''Serializer for the Creature Type object'''

api_v2/views/creature.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Meta:
1616
'name': ['iexact', 'exact'],
1717
'document__key': ['in','iexact','exact'],
1818
'size': ['exact'],
19+
'challenge_rating_decimal': ['exact','lt','lte','gt','gte'],
1920
'armor_class': ['exact','lt','lte','gt','gte'],
2021
'ability_score_strength': ['exact','lt','lte','gt','gte'],
2122
'ability_score_dexterity': ['exact','lt','lte','gt','gte'],
@@ -69,6 +70,7 @@ class CreatureTypeViewSet(viewsets.ReadOnlyModelViewSet):
6970
queryset = models.CreatureType.objects.all().order_by('pk')
7071
serializer_class = serializers.CreatureTypeSerializer
7172

73+
7274
class CreatureSetViewSet(viewsets.ReadOnlyModelViewSet):
7375
"""
7476
list: API endpoint for returning a list of creature sets, which is similar to tags.

0 commit comments

Comments
 (0)