Make standing cost money to keep, in both settings
Each pack declares a lifestyle tier, bought on the second rung and charged for every cycle after: Corporate Ladder's car and address, the Frontier's bay and the room over the Ellis place. Falling behind what the job expects costs standing, in steps that steepen as standing rises. A Dispatch coordinator keeping up fully nets -21 a week and earns the difference out of the days. No engine change; the only interface change is a tier display format. Sized by measurement, not feel (DECISIONS #36): a -2/week penalty is invisible against Dispatch's standing gains, and a player who chases standing every turn beats any flat penalty — 99 standing while buying nothing, and $2,245 richer than one who kept up. Hence the top step. Two defects fixed on the way. The conformance suite excluded debt from the economic baseline by matching /debt|owed|loan/i on path names, which would have counted every lifestyle tier into it; packs now declare tuning.baselineExcludes. And 'the promotion leaves a player better off' pooled end balances across archetypes that do not spend alike, so it measured the mix — it is now derived from the upkeep arithmetic. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RxdJFbLq1rBKsUeticGV1g
This commit is contained in:
co-authored by
Claude Opus 5
parent
7f20be83e8
commit
5d645e6452
@@ -485,6 +485,65 @@ export const dispatch = [
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
// The cost of standing, offered rather than imposed. Buying nothing is
|
||||
// always playable and always cheaper; it is Dispatch's weekly "looking the
|
||||
// part" charge that makes it a real decision instead of a shop.
|
||||
id: 'the_car_lot',
|
||||
stage: 'dispatch',
|
||||
weight: 45,
|
||||
cooldown: 6,
|
||||
requires: [{ path: 'lifestyle', op: '<', value: 2 }],
|
||||
description:
|
||||
'Marlene mentions, not quite to you, that the coordinator before last ' +
|
||||
'drove something with a roof rack, and that people noticed when he ' +
|
||||
'stopped. There is a lot on Ninth with a sign about payments.',
|
||||
options: [
|
||||
{
|
||||
id: 'buy_the_car',
|
||||
label: 'Put money down on the car.',
|
||||
requires: [
|
||||
{ path: 'lifestyle', op: '==', value: 0 },
|
||||
{ path: 'money', op: '>=', value: 450 },
|
||||
],
|
||||
result:
|
||||
'It is four years old and the radio only gets one station, and on ' +
|
||||
'Monday two people who have never spoken to you ask about it.',
|
||||
effects: [
|
||||
{ path: 'money', op: 'add', value: -450 },
|
||||
{ path: 'lifestyle', op: 'set', value: 1 },
|
||||
{ path: 'reputation', op: 'add', value: 3 },
|
||||
{ path: 'notable', op: 'push', value: 'Bought a car with a roof rack.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'trade_up',
|
||||
label: 'Trade up, and take the lease on the better side of the park.',
|
||||
requires: [
|
||||
{ path: 'lifestyle', op: '==', value: 1 },
|
||||
{ path: 'money', op: '>=', value: 900 },
|
||||
],
|
||||
result:
|
||||
'The address is two stops closer and four hundred a month dearer. ' +
|
||||
'Nobody says anything about it, which is the entire point of it.',
|
||||
effects: [
|
||||
{ path: 'money', op: 'add', value: -900 },
|
||||
{ path: 'lifestyle', op: 'set', value: 2 },
|
||||
{ path: 'reputation', op: 'add', value: 5 },
|
||||
{ path: 'notable', op: 'push', value: 'Moved to the better side of the park.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'keep_the_bus_pass',
|
||||
label: 'Keep the bus pass. The bus is fine.',
|
||||
result:
|
||||
'The bus is fine. You read two chapters a day on it, which is two ' +
|
||||
'more than anybody on Ninth manages.',
|
||||
effects: [{ path: 'skills.logistics', op: 'add', value: 1 }],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default dispatch;
|
||||
|
||||
@@ -45,6 +45,10 @@ export const corporateLadder = {
|
||||
'reputation': { initial: 50, min: 0, max: 100 },
|
||||
'skills.negotiation': { initial: 5, min: 0, max: 100 },
|
||||
'skills.logistics': { initial: 5, min: 0, max: 100 },
|
||||
// What standing costs to keep. Nothing forces a player to climb this, but
|
||||
// Dispatch charges standing for staying at the bottom of it — see the
|
||||
// "Looking the part" entries in upkeep, and DECISIONS #36.
|
||||
'lifestyle': { initial: 0, min: 0, max: 2 },
|
||||
'flags.took_loan': { initial: false },
|
||||
'flags.holds_the_envelope': { initial: false },
|
||||
'flags.covered_for_trevor': { initial: false },
|
||||
@@ -96,6 +100,76 @@ export const corporateLadder = {
|
||||
effects: [{ path: 'money', op: 'add', value: 1260 }],
|
||||
},
|
||||
{ label: 'Rent', every: 7, offset: 7, effects: [{ path: 'money', op: 'add', value: -455 }] },
|
||||
// What the job expects of you, and what meeting that expectation costs.
|
||||
// Dispatch nets +49 a week; a coordinator with the car is +19, and one
|
||||
// with the car and the address is -21 and has to earn the difference out
|
||||
// of the days themselves. That is the answer to "money stops mattering
|
||||
// late": it stops mattering only if standing is free to keep.
|
||||
{
|
||||
label: 'Car payment and parking',
|
||||
every: 7,
|
||||
offset: 7,
|
||||
requires: [{ path: 'lifestyle', op: '>=', value: 1 }],
|
||||
effects: [{ path: 'money', op: 'add', value: -30 }],
|
||||
},
|
||||
{
|
||||
label: 'The better address',
|
||||
every: 7,
|
||||
offset: 7,
|
||||
requires: [{ path: 'lifestyle', op: '>=', value: 2 }],
|
||||
effects: [{ path: 'money', op: 'add', value: -40 }],
|
||||
},
|
||||
// The pressure that makes the spending a choice rather than a vanity. Both
|
||||
// are gated on Dispatch: the mailroom pays too little for this to be
|
||||
// anything but a trap, and "later in a career" is the point.
|
||||
{
|
||||
label: 'Looking the part',
|
||||
every: 7,
|
||||
offset: 7,
|
||||
requires: [
|
||||
{ path: 'stage', op: '==', value: 'dispatch' },
|
||||
{ path: 'lifestyle', op: '<', value: 1 },
|
||||
],
|
||||
effects: [{ path: 'reputation', op: 'add', value: -4 }],
|
||||
},
|
||||
{
|
||||
// Standing above sixty-five is a thing you are seen to be, and being seen
|
||||
// to be it runs on a better address than a coordinator's first one.
|
||||
//
|
||||
// Sized by measurement, not by feel. At -2 a week this was invisible:
|
||||
// Dispatch hands out standing several points at a time, so a coordinator
|
||||
// who bought nothing still finished pinned at 100 and the charge may as
|
||||
// well not have existed. At -6, with the entry above, a non-buyer settles
|
||||
// in the low seventies while somebody keeping up finishes at 100 — the
|
||||
// ceiling is real and money is what lifts it.
|
||||
label: 'Looking the part',
|
||||
every: 7,
|
||||
offset: 7,
|
||||
requires: [
|
||||
{ path: 'stage', op: '==', value: 'dispatch' },
|
||||
{ path: 'reputation', op: '>=', value: 65 },
|
||||
{ path: 'lifestyle', op: '<', value: 2 },
|
||||
],
|
||||
effects: [{ path: 'reputation', op: 'add', value: -6 }],
|
||||
},
|
||||
{
|
||||
// The top step, and the one that makes the whole thing a choice rather
|
||||
// than a tax on carelessness. Without it, a player who spends every turn
|
||||
// chasing standing simply out-earns the charge: measured, they held 99
|
||||
// while never buying anything, and finished $2,245 richer than a player
|
||||
// who kept up — so the lifestyle was a pure loss to anybody paying
|
||||
// attention. With it they plateau in the low eighties. What money buys
|
||||
// up here is the last fifteen points, which cannot be worked for.
|
||||
label: 'Looking the part',
|
||||
every: 7,
|
||||
offset: 7,
|
||||
requires: [
|
||||
{ path: 'stage', op: '==', value: 'dispatch' },
|
||||
{ path: 'reputation', op: '>=', value: 80 },
|
||||
{ path: 'lifestyle', op: '<', value: 2 },
|
||||
],
|
||||
effects: [{ path: 'reputation', op: 'add', value: -14 }],
|
||||
},
|
||||
// The service charge steps up with the size of the debt, so the spiral
|
||||
// tightens instead of flattening out. A step function in data costs the
|
||||
// engine nothing; a percentage would have needed a multiply operation.
|
||||
@@ -132,6 +206,9 @@ export const corporateLadder = {
|
||||
mailroom: [-45, 5],
|
||||
dispatch: [5, 125],
|
||||
},
|
||||
// Upkeep gated on these is excluded from that baseline: both are states a
|
||||
// player opts into, and the baseline is the floor underneath everybody.
|
||||
baselineExcludes: ['debt', 'lifestyle'],
|
||||
},
|
||||
|
||||
// How the interface names and formats this pack's state. The UI reads only
|
||||
@@ -142,6 +219,12 @@ export const corporateLadder = {
|
||||
'reputation': { label: 'Standing', format: 'meter', order: 3 },
|
||||
'skills.negotiation': { label: 'Negotiation', format: 'meter', order: 4 },
|
||||
'skills.logistics': { label: 'Logistics', format: 'meter', order: 5 },
|
||||
// Hidden until it is bought: a mailroom associate has no lifestyle to
|
||||
// speak of, and a row reading "The bus" from day one is noise.
|
||||
'lifestyle': {
|
||||
label: 'Lifestyle', format: 'tier', order: 6, hideWhenZero: true,
|
||||
labels: ['The bus', 'A car', 'The address'],
|
||||
},
|
||||
// Kept out of the header, and out of the ledger too: `notable` is the
|
||||
// retrospective's own list, and "Notable — changed" tells nobody anything.
|
||||
'notable': { hidden: true, inLedger: false },
|
||||
|
||||
@@ -579,6 +579,66 @@ export const deputy = [
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
// Corporate Ladder's car lot, in Cold Fork's terms and at its scale. Same
|
||||
// structure deliberately: an offer, never an obligation, with the weekly
|
||||
// charge for falling short of it sitting in upkeep instead.
|
||||
id: 'the_sale_barn',
|
||||
stage: 'deputy',
|
||||
weight: 45,
|
||||
cooldown: 6,
|
||||
requires: [{ path: 'lifestyle', op: '<', value: 2 }],
|
||||
description:
|
||||
'The sale barn has a bay with four good years in him and a price on ' +
|
||||
'him. Ward says nothing about it, except that the county pays mileage ' +
|
||||
'on a horse a man owns and nothing at all on a hired one.',
|
||||
options: [
|
||||
{
|
||||
id: 'buy_the_bay',
|
||||
label: 'Buy the bay.',
|
||||
requires: [
|
||||
{ path: 'lifestyle', op: '==', value: 0 },
|
||||
{ path: 'money', op: '>=', value: 70 },
|
||||
],
|
||||
result:
|
||||
'He is a better animal than the livery has ever put under you, and ' +
|
||||
'the whole street watches you ride him down it once.',
|
||||
effects: [
|
||||
{ path: 'money', op: 'add', value: -70 },
|
||||
{ path: 'lifestyle', op: 'set', value: 1 },
|
||||
{ path: 'standing', op: 'add', value: 3 },
|
||||
{ path: 'notable', op: 'push', value: 'Bought the bay out of the sale barn.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'take_the_room',
|
||||
label: 'Take the room over the Ellis place, with the stove.',
|
||||
requires: [
|
||||
{ path: 'lifestyle', op: '==', value: 1 },
|
||||
{ path: 'money', op: '>=', value: 150 },
|
||||
],
|
||||
result:
|
||||
'A door that locks, a stove, and a window over the street. The ' +
|
||||
'Cordwood does not hold it against you; the Cordwood holds nothing ' +
|
||||
'against anybody who pays up.',
|
||||
effects: [
|
||||
{ path: 'money', op: 'add', value: -150 },
|
||||
{ path: 'lifestyle', op: 'set', value: 2 },
|
||||
{ path: 'standing', op: 'add', value: 5 },
|
||||
{ path: 'notable', op: 'push', value: 'Took the room with the stove over the Ellis place.' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'ride_the_livery',
|
||||
label: 'Ride what the livery gives you.',
|
||||
result:
|
||||
'A different animal every week, and you learn something about each ' +
|
||||
'one of them in the first mile.',
|
||||
effects: [{ path: 'skills.trade', op: 'add', value: 1 }],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default deputy;
|
||||
|
||||
@@ -54,6 +54,10 @@ export const frontier = {
|
||||
'standing': { initial: 50, min: 0, max: 100 },
|
||||
'skills.nerve': { initial: 5, min: 0, max: 100 },
|
||||
'skills.trade': { initial: 5, min: 0, max: 100 },
|
||||
// The same shape as Corporate Ladder's lifestyle, in this setting's own
|
||||
// terms and at this setting's own scale: what the office expects a man to
|
||||
// turn up on, and what keeping that up costs. See DECISIONS #36.
|
||||
'lifestyle': { initial: 0, min: 0, max: 2 },
|
||||
'flags.carries_iron': { initial: false },
|
||||
'flags.owes_the_store': { initial: false },
|
||||
'flags.covered_for_dutch': { initial: false },
|
||||
@@ -112,6 +116,66 @@ export const frontier = {
|
||||
requires: [{ path: 'stage', op: '==', value: 'deputy' }],
|
||||
effects: [{ path: 'money', op: 'add', value: 38 }],
|
||||
},
|
||||
// What the star is expected to arrive on, and what that expectation costs
|
||||
// to meet. The office nets +18 a run; a deputy on his own horse is +11,
|
||||
// and one with the horse and the room is +4 and makes the rest on the
|
||||
// days. Money is meant to keep mattering after the promotion — but the
|
||||
// first pass charged 9 for the room and left a keeper's median balance at
|
||||
// $8 after 200 turns, which is not pressure, it is the debt trap this pack
|
||||
// was tuned twice to avoid.
|
||||
{
|
||||
label: 'Feed and shoeing',
|
||||
every: 4,
|
||||
offset: 4,
|
||||
requires: [{ path: 'lifestyle', op: '>=', value: 1 }],
|
||||
effects: [{ path: 'money', op: 'add', value: -7 }],
|
||||
},
|
||||
{
|
||||
label: 'The room over the Ellis place',
|
||||
every: 4,
|
||||
offset: 4,
|
||||
requires: [{ path: 'lifestyle', op: '>=', value: 2 }],
|
||||
effects: [{ path: 'money', op: 'add', value: -7 }],
|
||||
},
|
||||
// Gated on the office for the same reason Corporate Ladder gates its
|
||||
// equivalent on Dispatch: a hand cannot afford any of this, and being
|
||||
// charged standing for that would be a trap rather than a choice.
|
||||
{
|
||||
label: 'What the star is expected to be',
|
||||
every: 4,
|
||||
offset: 4,
|
||||
requires: [
|
||||
{ path: 'stage', op: '==', value: 'deputy' },
|
||||
{ path: 'lifestyle', op: '<', value: 1 },
|
||||
],
|
||||
effects: [{ path: 'standing', op: 'add', value: -2 }],
|
||||
},
|
||||
{
|
||||
label: 'What the star is expected to be',
|
||||
every: 4,
|
||||
offset: 4,
|
||||
requires: [
|
||||
{ path: 'stage', op: '==', value: 'deputy' },
|
||||
{ path: 'standing', op: '>=', value: 65 },
|
||||
{ path: 'lifestyle', op: '<', value: 2 },
|
||||
],
|
||||
effects: [{ path: 'standing', op: 'add', value: -2 }],
|
||||
},
|
||||
{
|
||||
// The top step, for the reason Corporate Ladder's has one: without it a
|
||||
// man who plays for standing every single day holds a hundred of it on a
|
||||
// livery horse, and the bay is money thrown away. With it he settles in
|
||||
// the low eighties and the last stretch has to be bought.
|
||||
label: 'What the star is expected to be',
|
||||
every: 4,
|
||||
offset: 4,
|
||||
requires: [
|
||||
{ path: 'stage', op: '==', value: 'deputy' },
|
||||
{ path: 'standing', op: '>=', value: 80 },
|
||||
{ path: 'lifestyle', op: '<', value: 2 },
|
||||
],
|
||||
effects: [{ path: 'standing', op: 'add', value: -14 }],
|
||||
},
|
||||
// Store credit costs more the deeper in you are, the same step function
|
||||
// Corporate Ladder uses for its loan — a shape, not a setting.
|
||||
{
|
||||
@@ -149,6 +213,9 @@ export const frontier = {
|
||||
hand: [0, 12],
|
||||
deputy: [10, 30],
|
||||
},
|
||||
// States a player opts into, excluded from the baseline above: the floor
|
||||
// is what a man faces owing nothing and keeping nothing.
|
||||
baselineExcludes: ['owed', 'lifestyle'],
|
||||
},
|
||||
|
||||
display: {
|
||||
@@ -157,6 +224,10 @@ export const frontier = {
|
||||
'standing': { label: 'Standing', format: 'meter', order: 3 },
|
||||
'skills.nerve': { label: 'Nerve', format: 'meter', order: 4 },
|
||||
'skills.trade': { label: 'Trade', format: 'meter', order: 5 },
|
||||
'lifestyle': {
|
||||
label: 'What you keep', format: 'tier', order: 6, hideWhenZero: true,
|
||||
labels: ['The livery horse', 'Your own horse', 'Horse and a room'],
|
||||
},
|
||||
'notable': { hidden: true, inLedger: false },
|
||||
'flags.carries_iron': {
|
||||
label: 'The scattergun', hidden: true,
|
||||
|
||||
Reference in New Issue
Block a user