77 lines
3.9 KiB
JavaScript
77 lines
3.9 KiB
JavaScript
/**
|
|
* Life Journey — Phase 1 board.
|
|
*
|
|
* A small representative subset of the full hand-drawn board (assets/game_board.png):
|
|
* a Career-vs-Education fork, a Relationship-vs-Investment fork, a High-Risk-vs-Safe
|
|
* fork, and a Finish. Same shape as the full sketch — more spaces can be inserted into
|
|
* any branch array later (repointing one `next`) without touching the reducer.
|
|
*
|
|
* Space shape: { id, type, label, next?, choices?, cash?, flavor? }
|
|
* type: 'start' | 'event' | 'money' | 'choice' | 'finish'
|
|
* next: id of the following space (absent on 'choice' and 'finish' spaces)
|
|
* choices: [id, id] of the branches offered by a 'choice' space
|
|
* cash: fixed integer delta applied on landing (absent/0 for pure flavor spaces)
|
|
*/
|
|
|
|
const spaceList = [
|
|
{ id: 'start', type: 'start', label: 'Start', next: 'crossroads' },
|
|
{ id: 'crossroads', type: 'choice', label: 'Crossroads', choices: ['career_1', 'edu_1'] },
|
|
|
|
{ id: 'career_1', type: 'event', label: 'High School Grad', next: 'career_2' },
|
|
{ id: 'career_2', type: 'event', label: 'New Job', next: 'career_3' },
|
|
{ id: 'career_3', type: 'money', label: 'Paycheck', cash: 300, next: 'career_4' },
|
|
{ id: 'career_4', type: 'money', label: 'Workplace Drama', cash: -150, next: 'career_5' },
|
|
{ id: 'career_5', type: 'money', label: 'Performance Review', cash: 250, next: 'join_1' },
|
|
|
|
{ id: 'edu_1', type: 'event', label: 'College Enrolled', next: 'edu_2' },
|
|
{ id: 'edu_2', type: 'money', label: 'Study Abroad', cash: -100, next: 'edu_3' },
|
|
{ id: 'edu_3', type: 'money', label: 'Student Loan', cash: -300, next: 'edu_4' },
|
|
{ id: 'edu_4', type: 'money', label: 'Scholarship', cash: 400, next: 'edu_5' },
|
|
{ id: 'edu_5', type: 'event', label: 'Graduation', next: 'join_1' },
|
|
|
|
{ id: 'join_1', type: 'event', label: 'Adulting Begins', next: 'life_crossroads' },
|
|
{ id: 'life_crossroads', type: 'choice', label: 'Life Crossroads', choices: ['relationship_1', 'investment_1'] },
|
|
|
|
{ id: 'relationship_1', type: 'event', label: 'New City', next: 'relationship_2' },
|
|
{ id: 'relationship_2', type: 'event', label: 'Dinner Party', next: 'relationship_3' },
|
|
{ id: 'relationship_3', type: 'money', label: 'Wedding', cash: -200, next: 'join_2' },
|
|
|
|
{ id: 'investment_1', type: 'money', label: 'Side Investment', cash: -150, next: 'investment_2' },
|
|
{ id: 'investment_2', type: 'money', label: 'Market Move', cash: 350, next: 'investment_3' },
|
|
{ id: 'investment_3', type: 'money', label: '401K Contribution', cash: -100, flavor: 'Future savings', next: 'join_2' },
|
|
|
|
{ id: 'join_2', type: 'event', label: 'Settling Down', next: 'high_risk_choice' },
|
|
{ id: 'high_risk_choice', type: 'choice', label: 'One Last Fork', choices: ['high_risk_1', 'safe_1'] },
|
|
|
|
{ id: 'high_risk_1', type: 'money', label: 'Startup Gamble', cash: 500, next: 'high_risk_2' },
|
|
{ id: 'high_risk_2', type: 'money', label: 'Bankruptcy', cash: -400, flavor: 'Ouch.', next: 'retirement_party' },
|
|
|
|
{ id: 'safe_1', type: 'money', label: 'Steady Savings', cash: 100, next: 'safe_2' },
|
|
{ id: 'safe_2', type: 'money', label: 'Modest Raise', cash: 150, next: 'retirement_party' },
|
|
|
|
{ id: 'retirement_party', type: 'event', label: 'Retirement Party', next: 'finish' },
|
|
{ id: 'finish', type: 'finish', label: 'Finish' },
|
|
];
|
|
|
|
export const board = {
|
|
id: 'phase1-demo',
|
|
startSpaceId: 'start',
|
|
spaces: Object.fromEntries(spaceList.map((space) => [space.id, space])),
|
|
};
|
|
|
|
/**
|
|
* Advance from `startId` by up to `steps` spaces, stopping immediately on arrival
|
|
* at a 'choice' or 'finish' space even if pips remain (they're discarded).
|
|
*/
|
|
export function walkForward(startId, steps) {
|
|
let current = startId;
|
|
for (let i = 0; i < steps; i++) {
|
|
const space = board.spaces[current];
|
|
if (!space.next) break; // sitting on a choice/finish space already — nowhere to advance
|
|
current = space.next;
|
|
const landed = board.spaces[current];
|
|
if (landed.type === 'choice' || landed.type === 'finish') break;
|
|
}
|
|
return current;
|
|
}
|