Add gameState — pure game logic functions
This commit is contained in:
101
src/gameState.js
Normal file
101
src/gameState.js
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user