33from django .db import models
44from django .core .validators import MinValueValidator
55
6- from .abstracts import HasName
6+ from .abstracts import HasName , HasDescription
77from .abstracts import distance_field , distance_unit_field
88from .document import FromDocument
99from drf_spectacular .utils import extend_schema_field
1010from drf_spectacular .types import OpenApiTypes
1111from rest_framework import serializers
1212
13+ class WeaponProperty (HasName , HasDescription , FromDocument ):
14+ class Meta :
15+ verbose_name_plural = "Weapon Properties"
16+ ordering = ["pk" ]
17+
18+ def __str__ (self ):
19+ return self .name
20+
21+
22+ class WeaponPropertyAssignment (FromDocument ):
23+ """
24+ This is an intermediate model that is used to assign WeaponProperties to
25+ Weapons while bundling in any extra contextual data in the `detail` field
26+ """
27+ weapon = models .ForeignKey (
28+ 'Weapon' ,
29+ related_name = 'properties' ,
30+ on_delete = models .CASCADE
31+ )
32+ property = models .ForeignKey (
33+ 'WeaponProperty' ,
34+ related_name = 'weapons' ,
35+ on_delete = models .CASCADE ,
36+ )
37+ detail = models .CharField (null = True , blank = True , max_length = 32 )
38+
1339class Weapon (HasName , FromDocument ):
1440 """
1541 This model represents types of weapons.
@@ -31,21 +57,12 @@ class Weapon(HasName, FromDocument):
3157 max_length = 100 ,
3258 help_text = 'The damage dice when used making an attack.' )
3359
34- versatile_dice = models .CharField (
35- null = False ,
36- default = 0 ,
37- max_length = 100 ,
38- help_text = """The damage dice when attacking using versatile.
39- A value of 0 means that the weapon does not have the versatile property.""" )
40-
41- reach = distance_field ()
42-
4360 range = distance_field ()
4461
4562 long_range = distance_field ()
4663
4764 distance_unit = distance_unit_field ()
48-
65+
4966 @property
5067 # or none
5168 @extend_schema_field (OpenApiTypes .STR )
@@ -54,52 +71,6 @@ def get_distance_unit(self):
5471 return self .document .distance_unit
5572 return self .distance_unit
5673
57-
58- is_finesse = models .BooleanField (
59- null = False ,
60- default = False ,
61- help_text = 'If the weapon is finesse.' )
62-
63- is_thrown = models .BooleanField (
64- null = False ,
65- default = False ,
66- help_text = 'If the weapon is thrown.' )
67-
68- is_two_handed = models .BooleanField (
69- null = False ,
70- default = False ,
71- help_text = 'If the weapon is two-handed.' )
72-
73- requires_ammunition = models .BooleanField (
74- null = False ,
75- default = False ,
76- help_text = 'If the weapon requires ammunition.' )
77-
78- requires_loading = models .BooleanField (
79- null = False ,
80- default = False ,
81- help_text = 'If the weapon requires loading.' )
82-
83- is_heavy = models .BooleanField (
84- null = False ,
85- default = False ,
86- help_text = 'If the weapon is heavy.' )
87-
88- is_light = models .BooleanField (
89- null = False ,
90- default = False ,
91- help_text = 'If the weapon is light.' )
92-
93- is_lance = models .BooleanField (
94- null = False ,
95- default = False ,
96- help_text = 'If the weapon is a lance.' )
97-
98- is_net = models .BooleanField (
99- null = False ,
100- default = False ,
101- help_text = 'If the weapon is a net.' )
102-
10374 is_simple = models .BooleanField (
10475 null = False ,
10576 default = False ,
@@ -109,71 +80,8 @@ def get_distance_unit(self):
10980 null = False ,
11081 default = False ,
11182 help_text = 'If the weapon is improvised.' )
112-
113- @property
114- @extend_schema_field (OpenApiTypes .BOOL )
115- def is_versatile (self ):
116- return self .versatile_dice != str (0 )
11783
11884 @property
11985 @extend_schema_field (OpenApiTypes .BOOL )
12086 def is_martial (self ):
121- return not self .is_simple
122-
123- @property
124- @extend_schema_field (OpenApiTypes .BOOL )
125- def is_melee (self ):
126- # Ammunition weapons can only be used as improvised melee weapons.
127- return not self .requires_ammunition
128-
129- @property
130- @extend_schema_field (OpenApiTypes .BOOL )
131- def ranged_attack_possible (self ):
132- # Only ammunition or throw weapons can make ranged attacks.
133- return self .requires_ammunition or self .is_thrown
134-
135- @property
136- # type is any
137- @extend_schema_field (OpenApiTypes .BOOL )
138- def range_melee (self ):
139- return self .reach
140-
141- @property
142- @extend_schema_field (OpenApiTypes .BOOL )
143- def is_reach (self ):
144- # A weapon with a longer reach than the default has the reach property.
145- return self .reach > 5
146-
147- @property
148- @extend_schema_field (serializers .ChoiceField (choices = ['special' , 'finesse' , 'ammunition' , 'light' , 'heavy' , 'thrown' , 'loading' , 'two-handed' , 'versatile' , 'reach' ]))
149- def properties (self ):
150- properties = []
151-
152- range_desc = "(range {}/{})" .format (
153- str (self .range ),
154- str (self .long_range ))
155-
156- versatile_desc = "({})" .format (self .versatile_dice )
157-
158- if self .is_net or self .is_lance :
159- properties .append ("special" )
160- if self .is_finesse :
161- properties .append ("finesse" )
162- if self .requires_ammunition :
163- properties .append ("ammuntion {}" .format (range_desc ))
164- if self .is_light :
165- properties .append ("light" )
166- if self .is_heavy :
167- properties .append ("heavy" )
168- if self .is_thrown :
169- properties .append ("thrown {}" .format (range_desc ))
170- if self .requires_loading :
171- properties .append ("loading" )
172- if self .is_two_handed :
173- properties .append ("two-handed" )
174- if self .is_versatile :
175- properties .append ("versatile {}" .format (versatile_desc ))
176- if self .is_reach :
177- properties .append ("reach" )
178-
179- return properties
87+ return not self .is_simple
0 commit comments