// The Frontier — the second content pack for The Ladder. // // Cold Fork, a freight town at the end of a stage line. You are a hired hand // in Vane & Co.'s yard; the town has a marshal who is tired and a road that is // not safe. Two rungs, the same as Corporate Ladder, and not one line of // engine code between them. // // This pack exists to prove the split holds. Everything that makes it a // different game from Corporate Ladder is in this directory: a four-day cycle // instead of a week, money that arrives from work rather than from a wage, // relationship stats named for a place where being owed a favour matters more // than being liked, and a skill pair of nerve and trade. import { characters } from './characters.js'; import { events } from './events/index.js'; export const frontier = { id: 'frontier', name: 'The Frontier', blurb: 'Cold Fork, at the end of a stage line: a freight yard, a road that is ' + 'not safe, and a marshal who has been six years retiring.', version: '0.1.1', turnUnit: 'day', startingStage: 'hand', peopleHeading: 'Cold Fork', stages: { hand: { label: 'The Yard', title: 'Hired Hand' }, deputy: { label: 'The Office', title: 'Deputy Marshal' }, }, // Not a week. The stage comes every fourth day, and the whole town runs on // that: the outfit settles up when the stage comes in, the boarding house // collects on the rest day before it. A pack that wants a seven-day week // says seven here; the engine has no opinion either way, and Corporate // Ladder's calendar is the same field with different numbers in it. calendar: { cycleLength: 4, cycleName: 'Run', unitNames: ['Stage day', 'Haul', 'Yard', 'Rest'], }, // Money is smaller here than in Corporate Ladder by a factor of about // fifteen, and it behaves differently: the settlement covers board and room // and very little else, so the difference between a good run and a bad one // is what you took from the work. See `tuning` below for the arithmetic that // is actually asserted. state: { 'money': { initial: 40, min: -400, max: 100000 }, // The store ledger. Named for what it is rather than for a loan: nobody in // Cold Fork lends money, they let you carry a balance. 'owed': { initial: 0, min: 0, max: 100000 }, '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 }, 'flags.sworn_in': { initial: false }, 'flags.spoke_for_dutch': { initial: false }, 'notable': { initial: [] }, }, // A different vocabulary from Corporate Ladder's likes/fears/helps, and the // reason the vocabulary is content's to choose. Out here the useful question // about a person is not whether they like you: it is whether they will take // your word, and whether they are carrying a debt to you they mean to pay. relationshipStats: { trusts_you: { label: 'Takes your word', initial: 45, min: 0, max: 100 }, owes_you: { label: 'Owes you', initial: 10, min: 0, max: 100 }, wary_of_you: { label: 'Wary of you', initial: 15, min: 0, max: 100 }, }, // The economic shape, and the thing that makes this pack a real test of the // engine rather than Corporate Ladder in a hat: there is no wage worth // living on. Vane settles up when the stage comes in and it covers the room // and the feed and four dollars besides. Everything else you earn, you earn // on a turn, by choosing to — and what the choices cost is where the // pressure comes from, not an unexplained drain. // // Keep this arithmetic honest when tuning. Per four-day run: // hand: -12 board -8 room +24 settlement = +4 // deputy: -12 board -8 room +38 pay = +18 // Both are asserted directly by the conformance suite against `tuning` // below, so a number changed here without re-deriving it fails the build // rather than trapping a player forty turns in. upkeep: [ { label: 'Board and feed', effects: [{ path: 'money', op: 'add', value: -3 }] }, // Turn 1 is a Stage day, so offset 3 is the first Rest day and offset 4 // the next Stage day — the room is collected the night before the outfit // settles up, which is the boarding house's whole business model. { label: 'Room at the Cordwood', every: 4, offset: 3, effects: [{ path: 'money', op: 'add', value: -8 }], }, // Labelled as wages, because they are. "Settlement" read as jargon to the // first real player, who could not tell it was the twenty-four a run the // first morning quotes; the ledger is written for a player (DECISIONS #27). { label: 'Wages from Vane', every: 4, offset: 4, requires: [{ path: 'stage', op: '==', value: 'hand' }], effects: [{ path: 'money', op: 'add', value: 24 }], }, { label: 'Wages from the county', every: 4, offset: 4, // The town pays a real wage, and it is still not much of a living. What // changes with the star is not the money; it is what the days contain. 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 }], }, { // The charge that never stops, for the reason Corporate Ladder has one: // without it a man who has bought everything and stands well with the // whole town has nothing left that money is for. Being somebody in Cold // Fork costs, every run, and nothing you can buy ends it. label: 'What the standing costs', every: 4, offset: 4, requires: [ { path: 'stage', op: '==', value: 'deputy' }, { path: 'standing', op: '>=', value: 85 }, ], // Four rather than six: this pack's late game is already flat — measured, // a deputy who has bought everything drifts 0 a run either way — so the // charge is here to keep money live, not to arrest an accumulation that // does not happen. Six left an ordinary run at 55; four leaves 105. effects: [{ path: 'money', op: 'add', value: -4 }], }, // Store credit costs more the deeper in you are, the same step function // Corporate Ladder uses for its loan — a shape, not a setting. { label: 'Store credit', every: 4, offset: 4, requires: [{ path: 'owed', op: '>', value: 0 }], effects: [{ path: 'money', op: 'add', value: -3 }], }, { label: 'Store credit (carried)', every: 4, offset: 4, requires: [{ path: 'owed', op: '>=', value: 60 }], effects: [{ path: 'money', op: 'add', value: -3 }], }, { label: 'Store credit (posted)', every: 4, offset: 4, requires: [{ path: 'owed', op: '>=', value: 120 }], effects: [{ path: 'money', op: 'add', value: -4 }], }, ], // What the conformance suite holds this pack to. Declaring it here rather // than writing it into a test is the same principle as the rest of the pack: // the numbers a setting must hit are the setting's business. See // DECISIONS.md #31. tuning: { // Net movement of `money` from upkeep alone, per calendar cycle, at each // stage. Upkeep is the floor a player plays against: barely above water in // the yard, and a real if unremarkable living with the star. baselinePerCycle: { hand: [0, 12], deputy: [10, 30], }, // States a player opts into or earns, excluded from the baseline above: // the floor is what a man faces owing nothing, keeping nothing, and being // nobody in particular. baselineExcludes: ['owed', 'lifestyle', 'standing'], }, display: { 'money': { label: 'Money', format: 'money', order: 1 }, 'owed': { label: 'Owed at the store', format: 'money', order: 2, hideWhenZero: true }, '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, whenTrue: 'You are carrying Vane’s scattergun on the box.', whenFalse: 'The scattergun is back under the office counter.', }, 'flags.owes_the_store': { label: 'The store ledger', hidden: true, whenTrue: 'Your name is in the book at the store.', whenFalse: 'You are square with the store.', }, 'flags.covered_for_dutch': { label: 'Dutch’s run', hidden: true, whenTrue: 'Dutch owes you a run.', whenFalse: 'You and Dutch are square.', }, 'flags.sworn_in': { label: 'The star', hidden: true, whenTrue: 'You are sworn in.', whenFalse: 'You are back in the yard.', }, 'flags.spoke_for_dutch': { label: 'Dutch’s name', hidden: true, whenTrue: 'Dutch’s name is in for the good runs.', whenFalse: 'Dutch’s name is not in for the good runs.', }, }, characters, events, }; export default frontier;