package game import "fmt" // Suit is the colored trade-in symbol printed on pet cards. Three pets of // the same suit can be traded (the "Triple" action) for a pick from the next // tier's deck. type Suit string const ( SuitRed Suit = "red" SuitBlue Suit = "blue" SuitYellow Suit = "yellow" ) // CardKind distinguishes pets from foods. type CardKind string const ( KindPet CardKind = "pet" KindFood CardKind = "food" ) // Food identifiers. const ( FoodApple = "apple" FoodHoney = "honey" FoodGarlic = "garlic" 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. type EffectTrigger string const ( TriggerFaint EffectTrigger = "faint" // defeated in battle TriggerSell EffectTrigger = "sell" // sold in the shop (the discard→apple action) TriggerBuy EffectTrigger = "buy" // purchased (also fires on pets gained via Triple) TriggerPlay EffectTrigger = "play" // revealed on the stack during battle TriggerTriple EffectTrigger = "triple" // used as one of the three traded-in cards TriggerHurt EffectTrigger = "hurt" // attacked and received damage // TriggerBattlePrep fires right after the shop phase ends, as players // begin ordering their decks. TriggerBattlePrep EffectTrigger = "battlePrep" // TriggerEnemyFaint fires on a pet in play whenever an enemy pet faints. TriggerEnemyFaint EffectTrigger = "enemyFaint" // TriggerEnemyPlay fires on a pet in play whenever the enemy plays a pet. TriggerEnemyPlay EffectTrigger = "enemyPlay" // 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. type EffectAction string const ( // ActionSummonTop puts Count cards (Effect.Card: "apple" or "bee") on // top of a deck/stack — the owner's, or the enemy's when Target is // "enemy". Battle-time. ActionSummonTop EffectAction = "summonTop" // ActionGainApple adds Count apples to the player's hand. Shop-time. ActionGainApple EffectAction = "gainApple" // ActionThrowRock rolls Count rock dice (faces: 0,0,1,1,2,2) and deals // the total to the opposing pet in play. Battle-time. ActionThrowRock EffectAction = "throwRock" // ActionEatApple gives the pet itself +Count power (as if it ate // apples), if it hasn't fainted. Battle-time. With Per set, Count is // multiplied by a battle statistic (see Effect.Per). ActionEatApple EffectAction = "eatApple" // ActionRefreshGold returns Count spent coins to the player (never // above the round's allowance). Shop-time. ActionRefreshGold EffectAction = "refreshGold" // ActionPreventDamage (passive) reduces every attack that hits this pet // by Count damage. ActionPreventDamage EffectAction = "preventDamage" // ActionRecycleApples (faint) puts up to Count of this pet's attached // apples back on top of its owner's deck. ActionRecycleApples EffectAction = "recycleApples" // ActionDelayedRocks (faint) sets the pet aside: when its owner plays // their next pet, it throws Count rocks. With Target "all" (Badger) // the volley hits EACH active pet — the owner's own included; // otherwise it targets the enemy pet as usual (Blowfish). ActionDelayedRocks EffectAction = "delayedRocks" // ActionRecurringRocks (faint) sets the pet aside: EVERY time its owner // plays a pet, it throws Count rocks at the enemy pet (Snake). ActionRecurringRocks EffectAction = "recurringRocks" // ActionEnemyLastPetRocks (faint) sets the pet aside: when the enemy // plays the last pet in their deck, it throws Count rocks (Crocodile). ActionEnemyLastPetRocks EffectAction = "enemyLastPetRocks" // ActionShieldNext (faint) sets the pet aside: the next Count times a // friendly pet is hit, ALL damage from that hit is prevented (Turtle). ActionShieldNext EffectAction = "shieldNext" // ActionShieldSelf gives the pet itself Count charges that each prevent // all damage from one hit (Gorilla on hurt, Melon on play). ActionShieldSelf EffectAction = "shieldSelf" // ActionStripFoods (play) discards every food attached to the enemy // pet in play (losing their buffs and perks, which can faint it). ActionStripFoods EffectAction = "stripFoods" // ActionStealApples (play) moves up to Count apples from the enemy pet // to this pet (Wolverine). Losing apples can faint the victim. ActionStealApples EffectAction = "stealApples" // ActionMillEnemy (play) discards cards off the top of the enemy deck // until a non-Bee pet is showing (Chili). ActionMillEnemy EffectAction = "millEnemy" // ActionHeal removes Count damage markers from the pet, if it hasn't // fainted. ActionHeal EffectAction = "heal" // ActionKnockout (passive) makes any pet this pet hurts with its clash // attack faint outright (Scorpion). Rocks don't count, and a fully // prevented attack KOs nothing. ActionKnockout EffectAction = "knockout" // ActionApplesInPlay (battle prep) starts the battle with Count apples // already in play, attached to the owner's first pet (Monkey). ActionApplesInPlay EffectAction = "applesInPlay" // ActionDoubleApples doubles the apples in the player's hand (Cat). // Shop-time. ActionDoubleApples EffectAction = "doubleApples" // ActionBeeAura (faint) sets the pet aside: the owner's Bees have // +Count power for the rest of the battle (Turkey). ActionBeeAura EffectAction = "beeAura" // 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. const ( PerFaintedBees = "faintedBees" // × friendly bees fainted this battle 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 ConditionFirstPet = "firstPet" // this is the first pet the side has played (Komodo) ) // Effect is one trigger→action pair printed on a card. type Effect struct { Trigger EffectTrigger `json:"trigger"` Action EffectAction `json:"action"` Card string `json:"card,omitempty"` // summonTop: "apple" | "bee" Count int `json:"count,omitempty"` // 0 means 1 Target string `json:"target,omitempty"` // summonTop: "" (self) | "enemy" // Per multiplies Count by a battle statistic (e.g. PerFaintedBees). Per string `json:"per,omitempty"` // Cap limits the final count when > 0 ("up to N"). Cap int `json:"cap,omitempty"` // Condition gates the effect (e.g. ConditionTripled). 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. func (e Effect) count() int { if e.Count <= 0 { return 1 } return e.Count } // Card is a single physical card instance. IDs are unique per game. type Card struct { ID string `json:"id"` Kind CardKind `json:"kind"` Name string `json:"name"` Tier int `json:"tier,omitempty"` Power int `json:"power,omitempty"` Suit Suit `json:"suit,omitempty"` // Effects drive the engine; EffectText is the human-readable rule shown // on the card face. Effects []Effect `json:"effects,omitempty"` EffectText string `json:"effectText,omitempty"` Food string `json:"food,omitempty"` // Perk foods (e.g. Honey) attach like any food, but a pet only benefits // from the last-applied perk. Perk bool `json:"perk,omitempty"` // Temporary cards (apples, bees) are removed from the deck after the // next battle. Temporary bool `json:"temporary,omitempty"` } func (c Card) IsPet() bool { return c.Kind == KindPet } func (c Card) IsFood() bool { return c.Kind == KindFood } // petTemplate is the printed definition of a pet. Suits lists the suit of // each physical copy in the tier deck (one card per entry). type petTemplate struct { Name string Power int Suits []Suit Effects []Effect EffectText string } // foodTemplate is the printed definition of a food card that lives in a // shop deck (e.g. Honey). type foodTemplate struct { Name string Food string Copies int Perk bool Effects []Effect EffectText string } // petTiers defines the shop decks' pets. Index 0 is tier 1 (round 1) // through index 5 for tier 6 (round 6). All six tiers are real card data. var petTiers = [MaxRounds][]petTemplate{ { // Tier 1 { Name: "Ant", Power: 1, Suits: []Suit{SuitBlue, SuitYellow}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "apple"}}, EffectText: "Faint: add an Apple on top of your deck", }, { Name: "Cricket", Power: 1, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee"}}, EffectText: "Faint: add a Bee on top of your deck", }, { Name: "Duck", Power: 2, Suits: []Suit{SuitYellow, SuitBlue}, Effects: []Effect{{Trigger: TriggerSell, Action: ActionGainApple}}, EffectText: "Sell: add 1 extra Apple to your hand", }, { Name: "Otter", Power: 1, Suits: []Suit{SuitYellow, SuitRed}, Effects: []Effect{{Trigger: TriggerBuy, Action: ActionGainApple}}, EffectText: "Buy: add an Apple to your hand", }, { Name: "Mosquito", Power: 2, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock}}, EffectText: "Play: throw 1 Rock", }, { Name: "Fish", Power: 2, Suits: []Suit{SuitYellow, SuitRed}, Effects: []Effect{{Trigger: TriggerTriple, Action: ActionGainApple}}, EffectText: "Triple: add an Apple to your hand", }, }, { // Tier 2 { Name: "Worm", Power: 2, Suits: []Suit{SuitBlue, SuitYellow}, Effects: []Effect{{Trigger: TriggerBuy, Action: ActionGainApple, Count: 2}}, EffectText: "Buy: add 2 Apples to your hand", }, { Name: "Flamingo", Power: 1, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "apple", Count: 2}}, EffectText: "Faint: add 2 Apples on top of your deck", }, { Name: "Peacock", Power: 2, Suits: []Suit{SuitBlue, SuitRed}, Effects: []Effect{{Trigger: TriggerHurt, Action: ActionEatApple}}, EffectText: "Hurt: if this pet hasn't fainted, it eats 1 Apple", }, { Name: "Swan", Power: 1, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerTriple, Action: ActionRefreshGold, MinRound: 3}}, EffectText: "Triple: if it is round 3 or later, refresh a spent Gold", }, { Name: "Rat", Power: 4, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee", Target: "enemy"}}, EffectText: "Faint: add a Bee on top of the enemy deck", }, { Name: "Spider", Power: 2, Suits: []Suit{SuitYellow, SuitBlue}, Effects: []Effect{ {Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee"}, {Trigger: TriggerFaint, Action: ActionSummonTop, Card: "apple"}, }, EffectText: "Faint: add a Bee, then an Apple, on top of your deck", }, }, { // Tier 3 { Name: "Dog", Power: 2, Suits: []Suit{SuitYellow, SuitBlue}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionEatApple, Per: PerFaintedBees}}, EffectText: "Play: eats 1 Apple for each friendly fainted Bee", }, { Name: "Dolphin", Power: 2, Suits: []Suit{SuitBlue, SuitRed}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock, Count: 3}}, EffectText: "Play: throw 3 Rocks", }, { Name: "Giraffe", Power: 2, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerBattlePrep, Action: ActionGainApple, Count: 2}}, EffectText: "Battle Prep: add 2 Apples to your hand", }, { Name: "Camel", Power: 3, Suits: []Suit{SuitYellow, SuitBlue}, Effects: []Effect{{Trigger: TriggerHurt, Action: ActionSummonTop, Card: "apple"}}, EffectText: "Hurt: add an Apple on top of your deck", }, { Name: "Sheep", Power: 3, Suits: []Suit{SuitYellow, SuitRed}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee", Count: 2}}, EffectText: "Faint: add 2 Bees on top of your deck", }, { Name: "Dodo", Power: 3, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionRecycleApples, Count: 3}}, EffectText: "Faint: put up to 3 of this pet's Apples on top of your deck", }, { Name: "Badger", Power: 3, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionDelayedRocks, Count: 2, Target: "all"}}, EffectText: "Faint: set aside — when you play your next pet, throw 2 Rocks at each active pet", }, }, { // Tier 4 { Name: "Squirrel", Power: 2, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{ {Trigger: TriggerBuy, Action: ActionGainApple, Count: 2}, {Trigger: TriggerSell, Action: ActionGainApple, Count: 2}, }, EffectText: "Buy: add 2 Apples to your hand · Sell: add 2 extra Apples to your hand", }, { Name: "Turtle", Power: 2, Suits: []Suit{SuitBlue, SuitYellow}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionShieldNext}}, EffectText: "Faint: set aside — the next time a friendly pet is hit, prevent all damage", }, { Name: "Rooster", Power: 4, Suits: []Suit{SuitYellow, SuitRed}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee", Per: PerEatenApples, Cap: 3}}, EffectText: "Faint: add a Bee on top of your deck for each Apple this pet ate, up to 3", }, { Name: "Bison", Power: 3, Suits: []Suit{SuitBlue, SuitYellow}, Effects: []Effect{{Trigger: TriggerBattlePrep, Action: ActionGainApple, Count: 3, Condition: ConditionTripled}}, EffectText: "Battle Prep: if you Tripled during this round's shop, add 3 Apples to your hand", }, { Name: "Blowfish", Power: 3, Suits: []Suit{SuitBlue, SuitRed}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionDelayedRocks, Count: 3}}, EffectText: "Faint: set aside — when you play your next pet, throw 3 Rocks", }, { Name: "Skunk", Power: 2, Suits: []Suit{SuitBlue, SuitYellow}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionStripFoods}}, EffectText: "Play: discard all Food from the enemy pet", }, { Name: "Hippo", Power: 4, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerEnemyFaint, Action: ActionHeal}}, EffectText: "Enemy Faints: if this pet hasn't fainted, heal 1 damage", }, }, { // Tier 5 { Name: "Monkey", Power: 3, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerBattlePrep, Action: ActionApplesInPlay, Count: 3}}, EffectText: "Battle Prep: start with 3 Apples in play, attached to your first pet", }, { Name: "Rhino", Power: 5, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerEnemyPlay, Action: ActionThrowRock}}, EffectText: "Enemy Played: throw 1 Rock", }, { Name: "Crocodile", Power: 4, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionEnemyLastPetRocks, Count: 3}}, EffectText: "Faint: set aside — when the last pet in the enemy deck is played, throw 3 Rocks", }, { Name: "Scorpion", Power: 1, Suits: []Suit{SuitBlue, SuitYellow}, Effects: []Effect{{Trigger: TriggerPassive, Action: ActionKnockout}}, EffectText: "This pet KOs any pet it hurts with an attack", }, { Name: "Seal", Power: 3, Suits: []Suit{SuitYellow, SuitRed}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionSummonTop, Card: "apple", Count: 3, Condition: ConditionHasPerk}}, EffectText: "Play: if this pet has a Perk, add 3 Apples on top of your deck", }, { Name: "Shark", Power: 1, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionEatApple, Per: PerFaintedPets}}, EffectText: "Play: eats 1 Apple for each friendly fainted pet", }, { Name: "Turkey", Power: 4, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionBeeAura}}, EffectText: "Faint: set aside — your Bees have +1 power", }, }, { // Tier 6 { Name: "Gorilla", Power: 6, Suits: []Suit{SuitBlue, SuitYellow}, Effects: []Effect{{Trigger: TriggerHurt, Action: ActionShieldSelf}}, EffectText: "Hurt: the next time this pet is hit, prevent all damage", }, { Name: "Fly", Power: 4, Suits: []Suit{SuitRed, SuitYellow}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee", Count: 3}}, EffectText: "Faint: add 3 Bees on top of your deck", }, { Name: "Leopard", Power: 4, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock, Per: PerPower}}, EffectText: "Play: throw Rocks equal to this pet's power", }, { Name: "Mammoth", Power: 4, Suits: []Suit{SuitYellow, SuitRed}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionPetAura}}, EffectText: "Faint: set aside — your pets have +1 power", }, { Name: "Cat", Power: 2, Suits: []Suit{SuitYellow, SuitBlue}, Effects: []Effect{ {Trigger: TriggerBuy, Action: ActionGainApple, Count: 2}, {Trigger: TriggerBuy, Action: ActionDoubleApples}, }, EffectText: "Buy: add 2 Apples to your hand, then double your Apples in hand", }, { Name: "Snake", Power: 2, Suits: []Suit{SuitRed, SuitBlue}, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionRecurringRocks, Count: 2}}, EffectText: "Faint: set aside — each time you play a pet, throw 2 Rocks", }, { Name: "Wolverine", Power: 5, Suits: []Suit{SuitBlue, SuitRed}, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionStealApples, Count: 3}}, EffectText: "Play: steal up to 3 Apples from the enemy pet", }, }, } // foodTiers defines the food cards mixed into each tier's shop deck. var foodTiers = [MaxRounds][]foodTemplate{ {}, // Tier 1 { // Tier 2 { Name: "Honey", Food: FoodHoney, Copies: 2, Perk: true, Effects: []Effect{{Trigger: TriggerFaint, Action: ActionSummonTop, Card: "bee"}}, EffectText: "Faint: add a Bee on top of your deck", }, }, { // Tier 3 { Name: "Garlic", Food: FoodGarlic, Copies: 2, Perk: true, Effects: []Effect{{Trigger: TriggerPassive, Action: ActionPreventDamage}}, EffectText: "Every attack that hits this pet deals 1 less damage", }, }, { // Tier 4 { Name: "Pineapple", Food: FoodPineapple, Copies: 2, Perk: true, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionThrowRock, Count: 3}}, EffectText: "Play: throw 3 Rocks", }, }, { // Tier 5 { Name: "Chili", Food: FoodChili, Copies: 2, Perk: true, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionMillEnemy}}, EffectText: "Play: discard cards from the top of the enemy deck until a non-Bee pet is showing", }, }, { // Tier 6 { Name: "Melon", Food: FoodMelon, Copies: 2, Perk: true, Effects: []Effect{{Trigger: TriggerPlay, Action: ActionShieldSelf}}, EffectText: "The first time this pet is hit, prevent all damage", }, }, } // 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++ return fmt.Sprintf("c%d", g.NextCardID) } // packTiers returns the pet and food templates for a pack, tier by tier. Only // the Turtle pack has real data today; the other (not-yet-playable) packs fall // 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 } } // buildShopDecks creates all six tier decks (unshuffled) for the game's pack. func (g *Game) buildShopDecks() { pets, foods := packTiers(g.Pack) g.ShopDecks = make([][]Card, MaxRounds) for tierIdx := range pets { var deck []Card for _, t := range pets[tierIdx] { for _, suit := range t.Suits { deck = append(deck, Card{ ID: g.newCardID(), Kind: KindPet, Name: t.Name, Tier: tierIdx + 1, Power: t.Power, Suit: suit, Effects: t.Effects, EffectText: t.EffectText, }) } } for _, f := range foods[tierIdx] { for range f.Copies { deck = append(deck, Card{ ID: g.newCardID(), Kind: KindFood, Name: f.Name, Tier: tierIdx + 1, Food: f.Food, Perk: f.Perk, Effects: f.Effects, EffectText: f.EffectText, }) } } g.ShopDecks[tierIdx] = deck } } // Catalog returns the default pack's representative cards. func Catalog() []Card { return CatalogForPack(DefaultPack) } // CatalogForPack returns one representative card for every pet and food in a // pack, tier by tier, for the debug "buy any card" panel. IDs are name-based // placeholders (not real instances); pets use their first printed suit. func CatalogForPack(pack string) []Card { pets, foods := packTiers(pack) var cards []Card for tierIdx := range pets { for _, t := range pets[tierIdx] { suit := SuitRed if len(t.Suits) > 0 { suit = t.Suits[0] } cards = append(cards, Card{ ID: "pet-" + t.Name, Kind: KindPet, Name: t.Name, Tier: tierIdx + 1, Power: t.Power, Suit: suit, Effects: t.Effects, EffectText: t.EffectText, }) } for _, f := range foods[tierIdx] { cards = append(cards, Card{ ID: "food-" + f.Name, Kind: KindFood, Name: f.Name, Tier: tierIdx + 1, Food: f.Food, Perk: f.Perk, Effects: f.Effects, EffectText: f.EffectText, }) } } return cards } // 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) { 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 { suit = t.Suits[0] } return Card{ ID: g.newCardID(), Kind: KindPet, Name: t.Name, Tier: tierIdx + 1, Power: t.Power, Suit: suit, Effects: t.Effects, EffectText: t.EffectText, }, true } } for _, f := range foods[tierIdx] { if f.Name == name { return Card{ ID: g.newCardID(), Kind: KindFood, Name: f.Name, Tier: tierIdx + 1, Food: f.Food, Perk: f.Perk, Effects: f.Effects, EffectText: f.EffectText, }, true } } } return Card{}, false } // newApple mints an apple food card. Apples are temporary: they vanish from // the deck after the next battle. func (g *Game) newApple() Card { return Card{ ID: g.newCardID(), Kind: KindFood, Name: "Apple", Food: FoodApple, Temporary: true, } } // newBee mints a bee: a temporary 1-power pet with no effect, summoned by // other pets' effects. It counts as a pet while it exists (foods can attach // to it in battle). func (g *Game) newBee() Card { return Card{ ID: g.newCardID(), Kind: KindPet, Name: "Bee", Power: 1, 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.", } }