Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f2952c905a | |||
| 8abd40f217 |
@@ -13,8 +13,8 @@ This file is the table of contents and install guide.
|
|||||||
|
|
||||||
| Artifact | Size | Purpose |
|
| Artifact | Size | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `patch-enUS-4.MPQ` | ~5 MB | DBC + GlueXML bake. Adds `CLASS_PARAGON` (id 12), the character-create slot, glue strings, talent-tab DBC entries, and the Paragon resource bar definitions. Required for character creation as Paragon to even show up. |
|
| `patch-enUS-4.MPQ` | ~5 MB | DBC + GlueXML bake. Adds `CLASS_PARAGON` (id 12), the character-create slot, glue strings, game-table DBCs, and a patched `Spell.dbc`: **(1)** `RuneCostID` zeroed on every rune-cost spell so non–Death Knight clients still send DK casts (rune costs are shown via `RuneFrame.lua`); **(2)** `Reagent[]` / `ReagentCount[]` zeroed on every spell whose `SpellFamilyName` is non-zero (all class abilities), while profession crafts (`SpellFamilyName == 0`) keep their materials. Both edits mirror server load-time corrections so client preflight and server validation stay aligned. Required for character creation as Paragon to even show up. |
|
||||||
| `patch-enUS-5.MPQ` | ~50 KB | FrameXML overrides. Replaces stock `PlayerFrame.lua` / `RuneFrame.lua` / `ComboFrame.lua` / `UnitFrame.lua` / `SpellBookFrame.lua` + `SpellBookFrame.xml` with Paragon-aware versions: rune simulator, combo-point simulator, server-authoritative resource sync over the `PARAA` addon channel, action-button usability + click guards, an expanded spellbook (higher `MAX_SPELLS`, 24 skill-line tabs instead of stock 8) so all-class spells render, and a tooltip post-processor that appends ", Paragon" to the "Classes:" line on class-restricted gear / glyphs (the server bypasses `AllowableClass` for class 12, but the engine paints the line red and omits Paragon — the Lua hook recolors it green and adds the name so the player can tell it's wearable). |
|
| `patch-enUS-5.MPQ` | ~50 KB | FrameXML overrides. Replaces stock `PlayerFrame.lua` / `RuneFrame.lua` / `ComboFrame.lua` / `UnitFrame.lua` / `SpellBookFrame.lua` + `SpellBookFrame.xml` with Paragon-aware versions: rune simulator, combo-point simulator, server-authoritative resource sync over the `PARAA` addon channel, action-button usability + click guards, an expanded spellbook (higher `MAX_SPELLS`, 24 skill-line tabs instead of stock 8) so all-class spells render, Paragon stat tooltips on the character sheet, and a tooltip post-processor that appends ", Paragon" to the "Classes:" line on class-restricted gear / glyphs (the server bypasses `AllowableClass` for class 12, but the engine paints the line red and omits Paragon — the Lua hook recolors it green and adds the name so the player can tell it's wearable). The paper-doll **ammo slot** follows stock visibility rules (shown for hunters / ranged weapons; hidden when `UnitHasRelicSlot` applies). |
|
||||||
| `patch-enUS-6.MPQ` | ~160 KB | The `ParagonAdvancement` addon. Replaces the talent pane (`N` key) for Paragon characters with the Character Advancement panel: per-class spell tabs, talent grid, Overview/Search tabs, AE/TE currency, commit / reset / preview, login-time toast suppression. |
|
| `patch-enUS-6.MPQ` | ~160 KB | The `ParagonAdvancement` addon. Replaces the talent pane (`N` key) for Paragon characters with the Character Advancement panel: per-class spell tabs, talent grid, Overview/Search tabs, AE/TE currency, commit / reset / preview, login-time toast suppression. |
|
||||||
| `Wow.exe` | ~7.5 MB | 3.3.5a (build 12340) client byte-patched to skip the MPQ signature check so custom `patch-enUS-N.MPQ` files load. Diff against stock is a few bytes; everything else is unchanged. |
|
| `Wow.exe` | ~7.5 MB | 3.3.5a (build 12340) client byte-patched to skip the MPQ signature check so custom `patch-enUS-N.MPQ` files load. Diff against stock is a few bytes; everything else is unchanged. |
|
||||||
|
|
||||||
@@ -233,7 +233,12 @@ tools\build_paragon_advancement_patch.ps1 -Deploy # -> patch-enUS-6.MPQ
|
|||||||
|
|
||||||
`patch-enUS-4.MPQ` is the DBC + GlueXML bake; the bake scripts live with
|
`patch-enUS-4.MPQ` is the DBC + GlueXML bake; the bake scripts live with
|
||||||
the rest of the dev tooling and are not part of this repo by design
|
the rest of the dev tooling and are not part of this repo by design
|
||||||
(see the repo-tidy policy in `README.txt` next to this file).
|
(see the repo-tidy policy in `README.txt` next to this file). Typical
|
||||||
|
order on a maintainer machine:
|
||||||
|
|
||||||
|
1. `fractured-tooling/from-workspace-root/_patch_spell_dbc_runes.py` — stage `Spell.dbc` with `RuneCostID` cleared.
|
||||||
|
2. `fractured-tooling/from-workspace-root/_patch_spell_dbc_reagents.py` — same staged `Spell.dbc`, clear class-spell reagents for client preflight.
|
||||||
|
3. `fractured-tooling/from-workspace-root/_make_paragon_dbc_patch.py` — rebuild `ChrClasses` / `CharBaseInfo` / game tables, then pack `patch-enUS-4.MPQ`.
|
||||||
|
|
||||||
The patched `Wow.exe` is a one-time hex-edit of the stock 3.3.5a
|
The patched `Wow.exe` is a one-time hex-edit of the stock 3.3.5a
|
||||||
client. The diff is publicly documented in the WoW emulation community
|
client. The diff is publicly documented in the WoW emulation community
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "SpellScript.h"
|
#include "SpellScript.h"
|
||||||
#include "SpellScriptLoader.h"
|
#include "SpellScriptLoader.h"
|
||||||
#include "UnitDefines.h"
|
|
||||||
#include "WorldPacket.h"
|
#include "WorldPacket.h"
|
||||||
#include "WorldSession.h"
|
#include "WorldSession.h"
|
||||||
|
|
||||||
@@ -66,6 +65,37 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unified relic / ranged slot for class 12.
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
// CLASS_CONTEXT_EQUIP_RELIC is read in exactly two places in core
|
||||||
|
// (PlayerStorage.cpp): FindEquipSlot's INVTYPE_RELIC switch, which
|
||||||
|
// routes Librams/Idols/Totems/Misc/Sigils into EQUIPMENT_SLOT_RANGED
|
||||||
|
// for the matching class only, and CanEquipUniqueItem's per-subclass
|
||||||
|
// proficiency gate. By claiming this context for paladin/druid/
|
||||||
|
// shaman/warlock/dk we let Paragon drop any of those relics into the
|
||||||
|
// ranged slot exactly the same way each native class does, with no
|
||||||
|
// core patch and no other side effects (the constant is not read
|
||||||
|
// anywhere else in the codebase).
|
||||||
|
//
|
||||||
|
// Bows/guns/crossbows already equip via the regular
|
||||||
|
// INVTYPE_RANGED/RANGEDRIGHT routing -- weapon proficiencies for
|
||||||
|
// class 12 are seeded by the Paragon proficiency SQL migrations, so
|
||||||
|
// they pass the GetSkillValue check in CanEquipUniqueItem.
|
||||||
|
if (context == CLASS_CONTEXT_EQUIP_RELIC)
|
||||||
|
{
|
||||||
|
switch (unitClass)
|
||||||
|
{
|
||||||
|
case CLASS_PALADIN:
|
||||||
|
case CLASS_DRUID:
|
||||||
|
case CLASS_SHAMAN:
|
||||||
|
case CLASS_WARLOCK:
|
||||||
|
case CLASS_DEATH_KNIGHT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -385,6 +385,13 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (getClass() == CLASS_PARAGON)
|
||||||
|
{
|
||||||
|
// Fractured class 12: same hybrid curve as requested for Paragon UI
|
||||||
|
// (level*2 + AGI + STR - 20). Implemented in core so we do not rely
|
||||||
|
// on PlayerScript hooks in this hot path.
|
||||||
|
val2 = level * 2.0f + GetStat(STAT_AGILITY) + GetStat(STAT_STRENGTH) - 20.0f;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
val2 = GetStat(STAT_AGILITY) - 10.0f;
|
val2 = GetStat(STAT_AGILITY) - 10.0f;
|
||||||
@@ -481,6 +488,10 @@ void Player::UpdateAttackPowerAndDamage(bool ranged)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (getClass() == CLASS_PARAGON)
|
||||||
|
{
|
||||||
|
val2 = level * 2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f;
|
||||||
|
}
|
||||||
else if (IsClass(CLASS_MAGE, CLASS_CONTEXT_STATS) || IsClass(CLASS_PRIEST, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARLOCK, CLASS_CONTEXT_STATS))
|
else if (IsClass(CLASS_MAGE, CLASS_CONTEXT_STATS) || IsClass(CLASS_PRIEST, CLASS_CONTEXT_STATS) || IsClass(CLASS_WARLOCK, CLASS_CONTEXT_STATS))
|
||||||
{
|
{
|
||||||
val2 = GetStat(STAT_STRENGTH) - 10.0f;
|
val2 = GetStat(STAT_STRENGTH) - 10.0f;
|
||||||
|
|||||||
@@ -9046,6 +9046,21 @@ int32 Unit::SpellBaseDamageBonusDone(SpellSchoolMask schoolMask)
|
|||||||
DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
|
DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
|
||||||
DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellDamageBonus();
|
DoneAdvertisedBenefit += ToPlayer()->GetBaseSpellDamageBonus();
|
||||||
|
|
||||||
|
// Fractured class 12 (Paragon) intrinsic spell power:
|
||||||
|
// SP = level*2 + INT + SPI - 20 (clamped at 0)
|
||||||
|
// Read live from current stats so character-sheet refreshes (via
|
||||||
|
// UpdateSpellDamageAndHealingBonus) and live spell casts both see the
|
||||||
|
// up-to-date value with no script hooks or m_baseSpellPower mutation.
|
||||||
|
if (ToPlayer()->getClass() == CLASS_PARAGON)
|
||||||
|
{
|
||||||
|
int32 paragonSP = int32(GetLevel()) * 2
|
||||||
|
+ int32(GetStat(STAT_INTELLECT))
|
||||||
|
+ int32(GetStat(STAT_SPIRIT))
|
||||||
|
- 20;
|
||||||
|
if (paragonSP > 0)
|
||||||
|
DoneAdvertisedBenefit += paragonSP;
|
||||||
|
}
|
||||||
|
|
||||||
// Damage bonus from stats
|
// Damage bonus from stats
|
||||||
AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
|
AuraEffectList const& mDamageDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT);
|
||||||
for (AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i)
|
for (AuraEffectList::const_iterator i = mDamageDoneOfStatPercent.begin(); i != mDamageDoneOfStatPercent.end(); ++i)
|
||||||
@@ -9803,6 +9818,20 @@ int32 Unit::SpellBaseHealingBonusDone(SpellSchoolMask schoolMask)
|
|||||||
AdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
|
AdvertisedBenefit += ToPlayer()->GetBaseSpellPowerBonus();
|
||||||
AdvertisedBenefit += ToPlayer()->GetBaseSpellHealingBonus();
|
AdvertisedBenefit += ToPlayer()->GetBaseSpellHealingBonus();
|
||||||
|
|
||||||
|
// Fractured class 12 (Paragon) intrinsic spell power: same level*2 +
|
||||||
|
// INT + SPI - 20 floor as on the damage side (the character sheet
|
||||||
|
// shows a single Spell Power value, so both sides must add the same
|
||||||
|
// bonus).
|
||||||
|
if (ToPlayer()->getClass() == CLASS_PARAGON)
|
||||||
|
{
|
||||||
|
int32 paragonSP = int32(GetLevel()) * 2
|
||||||
|
+ int32(GetStat(STAT_INTELLECT))
|
||||||
|
+ int32(GetStat(STAT_SPIRIT))
|
||||||
|
- 20;
|
||||||
|
if (paragonSP > 0)
|
||||||
|
AdvertisedBenefit += paragonSP;
|
||||||
|
}
|
||||||
|
|
||||||
// Healing bonus from stats
|
// Healing bonus from stats
|
||||||
AuraEffectList const& mHealingDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
|
AuraEffectList const& mHealingDoneOfStatPercent = GetAuraEffectsByType(SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT);
|
||||||
for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
|
for (AuraEffectList::const_iterator i = mHealingDoneOfStatPercent.begin(); i != mHealingDoneOfStatPercent.end(); ++i)
|
||||||
|
|||||||
@@ -5368,6 +5368,44 @@ void SpellMgr::LoadSpellInfoCorrections()
|
|||||||
LockEntry* key = const_cast<LockEntry*>(sLockStore.LookupEntry(36)); // 3366 Opening, allows to open without proper key
|
LockEntry* key = const_cast<LockEntry*>(sLockStore.LookupEntry(36)); // 3366 Opening, allows to open without proper key
|
||||||
key->Type[2] = LOCK_KEY_NONE;
|
key->Type[2] = LOCK_KEY_NONE;
|
||||||
|
|
||||||
|
// Fractured: strip reagent requirements from every player-class spell at
|
||||||
|
// load time. Filtered by SpellFamilyName != 0 so that profession spells
|
||||||
|
// (cooking, alchemy, enchanting, blacksmithing, jewelcrafting, leatherworking,
|
||||||
|
// tailoring, engineering, inscription, mining, herbalism, skinning, fishing,
|
||||||
|
// first aid — all SpellFamilyName == SPELLFAMILY_GENERIC == 0) keep their
|
||||||
|
// mats and only the class abilities that asked for ankhs / candles / soul
|
||||||
|
// shards / verdant spheres / etc. cast freely. Done here in core spell
|
||||||
|
// data rather than as a runtime bypass in Spell::CheckItems / TakeReagents
|
||||||
|
// so the change is data-driven (the in-memory SpellInfo simply has no
|
||||||
|
// reagents to require). The client-side preflight is mirrored by the
|
||||||
|
// matching Spell.dbc patch shipped via patch-enUS-4.MPQ
|
||||||
|
// (fractured-tooling/_patch_spell_dbc_reagents.py).
|
||||||
|
{
|
||||||
|
uint32 fixedClassSpells = 0;
|
||||||
|
for (uint32 spellId = 1; spellId < sSpellMgr->GetSpellInfoStoreSize(); ++spellId)
|
||||||
|
{
|
||||||
|
SpellInfo const* info = sSpellMgr->GetSpellInfo(spellId);
|
||||||
|
if (!info || info->SpellFamilyName == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool hadAny = false;
|
||||||
|
for (uint32 i = 0; i < MAX_SPELL_REAGENTS; ++i)
|
||||||
|
if (info->Reagent[i] != 0 || info->ReagentCount[i] != 0)
|
||||||
|
{ hadAny = true; break; }
|
||||||
|
if (!hadAny)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SpellInfo* mut = const_cast<SpellInfo*>(info);
|
||||||
|
for (uint32 i = 0; i < MAX_SPELL_REAGENTS; ++i)
|
||||||
|
{
|
||||||
|
mut->Reagent[i] = 0;
|
||||||
|
mut->ReagentCount[i] = 0;
|
||||||
|
}
|
||||||
|
++fixedClassSpells;
|
||||||
|
}
|
||||||
|
LOG_INFO("server.loading", ">> Fractured: cleared reagents on {} class spells", fixedClassSpells);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_INFO("server.loading", ">> Loading spell dbc data corrections in {} ms", GetMSTimeDiffToNow(oldMSTime));
|
LOG_INFO("server.loading", ">> Loading spell dbc data corrections in {} ms", GetMSTimeDiffToNow(oldMSTime));
|
||||||
LOG_INFO("server.loading", " ");
|
LOG_INFO("server.loading", " ");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user