diff --git a/CLAUDE.md b/CLAUDE.md index 3673ee7..0210bfb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,6 +27,7 @@ Svelte 5 + TypeScript + Vite. Public repository. | Acid Lab, production boost | `data/production.ts`, `lib/production.ts` (017) | | Money Fronts safe and heat | `data/fronts.ts`, `lib/fronts.ts` (018) | | Value bonus for owning a front | `ownedBonus` in `data/production.ts` (019) | +| Shut-down businesses (owned, not running) | `isRunning` in `lib/properties.ts` (020) | | Theme tokens | `src/app.css` (decision 009) | | CI, templates | `.github/` | | Skills: `handoff`, `finish-pr`; agent: `scout` | `.claude/` | diff --git a/docs/decisions/011-owned-properties.md b/docs/decisions/011-owned-properties.md index be44f3f..dc4a0d5 100644 --- a/docs/decisions/011-owned-properties.md +++ b/docs/decisions/011-owned-properties.md @@ -18,7 +18,9 @@ - **UI:** Settings has a Properties panel with every catalog entry: the name as the row label and a toggle button next to it, "Owned" (accent, filled) or "Not owned" (muted, outlined), with `aria-pressed` and the name as its accessible label, so the state reads at a glance (issue - #31; it replaced an "Own " checkbox). Upgrades appear once owned. The Businesses tab shows only owned properties, each panel with a gear + #31; it replaced an "Own " checkbox). Upgrades appear once owned. The panel spans the + page below Clock and Backup, with the properties in as many columns as fit (issue #38). The + Businesses tab shows only owned properties, each panel with a gear button that opens the same settings in place; closed, it summarises the bought upgrades. Both components take the catalog as a prop, so `#/kit` previews them with sample entries. diff --git a/docs/decisions/015-nightclub-warehouse.md b/docs/decisions/015-nightclub-warehouse.md index 5e0f600..5b9d70c 100644 --- a/docs/decisions/015-nightclub-warehouse.md +++ b/docs/decisions/015-nightclub-warehouse.md @@ -15,7 +15,7 @@ - **Only ownership is needed.** The source says technicians need no supplies, so goods do not depend on the linked business's stock or supplies. Goods whose business is not owned do not run and the card says "Locked". Two technicians on one type count once (the game allows one). - A shut-down business locks its goods too; marking one shut down is issue #38. + A shut-down business locks its goods too (decision 020). - **Saved state** (version 6): `nightclub` maps a goods id to crates, fractions included. Crates, not percent, so changing the floors keeps the count the game shows. Stock above the capacity (fewer floors set) stays until changed. diff --git a/docs/decisions/018-money-fronts.md b/docs/decisions/018-money-fronts.md index 2d8f2dd..00e3960 100644 --- a/docs/decisions/018-money-fronts.md +++ b/docs/decisions/018-money-fronts.md @@ -16,9 +16,8 @@ - **Payout** (`src/data/fronts.ts`), every in-game day (48 minutes of play time), up to $100,000: $750 per front ($1,500 after 15 laundering missions) plus a fixed amount for each other business owned, from the in-game safe screen (data comment has the sources). A front at - 100% heat pays nothing; the Car Wash at 100% stops the whole safe. LSOS counts every owned - business; the game skips biker businesses and the Bunker while shut down or not set up, which - the card says (shutting down: issue #38). + 100% heat pays nothing; the Car Wash at 100% stops the whole safe. A shut-down business + adds nothing (decision 020); one bought but not set up still counts in LSOS. - **Heat** per front, saved with the safe (`heat` by front id, data version 9). At the end of each day, after the payout, every front below 100% gains 10%, one less per other front below 100% (8% with all three). A laundering mission or Mr. Faber job adds 10% to the front it was diff --git a/docs/decisions/020-shut-down.md b/docs/decisions/020-shut-down.md new file mode 100644 index 0000000..004ef93 --- /dev/null +++ b/docs/decisions/020-shut-down.md @@ -0,0 +1,32 @@ +# 020: Shut-down businesses + +2026-10-15, issue #38. Builds on decisions 011, 012, 015 and 018. + +## Decision + +- **A flag apart from owned:** `shutDown` in a property's saved settings, next to `owned` and + the upgrades (data version 10). Absent means running, so older entries need no change. Owning + or selling keeps it, like the upgrades. +- **Only businesses the game can shut down** get a "Running"/"Shut down" toggle button next to + "Owned", shown while owned (`canShutDown` in `src/data/properties.ts`): the five biker + businesses and the Bunker, the ones decision 018 names. The Acid Lab is left out: no source + says it can be shut down. A button like "Owned", not an upgrade checkbox: it is a state of the + business, not something bought. +- **Shutting down empties the stock and keeps the supplies** (checked in game, 2026-10-15): + `clearShutDownStock` in `lib/production.ts`, applied by `setProperties` in the store whenever a + business goes from running to shut down. Starting it again changes nothing. +- **Shut down means "not running" everywhere** (`isRunning` in `lib/properties.ts`): + - production (decision 012) makes no stock and uses no supplies; the card is dimmed (darker, + colours kept) but readable, keeps its bars and value, has a grey "Shut down" note (not the yellow warning), + and hides the countdowns and the boost; + - nightclub goods (decision 015) whose only unlocking business is shut down count as locked, + so the Locked note and the best-setup suggestion follow; + - the Money Fronts safe (decision 018) gets nothing from it. +- **Not modelled:** whether a nightclub technician must be reassigned after the business starts + again. LSOS keeps the assignment and resumes counting. + +## Why + +Marking a shut-down business "Not owned" hid its stock and lost the card. The flag keeps both. +gta.wiki does not describe shutting down from the laptop (checked 2026-10-15); the nightclub +and Money Fronts rules rest on the sources in decisions 015 and 018 and the issue. diff --git a/docs/decisions/README.md b/docs/decisions/README.md index 06c64ca..2046958 100644 --- a/docs/decisions/README.md +++ b/docs/decisions/README.md @@ -30,3 +30,4 @@ free number, add one line below. **Replacing one:** write a new decision, then m - [017](017-production-boost.md) Acid Lab: optional far sale, value bonus (named product), no raids; production boost by units made or 24 real hours, once a day - [018](018-money-fronts.md) Money Fronts: one Car Wash safe card on the Safes tab, paid by the fronts and other businesses, heat per front (est.), missions and legal jobs - [019](019-owned-value-bonus.md) Money Front value bonus: owning Car Wash or Smoke on the Water adds 35% to Counterfeit Cash or Weed, far value adds the bonuses (est.), Helitours left out +- [020](020-shut-down.md) Shut-down businesses: a Running/Shut down button next to Owned for biker businesses and the Bunker; shutting down clears the stock; no production, card greyed, nightclub goods locked, nothing to the Money Fronts safe diff --git a/src/App.svelte b/src/App.svelte index 1f11a22..cfd201c 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -13,7 +13,7 @@ import { clocks } from './lib/clock.svelte' import './lib/production.svelte' import './lib/safes.svelte' - import { store } from './lib/store.svelte' + import { setProperties, store } from './lib/store.svelte' import { TABS, tabFromHash } from './lib/tabs' let hash = $state(location.hash) @@ -51,7 +51,7 @@ (store.state.properties = owned)} + onchange={setProperties} productions={PRODUCTION} businesses={store.state.businesses} now={clocks.now} @@ -74,7 +74,7 @@ safes={SAFES} catalog={PROPERTIES} owned={store.state.properties} - onchange={(owned) => (store.state.properties = owned)} + onchange={setProperties} stored={store.state.safes} onresync={(id, safe) => (store.state.safes = { ...store.state.safes, [id]: safe })} /> diff --git a/src/components/BusinessProduction.svelte b/src/components/BusinessProduction.svelte index a269662..c83e193 100644 --- a/src/components/BusinessProduction.svelte +++ b/src/components/BusinessProduction.svelte @@ -27,6 +27,8 @@ rate: ProductionRate | undefined /** The same rate if it can run on its own (its supply use is known). */ running: KnownRate | undefined + /** Shut down from its laptop: nothing is made or used until it runs again (issue #38). */ + shutDown?: boolean bars: Bars /** Wall-clock time, for supply deliveries. */ now: number @@ -47,6 +49,7 @@ production, rate, running, + shutDown = false, bars, now, editing, @@ -71,7 +74,9 @@ const boosting = $derived(boostRunning(boost, production.boost, now)) const nextBoost = $derived(production.boost ? nextBoostAt(boost, production.boost) : 0) const ahead = $derived( - running ? forecast(current, production, running, boosting ? boost!.unitsLeft : 0) : null, + running && !shutDown + ? forecast(current, production, running, boosting ? boost!.unitsLeft : 0) + : null, ) const percent = (value: number) => formatValue(value, 'percent') // Numbers resting on estimated rates say so (decision 013). The value also counts units made @@ -115,7 +120,7 @@ {/if} -{#if production.boost && running?.boostedMinutesPerUnit !== undefined} +{#if production.boost && running?.boostedMinutesPerUnit !== undefined && !shutDown}
{#if boosting} @@ -137,7 +142,11 @@ {/if} {/if} -{#if ahead} +{#if shutDown} +

+ Shut down. No stock is made and no supplies are used until you start it again. +

+{:else if ahead} {#if ahead.fullInMs !== null} diff --git a/src/components/Businesses.svelte b/src/components/Businesses.svelte index 1ab5bca..fb49100 100644 --- a/src/components/Businesses.svelte +++ b/src/components/Businesses.svelte @@ -21,7 +21,12 @@ type BoostsById, type BusinessBarsById, } from '../lib/production' - import { ownedProperties, upgradeValue, type OwnedProperties } from '../lib/properties' + import { + isShutDown, + ownedProperties, + upgradeValue, + type OwnedProperties, + } from '../lib/properties' import type { GoodsStock } from '../lib/nightclub' import type { Bars } from '../lib/resync' import { hashForTab } from '../lib/tabs' @@ -238,6 +243,7 @@ class="lift" class:lifted={moving === property.id} class:settling={settling === property.id} + class:shut={isShutDown(owned, property.id)} style:translate={moving === property.id ? `${lift.x}px ${lift.y}px` : undefined} > @@ -251,6 +257,7 @@ {production} rate={matchingRate(production, owned, property)} running={rateFor(production, owned, property)} + shutDown={isShutDown(owned, property.id)} bars={businesses[property.id] ?? emptyBars()} {now} editing={editing === property.id} @@ -314,6 +321,11 @@ outline-offset: -1px; } + /* A shut-down business is dimmed like a disabled control: same colours, darker (issue #38). */ + .lift.shut { + filter: brightness(0.65); + } + .lift.lifted { box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 0.5); pointer-events: none; diff --git a/src/components/MoneyFrontsCard.svelte b/src/components/MoneyFrontsCard.svelte index 900e2a3..71858ec 100644 --- a/src/components/MoneyFrontsCard.svelte +++ b/src/components/MoneyFrontsCard.svelte @@ -131,8 +131,8 @@ {money(parts.fronts + parts.others)} a day

- Fronts {money(parts.fronts)} + your other businesses {money(parts.others)}. Biker businesses and - the Bunker only count while set up and not shut down. + Fronts {money(parts.fronts)} + your other businesses {money(parts.others)}. A shut-down business + adds nothing.

diff --git a/src/components/NightclubWarehouse.svelte b/src/components/NightclubWarehouse.svelte index d0a4a6d..1683bfc 100644 --- a/src/components/NightclubWarehouse.svelte +++ b/src/components/NightclubWarehouse.svelte @@ -160,7 +160,7 @@

Locked. {locked.map((g) => g.label).join(', ')}: own the business that makes - {locked.length === 1 ? 'it' : 'them'} to start production. + {locked.length === 1 ? 'it' : 'them'}, and keep it running, to start production.

{/if} {#if setup.doubled} diff --git a/src/components/PropertyList.svelte b/src/components/PropertyList.svelte index 2f00589..2a65870 100644 --- a/src/components/PropertyList.svelte +++ b/src/components/PropertyList.svelte @@ -15,15 +15,24 @@ - {#each catalog as property (property.id)} - - {:else} -

No properties yet. They appear here as their trackers are built.

- {/each} +
+ {#each catalog as property (property.id)} + + {:else} +

No properties yet. They appear here as their trackers are built.

+ {/each} +

Trackers show only what you own. Upgrades change how fast they count.