Initial pass at Golden Pack.

This commit is contained in:
Greyson Parrelli
2026-07-24 07:47:05 -04:00
parent e74f983470
commit dd395f4bbf
27 changed files with 2770 additions and 150 deletions
+395 -7
View File
@@ -29,6 +29,14 @@ const (
FoodPineapple = "pineapple"
FoodChili = "chili"
FoodMelon = "melon"
// FoodAvocado (Golden pack) is a persistent set-aside token: buying it puts
// it aside rather than in the deck, and it can later be discarded in place
// of spending a coin on a buy. It is neither a perk nor a battle food.
FoodAvocado = "avocado"
// FoodPotato / FoodDurian / FoodTomato (Golden pack) are perk foods.
FoodPotato = "potato"
FoodDurian = "durian"
FoodTomato = "tomato"
)
// EffectTrigger is when an effect fires.
@@ -51,6 +59,13 @@ const (
// TriggerPassive marks always-on effects (e.g. Garlic's damage
// prevention); they're consulted contextually rather than fired.
TriggerPassive EffectTrigger = "passive"
// TriggerAfterAttack fires on a pet right after it survives a clash it
// took part in (Golden pack: Bulldog). Effects here may be marked once
// per battle via the unit's after-attack flag.
TriggerAfterAttack EffectTrigger = "afterAttack"
// TriggerShopStart fires on a pet in the deck at the moment a shop round
// opens (Golden pack: Manta Ray).
TriggerShopStart EffectTrigger = "shopStart"
)
// EffectAction is what the effect does.
@@ -124,6 +139,77 @@ const (
// ActionPetAura (faint) sets the pet aside: the owner's pets have
// +Count power for the rest of the battle (Mammoth).
ActionPetAura EffectAction = "petAura"
// --- Golden pack ---
// ActionGainTrumpet adds Count Trumpets to the acting side's battle pool
// (Groundhog, Black-Necked Stilt, Guinea Fowl, Osprey, Honduran White
// Bat). With Per set, Count is multiplied by a battle statistic.
ActionGainTrumpet EffectAction = "gainTrumpet"
// ActionDrainTrumpet removes up to Count Trumpets from the enemy side's
// pool (Flea).
ActionDrainTrumpet EffectAction = "drainTrumpet"
// ActionPreventNextHit (faint) sets the pet aside: the next time a friendly
// pet is hit, prevent Count damage from that hit (Cone Snail). Unlike
// ActionShieldNext (Turtle), it reduces rather than fully blocks.
ActionPreventNextHit EffectAction = "preventNextHit"
// ActionSummonBottom puts Count cards (Effect.Card) on the BOTTOM of a
// deck. With Target "all" it hits every player's deck (Bear).
ActionSummonBottom EffectAction = "summonBottom"
// ActionBuyTopFree (sell) takes the top card of the current tier's shop
// deck into the player's deck for free, firing its Buy effect (Stoat).
ActionBuyTopFree EffectAction = "buyTopFree"
// ActionSetAside (buy) diverts the just-bought card out of the deck into a
// persistent set-aside zone (Avocado). Shop-time.
ActionSetAside EffectAction = "setAside"
// --- Golden pack, tiers 4-5 ---
// ActionDoubleTrumpets (play) grants the side extra Trumpets equal to what
// it holds, up to Cap (Vaquita).
ActionDoubleTrumpets EffectAction = "doubleTrumpets"
// ActionBeeRocks (faint) sets the pet aside: each time its owner plays a
// Bee, throw Count rocks at the enemy (Poison Dart Frog).
ActionBeeRocks EffectAction = "beeRocks"
// ActionFeedOnPlay (faint) sets the pet aside: each time its owner plays a
// pet, spend 1 Trumpet to feed that pet Count apples — mandatory when
// affordable (Giant Isopod).
ActionFeedOnPlay EffectAction = "feedOnPlay"
// ActionStealPerk (play) takes the enemy pet's active perk and puts it on
// top of this pet's owner's deck (Raccoon).
ActionStealPerk EffectAction = "stealPerk"
// ActionRecyclePerkApples (faint) puts this pet's active perk and up to
// Count of its apples on top of the owner's deck (Macaque).
ActionRecyclePerkApples EffectAction = "recyclePerkApples"
// ActionPreventSelf (play) gives the pet Cap one-shot charges that each
// prevent Count damage from a hit (Potato perk).
ActionPreventSelf EffectAction = "preventSelf"
// ActionStripApples (play) discards every apple attached to the enemy pet
// in play (Durian perk) — like ActionStripFoods but apples only.
ActionStripApples EffectAction = "stripApples"
// ActionSpendRocks (play) asks the owner how many Trumpets to spend (0..Count)
// and throws twice that many rocks at the enemy (Nurse Shark). This is the
// one battle-time player decision.
ActionSpendRocks EffectAction = "spendRocks"
// ActionFirstBuyFree (shop start) makes the player's first Buy this round
// cost no gold, if they hold Count or fewer pets (Manta Ray).
ActionFirstBuyFree EffectAction = "firstBuyFree"
// ActionRevealForApples (buy) asks the player to reveal another pet in hand;
// they gain apples equal to its power (Cockatoo). Shop-time decision.
ActionRevealForApples EffectAction = "revealForApples"
// --- Golden pack, tier 6 ---
// ActionShuffleApples (play) shuffles Count apples into random positions of
// the owner's remaining deck (Komodo). Gated by ConditionFirstPet.
ActionShuffleApples EffectAction = "shuffleApples"
// ActionReactivateBuys (battle prep) re-fires the Buy ability of every pet
// in the owner's hand (Catfish).
ActionReactivateBuys EffectAction = "reactivateBuys"
// ActionStartTrumpets (buy) banks Count Trumpets to start the next battle
// with (Bird of Paradise).
ActionStartTrumpets EffectAction = "startTrumpets"
// ActionGuardRetriever (faint) sets the pet aside: the owner's Golden
// Retriever, when summoned, prevents Count damage on its first hit (German
// Shepherd).
ActionGuardRetriever EffectAction = "guardRetriever"
)
// Per multipliers for dynamic effect counts.
@@ -132,12 +218,25 @@ const (
PerFaintedPets = "faintedPets" // × friendly pets fainted this battle
PerEatenApples = "eatenApples" // × apples this pet ate (its attached apples)
PerPower = "power" // × this pet's current power
// PerUniqueFaintedHats × distinct suits ("hats") among friendly fainted
// pets this battle (Honduran White Bat). Battle-time.
PerUniqueFaintedHats = "uniqueFaintedHats"
// PerEnemyFaintedPets × pets the ENEMY side has fainted this battle (Royal
// Flycatcher). Battle-time.
PerEnemyFaintedPets = "enemyFaintedPets"
// PerShopFaintPets × pets currently in the shop row with a Faint effect
// (Opossum). Shop-time.
PerShopFaintPets = "shopFaintPets"
// PerBuysThisRound × Buy actions the player has taken this round, including
// the current one (Blue-Ringed Octopus). Shop-time.
PerBuysThisRound = "buysThisRound"
)
// Effect conditions.
const (
ConditionTripled = "tripledThisRound" // player Tripled during this round's shop
ConditionHasPerk = "hasPerk" // this pet has a perk attached
ConditionTripled = "tripledThisRound" // player Tripled during this round's shop
ConditionHasPerk = "hasPerk" // this pet has a perk attached
ConditionFirstPet = "firstPet" // this is the first pet the side has played (Komodo)
)
// Effect is one trigger→action pair printed on a card.
@@ -155,6 +254,10 @@ type Effect struct {
Condition string `json:"condition,omitempty"`
// MinRound gates the effect to round >= MinRound (0 = always).
MinRound int `json:"minRound,omitempty"`
// CostTrumpet, when > 0, is a Trumpet cost the acting side must pay for the
// effect to fire (Golden pack). It's auto-paid when affordable and the
// effect is skipped otherwise — battles take no player input.
CostTrumpet int `json:"costTrumpet,omitempty"`
}
// count normalizes the zero value to 1.
@@ -476,6 +579,272 @@ var foodTiers = [MaxRounds][]foodTemplate{
},
}
// goldenPetTiers defines the Golden pack's pets — all six tiers. Each pet ships
// as two copies (one per listed suit).
var goldenPetTiers = [MaxRounds][]petTemplate{
{ // Tier 1
{
Name: "Groundhog", Power: 1, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionGainTrumpet}},
EffectText: "Faint: gain 1 Trumpet",
},
{
Name: "Pied Tamarin", Power: 2, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock, Count: 2, CostTrumpet: 1}},
EffectText: "Play: spend 1 Trumpet to throw 2 Rocks",
},
{
Name: "Chipmunk", Power: 1, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{{Trigger: TriggerSell, Action: ActionGainApple, Count: 2}},
EffectText: "Sell: add 2 extra Apples to your hand",
},
{
Name: "Cone Snail", Power: 1, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionPreventNextHit, Count: 2}},
EffectText: "Faint: set aside — the next time a friendly pet is hit, prevent 2 damage",
},
{
Name: "Bulldog", Power: 2, Suits: []Suit{SuitRed, SuitYellow},
Effects: []Effect{{Trigger: TriggerAfterAttack, Action: ActionEatApple}},
EffectText: "After Attacking: if it hasn't fainted, eat 1 Apple (once per round)",
},
{
Name: "Opossum", Power: 2, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{{Trigger: TriggerSell, Action: ActionGainApple, Per: PerShopFaintPets}},
EffectText: "Sell: add 1 extra Apple to your hand for each Faint pet in the shop",
},
},
{ // Tier 2
{
Name: "Black-Necked Stilt", Power: 2, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionGainTrumpet}},
EffectText: "Faint: gain 1 Trumpet",
},
{
Name: "Lizard", Power: 2, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerHurt, Action: ActionSummonTop, Card: "bee"}},
EffectText: "Hurt: add a Bee on top of your deck",
},
{
Name: "Hercules Beetle", Power: 1, Suits: []Suit{SuitBlue, SuitRed},
Effects: []Effect{{Trigger: TriggerSell, Action: ActionApplesInPlay, Count: 3, MinRound: 3}},
EffectText: "Sell: if it is round 3 or later, start the battle with 3 Apples in play",
},
{
Name: "Stoat", Power: 2, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerSell, Action: ActionBuyTopFree}},
EffectText: "Sell: buy the top card of the shop deck for free",
},
{
Name: "Desert Rain Frog", Power: 2, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee", Count: 2, CostTrumpet: 1}},
EffectText: "Faint: spend 1 Trumpet to add 2 Bees on top of your deck",
},
{
Name: "Honduran White Bat", Power: 2, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionGainTrumpet, Per: PerUniqueFaintedHats}},
EffectText: "Play: gain 1 Trumpet for each unique suit among friendly fainted pets",
},
},
{ // Tier 3
{
Name: "Guinea Fowl", Power: 3, Suits: []Suit{SuitRed, SuitYellow},
Effects: []Effect{{Trigger: TriggerHurt, Action: ActionGainTrumpet}},
EffectText: "Hurt: gain 1 Trumpet",
},
{
Name: "Surgeon Fish", Power: 3, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionSummonTop, Card: "apple", Count: 3, CostTrumpet: 1}},
EffectText: "Play: spend 1 Trumpet to add 3 Apples on top of your deck",
},
{
Name: "Osprey", Power: 3, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{
{Trigger: TriggerFaint, Action: ActionGainTrumpet},
{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee"},
},
EffectText: "Faint: gain 1 Trumpet and add a Bee on top of your deck",
},
{
Name: "Anteater", Power: 3, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{
{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "apple"},
{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee"},
},
EffectText: "Faint: add an Apple, then a Bee, on top of your deck",
},
{
Name: "Bear", Power: 4, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonBottom, Card: "bee", Target: "all"}},
EffectText: "Faint: add a Bee to the bottom of every player's deck",
},
{
Name: "Royal Flycatcher", Power: 1, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock, Per: PerEnemyFaintedPets}},
EffectText: "Play: throw a Rock for each enemy fainted pet",
},
{
Name: "Flea", Power: 2, Suits: []Suit{SuitBlue, SuitRed},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionDrainTrumpet, Count: 3}},
EffectText: "Faint: your opponent loses 3 Trumpets",
},
},
{ // Tier 4
{
Name: "Saiga Antelope", Power: 1, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionGainTrumpet, Per: PerFaintedPets}},
EffectText: "Play: gain 1 Trumpet for each friendly fainted pet",
},
{
Name: "Vaquita", Power: 2, Suits: []Suit{SuitBlue, SuitRed},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionDoubleTrumpets, Cap: 4}},
EffectText: "Play: double your Trumpets (up to 4 gained)",
},
{
Name: "Poison Dart Frog", Power: 2, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionBeeRocks, Count: 2}},
EffectText: "Faint: set aside — each time you play a Bee, throw 2 Rocks",
},
{
Name: "Manta Ray", Power: 4, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{{Trigger: TriggerShopStart, Action: ActionFirstBuyFree, Count: 4}},
EffectText: "Shop start: if you have 4 or fewer pets, your first Buy is free",
},
{
Name: "Slug", Power: 3, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{
{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee", Count: 2},
{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "apple"},
},
EffectText: "Faint: add 2 Bees, then an Apple, on top of your deck",
},
{
Name: "Cockatoo", Power: 2, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerBuy, Action: ActionRevealForApples}},
EffectText: "Buy: reveal another pet in your hand — gain Apples equal to its Power",
},
{
Name: "Manatee", Power: 3, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{
{Trigger: TriggerPlay, Action: ActionThrowRock, Count: 2, Target: "self"},
{Trigger: TriggerPlay, Action: ActionSummonTop, Card: "apple", Count: 4},
},
EffectText: "Play: throw 2 Rocks at itself, then add 4 Apples on top of your deck",
},
},
{ // Tier 5
{
Name: "Nyala", Power: 4, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionGainTrumpet, Count: 2}},
EffectText: "Faint: gain 2 Trumpets",
},
{
Name: "Nurse Shark", Power: 3, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionSpendRocks, Count: 3}},
EffectText: "Play: spend up to 3 Trumpets to throw twice as many Rocks",
},
{
Name: "Giant Isopod", Power: 4, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionFeedOnPlay, Count: 2}},
EffectText: "Faint: set aside — each time you play a pet, spend 1 Trumpet to feed it 2 Apples",
},
{
Name: "Blue-Ringed Octopus", Power: 4, Suits: []Suit{SuitBlue, SuitRed},
Effects: []Effect{{Trigger: TriggerBuy, Action: ActionGainApple, Per: PerBuysThisRound}},
EffectText: "Buy: add an Apple to your hand for each Buy you've made this round",
},
{
Name: "Raccoon", Power: 3, Suits: []Suit{SuitBlue, SuitYellow},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionStealPerk}},
EffectText: "Play: steal the enemy pet's Perk onto the top of your deck",
},
{
Name: "Fire Ant", Power: 2, Suits: []Suit{SuitRed, SuitYellow},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "apple", Count: 4}},
EffectText: "Faint: add 4 Apples on top of your deck",
},
{
Name: "Macaque", Power: 2, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionRecyclePerkApples, Count: 4}},
EffectText: "Faint: put this pet's Perk and up to 4 of its Apples on top of your deck",
},
},
{ // Tier 6
{
Name: "Highland Cow", Power: 3, Suits: []Suit{SuitBlue, SuitRed},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionGainTrumpet, Per: PerPower}},
EffectText: "Play: gain Trumpets equal to this pet's Power",
},
{
Name: "Wildebeest", Power: 6, Suits: []Suit{SuitYellow, SuitBlue},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionShieldSelf, CostTrumpet: 3}},
EffectText: "Play: spend 3 Trumpets to prevent all damage the first time it is hit",
},
{
Name: "Grizzly Bear", Power: 5, Suits: []Suit{SuitYellow, SuitRed},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock, Per: PerFaintedPets}},
EffectText: "Play: throw a Rock for each friendly fainted pet",
},
{
Name: "Catfish", Power: 5, Suits: []Suit{SuitBlue, SuitRed},
Effects: []Effect{{Trigger: TriggerBattlePrep, Action: ActionReactivateBuys}},
EffectText: "Battle Prep: reactivate every Buy ability on the pets in your hand",
},
{
Name: "Komodo", Power: 6, Suits: []Suit{SuitYellow, SuitBlue},
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionShuffleApples, Count: 6, Condition: ConditionFirstPet}},
EffectText: "Play: if this is your first pet, shuffle 6 Apples into your deck",
},
{
Name: "Bird of Paradise", Power: 4, Suits: []Suit{SuitRed, SuitYellow},
Effects: []Effect{
{Trigger: TriggerBuy, Action: ActionApplesInPlay, Count: 2},
{Trigger: TriggerBuy, Action: ActionStartTrumpets, Count: 2},
},
EffectText: "Buy: start the next battle with 2 Apples and 2 Trumpets in play",
},
{
Name: "German Shepherd", Power: 5, Suits: []Suit{SuitRed, SuitBlue},
Effects: []Effect{{Trigger: TriggerFaint, Action: ActionGuardRetriever, Count: 5}},
EffectText: "Faint: set aside — your Golden Retriever prevents 5 damage the first time it is hit",
},
},
}
// goldenFoodTiers defines the Golden pack's food cards. Only Avocado (tier 3)
// exists so far.
var goldenFoodTiers = [MaxRounds][]foodTemplate{
{}, {}, // Tiers 1-2
{ // Tier 3
{
Name: "Avocado", Food: FoodAvocado, Copies: 2,
Effects: []Effect{{Trigger: TriggerBuy, Action: ActionSetAside}},
EffectText: "Buy: set aside — later discard it instead of a coin to buy a card",
},
},
{ // Tier 4
{
Name: "Potato", Food: FoodPotato, Copies: 2, Perk: true,
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionPreventSelf, Count: 2, Cap: 2}},
EffectText: "The first two times this pet is hit, prevent 2 damage",
},
},
{ // Tier 5
{
Name: "Durian", Food: FoodDurian, Copies: 2, Perk: true,
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionStripApples}},
EffectText: "Play: discard all enemy Apples in play",
},
},
{ // Tier 6
{
Name: "Tomato", Food: FoodTomato, Copies: 2, Perk: true,
Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock, Count: 4}},
EffectText: "Play: throw 4 Rocks",
},
},
}
// newCardID mints a unique card ID within the game.
func (g *Game) newCardID() string {
g.NextCardID++
@@ -487,6 +856,8 @@ func (g *Game) newCardID() string {
// back to it so this is the single seam future packs plug their cards into.
func packTiers(pack string) (*[MaxRounds][]petTemplate, *[MaxRounds][]foodTemplate) {
switch pack {
case "golden":
return &goldenPetTiers, &goldenFoodTiers
default: // turtle (and the placeholder packs, until they ship)
return &petTiers, &foodTiers
}
@@ -556,11 +927,13 @@ func Catalog() []Card {
return cards
}
// cardByName mints a fresh instance of the named pet or food from its
// template (pets take their first printed suit). Returns false if unknown.
// cardByName mints a fresh instance of the named pet or food from the current
// pack's templates (pets take their first printed suit). Returns false if
// unknown.
func (g *Game) cardByName(name string) (Card, bool) {
for tierIdx := range petTiers {
for _, t := range petTiers[tierIdx] {
pets, foods := packTiers(g.Pack)
for tierIdx := range pets {
for _, t := range pets[tierIdx] {
if t.Name == name {
suit := SuitRed
if len(t.Suits) > 0 {
@@ -572,7 +945,7 @@ func (g *Game) cardByName(name string) (Card, bool) {
}, true
}
}
for _, f := range foodTiers[tierIdx] {
for _, f := range foods[tierIdx] {
if f.Name == name {
return Card{
ID: g.newCardID(), Kind: KindFood, Name: f.Name, Tier: tierIdx + 1,
@@ -608,3 +981,18 @@ func (g *Game) newBee() Card {
Temporary: true,
}
}
// newGoldenRetriever mints the Golden pack's supply pet: a temporary,
// unbuyable pet whose base Power equals the Trumpets that summoned it. Those
// Trumpets can't be added to or removed, so it takes no auras and eats no
// apples (documented no-op today: tiers 1-3 have no auras).
func (g *Game) newGoldenRetriever(power int) Card {
return Card{
ID: g.newCardID(),
Kind: KindPet,
Name: "Golden Retriever",
Power: power,
Temporary: true,
EffectText: "Its Power equals its Trumpets, which can't be changed.",
}
}