@@ -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 */
7287export 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). */
540564const 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