feat: 收敛玩法运行时配置并加入故障恢复
This commit is contained in:
@@ -11,6 +11,11 @@ import {
|
||||
resolveContentCardCtaConfig,
|
||||
} from '../experience/contentCard'
|
||||
import { type OrienteeringCourseData } from '../../utils/orienteeringCourse'
|
||||
import {
|
||||
getDefaultSkipRadiusMeters,
|
||||
getGameModeDefaults,
|
||||
resolveDefaultControlScore,
|
||||
} from '../core/gameModeDefaults'
|
||||
|
||||
function sortBySequence<T extends { sequence: number | null }>(items: T[]): T[] {
|
||||
return [...items].sort((a, b) => (a.sequence || 0) - (b.sequence || 0))
|
||||
@@ -86,18 +91,48 @@ export function buildGameDefinitionFromCourse(
|
||||
course: OrienteeringCourseData,
|
||||
controlRadiusMeters: number,
|
||||
mode: GameDefinition['mode'] = 'classic-sequential',
|
||||
autoFinishOnLastControl = true,
|
||||
sessionCloseAfterMs?: number,
|
||||
sessionCloseWarningMs?: number,
|
||||
minCompletedControlsBeforeFinish?: number,
|
||||
autoFinishOnLastControl?: boolean,
|
||||
punchPolicy: PunchPolicyType = 'enter-confirm',
|
||||
punchRadiusMeters = 5,
|
||||
requiresFocusSelection = false,
|
||||
skipEnabled = false,
|
||||
skipRadiusMeters = 30,
|
||||
skipRequiresConfirm = true,
|
||||
requiresFocusSelection?: boolean,
|
||||
skipEnabled?: boolean,
|
||||
skipRadiusMeters?: number,
|
||||
skipRequiresConfirm?: boolean,
|
||||
controlScoreOverrides: Record<string, number> = {},
|
||||
defaultControlContentOverride: GameControlDisplayContentOverride | null = null,
|
||||
controlContentOverrides: Record<string, GameControlDisplayContentOverride> = {},
|
||||
defaultControlScore: number | null = null,
|
||||
): GameDefinition {
|
||||
const controls: GameControl[] = []
|
||||
const modeDefaults = getGameModeDefaults(mode)
|
||||
const resolvedSessionCloseAfterMs = sessionCloseAfterMs !== undefined
|
||||
? sessionCloseAfterMs
|
||||
: modeDefaults.sessionCloseAfterMs
|
||||
const resolvedSessionCloseWarningMs = sessionCloseWarningMs !== undefined
|
||||
? sessionCloseWarningMs
|
||||
: modeDefaults.sessionCloseWarningMs
|
||||
const resolvedMinCompletedControlsBeforeFinish = minCompletedControlsBeforeFinish !== undefined
|
||||
? minCompletedControlsBeforeFinish
|
||||
: modeDefaults.minCompletedControlsBeforeFinish
|
||||
const resolvedRequiresFocusSelection = requiresFocusSelection !== undefined
|
||||
? requiresFocusSelection
|
||||
: modeDefaults.requiresFocusSelection
|
||||
const resolvedSkipEnabled = skipEnabled !== undefined
|
||||
? skipEnabled
|
||||
: modeDefaults.skipEnabled
|
||||
const resolvedSkipRadiusMeters = skipRadiusMeters !== undefined
|
||||
? skipRadiusMeters
|
||||
: getDefaultSkipRadiusMeters(mode, punchRadiusMeters)
|
||||
const resolvedSkipRequiresConfirm = skipRequiresConfirm !== undefined
|
||||
? skipRequiresConfirm
|
||||
: modeDefaults.skipRequiresConfirm
|
||||
const resolvedAutoFinishOnLastControl = autoFinishOnLastControl !== undefined
|
||||
? autoFinishOnLastControl
|
||||
: modeDefaults.autoFinishOnLastControl
|
||||
const resolvedDefaultControlScore = resolveDefaultControlScore(mode, defaultControlScore)
|
||||
|
||||
for (let startIndex = 0; startIndex < course.layers.starts.length; startIndex += 1) {
|
||||
const start = course.layers.starts[startIndex]
|
||||
@@ -114,11 +149,11 @@ export function buildGameDefinitionFromCourse(
|
||||
template: 'focus',
|
||||
title: '比赛开始',
|
||||
body: `${start.label || '开始点'}已激活,按提示前往下一个目标点。`,
|
||||
autoPopup: true,
|
||||
autoPopup: false,
|
||||
once: false,
|
||||
priority: 1,
|
||||
clickTitle: '比赛开始',
|
||||
clickBody: `${start.label || '开始点'}已激活,按提示前往下一个目标点。`,
|
||||
clickTitle: null,
|
||||
clickBody: null,
|
||||
ctas: [],
|
||||
contentExperience: null,
|
||||
clickExperience: null,
|
||||
@@ -131,7 +166,7 @@ export function buildGameDefinitionFromCourse(
|
||||
const controlId = `control-${control.sequence}`
|
||||
const score = controlId in controlScoreOverrides
|
||||
? controlScoreOverrides[controlId]
|
||||
: defaultControlScore
|
||||
: resolvedDefaultControlScore
|
||||
controls.push({
|
||||
id: controlId,
|
||||
code: label,
|
||||
@@ -140,19 +175,22 @@ export function buildGameDefinitionFromCourse(
|
||||
point: control.point,
|
||||
sequence: control.sequence,
|
||||
score,
|
||||
displayContent: applyDisplayContentOverride({
|
||||
template: 'story',
|
||||
title: score !== null ? `收集 ${label} (+${score}分)` : `收集 ${label}`,
|
||||
body: score !== null ? `${buildDisplayBody(label, control.sequence)} · ${score}分` : buildDisplayBody(label, control.sequence),
|
||||
autoPopup: true,
|
||||
once: false,
|
||||
priority: 1,
|
||||
clickTitle: score !== null ? `收集 ${label} (+${score}分)` : `收集 ${label}`,
|
||||
clickBody: score !== null ? `${buildDisplayBody(label, control.sequence)} · ${score}分` : buildDisplayBody(label, control.sequence),
|
||||
ctas: [],
|
||||
contentExperience: null,
|
||||
clickExperience: null,
|
||||
}, controlContentOverrides[controlId]),
|
||||
displayContent: applyDisplayContentOverride(
|
||||
applyDisplayContentOverride({
|
||||
template: 'story',
|
||||
title: score !== null ? `收集 ${label} (+${score}分)` : `收集 ${label}`,
|
||||
body: score !== null ? `${buildDisplayBody(label, control.sequence)} · ${score}分` : buildDisplayBody(label, control.sequence),
|
||||
autoPopup: false,
|
||||
once: false,
|
||||
priority: 1,
|
||||
clickTitle: null,
|
||||
clickBody: null,
|
||||
ctas: [],
|
||||
contentExperience: null,
|
||||
clickExperience: null,
|
||||
}, defaultControlContentOverride || undefined),
|
||||
controlContentOverrides[controlId],
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -172,11 +210,11 @@ export function buildGameDefinitionFromCourse(
|
||||
template: 'focus',
|
||||
title: '完成路线',
|
||||
body: `${finish.label || '结束点'}已完成,准备查看本局结果。`,
|
||||
autoPopup: true,
|
||||
autoPopup: false,
|
||||
once: false,
|
||||
priority: 2,
|
||||
clickTitle: '完成路线',
|
||||
clickBody: `${finish.label || '结束点'}已完成,准备查看本局结果。`,
|
||||
clickTitle: null,
|
||||
clickBody: null,
|
||||
ctas: [],
|
||||
contentExperience: null,
|
||||
clickExperience: null,
|
||||
@@ -189,13 +227,16 @@ export function buildGameDefinitionFromCourse(
|
||||
mode,
|
||||
title: course.title || (mode === 'score-o' ? 'Score-O' : 'Classic Sequential'),
|
||||
controlRadiusMeters,
|
||||
sessionCloseAfterMs: resolvedSessionCloseAfterMs,
|
||||
sessionCloseWarningMs: resolvedSessionCloseWarningMs,
|
||||
minCompletedControlsBeforeFinish: resolvedMinCompletedControlsBeforeFinish,
|
||||
punchRadiusMeters,
|
||||
punchPolicy,
|
||||
requiresFocusSelection,
|
||||
skipEnabled,
|
||||
skipRadiusMeters,
|
||||
skipRequiresConfirm,
|
||||
requiresFocusSelection: resolvedRequiresFocusSelection,
|
||||
skipEnabled: resolvedSkipEnabled,
|
||||
skipRadiusMeters: resolvedSkipRadiusMeters,
|
||||
skipRequiresConfirm: resolvedSkipRequiresConfirm,
|
||||
controls,
|
||||
autoFinishOnLastControl,
|
||||
autoFinishOnLastControl: resolvedAutoFinishOnLastControl,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user