Add events log, active_dispatch tracking, and galleyProgress to gameState
This commit is contained in:
@@ -37,7 +37,52 @@ export function isRouteUnlocked(state, routeId) {
|
|||||||
return state.den >= r.unlock_den && state.aut >= r.unlock_aut
|
return state.den >= r.unlock_den && state.aut >= r.unlock_aut
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply a completed dispatch — returns new state
|
// Returns a 0–1 progress float for a dispatched galley along its route.
|
||||||
|
// 0 = just departed, 1 = returned. Returns null if no active dispatch.
|
||||||
|
// This function is pure — it takes a snapshot of active_dispatch and a
|
||||||
|
// current timestamp. OTIVM-IV will feed real duration_ms values.
|
||||||
|
// OTIVM-VII will map the progress float onto H3 waypoints along the route.
|
||||||
|
export function galleyProgress(active_dispatch, now_ms) {
|
||||||
|
if (!active_dispatch) return null
|
||||||
|
const { started_utc, duration_ms } = active_dispatch
|
||||||
|
const elapsed = now_ms - new Date(started_utc).getTime()
|
||||||
|
return Math.min(elapsed / duration_ms, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append an event to state — returns new state.
|
||||||
|
// Internal helper used by apply* functions below.
|
||||||
|
function appendEvent(state, type, route_id = null) {
|
||||||
|
const event = {
|
||||||
|
type,
|
||||||
|
route_id,
|
||||||
|
timestamp_utc: new Date().toISOString(),
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
events: [...(state.events || []), event],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply cost of launching a dispatch — returns new state or null if insufficient funds.
|
||||||
|
// Sets active_dispatch so galleyProgress can track position.
|
||||||
|
export function applyDispatchCost(state, routeId) {
|
||||||
|
const r = ROUTES.find((x) => x.id === routeId)
|
||||||
|
if (!r) return null
|
||||||
|
if (state.den < r.cost) return null
|
||||||
|
const withCost = { ...state, den: state.den - r.cost }
|
||||||
|
const withDispatch = {
|
||||||
|
...withCost,
|
||||||
|
active_dispatch: {
|
||||||
|
route_id: routeId,
|
||||||
|
started_utc: new Date().toISOString(),
|
||||||
|
duration_ms: r.duration_ms,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return appendEvent(withDispatch, 'dispatch_start', routeId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply a completed dispatch — returns new state.
|
||||||
|
// Clears active_dispatch on completion.
|
||||||
export function applyDispatch(state, routeId) {
|
export function applyDispatch(state, routeId) {
|
||||||
const r = ROUTES.find((x) => x.id === routeId)
|
const r = ROUTES.find((x) => x.id === routeId)
|
||||||
if (!r) return state
|
if (!r) return state
|
||||||
@@ -49,6 +94,7 @@ export function applyDispatch(state, routeId) {
|
|||||||
|
|
||||||
const den = state.den + r.profit
|
const den = state.den + r.profit
|
||||||
const dispatches = state.dispatches + 1
|
const dispatches = state.dispatches + 1
|
||||||
|
const prevChapter = state.chapter
|
||||||
const chapter = getChapter(den, state.aut)
|
const chapter = getChapter(den, state.aut)
|
||||||
|
|
||||||
// Check for new journal entry
|
// Check for new journal entry
|
||||||
@@ -59,22 +105,21 @@ export function applyDispatch(state, routeId) {
|
|||||||
? [...state.journal_seen, { routeId, dispatch: dispatchCount }]
|
? [...state.journal_seen, { routeId, dispatch: dispatchCount }]
|
||||||
: state.journal_seen
|
: state.journal_seen
|
||||||
|
|
||||||
return {
|
let next = {
|
||||||
...state,
|
...state,
|
||||||
den,
|
den,
|
||||||
dispatches,
|
dispatches,
|
||||||
chapter,
|
chapter,
|
||||||
route_dispatches,
|
route_dispatches,
|
||||||
journal_seen,
|
journal_seen,
|
||||||
}
|
active_dispatch: null,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply cost of launching a dispatch — returns new state or null if insufficient funds
|
next = appendEvent(next, 'dispatch_complete', routeId)
|
||||||
export function applyDispatchCost(state, routeId) {
|
if (entry) next = appendEvent(next, 'journal_unlock', routeId)
|
||||||
const r = ROUTES.find((x) => x.id === routeId)
|
if (chapter > prevChapter) next = appendEvent(next, 'chapter_advance', null)
|
||||||
if (!r) return null
|
|
||||||
if (state.den < r.cost) return null
|
return next
|
||||||
return { ...state, den: state.den - r.cost }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply completed otium — returns new state
|
// Apply completed otium — returns new state
|
||||||
@@ -82,7 +127,8 @@ export function applyOtium(state) {
|
|||||||
const gain = OTIUM_BASE_AUT + Math.floor(state.dispatches / 3)
|
const gain = OTIUM_BASE_AUT + Math.floor(state.dispatches / 3)
|
||||||
const aut = state.aut + gain
|
const aut = state.aut + gain
|
||||||
const chapter = getChapter(state.den, aut)
|
const chapter = getChapter(state.den, aut)
|
||||||
return { ...state, aut, chapter }
|
const next = { ...state, aut, chapter }
|
||||||
|
return appendEvent(next, 'otium', null)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the journal entry to show for a completed dispatch, or null
|
// Returns the journal entry to show for a completed dispatch, or null
|
||||||
|
|||||||
Reference in New Issue
Block a user