Earthman deck: new TarotCard fields + full 49-card major arcana reseed
All checks were successful
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline was successful

- TarotCard: add reversal, levity/gravity_qualifier, levity/gravity_emanation, levity/gravity_reversal, mechanisms, articulations; emanation_for(polarity) + reversal_for(polarity) methods
- 0035: schema migration for new fields
- 0036: reseed major arcana — 52 cards → 50 (Nomad untouched); delete Wheel of Fortune/Junkboat/Great Hunt; insert Asteroid Belt; rename/renumber all into Pope/Horseman, Elements, Realms, Virtues, Zodiac, Lunars, Planets, Inner Rings; levity/gravity qualifiers throughout; cards 48-49 polarity-split levity/gravity emanation + reversal
- 0037: Polestar qualifiers → Precessional / Recessional
- 0038: correspondences → Fiorentine card names (Magician–Hierophant for 1-5; sign names for zodiac 22-33)
- 0039: reversals — Pope/Horseman 1-5 → Territoriality/Despotism/Capitalism/Fascism; Zodiac 22-33 → House of Self … House of Reprisal
- 0040: trump 21 → Intent (was Jovent)

⚠ pending: cards 1-2 reversal both 'Territoriality' — confirm if distinct; Implicit/Explicit Virtue qualifiers blank

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-04-27 01:51:40 -04:00
parent ad7a354f8c
commit c3f0342a2d
7 changed files with 561 additions and 2 deletions

View File

@@ -242,10 +242,19 @@ class TarotCard(models.Model):
arcana = models.CharField(max_length=6, choices=ARCANA_CHOICES)
suit = models.CharField(max_length=10, choices=SUIT_CHOICES, null=True, blank=True)
icon = models.CharField(max_length=50, blank=True, default='') # FA icon override (e.g. major arcana)
number = models.IntegerField() # 021 major (Fiorentine); 051 major (Earthman); 114 minor
number = models.IntegerField() # 021 major (Fiorentine); 049 major (Earthman); 114 minor
slug = models.SlugField(max_length=120)
correspondence = models.CharField(max_length=200, blank=True) # standard / Italian equivalent
correspondence = models.CharField(max_length=200, blank=True) # Tarot / Minchiate equivalent
group = models.CharField(max_length=100, blank=True) # Earthman major grouping
reversal = models.CharField(max_length=200, blank=True, default='') # reversed-state title; blank = same as name
levity_qualifier = models.CharField(max_length=100, blank=True, default='')
gravity_qualifier = models.CharField(max_length=100, blank=True, default='')
levity_emanation = models.CharField(max_length=200, blank=True, default='') # polarity-split upright (cards 48-49)
gravity_emanation = models.CharField(max_length=200, blank=True, default='')
levity_reversal = models.CharField(max_length=200, blank=True, default='') # polarity-split reversal (card 48)
gravity_reversal = models.CharField(max_length=200, blank=True, default='')
mechanisms = models.JSONField(default=list) # list of dicts; in-game effects
articulations = models.JSONField(default=list) # list of dicts; combinatory effects
keywords_upright = models.JSONField(default=list)
keywords_reversed = models.JSONField(default=list)
cautions = models.JSONField(default=list)
@@ -274,6 +283,24 @@ class TarotCard(models.Model):
court = {11: 'M', 12: 'J', 13: 'Q', 14: 'K'}
return court.get(self.number, str(self.number))
def emanation_for(self, polarity):
"""Return the upright title for a given polarity ('levity' or 'gravity').
Falls back to name for cards without a polarity split."""
if polarity == 'levity' and self.levity_emanation:
return self.levity_emanation
if polarity == 'gravity' and self.gravity_emanation:
return self.gravity_emanation
return self.name
def reversal_for(self, polarity):
"""Return the reversed title for a given polarity.
Falls back to reversal (blank = same as emanation_for)."""
if polarity == 'levity' and self.levity_reversal:
return self.levity_reversal
if polarity == 'gravity' and self.gravity_reversal:
return self.gravity_reversal
return self.reversal or self.emanation_for(polarity)
@property
def name_group(self):
"""Returns 'Group N:' prefix if the name contains ': ', else ''."""