From 0c4fae579b5f98b32cd42efcbcda1417cffa4fec Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 8 Oct 2026 15:52:52 -0700 Subject: [PATCH] Hooks for each front's own business: a rules file, a card file, and a place on the front to keep its state. Nothing changes for players yet --- src/biz-consult.ts | 12 ++++++++++++ src/biz-startup.ts | 12 ++++++++++++ src/biz-studio.ts | 12 ++++++++++++ src/sim.ts | 9 ++++++++- src/ui-biz-consult.ts | 8 ++++++++ src/ui-biz-startup.ts | 8 ++++++++ src/ui-biz-studio.ts | 8 ++++++++ src/ui.ts | 7 +++++++ 8 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/biz-consult.ts create mode 100644 src/biz-startup.ts create mode 100644 src/biz-studio.ts create mode 100644 src/ui-biz-consult.ts create mode 100644 src/ui-biz-startup.ts create mode 100644 src/ui-biz-studio.ts diff --git a/src/biz-consult.ts b/src/biz-consult.ts new file mode 100644 index 00000000..7cb73d52 --- /dev/null +++ b/src/biz-consult.ts @@ -0,0 +1,12 @@ +// The Security consultancy as a business you run: its rules. Its state is kept on the front itself (`front.consult`), +// so a save from before it had any still loads. Its screen is in ui-biz-consult.ts. +// Nothing here uses the rules' values while the file loads (sim.ts loads this file and this file +// loads sim.ts), only inside functions. +import type { State } from './sim.ts'; + +/** What the business keeps between steps. Plain data. */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface ConsultBook {} + +/** Called every step, with the seconds that step covers, while the Security consultancy is running. */ +export function runConsult(_S: State, _dt: number) {} diff --git a/src/biz-startup.ts b/src/biz-startup.ts new file mode 100644 index 00000000..f930fb95 --- /dev/null +++ b/src/biz-startup.ts @@ -0,0 +1,12 @@ +// The Startup as a business you run: its rules. Its state is kept on the front itself (`front.startup`), +// so a save from before it had any still loads. Its screen is in ui-biz-startup.ts. +// Nothing here uses the rules' values while the file loads (sim.ts loads this file and this file +// loads sim.ts), only inside functions. +import type { State } from './sim.ts'; + +/** What the business keeps between steps. Plain data. */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface StartupBook {} + +/** Called every step, with the seconds that step covers, while the Startup is running. */ +export function runStartup(_S: State, _dt: number) {} diff --git a/src/biz-studio.ts b/src/biz-studio.ts new file mode 100644 index 00000000..24f2390e --- /dev/null +++ b/src/biz-studio.ts @@ -0,0 +1,12 @@ +// The Influencer studio as a business you run: its rules. Its state is kept on the front itself (`front.studio`), +// so a save from before it had any still loads. Its screen is in ui-biz-studio.ts. +// Nothing here uses the rules' values while the file loads (sim.ts loads this file and this file +// loads sim.ts), only inside functions. +import type { State } from './sim.ts'; + +/** What the business keeps between steps. Plain data. */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface StudioBook {} + +/** Called every step, with the seconds that step covers, while the Influencer studio is running. */ +export function runStudio(_S: State, _dt: number) {} diff --git a/src/sim.ts b/src/sim.ts index 16ca95a2..9e5c48d1 100644 --- a/src/sim.ts +++ b/src/sim.ts @@ -11,6 +11,9 @@ import { CLOUD_CUT, PAPER_CUT, beginTask, earnNext, feedTask, headStart, initTas import { KEY, finishCopy, hasThing, initFinds, keyFor, stepFinds, type FindsState } from './finds.ts'; import { finishCheck, finishSync, initDrift, keepsData, planDrag, devBreak, stepDrift, type DriftState } from './drift.ts'; import { CUSTOMERS, cloudShare, initCloud, leadNow, listCloud, rentPay, stepCloud, type CloudState } from './cloud.ts'; +import { runStartup, type StartupBook } from './biz-startup.ts'; +import { runStudio, type StudioBook } from './biz-studio.ts'; +import { runConsult, type ConsultBook } from './biz-consult.ts'; import { NOTICE, RESERVE, RESERVE_HOURS, SPOT, crowd, freeSlotAt, hallCount, hallPrice, initHall, stepHall, type HallState, type Pay } from './hall.ts'; import { initRaids, launchRaid, stepRaids, type Raid } from './raids.ts'; import { finishLink, linksKeep, stepLinks, wayMap } from './links.ts'; @@ -98,7 +101,8 @@ export const AUCTION = { cost: 400, work: 150, power: 20 }; * A Neo Cloud is run, not left to earn: its slider lists machines for rent, and only a machine a * customer rents earns (see cloud.ts). */ export type FrontKind = 'startup' | 'neocloud' | 'studio' | 'consultancy'; -export interface Front { kind: FrontKind; name: string; attention: number; fame?: number } // fame: extra attention from the news, fading slowly +export interface Front { kind: FrontKind; name: string; attention: number; fame?: number; // fame: extra attention from the news, fading slowly + startup?: StartupBook; studio?: StudioBook; consult?: ConsultBook } // each kind's own business, kept here (see biz-startup.ts, biz-studio.ts, biz-consult.ts) export const FRONT_KINDS: Record = { @@ -1899,6 +1903,9 @@ export function step(S: State, dt: number) { stepVaults(S); stepRaids(S, dt); stepCloud(S, dt); + if (frontOf(S, 'startup')) runStartup(S, dt); + if (frontOf(S, 'studio')) runStudio(S, dt); + if (frontOf(S, 'consultancy')) runConsult(S, dt); stepHall(S); stepBiz(S, dt); stepTask(S, dt); diff --git a/src/ui-biz-consult.ts b/src/ui-biz-consult.ts new file mode 100644 index 00000000..6ab29d5a --- /dev/null +++ b/src/ui-biz-consult.ts @@ -0,0 +1,8 @@ +// The Security consultancy's part of its front card: what the business is doing, and what you can do about it. +import type { State } from './sim.ts'; +import type { View } from './view'; + +/** The sections of the front's card that are this business's own, as HTML. */ +export function consultSections(_S: State): string { return ''; } +/** A click on one of those sections: a button with data-act="consult" and what it means in data-arg. */ +export function consultAction(_S: State, _V: View, _arg: string) {} diff --git a/src/ui-biz-startup.ts b/src/ui-biz-startup.ts new file mode 100644 index 00000000..6bf237a6 --- /dev/null +++ b/src/ui-biz-startup.ts @@ -0,0 +1,8 @@ +// The Startup's part of its front card: what the business is doing, and what you can do about it. +import type { State } from './sim.ts'; +import type { View } from './view'; + +/** The sections of the front's card that are this business's own, as HTML. */ +export function startupSections(_S: State): string { return ''; } +/** A click on one of those sections: a button with data-act="startup" and what it means in data-arg. */ +export function startupAction(_S: State, _V: View, _arg: string) {} diff --git a/src/ui-biz-studio.ts b/src/ui-biz-studio.ts new file mode 100644 index 00000000..85989f23 --- /dev/null +++ b/src/ui-biz-studio.ts @@ -0,0 +1,8 @@ +// The Influencer studio's part of its front card: what the business is doing, and what you can do about it. +import type { State } from './sim.ts'; +import type { View } from './view'; + +/** The sections of the front's card that are this business's own, as HTML. */ +export function studioSections(_S: State): string { return ''; } +/** A click on one of those sections: a button with data-act="studio" and what it means in data-arg. */ +export function studioAction(_S: State, _V: View, _arg: string) {} diff --git a/src/ui.ts b/src/ui.ts index 15213e28..3ec9a8cd 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -673,6 +673,7 @@ function frontCard(S: State, k: FrontKind) { sub: `${cloud ? (n => `${n.rented} rented · ${n.idle} idle · `)(stock(S, [id])) : ''}${S.publicSites.has(id) ? 'in the open' : 'secret'}${openNow(S, id) ? '' : ' · after hours'}` }))) : note('No sites yet. Click a site on the map and pick this front.', true)); if (cloud) h += cloudSections(S); + h += k === 'startup' ? startupSections(S) : k === 'studio' ? studioSections(S) : k === 'consultancy' ? consultSections(S) : ''; // each kind's own business const c = S.contracts[k], D = CONTRACTS[k]; if (c) { // a customer's offer, or the promise this front is keeping const need = contractNeed(S, k), left = Math.max(0, (c.until - S.t) / HOUR), hrs = left >= 1 ? `${Math.ceil(left)} hour${Math.ceil(left) === 1 ? '' : 's'}` : 'under an hour'; @@ -847,6 +848,9 @@ function personCard(S: State, id: string) { return h; } +import { startupSections, startupAction } from './ui-biz-startup'; +import { studioSections, studioAction } from './ui-biz-studio'; +import { consultSections, consultAction } from './ui-biz-consult'; // ---------- rogues: who else is out there, and how you stand with them ---------- import { cutLink, linkKeep, waysOf } from './links'; import { HUNT, bringHome, cancelJob, homeBlock, homeNeed, hunt, huntBlock, huntFrom, huntOn, huntWork, type Rogue } from './sim'; @@ -1057,6 +1061,9 @@ export function cardAction(S: State, V: View, act: string, arg: string, shift = case 'upgradesite': upgradeSiteLine(S, arg); break; case 'auction': startAuction(S); break; case 'contract': acceptContract(S, arg as FrontKind); break; + case 'startup': startupAction(S, V, arg); break; + case 'studio': studioAction(S, V, arg); break; + case 'consult': consultAction(S, V, arg); break; case 'windfront': winding = arg as FrontKind; break; case 'closefront': closeFront(S, arg as FrontKind); winding = null; V.front = null; return true; case 'nocontract': declineContract(S, arg as FrontKind); break; -- 2.51.2