Update Healer Man server
This commit is contained in:
1 parent
39458d5de6
commit
6cc1b9217f
203 files changed
+133929
-31271
No files matched your search
+49
-26
@@ -26,7 +26,9 @@ import {
|
||||
damageAfterEquipmentMitigation,
|
||||
deriveCharacterStats,
|
||||
} from "./wotlkStats";
|
||||
import { clampPlayerLevel } from "./progression";
|
||||
import type { InventoryItem } from "./lootTypes";
|
||||
import type { RomNativeRecoveryClock } from "./romNativeRecovery";
|
||||
import {
|
||||
runtimeDefaultPartyTalentProfile,
|
||||
runtimePartyTalentRanksForLevel,
|
||||
@@ -91,6 +93,7 @@ export interface PartyMember {
|
||||
readonly appearance: CharacterAppearance;
|
||||
readonly classId: ClassId;
|
||||
readonly statRuleset?: CharacterStatRuleset;
|
||||
readonly romNativeRecoveryClock?: RomNativeRecoveryClock;
|
||||
readonly secondaryClassId?: ClassId | null;
|
||||
readonly specialization: string;
|
||||
readonly specializationId: string | null;
|
||||
@@ -202,20 +205,15 @@ function wowTemplates(
|
||||
}
|
||||
|
||||
const ROM_TANK_TEMPLATES: readonly PartyTemplate[] = Object.freeze([
|
||||
{ name: "Aldric", classId: "rom-warrior", statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
{ ...romFiveIdentity("rom-knight", "tank")!, statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
{ name: "Maerwen", classId: "rom-warden", statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
{ name: "Bronn", classId: "rom-champion", statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
]);
|
||||
const ROM_HEALER_TEMPLATES: readonly PartyTemplate[] = Object.freeze([
|
||||
{ ...romFiveIdentity("rom-priest", "healer")!, statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
{ name: "Sylva", classId: "rom-druid", statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
]);
|
||||
const ROM_DAMAGE_TEMPLATES: readonly PartyTemplate[] = Object.freeze([
|
||||
{ ...romFiveIdentity("rom-scout", "damage")!, statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
{ ...romFiveIdentity("rom-rogue", "damage")!, statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
{ ...romFiveIdentity("rom-mage", "damage")!, statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
{ name: "Morgha", classId: "rom-warlock", statRuleset: "rom", specialization: "Primary", talentTreeId: "" },
|
||||
]);
|
||||
|
||||
export const TANK_SPECIALIZATIONS = Object.freeze(new Set(
|
||||
@@ -264,7 +262,7 @@ function memberMaxHealth(
|
||||
secondaryClassId?: ClassId | null,
|
||||
gender: GenderId = "male",
|
||||
): number {
|
||||
const safeLevel = Math.max(1, Math.trunc(level));
|
||||
const safeLevel = clampPlayerLevel(level);
|
||||
if (statRuleset === "rom") {
|
||||
return deriveCharacterStats(classId, safeLevel, gearStats, raceId, {}, secondaryClassId, gender, statRuleset).health;
|
||||
}
|
||||
@@ -285,9 +283,10 @@ function memberMaxResource(
|
||||
secondaryClassId?: ClassId | null,
|
||||
gender: GenderId = "male",
|
||||
): number {
|
||||
const safeLevel = clampPlayerLevel(level);
|
||||
const profile = resourceProfileForClass(classId);
|
||||
return profile.type === "mana"
|
||||
? deriveCharacterStats(classId, level, gearStats, raceId, {}, secondaryClassId, gender, statRuleset).mana
|
||||
? deriveCharacterStats(classId, safeLevel, gearStats, raceId, {}, secondaryClassId, gender, statRuleset).mana
|
||||
: profile.maximum;
|
||||
}
|
||||
|
||||
@@ -311,6 +310,19 @@ function initialSecondaryResource(type: ResourceType, maximum: number): number {
|
||||
: maximum;
|
||||
}
|
||||
|
||||
function rescaledMemberValue(
|
||||
current: number,
|
||||
currentMaximum: number,
|
||||
nextMaximum: number,
|
||||
preserveNativeCap: boolean,
|
||||
minimum: number,
|
||||
): number {
|
||||
if (current <= 0) return 0;
|
||||
const fraction = Math.max(0, Math.min(1, current / Math.max(1, currentMaximum)));
|
||||
if (preserveNativeCap && fraction >= 1) return nextMaximum;
|
||||
return Math.max(minimum, Math.min(nextMaximum, Math.round(fraction * nextMaximum)));
|
||||
}
|
||||
|
||||
/** Keeps every resource used by the member's learned kit available to companion AI. */
|
||||
function withMemberAbilityResourcePools(member: PartyMember): PartyMember {
|
||||
const types = new Set<ResourceType>([member.resourceType]);
|
||||
@@ -370,13 +382,13 @@ function withMemberGearStats(member: PartyMember, gearStats: ItemStats): PartyMe
|
||||
);
|
||||
const health = member.health <= 0
|
||||
? 0
|
||||
: Math.max(1, Math.round(member.health / Math.max(1, member.maxHealth) * maxHealth));
|
||||
: rescaledMemberValue(member.health, member.maxHealth, maxHealth, member.statRuleset === "rom", 1);
|
||||
const maxResource = memberMaxResource(
|
||||
member.classId, member.level, member.raceId, gearStats, member.statRuleset, member.secondaryClassId, member.gender,
|
||||
);
|
||||
const resource = Math.max(0, Math.round(
|
||||
member.resource / Math.max(1, member.maxResource) * maxResource,
|
||||
));
|
||||
const resource = rescaledMemberValue(
|
||||
member.resource, member.maxResource, maxResource, member.statRuleset === "rom", 0,
|
||||
);
|
||||
return withMemberAbilityResourcePools({
|
||||
...member,
|
||||
resourceMaximums: undefined,
|
||||
@@ -397,6 +409,7 @@ function createMember(
|
||||
seed: string,
|
||||
configuredTalentRanks?: TalentRanks,
|
||||
): PartyMember {
|
||||
const safeLevel = clampPlayerLevel(level);
|
||||
// Appearance has its own keyed stream so adding customization fields later
|
||||
// cannot reshuffle which class/spec templates make up this character's party.
|
||||
const identityRandom = {
|
||||
@@ -432,22 +445,28 @@ function createMember(
|
||||
ownerId: id,
|
||||
ownerKind: "party",
|
||||
classId: template.classId,
|
||||
secondaryClassId: level >= ROM_SECONDARY_UNLOCK_LEVEL ? template.secondaryClassId ?? null : null,
|
||||
secondaryClassId: safeLevel >= ROM_SECONDARY_UNLOCK_LEVEL ? template.secondaryClassId ?? null : null,
|
||||
specializationId,
|
||||
role,
|
||||
level,
|
||||
level: safeLevel,
|
||||
});
|
||||
const secondaryClassId = level >= ROM_SECONDARY_UNLOCK_LEVEL ? template.secondaryClassId ?? null : null;
|
||||
const secondaryClassId = safeLevel >= ROM_SECONDARY_UNLOCK_LEVEL ? template.secondaryClassId ?? null : null;
|
||||
const maxHealth = memberMaxHealth(
|
||||
level, role, gearStats, template.classId, race.id, statRuleset, secondaryClassId, gender,
|
||||
safeLevel, role, gearStats, template.classId, race.id, statRuleset, secondaryClassId, gender,
|
||||
);
|
||||
const resourceProfile = resourceProfileForClass(template.classId);
|
||||
const maxResource = memberMaxResource(
|
||||
template.classId, level, race.id, gearStats, statRuleset, secondaryClassId, gender,
|
||||
);
|
||||
const resource = Math.round(
|
||||
maxResource * (resourceProfile.maximum > 0 ? resourceProfile.initial / resourceProfile.maximum : 0),
|
||||
template.classId, safeLevel, race.id, gearStats, statRuleset, secondaryClassId, gender,
|
||||
);
|
||||
const resource = statRuleset === "rom"
|
||||
? resourceProfile.initial === resourceProfile.maximum && resourceProfile.maximum > 0
|
||||
? maxResource
|
||||
: Math.max(0, Math.min(maxResource, Math.round(
|
||||
maxResource * (resourceProfile.maximum > 0 ? resourceProfile.initial / resourceProfile.maximum : 0),
|
||||
)))
|
||||
: Math.round(
|
||||
maxResource * (resourceProfile.maximum > 0 ? resourceProfile.initial / resourceProfile.maximum : 0),
|
||||
);
|
||||
return withMemberAbilityResourcePools({
|
||||
id,
|
||||
name: template.name,
|
||||
@@ -463,9 +482,9 @@ function createMember(
|
||||
talentProfileId: template.talentProfileId ?? null,
|
||||
talentRanks: configuredTalentRanks ?? (isRomClassId(template.classId)
|
||||
? Object.freeze({})
|
||||
: runtimePartyTalentRanksForLevel(template.classId, template.specialization, level, template.talentProfileId ?? undefined)),
|
||||
: runtimePartyTalentRanksForLevel(template.classId, template.specialization, safeLevel, template.talentProfileId ?? undefined)),
|
||||
role,
|
||||
level: Math.max(1, Math.trunc(level)),
|
||||
level: safeLevel,
|
||||
health: maxHealth,
|
||||
maxHealth,
|
||||
resourceType: resourceProfile.type,
|
||||
@@ -739,7 +758,7 @@ export const usePartyStore = create<PartyState>((set, get) => ({
|
||||
}),
|
||||
|
||||
syncLevel: (level) => set((state) => {
|
||||
const safeLevel = Math.max(1, Math.trunc(level));
|
||||
const safeLevel = clampPlayerLevel(level);
|
||||
if (state.members.every((member) => member.level === safeLevel)) return state;
|
||||
return {
|
||||
members: state.members.map((member) => {
|
||||
@@ -761,7 +780,9 @@ export const usePartyStore = create<PartyState>((set, get) => ({
|
||||
);
|
||||
const health = member.health <= 0
|
||||
? 0
|
||||
: Math.max(1, Math.round(member.health / Math.max(1, member.maxHealth) * maxHealth));
|
||||
: rescaledMemberValue(
|
||||
member.health, member.maxHealth, maxHealth, member.statRuleset === "rom", 1,
|
||||
);
|
||||
const maxResource = memberMaxResource(
|
||||
member.classId,
|
||||
safeLevel,
|
||||
@@ -771,9 +792,9 @@ export const usePartyStore = create<PartyState>((set, get) => ({
|
||||
nextSecondaryClassId,
|
||||
member.gender,
|
||||
);
|
||||
const resource = Math.max(0, Math.round(
|
||||
member.resource / Math.max(1, member.maxResource) * maxResource,
|
||||
));
|
||||
const resource = rescaledMemberValue(
|
||||
member.resource, member.maxResource, maxResource, member.statRuleset === "rom", 0,
|
||||
);
|
||||
return withMemberAbilityResourcePools({
|
||||
...member,
|
||||
resourceMaximums: undefined,
|
||||
@@ -900,6 +921,7 @@ export const usePartyStore = create<PartyState>((set, get) => ({
|
||||
return {
|
||||
...member,
|
||||
health: restored,
|
||||
romNativeRecoveryClock: undefined,
|
||||
status: "ready",
|
||||
controlledUntil: 0,
|
||||
controlMechanic: null,
|
||||
@@ -928,6 +950,7 @@ export const usePartyStore = create<PartyState>((set, get) => ({
|
||||
return {
|
||||
...member,
|
||||
health,
|
||||
romNativeRecoveryClock: health <= 0 ? undefined : member.romNativeRecoveryClock,
|
||||
status: health <= 0 ? "down" : member.status,
|
||||
};
|
||||
}),
|
||||
|
||||
Reference in new issue
Block a user