feat: deepen audiovisual story immersion
This commit is contained in:
@@ -85,6 +85,17 @@ export type BattleSaveCoreResonanceStats = {
|
||||
additionalDamage: number;
|
||||
};
|
||||
|
||||
export type BattleSaveEventPriority = 'critical' | 'high' | 'normal' | 'low';
|
||||
|
||||
export type BattleSavePendingEvent = {
|
||||
key: string;
|
||||
title: string;
|
||||
lines: string[];
|
||||
priority: BattleSaveEventPriority;
|
||||
playCue: boolean;
|
||||
presented?: boolean;
|
||||
};
|
||||
|
||||
export type BattleSaveState = {
|
||||
version: 1;
|
||||
battleId: string;
|
||||
@@ -111,6 +122,7 @@ export type BattleSaveState = {
|
||||
tacticalCommand?: BattleSaveTacticalCommandState;
|
||||
enemyUsableUseKeys?: string[];
|
||||
triggeredBattleEvents?: string[];
|
||||
pendingBattleEvents?: BattleSavePendingEvent[];
|
||||
};
|
||||
|
||||
export type BattleSaveValidationOptions = {
|
||||
@@ -135,6 +147,9 @@ const maxBattleLogEntries = 10;
|
||||
const maxBattleLogEntryLength = 96;
|
||||
const maxBattleBondEntries = 128;
|
||||
const maxTriggeredBattleEventLength = 96;
|
||||
const maxPendingBattleEventTitleLength = 96;
|
||||
const maxPendingBattleEventLineLength = 256;
|
||||
const maxPendingBattleEventLines = 12;
|
||||
const defaultBattleSaveArrayLimit = 128;
|
||||
const defaultBattleItemStockLimit = 9;
|
||||
const maxBattleEffectLabelLength = 32;
|
||||
@@ -272,7 +287,8 @@ export function isValidBattleSaveState(state: unknown, options: BattleSaveValida
|
||||
options
|
||||
) ||
|
||||
!isOptionalEnemyUsableUseKeyArray(state.enemyUsableUseKeys, state.battleId, options) ||
|
||||
!isOptionalTriggeredBattleEventArray(state.triggeredBattleEvents, options)
|
||||
!isOptionalTriggeredBattleEventArray(state.triggeredBattleEvents, options) ||
|
||||
!isOptionalPendingBattleEventArray(state.pendingBattleEvents, state.triggeredBattleEvents, options)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
@@ -922,6 +938,58 @@ function isOptionalTriggeredBattleEventArray(value: unknown, options: BattleSave
|
||||
);
|
||||
}
|
||||
|
||||
function isOptionalPendingBattleEventArray(
|
||||
value: unknown,
|
||||
triggeredEvents: unknown,
|
||||
options: BattleSaveValidationOptions
|
||||
) {
|
||||
if (value === undefined) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
!Array.isArray(value) ||
|
||||
value.length > triggeredBattleEventLimit(options) ||
|
||||
!hasUniqueRecordStrings(value, 'key')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const presentedIndices = value
|
||||
.map((event, index) => (isRecord(event) && event.presented === true ? index : -1))
|
||||
.filter((index) => index >= 0);
|
||||
if (presentedIndices.length > 1 || (presentedIndices.length === 1 && presentedIndices[0] !== 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const completedKeys = new Set(Array.isArray(triggeredEvents) ? triggeredEvents : []);
|
||||
return value.every((event) => (
|
||||
isRecord(event) &&
|
||||
typeof event.key === 'string' &&
|
||||
event.key.length > 0 &&
|
||||
event.key.length <= maxTriggeredBattleEventLength &&
|
||||
!completedKeys.has(event.key) &&
|
||||
(!options.validTriggeredBattleEventIds || options.validTriggeredBattleEventIds.has(event.key)) &&
|
||||
typeof event.title === 'string' &&
|
||||
event.title.trim().length > 0 &&
|
||||
event.title.length <= maxPendingBattleEventTitleLength &&
|
||||
Array.isArray(event.lines) &&
|
||||
event.lines.length > 0 &&
|
||||
event.lines.length <= maxPendingBattleEventLines &&
|
||||
event.lines.every((line) => (
|
||||
typeof line === 'string' &&
|
||||
line.trim().length > 0 &&
|
||||
line.length <= maxPendingBattleEventLineLength
|
||||
)) &&
|
||||
isBattleSaveEventPriority(event.priority) &&
|
||||
typeof event.playCue === 'boolean' &&
|
||||
(event.presented === undefined || typeof event.presented === 'boolean')
|
||||
));
|
||||
}
|
||||
|
||||
function isBattleSaveEventPriority(value: unknown): value is BattleSaveEventPriority {
|
||||
return value === 'critical' || value === 'high' || value === 'normal' || value === 'low';
|
||||
}
|
||||
|
||||
function isEnemyUsableUseKey(value: unknown, battleId: string, options: BattleSaveValidationOptions) {
|
||||
if (typeof value !== 'string') {
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user