mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
feat: resolve spell \$d duration to real seconds from SpellDuration.dbc
Spell descriptions now substitute \$d with actual duration values: Before: "X damage over X sec" After: "30 damage over 18 sec" Implementation: - DurationIndex field (40) added to all expansion Spell.dbc layouts - SpellDuration.dbc loaded during cache build: maps index → base ms - cleanSpellDescription substitutes \$d with resolved seconds/minutes - getSpellDuration() accessor on GameHandler Combined with \$s1/\$s2/\$s3 from the previous commit, most common spell description templates are now fully resolved with real values.
This commit is contained in:
parent
a5aa1faf7a
commit
11ecc475c8
7 changed files with 48 additions and 4 deletions
|
|
@ -168,6 +168,7 @@
|
||||||
"AttributesEx": 6,
|
"AttributesEx": 6,
|
||||||
"CastingTimeIndex": 15,
|
"CastingTimeIndex": 15,
|
||||||
"DispelType": 4,
|
"DispelType": 4,
|
||||||
|
"DurationIndex": 40,
|
||||||
"EffectBasePoints0": 80,
|
"EffectBasePoints0": 80,
|
||||||
"EffectBasePoints1": 81,
|
"EffectBasePoints1": 81,
|
||||||
"EffectBasePoints2": 82,
|
"EffectBasePoints2": 82,
|
||||||
|
|
|
||||||
|
|
@ -207,6 +207,7 @@
|
||||||
"AttributesEx": 6,
|
"AttributesEx": 6,
|
||||||
"CastingTimeIndex": 22,
|
"CastingTimeIndex": 22,
|
||||||
"DispelType": 3,
|
"DispelType": 3,
|
||||||
|
"DurationIndex": 40,
|
||||||
"EffectBasePoints0": 80,
|
"EffectBasePoints0": 80,
|
||||||
"EffectBasePoints1": 81,
|
"EffectBasePoints1": 81,
|
||||||
"EffectBasePoints2": 82,
|
"EffectBasePoints2": 82,
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,7 @@
|
||||||
"AttributesEx": 6,
|
"AttributesEx": 6,
|
||||||
"CastingTimeIndex": 15,
|
"CastingTimeIndex": 15,
|
||||||
"DispelType": 4,
|
"DispelType": 4,
|
||||||
|
"DurationIndex": 40,
|
||||||
"EffectBasePoints0": 80,
|
"EffectBasePoints0": 80,
|
||||||
"EffectBasePoints1": 81,
|
"EffectBasePoints1": 81,
|
||||||
"EffectBasePoints2": 82,
|
"EffectBasePoints2": 82,
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,7 @@
|
||||||
"AttributesEx": 5,
|
"AttributesEx": 5,
|
||||||
"CastingTimeIndex": 47,
|
"CastingTimeIndex": 47,
|
||||||
"DispelType": 2,
|
"DispelType": 2,
|
||||||
|
"DurationIndex": 40,
|
||||||
"EffectBasePoints0": 80,
|
"EffectBasePoints0": 80,
|
||||||
"EffectBasePoints1": 81,
|
"EffectBasePoints1": 81,
|
||||||
"EffectBasePoints2": 82,
|
"EffectBasePoints2": 82,
|
||||||
|
|
|
||||||
|
|
@ -2245,6 +2245,7 @@ public:
|
||||||
/// Returns the tooltip/description text from Spell.dbc (empty if unknown or has no text).
|
/// Returns the tooltip/description text from Spell.dbc (empty if unknown or has no text).
|
||||||
const std::string& getSpellDescription(uint32_t spellId) const;
|
const std::string& getSpellDescription(uint32_t spellId) const;
|
||||||
const int32_t* getSpellEffectBasePoints(uint32_t spellId) const;
|
const int32_t* getSpellEffectBasePoints(uint32_t spellId) const;
|
||||||
|
float getSpellDuration(uint32_t spellId) const;
|
||||||
std::string getEnchantName(uint32_t enchantId) const;
|
std::string getEnchantName(uint32_t enchantId) const;
|
||||||
const std::string& getSkillLineName(uint32_t spellId) const;
|
const std::string& getSkillLineName(uint32_t spellId) const;
|
||||||
/// Returns the DispelType for a spell (0=none,1=magic,2=curse,3=disease,4=poison,5+=other)
|
/// Returns the DispelType for a spell (0=none,1=magic,2=curse,3=disease,4=poison,5+=other)
|
||||||
|
|
@ -3327,6 +3328,7 @@ private:
|
||||||
std::string name; std::string rank; std::string description;
|
std::string name; std::string rank; std::string description;
|
||||||
uint32_t schoolMask = 0; uint8_t dispelType = 0; uint32_t attrEx = 0;
|
uint32_t schoolMask = 0; uint8_t dispelType = 0; uint32_t attrEx = 0;
|
||||||
int32_t effectBasePoints[3] = {0, 0, 0};
|
int32_t effectBasePoints[3] = {0, 0, 0};
|
||||||
|
float durationSec = 0.0f; // resolved from DurationIndex → SpellDuration.dbc
|
||||||
};
|
};
|
||||||
std::unordered_map<uint32_t, SpellNameEntry> spellNameCache_;
|
std::unordered_map<uint32_t, SpellNameEntry> spellNameCache_;
|
||||||
bool spellNameCacheLoaded_ = false;
|
bool spellNameCacheLoaded_ = false;
|
||||||
|
|
|
||||||
|
|
@ -1627,7 +1627,7 @@ static int lua_GetSpellBookItemName(lua_State* L) {
|
||||||
|
|
||||||
// GetSpellDescription(spellId) → description string
|
// GetSpellDescription(spellId) → description string
|
||||||
// Clean spell description template variables for display
|
// Clean spell description template variables for display
|
||||||
static std::string cleanSpellDescription(const std::string& raw, const int32_t effectBase[3] = nullptr) {
|
static std::string cleanSpellDescription(const std::string& raw, const int32_t effectBase[3] = nullptr, float durationSec = 0.0f) {
|
||||||
if (raw.empty() || raw.find('$') == std::string::npos) return raw;
|
if (raw.empty() || raw.find('$') == std::string::npos) return raw;
|
||||||
std::string result;
|
std::string result;
|
||||||
result.reserve(raw.size());
|
result.reserve(raw.size());
|
||||||
|
|
@ -1657,8 +1657,15 @@ static std::string cleanSpellDescription(const std::string& raw, const int32_t e
|
||||||
i += 1;
|
i += 1;
|
||||||
while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i;
|
while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i;
|
||||||
} else if (next == 'd' || next == 'D') {
|
} else if (next == 'd' || next == 'D') {
|
||||||
// $d = duration — replace with "X sec"
|
// $d = duration
|
||||||
result += "X sec";
|
if (durationSec > 0.0f) {
|
||||||
|
if (durationSec >= 60.0f)
|
||||||
|
result += std::to_string(static_cast<int>(durationSec / 60.0f)) + " min";
|
||||||
|
else
|
||||||
|
result += std::to_string(static_cast<int>(durationSec)) + " sec";
|
||||||
|
} else {
|
||||||
|
result += "X sec";
|
||||||
|
}
|
||||||
++i;
|
++i;
|
||||||
while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i;
|
while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i;
|
||||||
} else if (next == 'a' || next == 'A') {
|
} else if (next == 'a' || next == 'A') {
|
||||||
|
|
@ -1698,7 +1705,8 @@ static int lua_GetSpellDescription(lua_State* L) {
|
||||||
uint32_t spellId = static_cast<uint32_t>(luaL_checknumber(L, 1));
|
uint32_t spellId = static_cast<uint32_t>(luaL_checknumber(L, 1));
|
||||||
const std::string& desc = gh->getSpellDescription(spellId);
|
const std::string& desc = gh->getSpellDescription(spellId);
|
||||||
const int32_t* ebp = gh->getSpellEffectBasePoints(spellId);
|
const int32_t* ebp = gh->getSpellEffectBasePoints(spellId);
|
||||||
std::string cleaned = cleanSpellDescription(desc, ebp);
|
float dur = gh->getSpellDuration(spellId);
|
||||||
|
std::string cleaned = cleanSpellDescription(desc, ebp, dur);
|
||||||
lua_pushstring(L, cleaned.c_str());
|
lua_pushstring(L, cleaned.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23200,9 +23200,33 @@ void GameHandler::loadSpellNameCache() {
|
||||||
if (f1 != 0xFFFFFFFF) entry.effectBasePoints[1] = static_cast<int32_t>(dbc->getUInt32(i, f1));
|
if (f1 != 0xFFFFFFFF) entry.effectBasePoints[1] = static_cast<int32_t>(dbc->getUInt32(i, f1));
|
||||||
if (f2 != 0xFFFFFFFF) entry.effectBasePoints[2] = static_cast<int32_t>(dbc->getUInt32(i, f2));
|
if (f2 != 0xFFFFFFFF) entry.effectBasePoints[2] = static_cast<int32_t>(dbc->getUInt32(i, f2));
|
||||||
}
|
}
|
||||||
|
// Duration: read DurationIndex and resolve via SpellDuration.dbc later
|
||||||
|
if (spellL) {
|
||||||
|
uint32_t durF = spellL->field("DurationIndex");
|
||||||
|
if (durF != 0xFFFFFFFF)
|
||||||
|
entry.durationSec = static_cast<float>(dbc->getUInt32(i, durF)); // store index temporarily
|
||||||
|
}
|
||||||
spellNameCache_[id] = std::move(entry);
|
spellNameCache_[id] = std::move(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Resolve DurationIndex → seconds via SpellDuration.dbc
|
||||||
|
auto durDbc = am->loadDBC("SpellDuration.dbc");
|
||||||
|
if (durDbc && durDbc->isLoaded()) {
|
||||||
|
std::unordered_map<uint32_t, float> durMap;
|
||||||
|
for (uint32_t di = 0; di < durDbc->getRecordCount(); ++di) {
|
||||||
|
uint32_t durId = durDbc->getUInt32(di, 0);
|
||||||
|
int32_t baseMs = static_cast<int32_t>(durDbc->getUInt32(di, 1));
|
||||||
|
if (baseMs > 0 && baseMs < 100000000) // filter out absurd values
|
||||||
|
durMap[durId] = baseMs / 1000.0f;
|
||||||
|
}
|
||||||
|
for (auto& [sid, entry] : spellNameCache_) {
|
||||||
|
uint32_t durIdx = static_cast<uint32_t>(entry.durationSec);
|
||||||
|
if (durIdx > 0) {
|
||||||
|
auto it = durMap.find(durIdx);
|
||||||
|
entry.durationSec = (it != durMap.end()) ? it->second : 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
LOG_INFO("Trainer: Loaded ", spellNameCache_.size(), " spell names from Spell.dbc");
|
LOG_INFO("Trainer: Loaded ", spellNameCache_.size(), " spell names from Spell.dbc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23445,6 +23469,12 @@ const int32_t* GameHandler::getSpellEffectBasePoints(uint32_t spellId) const {
|
||||||
return (it != spellNameCache_.end()) ? it->second.effectBasePoints : nullptr;
|
return (it != spellNameCache_.end()) ? it->second.effectBasePoints : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float GameHandler::getSpellDuration(uint32_t spellId) const {
|
||||||
|
const_cast<GameHandler*>(this)->loadSpellNameCache();
|
||||||
|
auto it = spellNameCache_.find(spellId);
|
||||||
|
return (it != spellNameCache_.end()) ? it->second.durationSec : 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& GameHandler::getSpellName(uint32_t spellId) const {
|
const std::string& GameHandler::getSpellName(uint32_t spellId) const {
|
||||||
auto it = spellNameCache_.find(spellId);
|
auto it = spellNameCache_.find(spellId);
|
||||||
return (it != spellNameCache_.end()) ? it->second.name : EMPTY_STRING;
|
return (it != spellNameCache_.end()) ? it->second.name : EMPTY_STRING;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue