Shop Combat & Karma System

Status: Designed Author: Nathan + Claude Last Updated: 2026-04-07 Implements Pillar: Risk/reward decisions, moral choice, replayability

Overview

Players can choose to rob the merchant at any shop node instead of buying. This triggers a unique combat encounter against the Merchant (and bodyguards at higher karma debt). Winning gives all shop items for free. Losing ends the run. A persistent karma system tracks robberies across runs, escalating consequences: higher prices, bodyguards, locked items, and altered narrative. Redemption is possible through legitimate purchases and shrine atonement.

The system adds a high-stakes moral dimension to every shop visit — do you play fair and invest gold, or risk everything for free loot?

Player Fantasy

The temptation of the shortcut. Every shop visit becomes a tense decision: "I could just take it all." The player who robs feels the thrill of getting away with it — but the creeping dread of consequences. The player who resists feels virtuous, but always wonders "what if?" The player deep in karma debt feels hunted — the merchant remembers, and the world pushes back.

Reference: Undertale's genocide route (consequences persist), Slay the Spire's risk/reward node choices, Balatro's "do I push my luck" tension.

Detailed Design

Core Flow

At any shop node, the player sees three options:

  1. Buy — normal shop behavior (browse, purchase with gold)
  2. Rob — initiate combat against the Merchant
  3. Leave — exit shop, proceed to next floor (no purchase, no fight)

Robbery Combat

When the player clicks "Rob":

  1. Warning dialog: "The Merchant won't go quietly. Are you sure?" with karma indicator
  2. If confirmed, transition to combat scene with the Merchant (+ bodyguards based on karma)
  3. Win: all shop items (relics, consumables, heal) added to player inventory
    • Relics respect the 8-relic cap — if full, swap picker shown
    • Consumables respect slot limit — excess discarded
    • Heal option auto-applied
    • Karma decreases by 10
  4. Lose: run ends (game over flow, skill points still awarded)
  5. During combat, player can Flee (replaces "Score" button on turn 1 only)
    • Flee = leave shop with nothing, no karma change, merchant remembers (dialogue only)

The Merchant (Enemy)

Unique enemy not in the normal pool. The Merchant is a defensive fighter — shields up, dirty tricks, calls for help.

StatAct 1Act 2Act 3
HP80120160
Shield/turn81216
Turns allowed554
TierELITEELITEELITE

Merchant Interference Actions (unique to this enemy):

ActionEffectWeight
POCKET_SANDBlind player for 1 turn (hides enemy intent)20%
STEAL_GOLDPlayer loses 5-15 gold25%
PRICE_CURSENext shop in this run: prices +30%15%
DEFENDGain shield (8/12/16 by act)25%
SMOKE_BOMBScramble 2 dice to random 1-3 (like CHAOS but fewer dice)15%

Merchant Passive — "Coin Purse": Immune to Burn (can't set a merchant on fire — bad for business). First 3 damage per hit absorbed (like Thick Hide but weaker).

Merchant Sprite: Hooded figure, uses existing shop_bg merchant silhouette style.

Bodyguards (Karma-Scaled)

At higher karma debt, the Merchant hires protection:

KarmaBodyguardsType
0 to -9 (first robbery)NoneSolo merchant
-10 to -19 (2 robberies)1 ThugBasic enemy, 40 HP, LOCK_HOLD + ATTACK
-20 to -29 (3 robberies)1 EnforcerElite enemy, 70 HP, STEAL_REROLL + HEAVY_ATTACK
-30+ (4+ robberies)1 Enforcer + 1 ThugBoth present, merchant gets +2 attack

Bodyguards use existing enemy sprites (pick from basic/elite pool) with "Hired" prefix in display name.

Karma System

Persistence: Stored in user://karma.save, independent of run data (survives across runs like skill tree).

Karma Value: Integer, starts at 0. Negative = criminal, positive = virtuous.

ActionKarma Change
Rob the merchant (win)-10
Rob the merchant (flee)0 (no change)
Buy any item at full price+1
Buy any item at Merchant Prince discount+1 (still counts)
Shrine Atonement (pay 50g)+15
Complete a run without robbing+2

Karma Consequences (applied at shop generation):

Karma RangeEffect
+10 or higher"Loyal Customer" — merchant occasionally offers 1 item at 20% discount
0 to +9Normal (no modifier)
-1 to -9Prices +15%. Merchant dialogue: wary
-10 to -19Prices +30%. 1 Thug bodyguard. Merchant dialogue: hostile
-20 to -29Prices +50%. 1 Enforcer bodyguard. 1 random item locked (can't buy). Dialogue: threatening
-30 or lowerPrices +75%. 1 Enforcer + 1 Thug. 2 items locked. Merchant is armed (+2 attack). Dialogue: "You again…"

Redemption: Karma naturally drifts toward 0 through legitimate play. A player at -30 karma needs ~30 purchases or 2 shrine atonements to return to neutral. This takes 5-8 runs of honest shopping.

Shrine Atonement

When karma < -5, shrines gain an additional blessing option:

  • "Atonement": Pay 50 gold. Karma +15. Flavor text: "The shrine absolves a fraction of your sins."
  • Appears alongside normal shrine blessings (heal, reroll, consumable)
  • Only available when karma is negative

Narrative Integration

Merchant Dialogue changes based on karma (shown as flavor text at top of shop screen):

KarmaDialogue Pool
+10+"Ah, my favorite customer! I saved something special for you."
0 to +9"Welcome, traveler. Browse at your leisure."
-1 to -9"…Keep your hands where I can see them."
-10 to -19"I've hired protection. Try anything and you'll regret it."
-20 to -29"You. I know what you are. My enforcer is watching."
-30+"Back for more? This time I'm ready. draws weapon"

First Robbery Cutscene (plays once via CutsceneManager):

  • "The merchant's eyes widen as you reach for your dice. This isn't a negotiation."
  • After victory: "You gather the merchant's wares. Somewhere, a ledger records your debt."

Karma Warning on Game Over/Victory:

  • If karma < -10, defeat screen shows: "The merchant's guild will remember this."
  • If karma < -20, victory screen shows: "Your reputation precedes you. Merchants whisper your name."

States and Transitions

SHOP_ENTER
  |-- Player browses items --> SHOPPING (normal flow)
  |-- Player clicks "Rob" --> ROBBERY_WARNING
  |-- Player clicks "Leave" --> MAP (no purchase)
  
ROBBERY_WARNING
  |-- Player confirms --> ROBBERY_COMBAT
  |-- Player cancels --> SHOPPING
  
ROBBERY_COMBAT
  |-- Player wins --> LOOT_ALL (items added, karma -10)
  |-- Player loses --> GAME_OVER
  |-- Player flees (turn 1 only) --> MAP (nothing gained, dialogue noted)
  
LOOT_ALL
  |-- Relic cap check --> SWAP_PICKER (if at cap) or MAP

Interactions with Other Systems

SystemInterfaceDirection
CombatReuses DiceCombatManager with Merchant enemy dataThis → Combat
ShopRob button added to shop UI, price modifier from karmaThis ↔ Shop
EconomyGold stolen by STEAL_GOLD, prices modified by karmaThis → Economy
Persistencekarma.save file, loaded on game startThis ↔ Disk
ShrineAtonement blessing option when karma < -5This → Shrine
NarrativeMerchant dialogue pool, robbery cutscene, karma warningsThis → Narrative
AchievementNew achievements for robbery/redemptionThis → Achievements
Wanderer Archetype"Shops always have relic" still applies to robbery lootArchetype → This

Formulas

Merchant HP Scaling

merchant_hp = BASE_MERCHANT_HP[act] + abs(karma) * 2

Where BASE_MERCHANT_HP = {1: 80, 2: 120, 3: 160}.

At -30 karma, Act 3 merchant has 160 + 60 = 220 HP (approaching boss territory).

Price Modifier

karma_price_mult = 1.0 + max(0, abs(min(karma, 0))) * 0.025

At karma 0: 1.0x. At -10: 1.25x. At -20: 1.5x. At -30: 1.75x.

Capped at 2.0x (karma -40 or lower).

Merchant Shield Per Turn

shield_per_turn = BASE_SHIELD[act] + max(0, abs(min(karma, 0)) / 10) * 4

At karma -30, Act 1: 8 + 12 = 20 shield/turn.

Loot Value

total_loot_value = sum(item_prices_in_shop)

Typically 200-500g worth of items per shop. This is the risk/reward calculation: spend 0g for ~300g worth of items, but risk game over + karma debt.

Karma Decay (Natural Drift)

Karma does NOT auto-decay. It only changes through player actions (buy, rob, atone). This means consequences are permanent until actively redeemed.

Edge Cases

SituationResolution
Rob at relic cap (8/8)Swap picker shown for each relic. Can skip individual relics.
Rob with full consumable slotsExcess consumables discarded. Player warned before combat.
Rob with 0 gold and STEAL_GOLD triggersGold can't go negative. Merchant steals 0 but action still plays.
Wanderer + RobWanderer's "shops always have relic" still applies — loot includes the guaranteed relic.
Merchant Prince keystone + karma pricesMerchant Prince discount applies AFTER karma price increase. At -20 karma + Merchant Prince: 1.5x * 0.7 = 1.05x (nearly neutral — build synergy!).
Rob the guaranteed F4 shop on first runAllowed. First-run tutorial tips warn about consequences.
Flee during robberyOnly available on turn 1. After turn 1, must fight to conclusion.
Player at karma -30 enters shop but doesn't robStill faces +75% prices and locked items. Must buy or leave.
All shop items locked by karmaAt least 1 item always remains purchasable (heal option can't be locked).
Shrine atonement when karma is 0+Atonement option hidden. Normal blessings only.
Rob twice in same run (F4 + F9)Both count. Karma -20 after run. Second shop already has bodyguards from first robbery this run (tracked in run_data).
Player dies to Merchant bodyguardNormal game over flow. Skill points + achievements still awarded.
Merchant killed by burn damageWorks normally. Burn isn't blocked by "Coin Purse" passive (only direct damage reduced). Wait — design says immune to burn. So burn just doesn't apply.

Dependencies

SystemTypeNotes
Combat (DiceCombatManager)HardRobbery IS a combat encounter
Shop (shop_screen.gd)HardRob button, price modifiers, loot collection
Enemy DatabaseHardMerchant + Thug + Enforcer enemy definitions
PersistenceHardkarma.save file
ShrineSoftAtonement option (shrine works without karma)
NarrativeSoftDialogue flavor (shop works without it)
AchievementSoftNew achievements (system works without them)

Tuning Knobs

KnobDefaultSafe RangeWhat Breaks
BASE_MERCHANT_HP{80, 120, 160}60-200 per actToo low: free loot. Too high: never worth robbing.
KARMA_PER_ROBBERY-10-5 to -20Too small: no consequences. Too large: one mistake = permanent debt.
KARMA_PER_PURCHASE+1+1 to +3Too high: karma trivially redeemable.
ATONEMENT_COST50g30-100gToo cheap: karma meaningless. Too expensive: never used.
ATONEMENT_KARMA+15+5 to +25Too high: one shrine fixes everything.
PRICE_MULT_PER_KARMA0.025 per point0.01-0.05Too high: shops unusable after 1 robbery.
PRICE_MULT_CAP2.0x1.5-3.0xToo high: shops become impossible.
MERCHANT_SHIELD_BASE{8, 12, 16}4-20Too low: merchant is a pushover. Too high: tedious fight.
BODYGUARD_KARMA_THRESHOLDS{-10, -20, -30}variesSpacing determines how fast consequences escalate.
FLEE_TURN_LIMIT1 (turn 1 only)1-2More turns = less risk = less tension.
LOYAL_CUSTOMER_THRESHOLD+10+5 to +20Too low: trivial to reach.
LOYAL_DISCOUNT20% on 1 item10-30%Too high: always-buy builds get free value.

Visual/Audio Requirements

Visual:

  • Merchant sprite: hooded figure with coin purse (1-bit style, existing art direction)
  • Thug sprite: reuse basic enemy sprite with dark tint
  • Enforcer sprite: reuse elite enemy sprite with gold tint
  • "Rob" button: red text, danger styling, positioned below "Leave" button
  • Karma indicator: small icon near gold display on shop screen (skull for negative, star for positive)
  • Price markup: original price shown with strikethrough, karma-inflated price in red

Audio:

  • Robbery initiation: tense SFX (reuse enemy_snipe or new "confrontation" sound)
  • Merchant defeat: coin shower SFX (reuse coin sounds from shop purchase)
  • Karma warning: low rumble on shop enter when karma < -10
  • Atonement: shrine chime + ascending tone

UI Requirements

Shop Screen Changes:

  • "Rob" button: bottom of shop UI, red text, small (doesn't dominate the layout)
  • Karma indicator: top-right corner, shows skull icon + number when negative
  • Price display: when karma < 0, show base price crossed out + inflated price
  • Locked items: greyed out with "[LOCKED]" label and padlock icon
  • Merchant dialogue: flavor text banner at top of shop, changes with karma

Combat Screen Changes:

  • Merchant name displays as "The Merchant" (not a generic enemy name)
  • "Flee" button replaces "Score" on turn 1 of robbery combat only
  • Bodyguard names: "Hired Thug", "Hired Enforcer"

Confirmation Dialog:

  • "Rob the Merchant?" + karma display + bodyguard warning
  • "This will anger the Merchant's Guild." (if karma already negative)
  • Confirm / Cancel buttons

Acceptance Criteria

  1. Player can click "Rob" at any shop to initiate combat with the Merchant
  2. Winning robbery grants all shop items (respecting caps, with swap picker)
  3. Losing robbery triggers normal game over flow
  4. Flee option available on turn 1 only, returns to map with no loot
  5. Karma persists across runs in user://karma.save
  6. Karma decreases by 10 on successful robbery
  7. Karma increases by 1 per purchase, +15 per shrine atonement
  8. Shop prices scale with negative karma (verified at -10, -20, -30)
  9. Bodyguards appear at correct karma thresholds
  10. Merchant HP scales with act + karma level
  11. Merchant uses unique interference actions (POCKET_SAND, STEAL_GOLD, etc.)
  12. Shrine shows Atonement option when karma < -5
  13. Merchant dialogue changes with karma level
  14. Locked items appear at karma -20 and below (heal always available)
  15. Loyal Customer discount appears at karma +10
  16. Merchant Prince keystone stacks correctly with karma price modifier
  17. Wanderer relic guarantee applies to robbery loot
  18. Two robberies in one run (F4 + F9) both apply karma and bodyguard escalation
  19. First robbery cutscene plays once via CutsceneManager

New Achievements

IDNameSPTrigger
first_robberySticky Fingers3Rob the merchant for the first time
rob_3_timesMost Wanted5Reach karma -30
redeem_karmaReformed5Return to karma 0 after being below -10
loyal_customerPreferred Buyer3Reach karma +10 (Loyal Customer status)
rob_and_winCrime Pays5Win a full run after robbing a merchant in that run

Open Questions

  1. Should karma affect non-shop systems? IMPLEMENTED — karma now affects:
    • Guardian choices (Kill/Save dialogue, resistance)
    • Shop prices (existing)
    • Multiple endings (determines Good/Bad/True ending)
    • Memory fragment collection (karma gates truth)
  2. Should there be a "Pacifist" achievement? Win without ever robbing (karma >= 0 after 10+ runs)
  3. How does this interact with the Player-Echo Boss? Could the echo boss inherit karma state — a "good" echo boss is weaker but the merchant helps you, an "evil" echo boss is stronger
  4. Multiplayer expansion: If co-op is ever added, does one player's robbery affect the other's karma?
  5. Visual karma indicator in hub? A wanted poster that appears on the camp wall when karma < -10
Built with LogoFlowershow