mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Fix spell cast audio to use correct magic school from Spell.dbc
Previously all player spell casts played ARCANE school sounds regardless of the actual spell school. Now loadSpellNameCache() reads SchoolMask (bitmask, TBC/WotLK) or SchoolEnum (Vanilla/Classic) from Spell.dbc and stores it in SpellNameEntry. handleSpellStart/handleSpellGo look up the spell's school and select the correct MagicSchool for cast sounds. DBC field indices: WotLK SchoolMask=225 (verified), TBC=215, Classic/Turtle SchoolEnum=1 (Vanilla enum 0-6 converted to bitmask).
This commit is contained in:
parent
3eded6772d
commit
d4ea416dd6
6 changed files with 50 additions and 10 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"Spell": {
|
"Spell": {
|
||||||
"ID": 0, "Attributes": 5, "IconID": 117,
|
"ID": 0, "Attributes": 5, "IconID": 117,
|
||||||
"Name": 120, "Tooltip": 147, "Rank": 129
|
"Name": 120, "Tooltip": 147, "Rank": 129, "SchoolEnum": 1
|
||||||
},
|
},
|
||||||
"ItemDisplayInfo": {
|
"ItemDisplayInfo": {
|
||||||
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"Spell": {
|
"Spell": {
|
||||||
"ID": 0, "Attributes": 5, "IconID": 124,
|
"ID": 0, "Attributes": 5, "IconID": 124,
|
||||||
"Name": 127, "Tooltip": 154, "Rank": 136
|
"Name": 127, "Tooltip": 154, "Rank": 136, "SchoolMask": 215
|
||||||
},
|
},
|
||||||
"ItemDisplayInfo": {
|
"ItemDisplayInfo": {
|
||||||
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"Spell": {
|
"Spell": {
|
||||||
"ID": 0, "Attributes": 5, "IconID": 117,
|
"ID": 0, "Attributes": 5, "IconID": 117,
|
||||||
"Name": 120, "Tooltip": 147, "Rank": 129
|
"Name": 120, "Tooltip": 147, "Rank": 129, "SchoolEnum": 1
|
||||||
},
|
},
|
||||||
"ItemDisplayInfo": {
|
"ItemDisplayInfo": {
|
||||||
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"Spell": {
|
"Spell": {
|
||||||
"ID": 0, "Attributes": 4, "IconID": 133,
|
"ID": 0, "Attributes": 4, "IconID": 133,
|
||||||
"Name": 136, "Tooltip": 139, "Rank": 153
|
"Name": 136, "Tooltip": 139, "Rank": 153, "SchoolMask": 225
|
||||||
},
|
},
|
||||||
"ItemDisplayInfo": {
|
"ItemDisplayInfo": {
|
||||||
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
"ID": 0, "LeftModel": 1, "LeftModelTexture": 3,
|
||||||
|
|
|
||||||
|
|
@ -1971,7 +1971,7 @@ private:
|
||||||
// Trainer
|
// Trainer
|
||||||
bool trainerWindowOpen_ = false;
|
bool trainerWindowOpen_ = false;
|
||||||
TrainerListData currentTrainerList_;
|
TrainerListData currentTrainerList_;
|
||||||
struct SpellNameEntry { std::string name; std::string rank; };
|
struct SpellNameEntry { std::string name; std::string rank; uint32_t schoolMask = 0; };
|
||||||
std::unordered_map<uint32_t, SpellNameEntry> spellNameCache_;
|
std::unordered_map<uint32_t, SpellNameEntry> spellNameCache_;
|
||||||
bool spellNameCacheLoaded_ = false;
|
bool spellNameCacheLoaded_ = false;
|
||||||
std::vector<TrainerTab> trainerTabs_;
|
std::vector<TrainerTab> trainerTabs_;
|
||||||
|
|
|
||||||
|
|
@ -12087,6 +12087,16 @@ void GameHandler::handleCastFailed(network::Packet& packet) {
|
||||||
addLocalChatMessage(msg);
|
addLocalChatMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static audio::SpellSoundManager::MagicSchool schoolMaskToMagicSchool(uint32_t mask) {
|
||||||
|
if (mask & 0x04) return audio::SpellSoundManager::MagicSchool::FIRE;
|
||||||
|
if (mask & 0x10) return audio::SpellSoundManager::MagicSchool::FROST;
|
||||||
|
if (mask & 0x02) return audio::SpellSoundManager::MagicSchool::HOLY;
|
||||||
|
if (mask & 0x08) return audio::SpellSoundManager::MagicSchool::NATURE;
|
||||||
|
if (mask & 0x20) return audio::SpellSoundManager::MagicSchool::SHADOW;
|
||||||
|
if (mask & 0x40) return audio::SpellSoundManager::MagicSchool::ARCANE;
|
||||||
|
return audio::SpellSoundManager::MagicSchool::ARCANE;
|
||||||
|
}
|
||||||
|
|
||||||
void GameHandler::handleSpellStart(network::Packet& packet) {
|
void GameHandler::handleSpellStart(network::Packet& packet) {
|
||||||
SpellStartData data;
|
SpellStartData data;
|
||||||
if (!SpellStartParser::parse(packet, data)) return;
|
if (!SpellStartParser::parse(packet, data)) return;
|
||||||
|
|
@ -12098,10 +12108,15 @@ void GameHandler::handleSpellStart(network::Packet& packet) {
|
||||||
castTimeTotal = data.castTime / 1000.0f;
|
castTimeTotal = data.castTime / 1000.0f;
|
||||||
castTimeRemaining = castTimeTotal;
|
castTimeRemaining = castTimeTotal;
|
||||||
|
|
||||||
// Play precast (channeling) sound
|
// Play precast (channeling) sound with correct magic school
|
||||||
if (auto* renderer = core::Application::getInstance().getRenderer()) {
|
if (auto* renderer = core::Application::getInstance().getRenderer()) {
|
||||||
if (auto* ssm = renderer->getSpellSoundManager()) {
|
if (auto* ssm = renderer->getSpellSoundManager()) {
|
||||||
ssm->playPrecast(audio::SpellSoundManager::MagicSchool::ARCANE, audio::SpellSoundManager::SpellPower::MEDIUM);
|
loadSpellNameCache();
|
||||||
|
auto it = spellNameCache_.find(data.spellId);
|
||||||
|
auto school = (it != spellNameCache_.end() && it->second.schoolMask)
|
||||||
|
? schoolMaskToMagicSchool(it->second.schoolMask)
|
||||||
|
: audio::SpellSoundManager::MagicSchool::ARCANE;
|
||||||
|
ssm->playPrecast(school, audio::SpellSoundManager::SpellPower::MEDIUM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12113,10 +12128,15 @@ void GameHandler::handleSpellGo(network::Packet& packet) {
|
||||||
|
|
||||||
// Cast completed
|
// Cast completed
|
||||||
if (data.casterUnit == playerGuid) {
|
if (data.casterUnit == playerGuid) {
|
||||||
// Play cast-complete sound before clearing state
|
// Play cast-complete sound with correct magic school
|
||||||
if (auto* renderer = core::Application::getInstance().getRenderer()) {
|
if (auto* renderer = core::Application::getInstance().getRenderer()) {
|
||||||
if (auto* ssm = renderer->getSpellSoundManager()) {
|
if (auto* ssm = renderer->getSpellSoundManager()) {
|
||||||
ssm->playCast(audio::SpellSoundManager::MagicSchool::ARCANE);
|
loadSpellNameCache();
|
||||||
|
auto it = spellNameCache_.find(data.spellId);
|
||||||
|
auto school = (it != spellNameCache_.end() && it->second.schoolMask)
|
||||||
|
? schoolMaskToMagicSchool(it->second.schoolMask)
|
||||||
|
: audio::SpellSoundManager::MagicSchool::ARCANE;
|
||||||
|
ssm->playCast(school);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -14269,6 +14289,17 @@ void GameHandler::loadSpellNameCache() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* spellL = pipeline::getActiveDBCLayout() ? pipeline::getActiveDBCLayout()->getLayout("Spell") : nullptr;
|
const auto* spellL = pipeline::getActiveDBCLayout() ? pipeline::getActiveDBCLayout()->getLayout("Spell") : nullptr;
|
||||||
|
|
||||||
|
// Determine school field (bitmask for TBC/WotLK, enum for Classic/Vanilla)
|
||||||
|
uint32_t schoolMaskField = 0, schoolEnumField = 0;
|
||||||
|
bool hasSchoolMask = false, hasSchoolEnum = false;
|
||||||
|
if (spellL) {
|
||||||
|
uint32_t f = spellL->field("SchoolMask");
|
||||||
|
if (f != 0xFFFFFFFF && f < dbc->getFieldCount()) { schoolMaskField = f; hasSchoolMask = true; }
|
||||||
|
f = spellL->field("SchoolEnum");
|
||||||
|
if (f != 0xFFFFFFFF && f < dbc->getFieldCount()) { schoolEnumField = f; hasSchoolEnum = true; }
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t count = dbc->getRecordCount();
|
uint32_t count = dbc->getRecordCount();
|
||||||
for (uint32_t i = 0; i < count; ++i) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
uint32_t id = dbc->getUInt32(i, spellL ? (*spellL)["ID"] : 0);
|
uint32_t id = dbc->getUInt32(i, spellL ? (*spellL)["ID"] : 0);
|
||||||
|
|
@ -14276,7 +14307,16 @@ void GameHandler::loadSpellNameCache() {
|
||||||
std::string name = dbc->getString(i, spellL ? (*spellL)["Name"] : 136);
|
std::string name = dbc->getString(i, spellL ? (*spellL)["Name"] : 136);
|
||||||
std::string rank = dbc->getString(i, spellL ? (*spellL)["Rank"] : 153);
|
std::string rank = dbc->getString(i, spellL ? (*spellL)["Rank"] : 153);
|
||||||
if (!name.empty()) {
|
if (!name.empty()) {
|
||||||
spellNameCache_[id] = {std::move(name), std::move(rank)};
|
SpellNameEntry entry{std::move(name), std::move(rank), 0};
|
||||||
|
if (hasSchoolMask) {
|
||||||
|
entry.schoolMask = dbc->getUInt32(i, schoolMaskField);
|
||||||
|
} else if (hasSchoolEnum) {
|
||||||
|
// Classic/Vanilla enum: 0=Physical,1=Holy,2=Fire,3=Nature,4=Frost,5=Shadow,6=Arcane
|
||||||
|
static const uint32_t enumToBitmask[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40};
|
||||||
|
uint32_t e = dbc->getUInt32(i, schoolEnumField);
|
||||||
|
entry.schoolMask = (e < 7) ? enumToBitmask[e] : 0;
|
||||||
|
}
|
||||||
|
spellNameCache_[id] = std::move(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG_INFO("Trainer: Loaded ", spellNameCache_.size(), " spell names from Spell.dbc");
|
LOG_INFO("Trainer: Loaded ", spellNameCache_.size(), " spell names from Spell.dbc");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue