diff options
| author | Ovahlord <dreadkiller@gmx.de> | 2024-07-11 17:13:55 +0200 |
|---|---|---|
| committer | Ovahlord <dreadkiller@gmx.de> | 2024-07-11 17:14:22 +0200 |
| commit | fe97a864153c1fcf1bc60299aadd40c8db45ce6a (patch) | |
| tree | 1a661234d2ca5b06164c57c92a6ac1a4e8b2a132 /src/server/game/Spells/Spell.cpp | |
| parent | 3bb327b2bc74745af3833f08e19d7a9e5cc88215 (diff) | |
Core/Player: update rune regeneration and consumption for Cataclysm Classic
* the regeneration bonus from haste is tied to the HasteRegen update field and must be implemented first before we can handle it
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 119 |
1 files changed, 94 insertions, 25 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 29a652721f3..370acf14178 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4729,7 +4729,7 @@ void Spell::SendSpellStart() && std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }) != m_powerCost.end()) castFlags |= CAST_FLAG_POWER_LEFT_SELF; - if (HasPowerTypeCost(POWER_RUNES)) + if (HasPowerTypeCost(POWER_RUNE_BLOOD) || HasPowerTypeCost(POWER_RUNE_FROST) || HasPowerTypeCost(POWER_RUNE_UNHOLY)) castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it if (m_spellInfo->HasAttribute(SPELL_ATTR8_HEAL_PREDICTION) && m_casttime && m_caster->IsUnit()) @@ -4775,10 +4775,10 @@ void Spell::SendSpellStart() { castData.RemainingRunes->Start = m_runesState; // runes state before castData.RemainingRunes->Count = player->GetRunesState(); // runes state after - for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i) + for (uint8 i = 0; i < MAX_RUNES; ++i) { // float casts ensure the division is performed on floats as we need float result - float baseCd = float(player->GetRuneBaseCooldown()); + float baseCd = float(RUNE_BASE_COOLDOWN); castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed } } @@ -4786,7 +4786,7 @@ void Spell::SendSpellStart() { castData.RemainingRunes->Start = 0; castData.RemainingRunes->Count = 0; - for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i) + for (uint8 i = 0; i < MAX_RUNES; ++i) castData.RemainingRunes->Cooldowns.push_back(0); } } @@ -4830,7 +4830,7 @@ void Spell::SendSpellGo() if ((m_caster->GetTypeId() == TYPEID_PLAYER) && (m_caster->ToPlayer()->GetClass() == CLASS_DEATH_KNIGHT) - && HasPowerTypeCost(POWER_RUNES) + && (HasPowerTypeCost(POWER_RUNE_BLOOD) || HasPowerTypeCost(POWER_RUNE_FROST) || HasPowerTypeCost(POWER_RUNE_UNHOLY)) && !(_triggeredCastFlags & TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)) { castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it @@ -4881,10 +4881,10 @@ void Spell::SendSpellGo() Player* player = ASSERT_NOTNULL(m_caster->ToPlayer()); castData.RemainingRunes->Start = m_runesState; // runes state before castData.RemainingRunes->Count = player->GetRunesState(); // runes state after - for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i) + for (uint8 i = 0; i < MAX_RUNES; ++i) { // float casts ensure the division is performed on floats as we need float result - float baseCd = float(player->GetRuneBaseCooldown()); + float baseCd = float(RUNE_BASE_COOLDOWN); castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed } } @@ -5455,7 +5455,7 @@ void Spell::TakePower() } } - if (powerType == POWER_RUNES) + if (powerType == POWER_RUNE_BLOOD || powerType == POWER_RUNE_FROST || powerType == POWER_RUNE_UNHOLY) { TakeRunePower(hit); continue; @@ -5483,12 +5483,12 @@ void Spell::TakePower() SpellCastResult Spell::CheckRuneCost() const { - int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost) + int32 totalRuneCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost) { - return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0); + return totalCost + ((cost.Power == POWER_RUNE_BLOOD || cost.Power == POWER_RUNE_FROST || cost.Power == POWER_RUNE_UNHOLY) ? cost.Amount : 0); }); - if (!runeCost) + if (!totalRuneCost) return SPELL_CAST_OK; Player* player = m_caster->ToPlayer(); @@ -5498,12 +5498,31 @@ SpellCastResult Spell::CheckRuneCost() const if (player->GetClass() != CLASS_DEATH_KNIGHT) return SPELL_CAST_OK; - int32 readyRunes = 0; - for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i) - if (player->GetRuneCooldown(i) == 0) - ++readyRunes; + std::array<int32, AsUnderlyingType(RuneType::Max)> runeCost = { }; // blood, frost, unholy, death + for (SpellPowerCost const& cost : m_powerCost) + { + switch (cost.Power) + { + case POWER_RUNE_BLOOD: runeCost[AsUnderlyingType(RuneType::Blood)] = cost.Amount; break; + case POWER_RUNE_FROST: runeCost[AsUnderlyingType(RuneType::Frost)] = cost.Amount; break; + case POWER_RUNE_UNHOLY: runeCost[AsUnderlyingType(RuneType::Unholy)] = cost.Amount; break; + default: + break; + } + } - if (readyRunes < runeCost) + for (uint32 i = 0; i < MAX_RUNES; ++i) + { + RuneType rune = player->GetCurrentRune(i); + if ((player->GetRuneCooldown(i) == 0) && (runeCost[AsUnderlyingType(rune)] > 0)) + runeCost[AsUnderlyingType(rune)]--; + } + + for (uint8 i = 0; i < AsUnderlyingType(RuneType::Death); ++i) + if (runeCost[i] > 0) + runeCost[AsUnderlyingType(RuneType::Death)] += runeCost[i]; + + if (runeCost[AsUnderlyingType(RuneType::Death)] > MAX_RUNES) return SPELL_FAILED_NO_POWER; // not sure if result code is correct return SPELL_CAST_OK; @@ -5514,20 +5533,70 @@ void Spell::TakeRunePower(bool didHit) if (m_caster->GetTypeId() != TYPEID_PLAYER || m_caster->ToPlayer()->GetClass() != CLASS_DEATH_KNIGHT) return; + int32 totalRuneCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost) + { + return totalCost + ((cost.Power == POWER_RUNE_BLOOD || cost.Power == POWER_RUNE_FROST || cost.Power == POWER_RUNE_UNHOLY) ? cost.Amount : 0); + }); + + // Spells that do not consume any runes, do not grant any Runic Power + if (!totalRuneCost) + return; + Player* player = m_caster->ToPlayer(); m_runesState = player->GetRunesState(); // store previous state + player->ClearLastUsedRuneMask(); + + std::array<int32, AsUnderlyingType(RuneType::Max)> runeCost = { }; // blood, frost, unholy, death + for (SpellPowerCost const& cost : m_powerCost) + { + switch (cost.Power) + { + case POWER_RUNE_BLOOD: runeCost[AsUnderlyingType(RuneType::Blood)] = cost.Amount; break; + case POWER_RUNE_FROST: runeCost[AsUnderlyingType(RuneType::Frost)] = cost.Amount; break; + case POWER_RUNE_UNHOLY: runeCost[AsUnderlyingType(RuneType::Unholy)] = cost.Amount; break; + default: + break; + } + } - int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost) + // Let's say we use a skill that requires a Frost rune. This is the order: + // - Frost rune + // - Death rune, originally a Frost rune + // - Death rune, any kind + for (uint32 i = 0; i < MAX_RUNES; ++i) { - return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0); - }); + RuneType rune = player->GetCurrentRune(i); + if (!player->GetRuneCooldown(i) && runeCost[AsUnderlyingType(rune)] > 0) + { + player->SetRuneCooldown(i, didHit ? uint32(RUNE_BASE_COOLDOWN) : uint32(RUNE_MISS_COOLDOWN)); + player->SetLastUsedRune(rune); + player->SetLastUsedRuneIndex(i); + --runeCost[AsUnderlyingType(rune)]; + } + } - for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i) + // Find a Death rune where the base rune matches the one we need + runeCost[AsUnderlyingType(RuneType::Death)] = runeCost[AsUnderlyingType(RuneType::Blood)] + runeCost[AsUnderlyingType(RuneType::Unholy)] + runeCost[AsUnderlyingType(RuneType::Frost)]; + + if (runeCost[AsUnderlyingType(RuneType::Death)] > 0) { - if (!player->GetRuneCooldown(i) && runeCost > 0) + for (uint8 i = 0; i < MAX_RUNES; ++i) { - player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown() : uint32(RUNE_MISS_COOLDOWN)); - --runeCost; + RuneType rune = player->GetCurrentRune(i); + if (!player->GetRuneCooldown(i) && rune == RuneType::Death) + { + player->SetRuneCooldown(i, didHit ? uint32(RUNE_BASE_COOLDOWN) : uint32(RUNE_MISS_COOLDOWN)); + player->SetLastUsedRune(rune); + player->SetLastUsedRuneIndex(i); + runeCost[AsUnderlyingType(rune)]--; + + // keep Death Rune type if missed + if (didHit) + player->RestoreBaseRune(i); + + if (runeCost[AsUnderlyingType(RuneType::Death)] == 0) + break; + } } } } @@ -7260,8 +7329,8 @@ SpellCastResult Spell::CheckPower() const return SPELL_FAILED_UNKNOWN; } - //check rune cost only if a spell has PowerType == POWER_RUNES - if (cost.Power == POWER_RUNES) + // check rune cost only if a spell has PowerType == POWER_RUNE_BLOOD or POWER_RUNE_FROST or POWER_RUNE_UNHOLY + if (cost.Power == POWER_RUNE_BLOOD || cost.Power == POWER_RUNE_FROST || cost.Power == POWER_RUNE_UNHOLY) { SpellCastResult failReason = CheckRuneCost(); if (failReason != SPELL_CAST_OK) |
