Skip to content

Commit 952b50c

Browse files
author
Sorra
committed
Merge branch 'main' of github.com:TheWizardsCode/Tableau-Card-Engine into main
2 parents 04c4ff5 + b541235 commit 952b50c

6 files changed

Lines changed: 730 additions & 20 deletions

File tree

example-games/main-street/MainStreetCards.ts

Lines changed: 146 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ export interface BusinessCard {
4747
incomeBonus: number;
4848
/** Cumulative synergy range extension from applied upgrades. */
4949
synergyRangeBonus: number;
50+
/**
51+
* IDs of upgrade cards that have been applied to this business instance,
52+
* in application order. Used to enforce multi-level chain requirements and
53+
* to prevent the same branch being applied twice.
54+
*
55+
* Omitting this field is treated as an empty array.
56+
*/
57+
appliedUpgrades?: string[];
5058
}
5159

5260
/**
@@ -68,6 +76,13 @@ export interface EventCard {
6876

6977
/**
7078
* An Upgrade card that enhances a specific Business card.
79+
*
80+
* Branching upgrades: multiple `UpgradeCard` entries may share the same
81+
* `targetBusiness` and `requiredLevel`, giving the player a choice of which
82+
* upgrade branch to take.
83+
*
84+
* Multi-level chains: set `requiredLevel > 0` so the card can only be applied
85+
* after the business has already been upgraded that many times.
7186
*/
7287
export interface UpgradeCard {
7388
readonly family: 'upgrade';
@@ -78,6 +93,14 @@ export interface UpgradeCard {
7893
readonly incomeBonus: number;
7994
readonly synergyRangeBonus: number;
8095
readonly description: string;
96+
/**
97+
* Minimum business level required before this upgrade may be applied.
98+
* 0 (default) = can be applied to the base (un-upgraded) business.
99+
* 1 = can only be applied after the business has been upgraded once, etc.
100+
*
101+
* Omitting this field is equivalent to setting it to 0.
102+
*/
103+
readonly requiredLevel?: number;
81104
}
82105

83106
/** Union of all card types in Main Street. */
@@ -140,14 +163,15 @@ export const CHALLENGE_BONUS_POINTS = 10;
140163

141164
/**
142165
* Creates a fresh copy of a BusinessCard from template data.
143-
* Mutable fields (level, incomeBonus, synergyRangeBonus) are reset.
166+
* Mutable fields (level, incomeBonus, synergyRangeBonus, appliedUpgrades) are reset.
144167
*/
145-
function makeBusiness(template: Omit<BusinessCard, 'family' | 'level' | 'incomeBonus' | 'synergyRangeBonus'>): BusinessCard {
168+
function makeBusiness(template: Omit<BusinessCard, 'family' | 'level' | 'incomeBonus' | 'synergyRangeBonus' | 'appliedUpgrades'>): BusinessCard {
146169
return {
147170
family: 'business',
148171
level: 0,
149172
incomeBonus: 0,
150173
synergyRangeBonus: 0,
174+
appliedUpgrades: [],
151175
...template,
152176
};
153177
}
@@ -161,7 +185,7 @@ const BUSINESS_TEMPLATES: Omit<BusinessCard, 'family' | 'level' | 'incomeBonus'
161185
baseIncome: 2,
162186
synergyTypes: ['Food'],
163187
upgradePath: 'Bakery',
164-
maxLevel: 1,
188+
maxLevel: 2,
165189
description: 'Provides warm pastries. Gains +1 coin for each adjacent Food business.',
166190
},
167191
{
@@ -171,7 +195,7 @@ const BUSINESS_TEMPLATES: Omit<BusinessCard, 'family' | 'level' | 'incomeBonus'
171195
baseIncome: 3,
172196
synergyTypes: ['Food'],
173197
upgradePath: 'Diner',
174-
maxLevel: 1,
198+
maxLevel: 2,
175199
description: 'Serves quick meals. Gains +1 coin per adjacent Food business.',
176200
},
177201
{
@@ -265,7 +289,7 @@ const BUSINESS_TEMPLATES: Omit<BusinessCard, 'family' | 'level' | 'incomeBonus'
265289
baseIncome: 3,
266290
synergyTypes: ['Entertainment'],
267291
upgradePath: 'Cinema',
268-
maxLevel: 1,
292+
maxLevel: 2,
269293
description: 'Shows the latest films. Gains +1 coin per adjacent Entertainment business.',
270294
},
271295
// Multi-synergy bridge cards (belong to two synergy types)
@@ -306,7 +330,7 @@ const BUSINESS_TEMPLATES: Omit<BusinessCard, 'family' | 'level' | 'incomeBonus'
306330
baseIncome: 3,
307331
synergyTypes: ['Service', 'Entertainment'],
308332
upgradePath: 'Day Spa',
309-
maxLevel: 1,
333+
maxLevel: 2,
310334
description: 'Relaxation and pampering. Bridges Service and Entertainment synergies.',
311335
},
312336
// Additional variety
@@ -538,6 +562,7 @@ const EVENT_TEMPLATES: EventCard[] = [
538562

539563
/** Template data for all Upgrade cards (M1 + M2 pool). */
540564
const UPGRADE_TEMPLATES: UpgradeCard[] = [
565+
// ── M1 Base Upgrades (requiredLevel: 0) ─────────────────────
541566
{
542567
family: 'upgrade',
543568
id: 'upg-patisserie',
@@ -546,6 +571,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
546571
cost: 4,
547572
incomeBonus: 1,
548573
synergyRangeBonus: 1,
574+
requiredLevel: 0,
549575
description: 'Turns a Bakery into a Patisserie, increasing income and synergy range.',
550576
},
551577
{
@@ -556,6 +582,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
556582
cost: 4,
557583
incomeBonus: 1,
558584
synergyRangeBonus: 1,
585+
requiredLevel: 0,
559586
description: 'Turns a Diner into a Bistro with higher foot-traffic.',
560587
},
561588
{
@@ -566,6 +593,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
566593
cost: 3,
567594
incomeBonus: 1,
568595
synergyRangeBonus: 0,
596+
requiredLevel: 0,
569597
description: 'Adds a cultural boost to the Bookshop.',
570598
},
571599
// ── M2 Expanded Upgrade Templates ───────────────────────────
@@ -577,6 +605,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
577605
cost: 3,
578606
incomeBonus: 1,
579607
synergyRangeBonus: 1,
608+
requiredLevel: 0,
580609
description: 'Expands the Park into a Garden with extended cultural reach.',
581610
},
582611
{
@@ -587,6 +616,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
587616
cost: 4,
588617
incomeBonus: 1,
589618
synergyRangeBonus: 1,
619+
requiredLevel: 0,
590620
description: 'Transforms the Hardware Store into a Home Improvement center.',
591621
},
592622
{
@@ -597,6 +627,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
597627
cost: 3,
598628
incomeBonus: 1,
599629
synergyRangeBonus: 0,
630+
requiredLevel: 0,
600631
description: 'Rebrands the Pawn Shop as a trendy Vintage Shop.',
601632
},
602633
{
@@ -607,6 +638,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
607638
cost: 4,
608639
incomeBonus: 1,
609640
synergyRangeBonus: 1,
641+
requiredLevel: 0,
610642
description: 'Elevates the Boutique to a Designer Store with premium clientele.',
611643
},
612644
{
@@ -617,6 +649,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
617649
cost: 3,
618650
incomeBonus: 1,
619651
synergyRangeBonus: 0,
652+
requiredLevel: 0,
620653
description: 'Upgrades the Laundromat to a full-service Dry Cleaners.',
621654
},
622655
{
@@ -627,6 +660,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
627660
cost: 3,
628661
incomeBonus: 1,
629662
synergyRangeBonus: 1,
663+
requiredLevel: 0,
630664
description: 'Expands the Barbershop into a modern Salon.',
631665
},
632666
{
@@ -637,6 +671,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
637671
cost: 4,
638672
incomeBonus: 1,
639673
synergyRangeBonus: 1,
674+
requiredLevel: 0,
640675
description: 'Transforms the Arcade into a state-of-the-art Gaming Lounge.',
641676
},
642677
{
@@ -647,6 +682,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
647682
cost: 5,
648683
incomeBonus: 2,
649684
synergyRangeBonus: 1,
685+
requiredLevel: 0,
650686
description: 'Upgrades the Cinema to an IMAX Theater with premium experience.',
651687
},
652688
{
@@ -657,6 +693,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
657693
cost: 3,
658694
incomeBonus: 1,
659695
synergyRangeBonus: 1,
696+
requiredLevel: 0,
660697
description: 'Turns the Cafe into a specialty Roastery with artisan appeal.',
661698
},
662699
{
@@ -667,6 +704,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
667704
cost: 2,
668705
incomeBonus: 1,
669706
synergyRangeBonus: 0,
707+
requiredLevel: 0,
670708
description: 'Elevates the Food Truck with gourmet offerings.',
671709
},
672710
{
@@ -677,6 +715,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
677715
cost: 4,
678716
incomeBonus: 1,
679717
synergyRangeBonus: 1,
718+
requiredLevel: 0,
680719
description: 'Expands the Art Gallery into a full Museum.',
681720
},
682721
{
@@ -687,6 +726,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
687726
cost: 5,
688727
incomeBonus: 2,
689728
synergyRangeBonus: 1,
729+
requiredLevel: 0,
690730
description: 'Transforms the Day Spa into a luxurious Resort Spa.',
691731
},
692732
{
@@ -697,6 +737,7 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
697737
cost: 3,
698738
incomeBonus: 1,
699739
synergyRangeBonus: 1,
740+
requiredLevel: 0,
700741
description: 'Expands the Florist into a full Garden Center.',
701742
},
702743
{
@@ -707,8 +748,107 @@ const UPGRADE_TEMPLATES: UpgradeCard[] = [
707748
cost: 5,
708749
incomeBonus: 2,
709750
synergyRangeBonus: 1,
751+
requiredLevel: 0,
710752
description: 'Upgrades the Clinic to a comprehensive Medical Center.',
711753
},
754+
// ── Branching Upgrades (alternative level-0 paths) ──────────
755+
// Bakery branches: Patisserie (above, food-artisan) vs Bread Factory (volume)
756+
{
757+
family: 'upgrade',
758+
id: 'upg-bread-factory',
759+
name: 'Upgrade to Bread Factory',
760+
targetBusiness: 'Bakery',
761+
cost: 3,
762+
incomeBonus: 2,
763+
synergyRangeBonus: 0,
764+
requiredLevel: 0,
765+
description: 'Scales the Bakery into a high-volume Bread Factory. More income, no range boost.',
766+
},
767+
// Diner branches: Bistro (above, quality) vs Fast Food (volume)
768+
{
769+
family: 'upgrade',
770+
id: 'upg-fast-food',
771+
name: 'Upgrade to Fast Food',
772+
targetBusiness: 'Diner',
773+
cost: 3,
774+
incomeBonus: 2,
775+
synergyRangeBonus: 0,
776+
requiredLevel: 0,
777+
description: 'Converts the Diner to a Fast Food outlet. Higher income, smaller synergy radius.',
778+
},
779+
// Cinema branches: IMAX (above, premium) vs Drive-In (community)
780+
{
781+
family: 'upgrade',
782+
id: 'upg-drive-in',
783+
name: 'Upgrade to Drive-In Theater',
784+
targetBusiness: 'Cinema',
785+
cost: 4,
786+
incomeBonus: 1,
787+
synergyRangeBonus: 2,
788+
requiredLevel: 0,
789+
description: 'Turns the Cinema into a Drive-In Theater with a much wider community reach.',
790+
},
791+
// Day Spa branches: Resort Spa (above, premium) vs Wellness Center (service-range)
792+
{
793+
family: 'upgrade',
794+
id: 'upg-wellness-center',
795+
name: 'Upgrade to Wellness Center',
796+
targetBusiness: 'Day Spa',
797+
cost: 4,
798+
incomeBonus: 1,
799+
synergyRangeBonus: 2,
800+
requiredLevel: 0,
801+
description: 'Expands the Day Spa into a Wellness Center with a broader service footprint.',
802+
},
803+
// ── Multi-Level Upgrades (requiredLevel: 1) ──────────────────
804+
// Level-2 upgrade for Bakery (after Patisserie or Bread Factory)
805+
{
806+
family: 'upgrade',
807+
id: 'upg-grand-bakehouse',
808+
name: 'Upgrade to Grand Bakehouse',
809+
targetBusiness: 'Bakery',
810+
cost: 5,
811+
incomeBonus: 2,
812+
synergyRangeBonus: 1,
813+
requiredLevel: 1,
814+
description: 'The pinnacle of baking craft — a Grand Bakehouse drawing visitors from afar.',
815+
},
816+
// Level-2 upgrade for Diner (after Bistro or Fast Food)
817+
{
818+
family: 'upgrade',
819+
id: 'upg-restaurant',
820+
name: 'Upgrade to Restaurant',
821+
targetBusiness: 'Diner',
822+
cost: 5,
823+
incomeBonus: 2,
824+
synergyRangeBonus: 1,
825+
requiredLevel: 1,
826+
description: 'Elevates the Diner all the way to a full-service Restaurant.',
827+
},
828+
// Level-2 upgrade for Cinema (after IMAX or Drive-In)
829+
{
830+
family: 'upgrade',
831+
id: 'upg-multiplex',
832+
name: 'Upgrade to Multiplex',
833+
targetBusiness: 'Cinema',
834+
cost: 6,
835+
incomeBonus: 3,
836+
synergyRangeBonus: 1,
837+
requiredLevel: 1,
838+
description: 'A massive Multiplex complex — the entertainment heart of Main Street.',
839+
},
840+
// Level-2 upgrade for Day Spa (after Resort Spa or Wellness Center)
841+
{
842+
family: 'upgrade',
843+
id: 'upg-luxury-retreat',
844+
name: 'Upgrade to Luxury Retreat',
845+
targetBusiness: 'Day Spa',
846+
cost: 6,
847+
incomeBonus: 3,
848+
synergyRangeBonus: 1,
849+
requiredLevel: 1,
850+
description: 'A destination Luxury Retreat — the most prestigious business on the street.',
851+
},
712852
];
713853

714854
// ── Deck Building ───────────────────────────────────────────

0 commit comments

Comments
 (0)