Update class mechanics, stat rulesets, and CoA reference catalogs

This commit is contained in:
phenom committed 2026-10-04 12:56:30 -04:00
1 parent b16821e92e
commit 39458d5de6
221 files changed
+2584962 -568

No files matched your search

@@ -42,6 +42,22 @@ const DRUID_WARRIOR_BRIAR_CHILD = {
passiveSourceSkillId: 499955,
childSourceSkillId: 499956,
};
const ROGUE_WARDEN_REVIVAL_STATE = {
mainClass: 3,
secondaryClass: 7,
level: 60,
keyItemId: 546772,
parentSourceSkillId: 499542,
childSourceSkillId: 499544,
};
const KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT = {
mainClass: 6,
secondaryClass: 3,
level: 50,
keyItemId: 542123,
parentSourceSkillId: 499934,
childSourceSkillId: 499909,
};
const RACE_MATRIX = {
"rom-human": [1, 2, 3, 4, 5, 6],
"rom-elf": [1, 2, 3, 4, 7, 8],
@@ -597,6 +613,75 @@ for (const key of [...eligiblePairs].sort()) {
iconResolution: "native-interface-fdb",
});
}
// RuneWaker's Rogue/Warden 499544 state has its own level-60 row behind
// 499542, sharing the exact elite key item. Preserve that second learned
// candidate instead of dropping it at the one-row milestone selector.
if (mapping.mainClass === ROGUE_WARDEN_REVIVAL_STATE.mainClass
&& mapping.secondaryClass === ROGUE_WARDEN_REVIVAL_STATE.secondaryClass
&& milestone.level === ROGUE_WARDEN_REVIVAL_STATE.level
&& milestone.keyItemId === ROGUE_WARDEN_REVIVAL_STATE.keyItemId
&& candidate.sourceSkillId === ROGUE_WARDEN_REVIVAL_STATE.parentSourceSkillId) {
const child = candidates.find((entry) => entry.classIndex === ROGUE_WARDEN_REVIVAL_STATE.mainClass
&& entry.sourceSkillId === ROGUE_WARDEN_REVIVAL_STATE.childSourceSkillId
&& entry.learnLevel === milestone.level
&& entry.keyItemId === milestone.keyItemId
&& entry.prerequisites.includes(ROGUE_WARDEN_REVIVAL_STATE.parentSourceSkillId));
if (!child) throw new Error("Rogue/Warden Revival state 499544 lost its source unlock row.");
const childSpell = sourceSpell(child.sourceSkillId, mapping.mainClass);
if (!childSpell) throw new Error("Rogue/Warden Revival state 499544 has no MagicCollect row.");
skills.push({
id: `${CLASS_IDS[mapping.mainClass - 1]}-${CLASS_IDS[mapping.secondaryClass - 1]}-elite-${milestone.level}-${child.sourceSkillId}`,
classId: CLASS_IDS[mapping.mainClass - 1],
secondaryClassId: CLASS_IDS[mapping.secondaryClass - 1],
group: childSpell.passive ? "passive" : "elite",
unlockLevel: child.learnLevel,
keyItemId: child.keyItemId,
...childSpell,
ranks: [{
rank: 1,
level: child.learnLevel,
prerequisites: child.prerequisites,
...nestedRankSpell(childSpell, childSpell.sourceSkillId),
}],
icon: `/assets/ui/rom-spells/${childSpell.source.imageId}.png`,
iconResolution: "native-interface-fdb",
});
}
// Knight/Rogue God's Vengeance explicitly unlocks its linked 499909
// Punishment as a second learned row on the same level-50 key item.
if (mapping.mainClass === KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.mainClass
&& mapping.secondaryClass === KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.secondaryClass
&& milestone.level === KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.level
&& milestone.keyItemId === KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.keyItemId
&& candidate.sourceSkillId === KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.parentSourceSkillId) {
const child = candidates.find((entry) => entry.classIndex === KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.mainClass
&& entry.sourceSkillId === KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.childSourceSkillId
&& entry.learnLevel === milestone.level
&& entry.keyItemId === milestone.keyItemId
&& entry.prerequisites.includes(KNIGHT_ROGUE_GODS_VENGEANCE_PUNISHMENT.parentSourceSkillId));
if (!child) throw new Error("Knight/Rogue God's Vengeance Punishment 499909 lost its learned source row.");
const childSpell = sourceSpell(child.sourceSkillId, mapping.mainClass);
if (!childSpell) throw new Error("Knight/Rogue God's Vengeance Punishment 499909 has no MagicCollect row.");
skills.push({
id: `${CLASS_IDS[mapping.mainClass - 1]}-${CLASS_IDS[mapping.secondaryClass - 1]}-elite-${milestone.level}-${childSpell.sourceSkillId}`,
classId: CLASS_IDS[mapping.mainClass - 1],
secondaryClassId: CLASS_IDS[mapping.secondaryClass - 1],
group: childSpell.passive ? "passive" : "elite",
unlockLevel: child.learnLevel,
keyItemId: child.keyItemId,
...childSpell,
ranks: [{
rank: 1,
level: child.learnLevel,
prerequisites: child.prerequisites,
...nestedRankSpell(childSpell, childSpell.sourceSkillId),
}],
icon: `/assets/ui/rom-spells/${childSpell.source.imageId}.png`,
iconResolution: "native-interface-fdb",
});
}
}
}
@@ -639,9 +724,10 @@ const audit = {
},
adaptations,
};
// In addition to the 660 ordinary milestones, this source emits the Druid/Warrior
// Cross of Thorns Attacks row behind its explicit learned prerequisite.
if (eliteMilestoneCount !== 660 || supplementalEliteCount !== 1 || unresolvedVisible.length !== 0
// In addition to the 660 ordinary milestones, the source emits the Druid/Warrior
// Cross of Thorns Attacks row, Rogue/Warden Revival state, and linked Knight/Rogue
// Punishment row behind their learned prerequisites.
if (eliteMilestoneCount !== 660 || supplementalEliteCount !== 3 || unresolvedVisible.length !== 0
|| audit.coverage.iconResolved !== skills.length || iconCoverage.requested !== iconCoverage.resolved) {
throw new Error(`Coverage failed: ${JSON.stringify(audit.coverage)}`);
}