129 lines
3.7 KiB
TypeScript
129 lines
3.7 KiB
TypeScript
import { CompanionState, GameState } from '../types';
|
|
import { MAX_COMPANIONS } from './npcInteractions';
|
|
|
|
function upsertCompanion(list: CompanionState[], companion: CompanionState) {
|
|
const next = [...list];
|
|
const existingIndex = next.findIndex(item => item.npcId === companion.npcId);
|
|
if (existingIndex >= 0) {
|
|
next[existingIndex] = companion;
|
|
return next;
|
|
}
|
|
|
|
next.push(companion);
|
|
return next;
|
|
}
|
|
|
|
function removeCompanion(list: CompanionState[], npcId: string) {
|
|
return list.filter(item => item.npcId !== npcId);
|
|
}
|
|
|
|
export function getRecruitedNpcIds(state: Pick<GameState, 'companions' | 'roster'>) {
|
|
return new Set([
|
|
...state.companions.map(companion => companion.npcId),
|
|
...state.roster.map(companion => companion.npcId),
|
|
]);
|
|
}
|
|
|
|
export function normalizeRoster(roster: CompanionState[], activeCompanions: CompanionState[]) {
|
|
const activeIds = new Set(activeCompanions.map(companion => companion.npcId));
|
|
return roster
|
|
.filter(companion => !activeIds.has(companion.npcId))
|
|
.reduce<CompanionState[]>((next, companion) => upsertCompanion(next, companion), []);
|
|
}
|
|
|
|
export function benchActiveCompanion(state: GameState, npcId: string) {
|
|
const activeCompanion = state.companions.find(companion => companion.npcId === npcId);
|
|
if (!activeCompanion) return state;
|
|
|
|
return {
|
|
...state,
|
|
companions: state.companions.filter(companion => companion.npcId !== npcId),
|
|
roster: upsertCompanion(state.roster, activeCompanion),
|
|
};
|
|
}
|
|
|
|
export function activateRosterCompanion(state: GameState, npcId: string, swapNpcId?: string | null) {
|
|
const reserveCompanion = state.roster.find(companion => companion.npcId === npcId);
|
|
if (!reserveCompanion) return state;
|
|
|
|
if (state.companions.some(companion => companion.npcId === npcId)) {
|
|
return {
|
|
...state,
|
|
roster: removeCompanion(state.roster, npcId),
|
|
};
|
|
}
|
|
|
|
if (state.companions.length < MAX_COMPANIONS) {
|
|
return {
|
|
...state,
|
|
companions: [...state.companions, reserveCompanion],
|
|
roster: removeCompanion(state.roster, npcId),
|
|
};
|
|
}
|
|
|
|
if (!swapNpcId) return state;
|
|
const swapIndex = state.companions.findIndex(companion => companion.npcId === swapNpcId);
|
|
if (swapIndex < 0) return state;
|
|
|
|
const swappedOut = state.companions[swapIndex];
|
|
if (!swappedOut) {
|
|
return state;
|
|
}
|
|
|
|
const nextCompanions = [...state.companions];
|
|
nextCompanions[swapIndex] = reserveCompanion;
|
|
|
|
return {
|
|
...state,
|
|
companions: nextCompanions,
|
|
roster: upsertCompanion(removeCompanion(state.roster, npcId), swappedOut),
|
|
};
|
|
}
|
|
|
|
export function recruitCompanionToParty(
|
|
state: GameState,
|
|
companion: CompanionState,
|
|
replacedNpcId?: string | null,
|
|
) {
|
|
const nextReserve = removeCompanion(state.roster, companion.npcId);
|
|
|
|
if (!replacedNpcId && state.companions.length < MAX_COMPANIONS) {
|
|
return {
|
|
...state,
|
|
companions: [...state.companions, companion],
|
|
roster: nextReserve,
|
|
};
|
|
}
|
|
|
|
if (!replacedNpcId) {
|
|
return {
|
|
...state,
|
|
companions: state.companions.slice(0, MAX_COMPANIONS),
|
|
roster: normalizeRoster(nextReserve, state.companions),
|
|
};
|
|
}
|
|
|
|
const replaceIndex = state.companions.findIndex(item => item.npcId === replacedNpcId);
|
|
if (replaceIndex < 0) {
|
|
return {
|
|
...state,
|
|
companions: [...state.companions, companion].slice(0, MAX_COMPANIONS),
|
|
roster: nextReserve,
|
|
};
|
|
}
|
|
|
|
const replacedCompanion = state.companions[replaceIndex];
|
|
if (!replacedCompanion) {
|
|
return state;
|
|
}
|
|
|
|
const nextCompanions = [...state.companions];
|
|
nextCompanions[replaceIndex] = companion;
|
|
|
|
return {
|
|
...state,
|
|
companions: nextCompanions,
|
|
roster: upsertCompanion(nextReserve, replacedCompanion),
|
|
};
|
|
}
|