Release Healer Man 0.1.6
This commit is contained in:
1 parent
55cfd43d66
commit
b12fb84859
96 files changed
+10874
-609
No files matched your search
@@ -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>
|
||||
|
||||
Reference in new issue
Block a user