Add gameState — pure game logic functions

This commit is contained in:
otivm
2026-04-25 15:03:06 +00:00
parent bff67cfd95
commit 567bc08d98

101
src/gameState.js Normal file
View File

@@ -0,0 +1,101 @@
import {
ROUTES,
JOURNAL,
INITIAL_STATE,
OTIUM_BASE_AUT,
} from './constants.js'
// Returns a fresh game state with a generated token
export function createState(token) {
return {
...INITIAL_STATE,
token,
created_at: new Date().toISOString(),
}
}
// Returns current chapter based on den and aut thresholds
export function getChapter(den, aut) {
if (aut >= 30 && den >= 800) return 5
if (aut >= 15 && den >= 350) return 4
if (aut >= 5 && den >= 120) return 3
if (den >= 40) return 2
return 1
}
// Returns routes available to this state (unlocked, not locked)
export function getUnlockedRoutes(state) {
return ROUTES.filter(
(r) => state.den >= r.unlock_den && state.aut >= r.unlock_aut
)
}
// Returns true if a route is unlocked
export function isRouteUnlocked(state, routeId) {
const r = ROUTES.find((x) => x.id === routeId)
if (!r) return false
return state.den >= r.unlock_den && state.aut >= r.unlock_aut
}
// Apply a completed dispatch — returns new state
export function applyDispatch(state, routeId) {
const r = ROUTES.find((x) => x.id === routeId)
if (!r) return state
const route_dispatches = {
...state.route_dispatches,
[routeId]: (state.route_dispatches[routeId] || 0) + 1,
}
const den = state.den + r.profit
const dispatches = state.dispatches + 1
const chapter = getChapter(den, state.aut)
// Check for new journal entry
const dispatchCount = route_dispatches[routeId]
const entries = JOURNAL[routeId] || []
const entry = entries.find((e) => e.dispatch === dispatchCount)
const journal_seen = entry
? [...state.journal_seen, { routeId, dispatch: dispatchCount }]
: state.journal_seen
return {
...state,
den,
dispatches,
chapter,
route_dispatches,
journal_seen,
}
}
// Apply cost of launching a dispatch — returns new state or null if insufficient funds
export function applyDispatchCost(state, routeId) {
const r = ROUTES.find((x) => x.id === routeId)
if (!r) return null
if (state.den < r.cost) return null
return { ...state, den: state.den - r.cost }
}
// Apply completed otium — returns new state
export function applyOtium(state) {
const gain = OTIUM_BASE_AUT + Math.floor(state.dispatches / 3)
const aut = state.aut + gain
const chapter = getChapter(state.den, aut)
return { ...state, aut, chapter }
}
// Returns the journal entry to show for a completed dispatch, or null
export function getNewJournalEntry(state, routeId) {
const dispatchCount = (state.route_dispatches[routeId] || 0)
const entries = JOURNAL[routeId] || []
return entries.find((e) => e.dispatch === dispatchCount) || null
}
// Returns all journal entries seen so far, in order seen
export function getSeenJournalEntries(state) {
return state.journal_seen.map(({ routeId, dispatch }) => {
const entries = JOURNAL[routeId] || []
return entries.find((e) => e.dispatch === dispatch)
}).filter(Boolean)
}