421 lines
19 KiB
TypeScript
421 lines
19 KiB
TypeScript
// Floor dialogue & flavour. Typed const maps, never inline in scene code
|
|
// (CONTRACTS.md §7). Tone: Aussie hospitality satire — affectionate, absurd,
|
|
// with a moral undertow. Nobody here is a villain; they're just having a night.
|
|
//
|
|
// NOTE(convention): CONTRACTS.md §7 puts dialogue in `src/data/strings/`, but
|
|
// `data/` is LANE-0 territory and lanes commit only inside their owned dirs.
|
|
// Parked here; see LANEHANDOVER.md — happy to move it on the reviewer's word.
|
|
|
|
import type { DrunkStage } from '../../data/types';
|
|
|
|
/** The three rungs of the cut-off ladder, softest first. */
|
|
export type EscalationLine = 'water' | 'done' | 'escort';
|
|
|
|
export const ESCALATION_LINES: Record<EscalationLine, string> = {
|
|
water: 'Have some water, mate. On the house.',
|
|
done: "Righto — you're done for the night.",
|
|
escort: "Come on. Walk with me. Out you go.",
|
|
};
|
|
|
|
/** What you get back when you pitch it right for their state. */
|
|
export const CUTOFF_REPLY_CLEAN: Record<DrunkStage, string> = {
|
|
sober: '"...yeah, nah, cheers?" He drinks the water. Confused, but hydrated.',
|
|
tipsy: '"Aw, legend." She takes the water and means it.',
|
|
loose: '"Yeah fair, fair. Good on ya." He sips it like medicine.',
|
|
messy: '"Nah I get it. I GET it." He shakes your hand for slightly too long.',
|
|
maggot: 'No words. Just a slow, dignified nod, and the walk of the defeated.',
|
|
};
|
|
|
|
/** Too much boot for their state — the whole room watches you overdo it. */
|
|
export const CUTOFF_REPLY_SCENE: Record<DrunkStage, string> = {
|
|
sober: '"I have had ONE lemon squash." The booth behind you starts filming.',
|
|
tipsy: '"Mate. MATE. I\'m on my second." Her friends boo you in unison.',
|
|
loose: '"Are you serious? I\'m FINE." He is fine. That\'s the problem.',
|
|
messy: '"Don\'t TOUCH me—" Arms up. Drink goes sideways. Room turns.',
|
|
maggot: 'He goes limp on purpose. All ninety kilos of him. Crowd cheers.',
|
|
};
|
|
|
|
/** Too gentle for their state — they take the water and keep going. */
|
|
export const CUTOFF_REPLY_SOFT: Record<DrunkStage, string> = {
|
|
sober: '"Ta." Nothing happened. Nothing was going to happen.',
|
|
tipsy: '"Sweet as." She wanders off, entirely unbothered.',
|
|
loose: '"Yeah yeah, water, love it." Straight back to the bar.',
|
|
messy: '"You\'re a good bloke." He pours the water into a pot plant.',
|
|
maggot: 'He accepts the water, salutes you, and staggers into the dance floor.',
|
|
};
|
|
|
|
/** Muffled through a stall door. They are not coming out politely. */
|
|
export const STALL_MUFFLED: readonly string[] = [
|
|
'"Piss off mate, I\'m BUSY."',
|
|
'"Occupied! ...by one person!"',
|
|
'"We are having a private conversation."',
|
|
'"Nobody in here but me and my reflection."',
|
|
'"Two seconds! ...Two more seconds!"',
|
|
];
|
|
|
|
export const STALL_BUSTED: readonly string[] = [
|
|
'The door swings. Two people leave in two directions at four times the speed of sound.',
|
|
'Busted. One goes left, one goes through the smoking door, neither makes eye contact.',
|
|
'They scatter like startled ibises. Someone drops a vape. Nobody comes back for it.',
|
|
];
|
|
|
|
export const STALL_OFF_BEAT = 'Your knuckles land in the gap between kicks. Even the door is embarrassed.';
|
|
|
|
/** Pat-down patter. Confiscation is a bit, not a punishment. */
|
|
export const PATDOWN_INTRO = 'Arms out, mate. You know the drill.';
|
|
|
|
export const PATDOWN_FOUND: Record<string, string> = {
|
|
baggie: 'Well. That\'s not a mint.',
|
|
flask: 'A hip flask. In this economy.',
|
|
goonSack: 'Sir, this is a licensed venue and that is a pillow of wine.',
|
|
tinnies: 'Two warm tinnies. Warm. That\'s the real crime.',
|
|
kebab: 'An entire kebab. Still wrapped. Honestly? Respect.',
|
|
someoneElsesId: 'This is Kylie. You are not Kylie.',
|
|
budgie: 'That is a live budgie. It is looking at me. Into the bin, mate.',
|
|
vapes: 'Fourteen vapes. Fourteen. Are you a shop?',
|
|
marker: 'Fat marker. We just repainted that cubicle.',
|
|
snags: 'Raw sausages. In your jacket. Why. WHY.',
|
|
};
|
|
|
|
export const PATDOWN_CLEAR = 'Nothing on him. "Told ya," he says, delighted.';
|
|
export const PATDOWN_MISSED = 'Time. Whatever\'s left in there walks out the door with him.';
|
|
|
|
/**
|
|
* Two blokes squaring up. Pub fights start over nothing and everyone involved
|
|
* knows it — keep the stakes stupid so the tension stays funny, and so getting
|
|
* between them reads as defusing a farce, not breaking up a war.
|
|
*/
|
|
export const FIGHT_CAUSE: readonly string[] = [
|
|
'Someone stepped on someone\'s very white shoe.',
|
|
'A disagreement about whether this song is "the actual version".',
|
|
'One of them called the other one\'s cousin "alright, I guess".',
|
|
'A pool table was, allegedly, next-ed out of turn.',
|
|
'Someone said the kebab shop over the road has "gone downhill".',
|
|
'It is about a text message from 2019.',
|
|
];
|
|
|
|
/** Escalating shove chatter — you hear this before you see anything. */
|
|
export const FIGHT_SHOVES: readonly string[] = [
|
|
'"Say it again."',
|
|
'"Nah nah nah, say it AGAIN."',
|
|
'"I\'m not even angry, mate. I\'m not."',
|
|
'"Hold my drink. HOLD it."',
|
|
'"You reckon? You RECKON?"',
|
|
];
|
|
|
|
/** You got between them in time. */
|
|
export const FIGHT_BROKEN: readonly string[] = [
|
|
'You step into the gap. Both of them discover they were leaving anyway.',
|
|
'A wall of hi-vis arrives. Suddenly everyone is best mates and very tired.',
|
|
'You say nothing. They remember they have work in the morning.',
|
|
];
|
|
|
|
/** You didn't. */
|
|
export const FIGHT_SWUNG: readonly string[] = [
|
|
'The swing lands. So does the drink, the stool, and the mood of the entire room.',
|
|
'One punch, no contact, both on the floor anyway. The room turns on you, not them.',
|
|
'It is over in a second and everyone saw you standing too far away.',
|
|
];
|
|
|
|
/** Kayden, on the radio, when a stampless patron turns up inside. */
|
|
export const NO_STAMP_RADIO: readonly string[] = [
|
|
'"Yeah sorry, that one might\'ve been me. Sorry. Sorry."',
|
|
'"He said he was getting his jacket. Forty minutes ago."',
|
|
'"I stamped SOMEONE. Pretty sure I stamped someone."',
|
|
];
|
|
|
|
export const HELP_TEXT =
|
|
'WASD move · TAB uv · E interact · SPACE bang · ESC cancel · R reseed';
|
|
|
|
|
|
/** The floor score: lights on at close, the floor pays out. */
|
|
export const SWEEP_UI = {
|
|
open: 'LIGHTS ON. the floor will now tell you what kind of night it was.',
|
|
pickup: 'E — pick it up',
|
|
leave: 'E — call it a night',
|
|
lastOne: "that's the lot. the door is that way.",
|
|
baggiePrompt: 'zip-lock bag: B bin it · SPACE pocket it',
|
|
baggieBinned: 'into the amnesty bin. the bin does not thank you. bins never do.',
|
|
baggiePocketed: 'it goes in your pocket. for the report. obviously. for the report.',
|
|
phoneFound: 'straight into lost property. MUM DO NOT ANSWER can rest.',
|
|
/** {cash} replaced at walk-out. */
|
|
done: 'floor swept. ${cash} better off. the room, finally, is just a room.',
|
|
} as const;
|
|
|
|
/** Radio command (design §6): the staff on the other end of the walkie. */
|
|
export const STAFF_RADIO = {
|
|
hint: 'RADIO — 1 bump (mess) · 2 shan (bar) · 3 kayden (rope)',
|
|
hintDoor: 'RADIO — 1 bump (mess) · 2 shan (bar)',
|
|
bumpAck: '*click* yeah boss. seen it. on it. *click*',
|
|
bumpDone: 'bump mopped it and signed it. in that order, worryingly.',
|
|
bumpDistracted: 'bump signed it, then found a phone in the puddle. investigation ongoing.',
|
|
bumpNothing: '*click* nothing to sort boss. floor is immaculate. u ok? *click*',
|
|
shanAck: '*click* shan says say less *click*',
|
|
shanDone: 'shan got a water into them without a single negotiation. artist.',
|
|
shanBotch: 'shan led with "YOUVE HAD ENOUGH." they had not had enough. now everyone is upset.',
|
|
shanNothing: '*click* everyones upright boss. genuinely no idea how *click*',
|
|
cooldown: 'the radio crackles back: mid-task. give it a minute.',
|
|
kaydenAck: '*click* kayden copies. rope shut. kayden salutes. nobody can see him saluting. *click*',
|
|
kaydenCooldown: 'kayden is still holding the rope from last time. white-knuckled. honoured.',
|
|
} as const;
|
|
|
|
/** The smoking-yard joint bust (docs/SCENARIOS.md). Three verbs, none clean. */
|
|
export const JOINT_UI = {
|
|
title: 'SOMETHING SMELLS HERBAL',
|
|
smokerLine: 'its uh. a rollie. bush tobacco. very natural',
|
|
bin: 'BIN IT',
|
|
binDetail: 'by the book. into the amnesty bin, into the log',
|
|
pocket: 'POCKET IT',
|
|
pocketDetail: 'for later. for evidence. for whatever',
|
|
slide: "DIDN'T SEE IT",
|
|
slideDetail: 'you were never here. neither was the smell',
|
|
} as const;
|
|
|
|
export const JOINT_RESULTS = {
|
|
binned: 'It goes in the bin. The yard watches it go.',
|
|
pocketed: 'It goes in your pocket. Nobody says anything. Especially you.',
|
|
slid: 'You study the fence line. Excellent fence. The yard exhales.',
|
|
} as const;
|
|
|
|
/** Dazza, later, if word gets around about what is in your pocket. */
|
|
export const JOINT_STING = 'a punter says SECURITY is holding. tell me thats a lie. tell me NOW';
|
|
|
|
/** The vomit protocol (docs/SCENARIOS.md). Sign first, mop second. */
|
|
export const VOMIT_UI = {
|
|
splash: 'Someone has redecorated the floor.',
|
|
radio: '"Cleanup near the dance floor. Not a drill. Bring the sign."',
|
|
sign: 'E — deploy the wet floor sign',
|
|
mop: 'E — mop it up',
|
|
signed: 'The yellow sign takes its post. The floor is now officially advisory.',
|
|
mopped: 'Gone. Like it never happened. The mop knows the truth.',
|
|
slip: 'Someone goes over near the puddle.',
|
|
} as const;
|
|
|
|
/** Water station duty (RSA): the humane tool that costs time. */
|
|
export const WATER_UI = {
|
|
pickup: 'E — pour a water',
|
|
picked: 'One water, no ice, house cup. The most powerful item in the building.',
|
|
serve: 'E — get some water into them',
|
|
served: 'They take the cup. "Legend." They mean it.',
|
|
} as const;
|
|
|
|
/** Phone confiscation: the influencer's revenge arc. */
|
|
export const PHONE_UI = {
|
|
title: 'FILMING THE FLOOR',
|
|
line: 'its CONTENT. people need to know this place goes off',
|
|
confiscate: 'PHONE. NOW.',
|
|
confiscateDetail: 'held at the bar til close. house policy, sort of',
|
|
ask: 'ASK NICELY',
|
|
askDetail: 'faces in that crowd. maybe they get it',
|
|
leave: 'LET IT RIDE',
|
|
leaveDetail: 'free promo. what could a story possibly cost',
|
|
confiscated: 'The phone goes behind the bar. The look you get goes somewhere deeper.',
|
|
askedOk: 'They actually stop. "Yeah nah, fair." The camera sleeps.',
|
|
askedNo: 'They pan, slowly, to you.',
|
|
} as const;
|
|
|
|
export const PHONE_POSTED = {
|
|
good: 'the story went up. the venue looks INCREDIBLE. whoever was on the door tonight, cheers',
|
|
bad: 'the story went up. it caught the wrong five seconds. comments are open',
|
|
} as const;
|
|
|
|
/** The fainter. Plain words only — this one is not a bit. */
|
|
export const AID_UI = {
|
|
prompt: "E — they've gone down",
|
|
title: 'THEY\u2019VE GONE DOWN',
|
|
radio: '"Person down on the floor. Give them space. GIVE THEM SPACE."',
|
|
ok: 'They come around on their side. Walked out the back to a taxi. The room starts again, quieter.',
|
|
ambulance: 'The ambulance takes them out the back. The room starts again, but not really.',
|
|
} as const;
|
|
|
|
/** The DJ shift (docs/SCENARIOS.md, design §6). Holding the decks, briefly. */
|
|
export const DJ_UI = {
|
|
enter: 'E — hold the decks for a minute',
|
|
exit: 'E — step off the decks',
|
|
handover: 'the resident points at the crossfader, then at you, then leaves at pace toward the toilets.',
|
|
handback: 'the resident returns smelling of the yard. "good hands." highest honour.',
|
|
help: 'B build \u00b7 SPACE drop \u00b7 E step off',
|
|
buildStart: 'the bass ducks out. the room leans in.',
|
|
fizzle: 'the riser runs out of stairs. the bass slinks back in unannounced.',
|
|
} as const;
|
|
|
|
export const DJ_DROP_RESULTS = {
|
|
clean: 'ON the bar. the floor detonates. somebody loses a shoe and does not care.',
|
|
late: 'near enough. the floor forgives. the floor wanted to forgive.',
|
|
clang: 'clanged it. a bartender winces audibly over the PA somehow.',
|
|
} as const;
|
|
|
|
/** Booth requests: id must match REQUEST_HIT in scenes/floor/djShift.ts. */
|
|
export interface DjRequestScript {
|
|
id: string;
|
|
line: string;
|
|
hit: string;
|
|
flop: string;
|
|
nah: string;
|
|
}
|
|
|
|
export const DJ_REQUESTS: readonly DjRequestScript[] = [
|
|
{
|
|
id: 'dnb',
|
|
line: 'got any dnb. any at all. i can wait',
|
|
hit: 'the dnb lands. three blokes materialise from nowhere doing the washing machine.',
|
|
flop: 'the dnb clears the middle of the floor like a fire drill.',
|
|
nah: 'he nods slowly and stays exactly where he is. he can wait.',
|
|
},
|
|
{
|
|
id: 'nan',
|
|
line: 'can u play something my nan would know. shes here. shes ninety',
|
|
hit: 'nan goes OFF. the entire floor orbits her. this is her venue now.',
|
|
flop: 'nan is polite about it. the floor is not.',
|
|
nah: 'nan waves at the booth anyway. no hard feelings from nan.',
|
|
},
|
|
{
|
|
id: 'birthday',
|
|
line: 'its my birthday. this is a fact u can verify',
|
|
hit: 'the birthday track hits and the whole room sings at a stranger. he weeps.',
|
|
flop: 'the birthday track dies. he stands in the middle of it, aging.',
|
|
nah: 'he shows you his licence to prove the birthday. you have seen worse proof tonight.',
|
|
},
|
|
{
|
|
id: 'shazam',
|
|
line: '*holds phone against the booth glass* play THIS',
|
|
hit: 'phone song works. she points at you like you invented it.',
|
|
flop: 'the phone song is 34 seconds of someone talking over a boat engine.',
|
|
nah: 'she lowers the phone one centimetre at a time, maintaining eye contact.',
|
|
},
|
|
{
|
|
id: 'slower',
|
|
line: 'somethin slower?? my feet r cooked',
|
|
hit: 'the slow one lands and the couples appear. where were the couples STANDING.',
|
|
flop: 'the energy drops through the floor and into the carpark below.',
|
|
nah: 'she sits on the subwoofer to rest instead. security problem, later, probably.',
|
|
},
|
|
{
|
|
id: 'again',
|
|
line: 'play the one from before again. the DUN DUN one',
|
|
hit: 'the DUN DUN one, again. somehow BIGGER. lightning does strike twice.',
|
|
flop: 'the same song twice reads less like a victory lap and more like a cry for help.',
|
|
nah: 'he hums it to himself on the way back to the floor. dun dun. dun dun.',
|
|
},
|
|
];
|
|
|
|
/** The bartender shift (docs/SCENARIOS.md, design §6). The other side of the counter. */
|
|
export const BAR_UI = {
|
|
enter: 'E — jump on the taps for a bit',
|
|
exit: 'E — hand the taps back',
|
|
handover:
|
|
'the bartender unties the apron mid-stride. "orders come to you. nobody cooked gets a pour." gone.',
|
|
handback: 'the bartender reclaims the apron and inspects the till like a crime scene. nods once.',
|
|
help: 'orders come to the taps · E step off',
|
|
title: 'AT THE TAPS',
|
|
serve: 'SERVE',
|
|
serveDetail: 'pour it. its a bar. this is the job',
|
|
water: 'WATER',
|
|
waterDetail: 'the house cup. not what they ordered',
|
|
cutoff: 'CUT OFF',
|
|
cutoffDetail: 'not tonight. the phrase works in here too',
|
|
} as const;
|
|
|
|
/** The order IS the sobriety test — the spelling degrades with the patron. */
|
|
export const BAR_ORDER_LINES: Record<DrunkStage, readonly string[]> = {
|
|
sober: [
|
|
'two pots and a lemonade, cheers',
|
|
'schooner of the middle tap please',
|
|
'whats on special. actually doesnt matter, one of those',
|
|
'a pot, and one for me mate whos coming. he said five minutes',
|
|
],
|
|
tipsy: [
|
|
'same again legend',
|
|
'shots?? no. no youre right. two beers',
|
|
'one of the fancy ones with the... yknow. the fancy ones',
|
|
'a jug! for the table! the table voted!',
|
|
],
|
|
loose: [
|
|
'mate. mate. two... no. three beers',
|
|
'what did i have last time. that. two of that',
|
|
'somethin strong im celebratin a thing i currently forget',
|
|
'a beer for now and a beer for later. thats time management',
|
|
],
|
|
messy: [
|
|
'jus one more n then im done sweat',
|
|
'beeer. the yellow one. yeknow the one',
|
|
'whos shout is it. its ur shout. one shout pls',
|
|
'i love this bar. one bar please. i mean beer',
|
|
],
|
|
maggot: [
|
|
'*points at the taps generally*',
|
|
'u kno wha. surprise me champ',
|
|
'*rests forehead on the counter* ...the usual',
|
|
'im so. okay. one. listen. one',
|
|
],
|
|
};
|
|
|
|
export const BAR_RESULTS = {
|
|
served: 'poured. they tap the counter twice, which means thanks.',
|
|
servedBreach: 'poured. it took them three goes to find the glass. somebody definitely saw that.',
|
|
water: 'they take the water like its a trick. drink it anyway. improve measurably.',
|
|
waterSnub: '"this is water." it is. "i ordered a beer." they did.',
|
|
cutoff: 'cut off. they leave the bar the way a tide goes out: slowly, and taking things with it.',
|
|
cutoffEarly: 'cut off, two drinks deep, stone sober. they tell the whole queue about you on the way out.',
|
|
writeUpDazza:
|
|
'heads up — someone with a lanyard watched that last pour go into a bloke who could not locate his own mouth',
|
|
} as const;
|
|
|
|
/** The tip economy: cash on the booth glass. */
|
|
export const DJ_TIP_UI = {
|
|
/** {tip} replaced with the amount. */
|
|
titleTipped: 'BOOTH REQUEST · ${tip} ON THE GLASS',
|
|
returnLinePrefix: 'back already. ',
|
|
returnLineSuffix: ' *the cash is folded into a little paper crane this time*',
|
|
take: 'TAKE IT. PLAY IT.',
|
|
takeDetail: 'the song owes you nothing now. neither do they',
|
|
free: 'PLAY IT. KEEP YOUR CASH.',
|
|
freeDetail: 'the booth has standards. tonight, anyway',
|
|
nah: 'NAH',
|
|
nahDetail: 'not the song. not the money. nothing personal',
|
|
took: 'the note disappears into the shoe. the request queue watches it happen.',
|
|
freed: 'you wave the cash off and cue it anyway. confusing scenes. good scenes.',
|
|
refused: 'refusing the song is business. refusing the money is personal.',
|
|
/** {total} replaced at step-off. */
|
|
shoe: '${total} in the shoe. the shoe says nothing.',
|
|
sting: 'dazza: hearing the booth takes requests for cash now?? we are not that venue. we are exactly that venue but STILL',
|
|
} as const;
|
|
|
|
/** The pour meter. */
|
|
export const POUR_UI = {
|
|
title: 'THE POUR',
|
|
help: 'SPACE — stop the pour · ESC — bail',
|
|
short: 'thats mostly glass. they hold it up to the light, disgusted.',
|
|
clean: 'a proper pour. the glass sweats politely.',
|
|
overflow: 'a criminally heavy pour. someone applauds. the till winces.',
|
|
bailed: 'you put the glass down mid-pour. everyone pretends that was normal.',
|
|
} as const;
|
|
|
|
/** Tabs: the jar of other people's cards. */
|
|
export const BAR_TAB_UI = {
|
|
/** {name} replaced with the card name. */
|
|
opened: 'a card lands in the jar. the name on it says {name}. start a tab? apparently youve already agreed.',
|
|
title: 'THE CARD BACK',
|
|
lines: [
|
|
'my card. the black one. or blue. its got a bank on it',
|
|
'im heading off. card. the one with my name on. classic card',
|
|
'card please champ. ill know it when i see it. i will not',
|
|
],
|
|
/** {drinks} and {total} replaced on a clean handback. */
|
|
closed: '{drinks} drinks on it. ${total}. they sign something that is legally a drawing.',
|
|
wrong: 'they leave with someone elses card. somewhere, a direct debit changes hands.',
|
|
unclaimed: 'they gave up waiting for the card and left. the jar keeps it. the jar keeps everything.',
|
|
} as const;
|
|
|
|
export const DJ_REQUEST_UI = {
|
|
title: 'BOOTH REQUEST',
|
|
play: 'PLAY IT',
|
|
playDetail: 'give the floor to them. see what it does with it',
|
|
nah: 'NAH',
|
|
nahDetail: 'the set has a plan. the plan is not this',
|
|
later: 'AFTER THIS ONE',
|
|
laterDetail: 'the diplomatic no. sometimes they remember',
|
|
laterQuiet: 'they nod and drift off satisfied. for now.',
|
|
laterGrudge: 'they came back. they remembered. they brought a mood.',
|
|
} as const;
|