This commit is contained in:
Ross
2025-12-05 10:46:16 +00:00
parent be1fea5fd4
commit bf9e90d754
13 changed files with 401 additions and 27 deletions
+137 -5
View File
@@ -19,12 +19,24 @@ class Dinosaur(models.Model):
diet = models.CharField(max_length=32, choices=DIET_CHOICES, default='herbivore')
description = models.TextField(blank=True)
image = models.ImageField(upload_to='dinosaurs/', blank=True, null=True)
background = models.ForeignKey(
'cards.BackgroundImage',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='dinosaurs',
help_text='Optional per-card background image'
)
# Top-trump style stats (0-100)
speed = models.PositiveSmallIntegerField(default=50)
weight = models.PositiveSmallIntegerField(default=50)
intelligence = models.PositiveSmallIntegerField(default=50)
height = models.PositiveSmallIntegerField(default=50)
# Stats stored in real-world units now:
# - `speed` in km/h
# - `weight` in kg
# - `height` in metres
# - `intelligence` remains a 0-100 score
speed = models.PositiveIntegerField(default=30, help_text='Speed in km/h')
weight = models.PositiveIntegerField(default=1000, help_text='Weight in kg')
intelligence = models.PositiveSmallIntegerField(default=50, help_text='Score 0-100')
height = models.DecimalField(max_digits=5, decimal_places=1, default=1.5, help_text='Height in metres')
facts = models.TextField(blank=True, help_text='One fact per line; shown as bullet points on the card')
created_at = models.DateTimeField(auto_now_add=True)
@@ -42,6 +54,126 @@ class Dinosaur(models.Model):
return []
return [f.strip() for f in self.facts.splitlines() if f.strip()]
# -- Unit helpers / display properties -------------------------------------------------
# These map the 0-100 top-trump style values to human-friendly units. The numeric
# mappings are conservative defaults and can be adjusted if you want different ranges.
# Ranges used to convert between stored unit values and the 0-100 bar/star scale.
SPEED_MAX_KMH = 60.0
WEIGHT_MAX_KG = 15000.0
HEIGHT_MAX_M = 12.0
# Display helpers (use stored unit values directly)
@property
def speed_display(self):
return f"{self.speed} km/h"
@property
def weight_display(self):
kg = int(self.weight)
if kg >= 1000:
tonnes = round(kg / 1000.0, 1)
return f"{tonnes} t"
return f"{kg} kg"
@property
def height_display(self):
# height is a DecimalField; format to one decimal place
return f"{float(self.height):.1f} m"
@property
def intelligence_display(self):
return f"{self.intelligence}%"
# Percent helpers: convert stored units back to a 0-100 scale for bars/stars
def speed_percent(self):
return min(100, int(round(self.speed / float(self.SPEED_MAX_KMH) * 100)))
def weight_percent(self):
return min(100, int(round(self.weight / float(self.WEIGHT_MAX_KG) * 100)))
def height_percent(self):
return min(100, int(round(float(self.height) / float(self.HEIGHT_MAX_M) * 100)))
def intelligence_percent(self):
return min(100, int(self.intelligence or 0))
# -- Star rating helpers -------------------------------------------------------------
def _star_rating_from_percent(self, percent):
"""Convert a 0-100 percent into a 0-5 star score in 0.5 increments."""
if percent is None:
return 0.0
val = float(percent) * 0.05 # scale 0-100 -> 0-5
# round to nearest 0.5
return round(val * 2) / 2.0
def _stars_string(self, percent):
"""Return a simple star string like '★★★★½' and trailing empty stars ''."""
stars = self._star_rating_from_percent(percent)
full = int(stars)
half = 1 if (stars - full) >= 0.5 else 0
empty = 5 - full - half
return "" * full + ("½" if half else "") + "" * empty
def _star_types_from_percent(self, percent):
"""Return a list of five items: 'full', 'half', or 'empty'."""
stars = self._star_rating_from_percent(percent)
full = int(stars)
half = 1 if (stars - full) >= 0.5 else 0
types = ['full'] * full
if half:
types.append('half')
types.extend(['empty'] * (5 - len(types)))
return types
# Expose star strings and original values for templates
@property
def speed_stars(self):
return self._stars_string(self.speed_percent())
@property
def speed_star_types(self):
return self._star_types_from_percent(self.speed_percent())
@property
def speed_orig(self):
return self.speed
@property
def weight_stars(self):
return self._stars_string(self.weight_percent())
@property
def weight_star_types(self):
return self._star_types_from_percent(self.weight_percent())
@property
def weight_orig(self):
return self.weight
@property
def height_stars(self):
return self._stars_string(self.height_percent())
@property
def height_star_types(self):
return self._star_types_from_percent(self.height_percent())
@property
def height_orig(self):
return self.height
@property
def intelligence_stars(self):
return self._stars_string(self.intelligence_percent())
@property
def intelligence_star_types(self):
return self._star_types_from_percent(self.intelligence_percent())
@property
def intelligence_orig(self):
return self.intelligence
class BackgroundImage(models.Model):
"""Background images used behind card renders.