Honor RoM off-hand and ranged equipment slots

This commit is contained in:
phenom committed 2026-09-23 19:59:21 -04:00
1 parent 0206fda9e2
commit 7449abdad2
15 files changed
+150 -29

No files matched your search

+23 -9
View File
@@ -41,6 +41,7 @@ export interface HeirloomContext {
readonly ownerId: string;
readonly ownerKind: HeirloomOwnerKind;
readonly classId: ClassId;
readonly secondaryClassId?: ClassId | null;
readonly specializationId: string | null;
readonly role: PartyRole;
readonly level: number;
@@ -96,18 +97,30 @@ function effectiveLevel(context: HeirloomContext): number {
return Math.max(1, Math.min(cap, Math.trunc(Number.isFinite(context.level) ? context.level : 1)));
}
function weaponSlots(layout: WeaponLayout): readonly EquipmentSlot[] {
function weaponSlots(context: HeirloomContext, layout: WeaponLayout): readonly EquipmentSlot[] {
let slots: readonly EquipmentSlot[];
switch (layout) {
case "dual-wield":
case "weapon-shield":
return ["main-hand", "off-hand"];
slots = ["main-hand", "off-hand"];
break;
case "ranged":
return ["main-hand", "ranged"];
slots = ["main-hand", "ranged"];
break;
case "caster":
return ["main-hand", "off-hand", "ranged"];
slots = ["main-hand", "off-hand", "ranged"];
break;
default:
return ["main-hand"];
slots = ["main-hand"];
}
if (!isRomHybridGearClass(context.classId)) return slots;
const level = effectiveLevel(context);
const resolved = new Set(slots);
if (context.classId === "rom-rogue" && level < 16) resolved.delete("off-hand");
if (context.classId === "rom-rogue" && level >= 12) resolved.add("ranged");
if (context.classId === "rom-knight" && context.secondaryClassId === "rom-scout" && level >= 10) resolved.add("ranged");
if (context.classId === "rom-scout" && context.secondaryClassId === "rom-rogue" && level >= 16) resolved.add("off-hand");
return [...resolved];
}
function armorTypeForSlot(classId: ClassId, slot: EquipmentSlot, layout: WeaponLayout): string | null {
@@ -117,8 +130,9 @@ function armorTypeForSlot(classId: ClassId, slot: EquipmentSlot, layout: WeaponL
}
function weaponTypeFor(classId: ClassId, slot: EquipmentSlot, profile: SpecializationDefinition): string | null {
if (slot === "off-hand" && profile.weaponLayout === "dual-wield") return "dagger";
if (slot === "ranged") return profile.gearArchetype === "spell-dps" || profile.gearArchetype === "healer" ? "wand" : "bow";
if (slot === "off-hand" && (profile.weaponLayout === "dual-wield" || classId === "rom-scout")) return "dagger";
if (slot === "ranged") return classId === "rom-rogue" ? "projectile"
: profile.gearArchetype === "spell-dps" || profile.gearArchetype === "healer" ? "wand" : "bow";
if (slot !== "main-hand") return null;
if (classId === "rom-scout" && profile.weaponLayout === "ranged") return "dagger";
if (classId === "rom-mage") return profile.weaponLayout === "two-hand" ? "staff" : "dagger";
@@ -283,7 +297,7 @@ export function resolvedEquipmentLoadout(
): Readonly<Partial<Record<EquipmentSlot, InventoryItem>>> {
const profile = gearProfileFor(context.classId, context.specializationId, context.role);
const result: Partial<Record<EquipmentSlot, InventoryItem>> = {};
for (const slot of [...BASE_SLOTS, ...weaponSlots(profile.weaponLayout)]) {
for (const slot of [...BASE_SLOTS, ...weaponSlots(context, profile.weaponLayout)]) {
if (isRomHybridGearClass(context.classId) && slot === "wrist") continue;
result[slot] = heirloomItem(context, profile, slot);
}
@@ -291,7 +305,7 @@ export function resolvedEquipmentLoadout(
const earned = assignments[context.ownerId] ?? {};
for (const slot of EQUIPMENT_SLOTS) {
const item = earned[slot] ? itemById.get(earned[slot]!) : null;
if (!item || !classCanEquipItem(context.classId, item)) continue;
if (!item || !classCanEquipItem(context.classId, item, context)) continue;
if (slot === "main-hand" && item.inventorySlot === "two-hand") delete result["off-hand"];
if (slot === "off-hand" && result["main-hand"]?.inventorySlot === "two-hand") {
result["main-hand"] = heirloomItem(context, profile, "main-hand", "one-hand");