feat: improve combat feedback and progression
This commit is contained in:
109
src/game/settings/combatPresentation.ts
Normal file
109
src/game/settings/combatPresentation.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
export const combatPresentationStorageKey = 'heros-web:combat-presentation-mode';
|
||||
|
||||
export type CombatPresentationMode = 'always' | 'important' | 'map';
|
||||
|
||||
export type CombatPresentationImportance = {
|
||||
signature?: boolean;
|
||||
critical?: boolean;
|
||||
defeated?: boolean;
|
||||
resonance?: boolean;
|
||||
growth?: boolean;
|
||||
};
|
||||
|
||||
type StorageLike = Pick<Storage, 'getItem' | 'setItem'>;
|
||||
|
||||
export const combatPresentationModes: readonly CombatPresentationMode[] = ['always', 'important', 'map'];
|
||||
|
||||
export const combatPresentationModeLabels: Record<CombatPresentationMode, string> = {
|
||||
always: '항상',
|
||||
important: '중요 장면만',
|
||||
map: '지도 연출'
|
||||
};
|
||||
|
||||
export function isCombatPresentationMode(value: unknown): value is CombatPresentationMode {
|
||||
return typeof value === 'string' && combatPresentationModes.includes(value as CombatPresentationMode);
|
||||
}
|
||||
|
||||
export function nextCombatPresentationMode(mode: CombatPresentationMode): CombatPresentationMode {
|
||||
const index = combatPresentationModes.indexOf(mode);
|
||||
return combatPresentationModes[(index + 1) % combatPresentationModes.length];
|
||||
}
|
||||
|
||||
export function combatPresentationModeLabel(mode: CombatPresentationMode) {
|
||||
return combatPresentationModeLabels[mode];
|
||||
}
|
||||
|
||||
export function shouldUseFullCombatCutIn(
|
||||
mode: CombatPresentationMode,
|
||||
importance: CombatPresentationImportance
|
||||
) {
|
||||
if (mode === 'always') {
|
||||
return true;
|
||||
}
|
||||
if (mode === 'map') {
|
||||
return false;
|
||||
}
|
||||
return Boolean(
|
||||
importance.signature ||
|
||||
importance.critical ||
|
||||
importance.defeated ||
|
||||
importance.resonance ||
|
||||
importance.growth
|
||||
);
|
||||
}
|
||||
|
||||
export function combatPresentationImportanceReason(importance: CombatPresentationImportance) {
|
||||
if (importance.signature) {
|
||||
return '고유 전법';
|
||||
}
|
||||
if (importance.defeated) {
|
||||
return '격파';
|
||||
}
|
||||
if (importance.critical) {
|
||||
return '치명타';
|
||||
}
|
||||
if (importance.resonance) {
|
||||
return '공명';
|
||||
}
|
||||
if (importance.growth) {
|
||||
return '레벨 상승';
|
||||
}
|
||||
return '일반 행동';
|
||||
}
|
||||
|
||||
export function loadCombatPresentationMode(storage = resolveStorage()): CombatPresentationMode {
|
||||
if (!storage) {
|
||||
return 'important';
|
||||
}
|
||||
try {
|
||||
const value = storage.getItem(combatPresentationStorageKey);
|
||||
return isCombatPresentationMode(value) ? value : 'important';
|
||||
} catch {
|
||||
return 'important';
|
||||
}
|
||||
}
|
||||
|
||||
export function saveCombatPresentationMode(
|
||||
mode: CombatPresentationMode,
|
||||
storage = resolveStorage()
|
||||
) {
|
||||
if (!storage) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
storage.setItem(combatPresentationStorageKey, mode);
|
||||
} catch {
|
||||
// Local storage can be unavailable in private or restricted browser contexts.
|
||||
}
|
||||
}
|
||||
|
||||
function resolveStorage(): StorageLike | undefined {
|
||||
if (typeof window === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return window.localStorage;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user