Release Healer Man 0.1.6

This commit is contained in:
phenom committed 2026-08-20 14:05:50 -04:00
1 parent 55cfd43d66
commit b12fb84859
96 files changed
+10874 -609

No files matched your search

+51 -12
View File
@@ -33,6 +33,8 @@ import { useMenuController, type MenuAction } from "../input/useMenuController";
import { LazyLocalCompanionPanel } from "./LazyLocalCompanionPanel";
import { ControllerButton } from "./ControllerButton";
import { BrandMark, ControllerLegend, FrontSurface } from "./FrontSurface";
import { OnlineGroupPanel } from "./OnlineGroupPanel";
import { useOnlineGroupStore } from "../app/onlineGroupStore";
installManastormShellRuntime();
@@ -49,10 +51,19 @@ export function ManastormSelectScreen() {
const saveSelectedManastormLoadout = useShellStore((state) => state.saveSelectedManastormLoadout);
const returnToMainMenu = useShellStore((state) => state.returnToMainMenu);
const notice = useShellStore((state) => state.notice);
const session = useShellStore((state) => state.session);
const onlineGroup = useOnlineGroupStore((state) => state.snapshot.group);
const fillWithAi = useOnlineGroupStore((state) => state.fillWithAi);
const updateOnlineMember = useOnlineGroupStore((state) => state.updateMember);
const startOnlineActivity = useOnlineGroupStore((state) => state.startActivity);
const adminConfig = useManastormAdminStore((state) => state.config);
const character = activeCharacter ?? rosterCharacter;
const availableRoles = character ? partyRolesForClass(character.classId) : [];
const [partySize, setPartySize] = useState<ManastormPartySize>(5);
const groupHumanCount = onlineGroup?.members.length ?? 1;
const effectivePartySize = onlineGroup
? (fillWithAi ? Math.max(partySize, groupHumanCount) : groupHumanCount) as ManastormPartySize
: partySize;
const [resume, setResume] = useState(true);
const progress = character?.manastormProgress ?? createEmptyManastormProgress();
const effectiveCatalog = useMemo(
@@ -71,7 +82,7 @@ export function ManastormSelectScreen() {
const canEnter = modeEnabled && hasReadyBosses;
const modeProgress = manastormModeProgress(progress, modeId);
const modeLabel = modeId === 2 ? "End-game" : "Leveling";
const partyProgress = manastormPartyProgress(progress, partySize, modeId);
const partyProgress = manastormPartyProgress(progress, effectivePartySize, modeId);
const checkpoint = Math.max(1, partyProgress.checkpointLevel);
const startingLevel = resume && checkpoint > 1 ? checkpoint : 1;
const cacheChance = modeId === 2
@@ -81,7 +92,7 @@ export function ManastormSelectScreen() {
try {
const preview = drawManastormStage(
startingLevel,
partySize,
effectivePartySize,
[],
null,
() => 0.5,
@@ -92,14 +103,14 @@ export function ManastormSelectScreen() {
return manastormReward(
preview.encounter,
startingLevel,
partySize,
effectivePartySize,
effectiveCatalog,
modeId,
);
} catch {
return null;
}
}, [effectiveCatalog, modeId, partyProgress.highestLevel, partySize, startingLevel]);
}, [effectiveCatalog, effectivePartySize, modeId, partyProgress.highestLevel, startingLevel]);
const spellLoadoutModel = useMemo(() => character
? manastormActiveSpellLoadoutModel(character.classId, character.level, character.talentRanks)
: null, [character?.classId, character?.level, character?.talentRanks]);
@@ -132,7 +143,7 @@ export function ManastormSelectScreen() {
character.id,
character.level,
role,
partySize,
effectivePartySize,
character.categoryId ?? "wow",
);
void preloadAvatarModels([character, ...party]).catch((error) => {
@@ -140,10 +151,30 @@ export function ManastormSelectScreen() {
});
};
const enterAsRole = async (role: PartyRole) => {
if (!canEnter || !character) return;
if (!onlineGroup || !session || session.kind !== "account") {
enterManastorm(role, partySize, startingLevel);
return;
}
if (!await updateOnlineMember(session, character, role)) return;
if (onlineGroup.leaderAccountId !== session.ownerId) {
useShellStore.getState().setNotice(`Ready as ${PARTY_ROLE_LABELS[role]}. Waiting for the group leader to start.`);
return;
}
await startOnlineActivity(session, {
type: "manastorm",
contentId: "manastorm",
partySize: effectivePartySize,
startingLevel,
});
};
const actions = useMemo<MenuAction[]>(() => [
...MANASTORM_PARTY_SIZES.map((size) => ({
id: `manastorm-party-${size}`,
run: () => setPartySize(size),
enabled: !onlineGroup || (size >= groupHumanCount && (fillWithAi || size === groupHumanCount)),
})),
{ id: "manastorm-start-fresh", run: () => setResume(false) },
...(checkpoint > 1 ? [{ id: "manastorm-start-resume", run: () => setResume(true) }] : []),
@@ -153,7 +184,7 @@ export function ManastormSelectScreen() {
})) ?? []),
...availableRoles.map((role) => ({
id: `manastorm-role-${role}`,
run: () => canEnter && enterManastorm(role, partySize, startingLevel),
run: () => { if (canEnter) void enterAsRole(role); },
enabled: canEnter,
})),
{ id: "manastorm-back", run: returnToMainMenu },
@@ -161,8 +192,10 @@ export function ManastormSelectScreen() {
availableRoles,
canEnter,
checkpoint,
enterManastorm,
partySize,
groupHumanCount,
fillWithAi,
onlineGroup,
effectivePartySize,
returnToMainMenu,
selectedSpellIds,
spellLoadoutModel,
@@ -235,6 +268,7 @@ export function ManastormSelectScreen() {
<h2 id="manastorm-role-title">Build your expedition</h2>
<small>Progress and first clears are tracked separately for every party size.</small>
</header>
<OnlineGroupPanel />
<div className="manastorm-setup-block">
<strong>Party size</strong>
@@ -245,8 +279,9 @@ export function ManastormSelectScreen() {
controlId={`manastorm-party-${size}`}
selectedId={controller.selectedId}
select={controller.select}
className={`manastorm-size-option ${partySize === size ? "is-active" : ""}`}
className={`manastorm-size-option ${effectivePartySize === size ? "is-active" : ""}`}
type="button"
disabled={Boolean(onlineGroup && (size < groupHumanCount || (!fillWithAi && size !== groupHumanCount)))}
onClick={() => setPartySize(size)}
>
{size}
@@ -254,7 +289,11 @@ export function ManastormSelectScreen() {
))}
</div>
<small>
{partySize === 1 ? "Solo" : `You + ${partySize - 1} companion${partySize === 2 ? "" : "s"}`}
{onlineGroup
? fillWithAi
? `${groupHumanCount} player${groupHumanCount === 1 ? "" : "s"} + ${Math.max(0, effectivePartySize - groupHumanCount)} AI teammate${effectivePartySize - groupHumanCount === 1 ? "" : "s"}`
: `${groupHumanCount} grouped player${groupHumanCount === 1 ? "" : "s"} · AI fill off`
: partySize === 1 ? "Solo" : `You + ${partySize - 1} companion${partySize === 2 ? "" : "s"}`}
{" · "}Highest clear {partyProgress.highestLevel}
</small>
</div>
@@ -345,11 +384,11 @@ export function ManastormSelectScreen() {
disabled={!canEnter}
onFocus={() => preloadRole(role)}
onPointerEnter={() => preloadRole(role)}
onClick={() => canEnter && enterManastorm(role, partySize, startingLevel)}
onClick={() => { if (canEnter) void enterAsRole(role); }}
>
<b aria-hidden="true">{ROLE_DETAILS[role].sigil}</b>
<span>
<strong>Enter as {PARTY_ROLE_LABELS[role]}</strong>
<strong>{onlineGroup && session?.ownerId !== onlineGroup.leaderAccountId ? "Ready" : "Enter"} as {PARTY_ROLE_LABELS[role]}</strong>
<small>{ROLE_DETAILS[role].summary}</small>
</span>
</ControllerButton>