charasheet/src/character/models/capabilities.py

153 lines
4.8 KiB
Python
Raw Normal View History

2022-10-31 22:32:14 +01:00
from __future__ import annotations
2022-10-29 00:32:18 +02:00
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django_extensions.db.models import TimeStampedModel
2022-10-30 09:44:28 +01:00
from common.models import DocumentedModel, UniquelyNamedModel
2022-10-29 00:32:18 +02:00
2022-10-30 09:44:28 +01:00
class Path(DocumentedModel, UniquelyNamedModel, TimeStampedModel, models.Model):
2022-10-29 00:32:18 +02:00
profile = models.ForeignKey(
"character.Profile",
on_delete=models.CASCADE,
related_name="paths",
blank=True,
null=True,
2022-10-30 11:09:46 +01:00
verbose_name="profil",
2022-10-29 00:32:18 +02:00
)
race = models.ForeignKey(
"character.Race",
on_delete=models.CASCADE,
related_name="paths",
blank=True,
null=True,
2022-10-30 11:09:46 +01:00
verbose_name="race",
2022-10-29 00:32:18 +02:00
)
class Category(models.TextChoices):
2022-10-30 11:09:46 +01:00
PROFILE = "profile", "Profil"
2022-10-29 00:32:18 +02:00
RACE = "race", "Race"
PRESTIGE = "prestige", "Prestige"
2022-10-30 11:09:46 +01:00
CREATURE = "creature", "Créature"
2022-10-29 00:32:18 +02:00
2022-10-30 11:09:46 +01:00
category = models.CharField(
max_length=20, choices=Category.choices, verbose_name="catégorie"
)
notes = models.TextField(blank=True, verbose_name="notes")
2022-11-02 23:10:48 +01:00
class Meta(UniquelyNamedModel.Meta, TimeStampedModel.Meta):
2022-10-30 11:09:46 +01:00
verbose_name = "Voie"
verbose_name_plural = "Voies"
2022-10-29 00:32:18 +02:00
2022-10-31 23:23:28 +01:00
def __str__(self):
name = f"{self.display_name}"
if self.related_to:
name += f" ({self.related_to.name})"
return name
2022-10-30 16:33:28 +01:00
@property
def display_name(self) -> str:
to_remove = ["voie de la", "voie de l'", "voie du", "voie des", "voie de"]
display_name = self.name.lower()
for text in to_remove:
display_name = display_name.replace(text, "")
return display_name.strip().capitalize()
@property
def related_to(self) -> UniquelyNamedModel | None:
category = Path.Category(self.category)
if category == Path.Category.PROFILE:
return self.profile
elif category == Path.Category.RACE:
return self.race
else:
return None
2022-10-31 22:32:14 +01:00
def get_next_capability(self, character) -> Capability:
2022-11-01 11:26:48 +01:00
next_rank = self.max_rank(character) + 1
2022-10-31 22:32:14 +01:00
return self.capabilities.get(rank=next_rank)
def has_next_capability(self, character) -> bool:
try:
self.get_next_capability(character)
return True
except Capability.DoesNotExist:
return False
2022-11-01 11:26:48 +01:00
def max_rank(self, character) -> int:
return character.capabilities.filter(path=self).count()
2022-10-29 00:32:18 +02:00
2022-11-01 09:13:34 +01:00
class CapabilityManager(models.Manager):
2022-11-01 09:57:21 +01:00
def get_by_natural_key(self, path, rank):
return self.get(path=path, rank=rank)
2022-11-01 09:13:34 +01:00
class Capability(DocumentedModel, TimeStampedModel, models.Model):
name = models.CharField(max_length=100, blank=False, null=False, verbose_name="nom")
2022-10-30 11:09:46 +01:00
path = models.ForeignKey(
2022-10-31 22:32:14 +01:00
"character.Path",
on_delete=models.CASCADE,
verbose_name="voie",
related_name="capabilities",
2022-10-30 11:09:46 +01:00
)
2022-10-29 00:32:18 +02:00
rank = models.PositiveSmallIntegerField(
2022-10-30 11:09:46 +01:00
validators=[MinValueValidator(1), MaxValueValidator(5)], verbose_name="rang"
2022-10-29 00:32:18 +02:00
)
2022-10-30 11:09:46 +01:00
limited = models.BooleanField(
blank=True, null=False, default=False, verbose_name="limitée"
)
spell = models.BooleanField(
blank=True, null=False, default=False, verbose_name="sort"
)
description = models.TextField(verbose_name="description")
2022-10-29 00:32:18 +02:00
2022-11-01 09:57:21 +01:00
objects = CapabilityManager()
2022-11-01 09:13:34 +01:00
2022-11-02 23:10:48 +01:00
class Meta(TimeStampedModel.Meta):
2022-10-29 00:32:18 +02:00
constraints = [models.UniqueConstraint("path", "rank", name="unique_path_rank")]
2022-10-30 11:09:46 +01:00
verbose_name = "Capacité"
verbose_name_plural = "Capacités"
2022-10-29 00:32:18 +02:00
def __str__(self):
2022-10-31 22:51:43 +01:00
description = f"{self.name} - {self.path.display_name} rang {self.rank}"
if self.path.related_to:
description += f" ({self.path.related_to.name})"
return description
2022-11-01 09:13:34 +01:00
def natural_key(self):
return (self.path_id, self.rank)
2022-11-10 22:44:53 +01:00
@property
def capability_points_cost(self) -> int:
if self.rank in [1, 2]:
return 1
return 2
2022-10-29 00:32:18 +02:00
2022-10-30 10:00:37 +01:00
class RacialCapabilityManager(models.Manager):
def get_by_natural_key(self, name: str, race_id: int):
return self.get(name=name, race_id=race_id)
class RacialCapability(DocumentedModel, TimeStampedModel, models.Model):
2022-10-30 11:09:46 +01:00
name = models.CharField(max_length=100, blank=False, null=False, verbose_name="nom")
race = models.ForeignKey(
"character.Race", on_delete=models.CASCADE, verbose_name="race"
)
description = models.TextField(verbose_name="description")
2022-10-29 00:32:18 +02:00
2022-10-30 10:00:37 +01:00
objects = RacialCapabilityManager()
2022-11-02 23:10:48 +01:00
class Meta(TimeStampedModel.Meta):
2022-10-30 11:09:46 +01:00
verbose_name = "Capacité raciale"
verbose_name_plural = "Capacités raciales"
2022-10-30 10:00:37 +01:00
constraints = [models.UniqueConstraint("name", "race", name="unique_name_race")]
def __str__(self):
return f"{self.name} ({self.race})"
def natural_key(self):
return (self.name, self.race_id)