Update Healer Man server

This commit is contained in:
phenom committed 2026-09-23 16:14:19 -04:00
1 parent f90ba7d989
commit 189b94d6b7
51 files changed
+3448 -154

No files matched your search

+30 -9
View File
@@ -39,6 +39,7 @@ import {
import type { RuntimeTalentRanks as TalentRanks } from "./talentRuntimeCatalog";
import type { EnemyControlMechanic } from "./enemyAttacks";
import type { ContentCategoryId } from "../app/contentCategories";
import { isValidRomClassPair, ROM_SECONDARY_UNLOCK_LEVEL } from "../app/romDualClass";
import type { PartyRole, PartySize } from "./partyRoles";
import {
abilitiesForCharacter,
@@ -47,6 +48,7 @@ import {
type ResourceType,
} from "./abilityCatalog";
import { createDeathKnightRunes, type CombatActorCastState, type DeathKnightRuneState } from "./combatActors";
import { romFiveIdentity } from "./romFiveIdentities";
export {
classCanFillPartyRole,
@@ -102,6 +104,8 @@ export interface PartyMember {
interface PartyTemplate {
readonly name: string;
readonly classId: ClassId;
readonly secondaryClassId?: ClassId | null;
readonly raceId?: RaceId;
readonly specialization: string;
readonly talentTreeId: string;
readonly talentProfileId?: string | null;
@@ -111,6 +115,7 @@ export interface ConfiguredPartyMemberSeed {
readonly name: string;
readonly classId: ClassId;
readonly secondaryClassId?: ClassId | null;
readonly raceId?: RaceId;
readonly specialization: string;
readonly specializationId?: string | null;
readonly talentTreeId?: string;
@@ -167,19 +172,19 @@ function wowTemplates(
const ROM_TANK_TEMPLATES: readonly PartyTemplate[] = Object.freeze([
{ name: "Aldric", classId: "rom-warrior", specialization: "Primary", talentTreeId: "" },
{ ...romFiveIdentity("rom-knight", "tank")!, specialization: "Primary", talentTreeId: "" },
{ name: "Maerwen", classId: "rom-warden", specialization: "Primary", talentTreeId: "" },
{ name: "Bronn", classId: "rom-champion", specialization: "Primary", talentTreeId: "" },
]);
const ROM_HEALER_TEMPLATES: readonly PartyTemplate[] = Object.freeze([
{ name: "Liora", classId: "rom-priest", specialization: "Primary", talentTreeId: "" },
{ ...romFiveIdentity("rom-priest", "healer")!, specialization: "Primary", talentTreeId: "" },
{ name: "Sylva", classId: "rom-druid", specialization: "Primary", talentTreeId: "" },
]);
const ROM_DAMAGE_TEMPLATES: readonly PartyTemplate[] = Object.freeze([
{ name: "Cael", classId: "rom-scout", specialization: "Primary", talentTreeId: "" },
{ name: "Veya", classId: "rom-rogue", specialization: "Primary", talentTreeId: "" },
{ name: "Ilyen", classId: "rom-mage", specialization: "Primary", talentTreeId: "" },
{ ...romFiveIdentity("rom-scout", "damage")!, specialization: "Primary", talentTreeId: "" },
{ ...romFiveIdentity("rom-rogue", "damage")!, specialization: "Primary", talentTreeId: "" },
{ ...romFiveIdentity("rom-mage", "damage")!, specialization: "Primary", talentTreeId: "" },
{ name: "Morgha", classId: "rom-warlock", specialization: "Primary", talentTreeId: "" },
{ name: "Roran", classId: "rom-knight", specialization: "Primary", talentTreeId: "" },
]);
export const TANK_SPECIALIZATIONS = Object.freeze(new Set(
@@ -322,11 +327,19 @@ function createMember(
const identityRandom = {
value: hashSeed(`${seed}:${role}:${index}:${template.classId}:${template.specialization}:appearance-v1`),
};
const eligibleRaces = PLAYABLE_RACES.filter((race) => classesForRace(race.id).some(
(candidate) => candidate.id === template.classId,
const eligibleRaces = PLAYABLE_RACES.filter((race) => (
classesForRace(race.id).some((candidate) => candidate.id === template.classId)
&& (!template.secondaryClassId || isValidRomClassPair(race.id, template.classId, template.secondaryClassId))
));
if (template.secondaryClassId && !eligibleRaces.length) {
throw new Error(`No playable race supports ${template.classId}/${template.secondaryClassId}.`);
}
if (template.raceId && !eligibleRaces.some((race) => race.id === template.raceId)) {
throw new Error(`Race ${template.raceId} cannot play ${template.classId}/${template.secondaryClassId ?? "none"}.`);
}
const racePool = eligibleRaces.length ? eligibleRaces : PLAYABLE_RACES;
const race = racePool[Math.floor(nextRandom(identityRandom) * racePool.length)] ?? racePool[0];
const race = racePool.find((candidate) => candidate.id === template.raceId)
?? racePool[Math.floor(nextRandom(identityRandom) * racePool.length)] ?? racePool[0];
const genders = supportedGenders(race.id);
const gender: GenderId = genders[Math.floor(nextRandom(identityRandom) * genders.length)] ?? genders[0] ?? "male";
const appearance = randomAppearance(race.id, gender, () => nextRandom(identityRandom));
@@ -354,6 +367,7 @@ function createMember(
gender,
appearance,
classId: template.classId,
secondaryClassId: level >= ROM_SECONDARY_UNLOCK_LEVEL ? template.secondaryClassId ?? null : null,
specialization: template.specialization,
specializationId,
talentTreeId: template.talentTreeId,
@@ -398,13 +412,14 @@ export function createConfiguredPartyMember(
const member = createMember({
name: configuration.name,
classId: configuration.classId,
secondaryClassId: configuration.secondaryClassId,
raceId: configuration.raceId,
specialization: configuration.specialization,
talentTreeId: configuration.talentTreeId ?? configuration.specializationId ?? "",
talentProfileId: configuration.talentProfileId ?? null,
}, configuration.role, level, index, seed, configuration.talentRanks);
return Object.freeze(withMemberAbilityResourcePools({
...member,
secondaryClassId: configuration.secondaryClassId ?? null,
specializationId: configuration.specializationId ?? member.specializationId,
talentRanks: configuration.talentRanks ?? member.talentRanks,
}));
@@ -655,6 +670,12 @@ export const usePartyStore = create<PartyState>((set, get) => ({
return withMemberAbilityResourcePools({
...member,
level: safeLevel,
secondaryClassId: isRomClassId(member.classId)
&& romFiveIdentity(member.classId, member.role)?.name === member.name
? (safeLevel >= ROM_SECONDARY_UNLOCK_LEVEL
? romFiveIdentity(member.classId, member.role)?.secondaryClassId ?? null
: null)
: member.secondaryClassId,
health,
maxHealth,
resource,