Content pass: give inflytande a purpose, branch the endings, deepen troende/Möllan/Universitet
Docker / build-and-push (push) Successful in 1m23s

Addresses the gaps flagged after surveying the existing game against the
new LORE-BIBLE.md:

- inflytande had exactly one spending sink in the whole game. Added
  favor_network (unlocks a bigger repeatable "call in a favor" upgrade)
  and neutralize_investigation, which pays off the previously-dead-end
  Kommissarie Fors thread from coc_investigator_dream -- she stops
  investigating, but why she was dreaming about the cult in the first
  place stays exactly as unexplained as the lore bible says it should.
- Lindqvist's and Hassan's event-chain flags (listened/silenced,
  empowered/sidelined) previously only rerouted flavor text on the way
  to identical win/lose copy. showOverlay() now picks a variant based on
  which flags are set, most-specific match first, so a run where both
  arcs resolved gets its own combined ending instead of falling through
  to whichever flag happened to be checked first.
- troende past nine was flavor-only even though the hard cap was removed
  in 0.3.0. Added troende_overflow (event) and bigger_venue (upgrade,
  gated behind nine_chairs_full + troende>=10) so outgrowing the
  basement has a real mechanical consequence, not just a stat that keeps
  climbing quietly.
- Möllan and Universitet (added in 0.6.0) had zero upgrade or event ties
  compared to Rosengård/Värnhem/Torso. Added mollan_regular +
  mollan_favor and universitet_seminar as a first pass -- lighter-touch
  than full area-gating (which would mean reshaping State.areas across
  engine/map/upgrades), but real content where there was none.
- Kaos events skewed entirely comic relief against standard events'
  near-total dread. Added four kaos entries in the heavier register
  (thirteen chimes, the mirror room, permanent lights on the Öresund
  seabed, the warm chair finally occupied) as a tonal counterweight,
  lower-weighted so they don't crowd out the existing jokes.

Added engine tests for all four new upgrades' gating and cost scaling.
21/21 tests pass, typecheck clean, build clean. Verified all six ending
variants (win base/hassan/lindqvist/combo/fors, lose base/hassan/
lindqvist) render correctly against a real build via injected save state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-08-08 21:04:23 +02:00
co-authored by Claude Sonnet 5
parent a420032594
commit e449cba288
6 changed files with 256 additions and 3 deletions
+50
View File
@@ -119,6 +119,56 @@ export const UPGRADES: Upgrade[] = [
available: s => s.upgrades.has('grand_ritual_prep'),
once: false,
},
{
id: 'favor_network',
name: 'Nätverket av tjänster',
desc: 'Kontakterna ni samlat på er är fler än ni insett. En tjänst ger en annan. Nätverket börjar arbeta för sin egen skull nu, inte bara för er räkning. +inflytande/s, och en ny, större sorts tjänst blir möjlig att kalla in.',
cost: () => ({ inflytande: 60 }),
effect: s => { s.inflytandeRate += 0.5; },
available: s => s.troende >= 3 && !s.upgrades.has('favor_network'),
once: true,
},
{
id: 'call_in_favor',
name: 'Kalla in en tjänst',
desc: 'Ring den som är skyldig er mest. Det är sällan gratis att bli påmind om vad man är skyldig — men det fungerar. Stor återhämtning av hemlighet, mot lite ökad kaos. Dyrare för varje gång ni ber om samma sak.',
cost: s => ({ inflytande: Math.round(50 * Math.pow(1.4, s.favorsCalled)) }),
effect: s => {
s.hemlighet = Math.min(100, s.hemlighet + 20);
s.kaos = Math.min(100, s.kaos + 6);
s.dread = Math.max(0, s.dread - 5);
s.favorsCalled += 1;
},
available: s => s.upgrades.has('favor_network'),
once: false,
},
{
id: 'neutralize_investigation',
name: 'Neutralisera utredningen',
desc: 'Kommissarie Fors har en chef. Chefen har en tjänst att göra gentjänst för. Utredningen läggs ner, officiellt av resursskäl. Fors fortsätter drömma om er ändå — hon skriver bara inte ner det längre.',
cost: () => ({ inflytande: 150, andakt: 300 }),
effect: s => { s.hemlighet = Math.min(100, s.hemlighet + 25); s.flags.add('fors_neutralized'); },
available: s => s.upgrades.has('favor_network') && s.usedEventIds.has('coc_investigator_dream') && !s.upgrades.has('neutralize_investigation'),
once: true,
},
{
id: 'bigger_venue',
name: 'Källaren är för liten',
desc: 'Ni flyttar till en större lokal, officiellt "för läsecirkeln." Fler rum, fler dörrar, fler saker att förklara för grannarna. Den varma stolen flyttar med. Den är fortfarande varm.',
cost: () => ({ andakt: 1200, dread: 150 }),
effect: s => { s.andaktRate += 2; s.kaosRate += 0.25; },
available: s => s.troende >= 10 && s.upgrades.has('nine_chairs_full') && !s.upgrades.has('bigger_venue'),
once: true,
},
{
id: 'mollan_favor',
name: 'Stamkund på Möllan',
desc: 'Handlaren ger er mer än rabatt nu. Hon ber inte om förklaringar, bara om att få vara med "när det händer." Ni har inte sagt ja. Ni har inte sagt nej heller.',
cost: () => ({ andakt: 250 }),
effect: s => { s.andaktRate += 0.4; },
available: s => s.usedEventIds.has('mollan_regular') && !s.upgrades.has('mollan_favor'),
once: true,
},
{
id: 'whisper_guidance',
name: 'Viskningen leder er',