diff --git a/src/sim/car.ts b/src/sim/car.ts index 610d9d3..3d5ef2b 100644 --- a/src/sim/car.ts +++ b/src/sim/car.ts @@ -149,13 +149,23 @@ const MAX_DAMAGE_PER_STEP = 0.25; * * Baseline wear is deliberately quicker than real life so decline is legible * within a session, but it has to stay inside what the parts economy can pay - * for — see the reasoning on the two constants above. + * for. The old figures did not: tyres shed 8e-5 per metre, so twelve clean + * kilometres — no crashes at all — took them from new to ruined, while a + * two-kilometre round trip paid about 0.3 parts against 0.24 of condition + * spent. Driving perfectly barely broke even and one knock put you permanently + * behind, which is a decline with no way to arrest it rather than a decision + * about how hard to push the car. + * + * At a quarter of that a typical mission spends about 0.06 condition against + * ~0.3 parts earned, so roughly two clean runs pay for one bad crash. That is + * the ratio the whole risk/reward loop rests on: enough slack to gamble with, + * not enough to ignore. */ export function applyWear(c: CarCondition, w: WearInput): CarCondition { const impact = w.impactForce / IMPACT_REFERENCE; const damage: Subsystems = { - engine: w.throttle * w.dt * 6e-4 + impact * 0.32, - tires: w.distance * 8e-5 + impact * 0.5, + engine: w.throttle * w.dt * 1.5e-4 + impact * 0.32, + tires: w.distance * 2e-5 + impact * 0.5, chassis: impact * 1.0, }; diff --git a/src/sim/sim.test.ts b/src/sim/sim.test.ts index f27238b..cf41af9 100644 --- a/src/sim/sim.test.ts +++ b/src/sim/sim.test.ts @@ -85,6 +85,20 @@ describe('car condition', () => { expect(crashes).toBeGreaterThan(5); }); + it('lets a careful driver come out ahead of the parts they are paid', () => { + // Two kilometres at 20 m/s with nothing hit: the shape of an ordinary + // mission. It has to cost distinctly less than the ~0.3 parts one pays, or + // driving perfectly is a losing move and the economy has no floor. + let c = freshCondition(); + const steps = Math.round((2000 / 20) * 60); + for (let i = 0; i < steps; i++) { + c = applyWear(c, { dt: 1 / 60, distance: 20 / 60, throttle: 1, impactForce: 0 }); + } + const spent = 3 - (c.level.engine + c.level.tires + c.level.chassis); + expect(spent).toBeGreaterThan(0.02); + expect(spent).toBeLessThan(0.12); + }); + it('makes a worn car measurably worse to drive', () => { const fresh = deriveHandling(freshCondition()); const worn = deriveHandling({