Files
healer-man/src/game/PartyBridge.tsx
T
2026-09-20 16:46:17 -04:00

108 lines
5.2 KiB
TypeScript

import { useEffect, useRef } from "react";
import { useShellStore } from "../app/shellStore";
import { useCombatStore } from "./combatStore";
import { resetPartyRuntimeClock } from "./partyRuntime";
import { usePartyStore } from "./partyStore";
import { useGameStore } from "./store";
import { useManastormStore } from "./manastormStore";
import { onlineGroupAiPartySize, useOnlineGroupStore } from "../app/onlineGroupStore";
import { useDungeonSimulationStore } from "./dungeonSimulationStore";
import { useCompanionSpecReadinessStore } from "./companionSpecReadinessStore";
import { useCompanionPartyPreferences } from "./companionPartyPreferences";
import { RANDOMIZED_BITE_SIZED_STOCKADES_DUNGEON_ID } from "./dungeonContentSource";
/** Owns party lifecycle; the combat interval itself remains in CombatBridge. */
export function PartyBridge() {
const character = useShellStore((state) => state.activeCharacter);
const playerRole = useShellStore((state) => state.activeDungeonRole);
const gameMode = useGameStore((state) => state.gameMode);
const manastormPartySize = useManastormStore((state) => state.partySize);
const onlineActivity = useOnlineGroupStore((state) => state.activeActivity);
const onlineGroup = useOnlineGroupStore((state) => state.snapshot.group);
const level = useCombatStore((state) => state.level);
const simulationMode = useDungeonSimulationStore((state) => state.sessionMode);
const simulationSeed = useDungeonSimulationStore((state) => state.seed);
const resetRevision = useGameStore((state) => state.resetRevision);
const readinessPolicy = useCompanionSpecReadinessStore((state) => state.config);
const readinessPolicyRevision = useCompanionSpecReadinessStore((state) => state.revision);
const deviceIncludeBetaSpecs = useCompanionPartyPreferences((state) => state.includeBetaSpecs);
const mountedResetRevision = useRef(resetRevision);
useEffect(() => {
if (!character) return;
const combat = useCombatStore.getState();
const party = usePartyStore.getState();
const requestedPartySize = gameMode === "manastorm" ? manastormPartySize : 5;
const aiPartySize = onlineActivity
&& onlineActivity.type === (gameMode === "manastorm" ? "manastorm" : "dungeon")
? onlineGroupAiPartySize(onlineActivity.partySize)
: requestedPartySize;
const sharedOnlineParty = onlineActivity && onlineGroup?.activity?.id === onlineActivity.id
? onlineGroup.members
: [];
const randomizedReadyOnly = onlineActivity?.type === "dungeon"
&& onlineActivity.contentId === RANDOMIZED_BITE_SIZED_STOCKADES_DUNGEON_ID;
const companionOptions = {
readinessPolicy,
readinessPolicyRevision: onlineActivity?.companionReadinessRevision ?? readinessPolicyRevision,
includeBetaSpecs: randomizedReadyOnly ? false : onlineActivity?.includeBetaSpecs ?? deviceIncludeBetaSpecs,
excludedPlayerSpecializationId: character.specializationId,
excludedPlayerSpecializationIds: sharedOnlineParty.flatMap((member) => (
member.character?.specializationId ? [member.character.specializationId] : []
)),
allowedCompanionSpecializationIds: onlineActivity?.companionSpecializationIds,
occupiedHumanRoles: sharedOnlineParty.flatMap((member) => member.role ? [member.role] : []),
};
if (simulationMode === "play") {
party.initializeParty(
onlineActivity?.id ?? character.id,
combat.level,
combat.health,
playerRole,
aiPartySize,
randomizedReadyOnly ? "wow" : character.categoryId ?? "wow",
companionOptions,
);
} else {
party.initializeSpectatorParty(simulationSeed, combat.level, character.categoryId ?? "wow", companionOptions);
}
usePartyStore.getState().syncEquipment(combat.equipment, combat.inventory);
combat.synchronizeActors();
combat.applyDefaultPartyBuffs();
combat.applyPrecombatPreparation();
resetPartyRuntimeClock();
}, [character?.id, deviceIncludeBetaSpecs, gameMode, manastormPartySize, onlineActivity?.id,
onlineActivity?.includeBetaSpecs, onlineGroup?.updatedAt, playerRole, readinessPolicy,
readinessPolicyRevision, simulationMode, simulationSeed]);
useEffect(() => {
const party = usePartyStore.getState();
const combat = useCombatStore.getState();
party.syncLevel(level);
usePartyStore.getState().syncEquipment(combat.equipment, combat.inventory);
combat.synchronizeActors();
combat.applyDefaultPartyBuffs();
combat.applyPrecombatPreparation();
}, [level]);
useEffect(() => {
if (mountedResetRevision.current === resetRevision) return;
mountedResetRevision.current = resetRevision;
const combat = useCombatStore.getState();
usePartyStore.getState().resetCombat(combat.level, combat.health);
usePartyStore.getState().syncEquipment(combat.equipment, combat.inventory);
combat.synchronizeActors();
combat.applyDefaultPartyBuffs();
combat.applyPrecombatPreparation();
resetPartyRuntimeClock();
}, [resetRevision]);
useEffect(() => useCombatStore.subscribe((state, previous) => {
if (state.selectedTargetId && state.selectedTargetId !== previous.selectedTargetId) {
usePartyStore.getState().clearSelection();
}
}), []);
return null;
}