From 4ea2a8f87d59a1c00a4be28007b5ef5fbdfdb1dd Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Thu, 31 Oct 2024 13:24:05 -0300 Subject: [PATCH 01/13] fix: wheel fixes --- data/scripts/lib/register_spells.lua | 2 +- data/scripts/spells/attack/divine_grenade.lua | 2 +- data/scripts/spells/attack/energy_beam.lua | 7 +- .../spells/attack/great_death_beam.lua | 28 +- .../spells/attack/great_energy_beam.lua | 12 +- data/scripts/spells/attack/ice_burst.lua | 37 +-- data/scripts/spells/attack/terra_burst.lua | 37 +-- .../spells/support/divine_empowerment.lua | 14 +- src/creatures/combat/combat.cpp | 5 - src/creatures/combat/spells.cpp | 5 + src/creatures/creatures_definitions.hpp | 2 + src/creatures/players/player.cpp | 2 +- src/creatures/players/wheel/player_wheel.cpp | 301 ++++++++++++++---- src/creatures/players/wheel/player_wheel.hpp | 82 ++--- .../players/wheel/wheel_definitions.hpp | 2 +- src/creatures/players/wheel/wheel_gems.cpp | 116 +++---- src/game/game.cpp | 4 +- src/io/io_wheel.cpp | 32 +- src/utils/tools.cpp | 6 + 19 files changed, 378 insertions(+), 318 deletions(-) diff --git a/data/scripts/lib/register_spells.lua b/data/scripts/lib/register_spells.lua index 8c549859640..f2e7cacee3d 100644 --- a/data/scripts/lib/register_spells.lua +++ b/data/scripts/lib/register_spells.lua @@ -386,7 +386,7 @@ AREA_RING1_BURST3 = { { 0, 0, 1, 1, 1, 1, 1, 0, 0 }, { 0, 1, 1, 1, 1, 1, 1, 1, 0 }, { 1, 1, 1, 0, 0, 0, 1, 1, 1 }, - { 1, 1, 1, 0, 3, 0, 1, 1, 1 }, + { 1, 1, 1, 0, 2, 0, 1, 1, 1 }, { 1, 1, 1, 0, 0, 0, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1, 0 }, { 0, 0, 1, 1, 1, 1, 1, 0, 0 }, diff --git a/data/scripts/spells/attack/divine_grenade.lua b/data/scripts/spells/attack/divine_grenade.lua index b1dc6399c7d..488962cb2f8 100644 --- a/data/scripts/spells/attack/divine_grenade.lua +++ b/data/scripts/spells/attack/divine_grenade.lua @@ -35,7 +35,7 @@ local explodeGrenade = function(position, playerId) end local var = {} - var.instantName = "Divine Grenade Explode" + var.instantName = "Divine Grenade" var.runeName = "" var.type = 2 -- VARIANT_POSITION var.pos = position diff --git a/data/scripts/spells/attack/energy_beam.lua b/data/scripts/spells/attack/energy_beam.lua index d3be218c0ca..049470f0ecb 100644 --- a/data/scripts/spells/attack/energy_beam.lua +++ b/data/scripts/spells/attack/energy_beam.lua @@ -28,11 +28,10 @@ local spell = Spell("instant") function spell.onCastSpell(creature, var) local player = creature:getPlayer() - if creature and player and player:instantSkillWOD("Beam Mastery") then - var.runeName = "Beam Mastery" - return combatWOD:execute(creature, var) + if not creature or not player then + return false end - return combat:execute(creature, var) + return player:instantSkillWOD("Beam Mastery") and combatWOD:execute(creature, var) or combat:execute(creature, var) end spell:group("attack") diff --git a/data/scripts/spells/attack/great_death_beam.lua b/data/scripts/spells/attack/great_death_beam.lua index 02a17c78f41..31fba671d56 100644 --- a/data/scripts/spells/attack/great_death_beam.lua +++ b/data/scripts/spells/attack/great_death_beam.lua @@ -17,6 +17,7 @@ end local combat1 = createCombat(initCombat, AREA_BEAM6) local combat2 = createCombat(initCombat, AREA_BEAM7) local combat3 = createCombat(initCombat, AREA_BEAM8) +local combat = { combat1, combat2, combat3 } local spell = Spell("instant") @@ -28,32 +29,15 @@ function spell.onCastSpell(creature, var) local grade = creature:upgradeSpellsWOD("Great Death Beam") if grade == WHEEL_GRADE_NONE then - creature:sendCancelMessage("You cannot cast this spell") + creature:sendCancelMessage("You need to learn this spell first") creature:getPosition():sendMagicEffect(CONST_ME_POFF) return false end - local cooldown = { 10, 8, 6 } - var.runeName = "Beam Mastery" - local executed = false - - local combat = { combat1, combat2, combat3 } - - executed = combat[grade]:execute(creature, var) - - if executed then - local condition = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 260) - local executedCooldown = cooldown[grade] - if executedCooldown ~= nil then - condition:setTicks((executedCooldown * 1000)) - end - creature:addCondition(condition) - return true - end - return false + return combat[grade]:execute(creature, var) end -spell:group("attack") +spell:group("attack", "greatbeams") spell:id(260) spell:name("Great Death Beam") spell:words("exevo max mort") @@ -62,8 +46,8 @@ spell:mana(140) spell:isPremium(false) spell:needDirection(true) spell:blockWalls(true) -spell:cooldown(1000) -- Cooldown is calculated on the casting -spell:groupCooldown(2 * 1000) +spell:cooldown(10 * 1000) +spell:groupCooldown(2 * 1000, 6 * 1000) spell:needLearn(true) spell:vocation("sorcerer;true", "master sorcerer;true") spell:register() diff --git a/data/scripts/spells/attack/great_energy_beam.lua b/data/scripts/spells/attack/great_energy_beam.lua index aae93e95c9a..f6b61f19fa4 100644 --- a/data/scripts/spells/attack/great_energy_beam.lua +++ b/data/scripts/spells/attack/great_energy_beam.lua @@ -28,15 +28,13 @@ local spell = Spell("instant") function spell.onCastSpell(creature, var) local player = creature:getPlayer() - if creature and player and player:instantSkillWOD("Beam Mastery") then - var.runeName = "Beam Mastery" - return combatWOD:execute(creature, var) + if not creature or not player then + return false end - - return combat:execute(creature, var) + return player:instantSkillWOD("Beam Mastery") and combatWOD:execute(creature, var) or combat:execute(creature, var) end -spell:group("attack") +spell:group("attack", "greatbeams") spell:id(23) spell:name("Great Energy Beam") spell:words("exevo gran vis lux") @@ -47,7 +45,7 @@ spell:isPremium(false) spell:needDirection(true) spell:blockWalls(true) spell:cooldown(6 * 1000) -spell:groupCooldown(2 * 1000) +spell:groupCooldown(2 * 1000, 6 * 1000) spell:needLearn(false) spell:vocation("sorcerer;true", "master sorcerer;true") spell:register() diff --git a/data/scripts/spells/attack/ice_burst.lua b/data/scripts/spells/attack/ice_burst.lua index 9e1560f9dc9..fedcd9d5a04 100644 --- a/data/scripts/spells/attack/ice_burst.lua +++ b/data/scripts/spells/attack/ice_burst.lua @@ -14,50 +14,27 @@ combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues") local spell = Spell("instant") function spell.onCastSpell(creature, var) - if not creature or not creature:isPlayer() then - return false - end - local grade = creature:revelationStageWOD("Twin Burst") if grade == 0 then - creature:sendCancelMessage("You cannot cast this spell") + creature:sendCancelMessage("You need to learn this spell first") creature:getPosition():sendMagicEffect(CONST_ME_POFF) return false end - local cooldown = 0 - if grade >= 3 then - cooldown = 14 - elseif grade >= 2 then - cooldown = 18 - elseif grade >= 1 then - cooldown = 22 - end - - var.instantName = "Twin Burst" - if combat:execute(creature, var) then - -- Ice cooldown - local condition1 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 262) - condition1:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN)) - creature:addCondition(condition1) - -- Earth cooldown - local condition2 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 263) - condition2:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN)) - creature:addCondition(condition2) - return true - end - return false + return combat:execute(creature, var) end -spell:group("attack") +spell:group("attack", "burstsofnature") spell:id(262) spell:name("Ice Burst") spell:words("exevo ulus frigo") +spell:castSound(SOUND_EFFECT_TYPE_SPELL_ETERNAL_WINTER) spell:level(300) spell:mana(230) spell:isPremium(true) -spell:cooldown(1000) -- Cooldown is calculated on the casting -spell:groupCooldown(2 * 1000) +spell:isSelfTarget(true) +spell:cooldown(22 * 1000) +spell:groupCooldown(2 * 1000, 22 * 1000) spell:needLearn(true) spell:vocation("druid;true", "elder druid;true") spell:register() diff --git a/data/scripts/spells/attack/terra_burst.lua b/data/scripts/spells/attack/terra_burst.lua index 8a805c0ba48..15ce35c4912 100644 --- a/data/scripts/spells/attack/terra_burst.lua +++ b/data/scripts/spells/attack/terra_burst.lua @@ -14,50 +14,27 @@ combat:setCallback(CALLBACK_PARAM_LEVELMAGICVALUE, "onGetFormulaValues") local spell = Spell("instant") function spell.onCastSpell(creature, var) - if not creature or not creature:isPlayer() then - return false - end - local grade = creature:revelationStageWOD("Twin Burst") if grade == 0 then - creature:sendCancelMessage("You cannot cast this spell") + creature:sendCancelMessage("You need to learn this spell first") creature:getPosition():sendMagicEffect(CONST_ME_POFF) return false end - local cooldown = 0 - if grade >= 3 then - cooldown = 14 - elseif grade >= 2 then - cooldown = 18 - elseif grade >= 1 then - cooldown = 22 - end - - var.instantName = "Twin Burst" - if combat:execute(creature, var) then - -- Ice cooldown - local condition1 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 262) - condition1:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN)) - creature:addCondition(condition1) - -- Earth cooldown - local condition2 = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 263) - condition2:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN)) - creature:addCondition(condition2) - return true - end - return false + return combat:execute(creature, var) end -spell:group("attack") +spell:group("attack", "burstsofnature") spell:id(263) spell:name("Terra Burst") spell:words("exevo ulus tera") +spell:castSound(SOUND_EFFECT_TYPE_SPELL_WRATH_OF_NATURE) spell:level(300) spell:mana(230) spell:isPremium(true) -spell:cooldown(1000) -- Cooldown is calculated on the casting -spell:groupCooldown(2 * 1000) +spell:isSelfTarget(true) +spell:cooldown(22 * 1000) +spell:groupCooldown(2 * 1000, 22 * 1000) spell:needLearn(true) spell:vocation("druid;true", "elder druid;true") spell:register() diff --git a/data/scripts/spells/support/divine_empowerment.lua b/data/scripts/spells/support/divine_empowerment.lua index e05203359f8..248f01a6e0f 100644 --- a/data/scripts/spells/support/divine_empowerment.lua +++ b/data/scripts/spells/support/divine_empowerment.lua @@ -26,18 +26,6 @@ function spell.onCastSpell(creature, var) return false end - local cooldown = 0 - if grade >= 3 then - cooldown = 24 - elseif grade >= 2 then - cooldown = 28 - elseif grade >= 1 then - cooldown = 32 - end - local condition = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 268) - condition:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN)) - creature:addCondition(condition) - local position = creature:getPosition() for x = -1, 1 do for y = -1, 1 do @@ -63,7 +51,7 @@ spell:isPremium(true) spell:range(7) spell:isSelfTarget(true) spell:isAggressive(false) -spell:cooldown(1000) -- Cooldown is calculated on the casting +spell:cooldown(32 * 1000) spell:groupCooldown(2 * 1000) spell:needLearn(true) spell:vocation("paladin;true", "royal paladin;true") diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index c65fdf7f053..0759a9a4ba8 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -1254,11 +1254,6 @@ void Combat::CombatFunc(const std::shared_ptr &caster, const Position combatTileEffects(spectators.data(), caster, tile, params); } - // Wheel of destiny update beam mastery damage - if (casterPlayer) { - casterPlayer->wheel()->updateBeamMasteryDamage(tmpDamage, beamAffectedTotal, beamAffectedCurrent); - } - postCombatEffects(caster, origin, pos, params); } diff --git a/src/creatures/combat/spells.cpp b/src/creatures/combat/spells.cpp index 26635d84421..77326cf16f4 100644 --- a/src/creatures/combat/spells.cpp +++ b/src/creatures/combat/spells.cpp @@ -686,7 +686,10 @@ void Spell::applyCooldownConditions(const std::shared_ptr &player) const g_logger().debug("[{}] spell name: {}, spellCooldown: {}, bonus: {}, augment {}", __FUNCTION__, name, spellCooldown, player->wheel()->getSpellBonus(name, WheelSpellBoost_t::COOLDOWN), augmentCooldownReduction); spellCooldown -= player->wheel()->getSpellBonus(name, WheelSpellBoost_t::COOLDOWN); spellCooldown -= augmentCooldownReduction; + const int32_t halfBaseCooldown = cooldown / 2; + spellCooldown = halfBaseCooldown > spellCooldown ? halfBaseCooldown : spellCooldown; // The cooldown should never be reduced less than half (50%) of its base cooldown if (spellCooldown > 0) { + player->wheel()->handleTwinBurstsCooldown(player, name, spellCooldown, rateCooldown); const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, m_spellId); player->addCondition(condition); } @@ -708,7 +711,9 @@ void Spell::applyCooldownConditions(const std::shared_ptr &player) const if (isUpgraded) { spellSecondaryGroupCooldown -= getWheelOfDestinyBoost(WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN, spellGrade); } + spellSecondaryGroupCooldown -= player->wheel()->getSpellBonus(name, WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN); if (spellSecondaryGroupCooldown > 0) { + player->wheel()->handleBeamMasteryCooldown(player, name, spellSecondaryGroupCooldown, rateCooldown); const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLGROUPCOOLDOWN, spellSecondaryGroupCooldown / rateCooldown, 0, false, secondaryGroup); player->addCondition(condition); } diff --git a/src/creatures/creatures_definitions.hpp b/src/creatures/creatures_definitions.hpp index 7ca12916946..2c41c39d282 100644 --- a/src/creatures/creatures_definitions.hpp +++ b/src/creatures/creatures_definitions.hpp @@ -706,6 +706,8 @@ enum SpellGroup_t : uint8_t { SPELLGROUP_CRIPPLING = 6, SPELLGROUP_FOCUS = 7, SPELLGROUP_ULTIMATESTRIKES = 8, + SPELLGROUP_BURSTS_OF_NATURE = 9, + SPELLGROUP_GREAT_BEAMS = 10, }; enum ChannelEvent_t : uint8_t { diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 3846d9ca99b..3f3751ca66e 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -5537,7 +5537,7 @@ int32_t Player::getPerfectShotDamage(uint8_t range, bool useCharges) const { } int32_t Player::getSpecializedMagicLevel(CombatType_t combat, bool useCharges) const { - int32_t result = specializedMagicLevel[combatTypeToIndex(combat)]; + int32_t result = specializedMagicLevel[combatTypeToIndex(combat)] + m_wheelPlayer->getSpecializedMagic(combat); for (const auto &item : getEquippedItems()) { const ItemType &itemType = Item::items[item->getID()]; if (!itemType.abilities) { diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 344bde5f03b..0db8f9461ef 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -951,6 +951,48 @@ int PlayerWheel::getSpellAdditionalDuration(const std::string &spellName) const return 0; } +bool PlayerWheel::handleTwinBurstsCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const { + bool applyCondition = false; + uint16_t spellId = 0; + if (spellName == "Terra Burst") { + const auto &spell = g_spells().getSpellByName("Ice Burst"); + spellId = spell->getSpellId(); + applyCondition = true; + } else if (spellName == "Ice Burst") { + const auto &spell = g_spells().getSpellByName("Terra Burst"); + spellId = spell->getSpellId(); + applyCondition = true; + } + + if (applyCondition) { + const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId); + return player->addCondition(condition); + } + + return false; +} + +bool PlayerWheel::handleBeamMasteryCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const { + bool applyCondition = false; + uint16_t spellId = 0; + if (spellName == "Great Death Beam") { + const auto &spell = g_spells().getSpellByName("Great Energy Beam"); + spellId = spell->getSpellId(); + applyCondition = true; + } else if (spellName == "Great Energy Beam") { + const auto &spell = g_spells().getSpellByName("Great Death Beam"); + spellId = spell->getSpellId(); + applyCondition = true; + } + + if (applyCondition) { + const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId); + return player->addCondition(condition); + } + + return false; +} + void PlayerWheel::addPromotionScrolls(NetworkMessage &msg) const { std::vector unlockedScrolls; @@ -972,17 +1014,17 @@ void PlayerWheel::addPromotionScrolls(NetworkMessage &msg) const { } } -std::shared_ptr PlayerWheel::gemsKV() const { +const std::shared_ptr &PlayerWheel::gemsKV() const { return m_player.kv()->scoped("wheel-of-destiny")->scoped("gems"); } -std::shared_ptr PlayerWheel::gemsGradeKV(WheelFragmentType_t type, uint8_t pos) const { +const std::shared_ptr &PlayerWheel::gemsGradeKV(WheelFragmentType_t type, uint8_t pos) const { return gemsKV()->scoped(std::string(magic_enum::enum_name(type)))->scoped(std::to_string(pos)); } uint8_t PlayerWheel::getGemGrade(WheelFragmentType_t type, uint8_t pos) const { uint8_t grade = 0; - auto gradeKV = gemsGradeKV(type, pos)->get("grade"); + const auto gradeKV = gemsGradeKV(type, pos)->get("grade"); if (gradeKV.has_value()) { grade = static_cast(gradeKV->get()); @@ -1184,7 +1226,7 @@ void PlayerWheel::destroyGem(uint16_t index) const { if (greaterFragments > 0) { const auto &fragmentsItem = Item::CreateItem(ITEM_GREATER_FRAGMENT, greaterFragments); - auto returnValue = g_game().internalPlayerAddItem(m_player.getPlayer(), fragmentsItem, false, CONST_SLOT_BACKPACK); + auto returnValue = g_game().internalPlayerAddItem(m_player.getPlayer(), fragmentsItem, false, CONST_SLOT_WHEREEVER); if (returnValue != RETURNVALUE_NOERROR) { g_logger().error("Failed to add {} greater fragments to player with name {}", greaterFragments, m_player.getName()); m_player.sendCancelMessage(getReturnMessage(RETURNVALUE_CONTACTADMINISTRATOR)); @@ -1195,8 +1237,11 @@ void PlayerWheel::destroyGem(uint16_t index) const { gem.remove(gemsKV()); - m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT)); - m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT)); + const auto totalLesserFragment = m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT) + m_player.getStashItemCount(ITEM_LESSER_FRAGMENT); + const auto totalGreaterFragment = m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT) + m_player.getStashItemCount(ITEM_GREATER_FRAGMENT); + + m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, totalLesserFragment); + m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, totalGreaterFragment); sendOpenWheelWindow(m_player.getID()); } @@ -1245,6 +1290,65 @@ void PlayerWheel::removeActiveGem(WheelGemAffinity_t affinity) const { gemsKV()->scoped("active")->remove(key); } +void PlayerWheel::addRevelationBonus(WheelGemAffinity_t affinity, uint16_t points) { + m_bonusRevelationPoints[static_cast(affinity)] += points; +} + +void PlayerWheel::resetRevelationBonus() { + m_bonusRevelationPoints = { 0, 0, 0, 0 }; +} + +void PlayerWheel::addSpellBonus(const std::string &spellName, const WheelSpells::Bonus &bonus) { + if (m_spellsBonuses.contains(spellName)) { + m_spellsBonuses[spellName].decrease.cooldown += bonus.decrease.cooldown; + m_spellsBonuses[spellName].decrease.manaCost += bonus.decrease.manaCost; + m_spellsBonuses[spellName].decrease.secondaryGroupCooldown += bonus.decrease.secondaryGroupCooldown; + m_spellsBonuses[spellName].increase.aditionalTarget += bonus.increase.aditionalTarget; + m_spellsBonuses[spellName].increase.area = bonus.increase.area; + m_spellsBonuses[spellName].increase.criticalChance += bonus.increase.criticalChance; + m_spellsBonuses[spellName].increase.criticalDamage += bonus.increase.criticalDamage; + m_spellsBonuses[spellName].increase.damage += bonus.increase.damage; + m_spellsBonuses[spellName].increase.damageReduction += bonus.increase.damageReduction; + m_spellsBonuses[spellName].increase.duration += bonus.increase.duration; + m_spellsBonuses[spellName].increase.heal += bonus.increase.heal; + m_spellsBonuses[spellName].leech.life += bonus.leech.life; + m_spellsBonuses[spellName].leech.mana += bonus.leech.mana; + return; + } + m_spellsBonuses[spellName] = bonus; +} + +int32_t PlayerWheel::getSpellBonus(const std::string &spellName, WheelSpellBoost_t boost) const { + if (!m_spellsBonuses.contains(spellName)) { + return 0; + } + const auto &[leech, increase, decrease] = m_spellsBonuses.at(spellName); + switch (boost) { + case WheelSpellBoost_t::COOLDOWN: + return decrease.cooldown; + case WheelSpellBoost_t::MANA: + return decrease.manaCost; + case WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN: + return decrease.secondaryGroupCooldown; + case WheelSpellBoost_t::CRITICAL_CHANCE: + return increase.criticalChance; + case WheelSpellBoost_t::CRITICAL_DAMAGE: + return increase.criticalDamage; + case WheelSpellBoost_t::DAMAGE: + return increase.damage; + case WheelSpellBoost_t::DAMAGE_REDUCTION: + return increase.damageReduction; + case WheelSpellBoost_t::HEAL: + return increase.heal; + case WheelSpellBoost_t::LIFE_LEECH: + return leech.life; + case WheelSpellBoost_t::MANA_LEECH: + return leech.mana; + default: + return 0; + } +} + void PlayerWheel::addGems(NetworkMessage &msg) const { const auto activeGems = getActiveGems(); msg.addByte(activeGems.size()); @@ -1337,7 +1441,7 @@ void PlayerWheel::improveGemGrade(WheelFragmentType_t fragmentType, uint8_t pos) return; } - if (!m_player.hasItemCountById(fragmentId, quantity, false)) { + if (!m_player.hasItemCountById(fragmentId, quantity, true)) { g_logger().error("[{}] Player {} does not have the required {} fragments with id {}", __FUNCTION__, m_player.getName(), quantity, fragmentId); return; } @@ -1347,7 +1451,7 @@ void PlayerWheel::improveGemGrade(WheelFragmentType_t fragmentType, uint8_t pos) return; } - if (!m_player.removeItemCountById(fragmentId, quantity, false)) { + if (!m_player.removeItemCountById(fragmentId, quantity, true)) { g_logger().error("[{}] Failed to remove {} fragments with id {} from player {}", std::source_location::current().function_name(), quantity, fragmentId, m_player.getName()); return; } @@ -1408,20 +1512,23 @@ void PlayerWheel::sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId) { addPromotionScrolls(msg); addGems(msg); addGradeModifiers(msg); - // TODO: read items from inventory + const auto &voc = m_player.getVocation(); if (!voc) { g_logger().error("[{}] Failed to get vocation for player {}", __FUNCTION__, m_player.getName()); return; } + const auto totalLesserFragment = m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT) + m_player.getStashItemCount(ITEM_LESSER_FRAGMENT); + const auto totalGreaterFragment = m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT) + m_player.getStashItemCount(ITEM_GREATER_FRAGMENT); + m_player.client->sendResourceBalance(RESOURCE_BANK, m_player.getBankBalance()); m_player.client->sendResourceBalance(RESOURCE_INVENTORY_MONEY, m_player.getMoney()); m_player.client->sendResourceBalance(RESOURCE_LESSER_GEMS, m_player.getItemTypeCount(voc->getWheelGemId(WheelGemQuality_t::Lesser))); m_player.client->sendResourceBalance(RESOURCE_REGULAR_GEMS, m_player.getItemTypeCount(voc->getWheelGemId(WheelGemQuality_t::Regular))); m_player.client->sendResourceBalance(RESOURCE_GREATER_GEMS, m_player.getItemTypeCount(voc->getWheelGemId(WheelGemQuality_t::Greater))); - m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, m_player.getItemTypeCount(ITEM_LESSER_FRAGMENT)); - m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, m_player.getItemTypeCount(ITEM_GREATER_FRAGMENT)); + m_player.client->sendResourceBalance(RESOURCE_LESSER_FRAGMENT, totalLesserFragment); + m_player.client->sendResourceBalance(RESOURCE_GREATER_FRAGMENT, totalGreaterFragment); } void PlayerWheel::sendGiftOfLifeCooldown() const { @@ -1563,7 +1670,7 @@ void PlayerWheel::saveSlotPointsOnPressSaveButton(NetworkMessage &msg) { */ void PlayerWheel::loadDBPlayerSlotPointsOnLogin() { auto resultString = fmt::format("SELECT `slot` FROM `player_wheeldata` WHERE `player_id` = {}", m_player.getGUID()); - const DBResult_ptr &result = Database::getInstance().storeQuery(resultString); + const DBResult_ptr &result = g_database().storeQuery(resultString); // Ignore if player not have nothing inserted in the table if (!result) { return; @@ -1584,8 +1691,6 @@ void PlayerWheel::loadDBPlayerSlotPointsOnLogin() { } bool PlayerWheel::saveDBPlayerSlotPointsOnLogout() const { - const Database &db = Database::getInstance(); - std::ostringstream query; DBInsert insertWheelData("INSERT INTO `player_wheeldata` (`player_id`, `slot`) VALUES "); insertWheelData.upsert({ "slot" }); PropWriteStream stream; @@ -1604,7 +1709,7 @@ bool PlayerWheel::saveDBPlayerSlotPointsOnLogout() const { size_t attributesSize; const char* attributes = stream.getStream(attributesSize); if (attributesSize > 0) { - query << m_player.getGUID() << ',' << db.escapeBlob(attributes, static_cast(attributesSize)); + const auto query = fmt::format("{}, {}", m_player.getGUID(), g_database().escapeBlob(attributes, static_cast(attributesSize))); if (!insertWheelData.addRow(query)) { g_logger().debug("[{}] failed to insert row data", __FUNCTION__); return false; @@ -1813,7 +1918,7 @@ void PlayerWheel::reloadPlayerData() const { void PlayerWheel::registerPlayerBonusData() { addStat(WheelStat_t::HEALTH, m_playerBonusData.stats.health); addStat(WheelStat_t::MANA, m_playerBonusData.stats.mana); - addStat(WheelStat_t::CAPACITY, m_playerBonusData.stats.capacity * 100); + addStat(WheelStat_t::CAPACITY, m_playerBonusData.stats.capacity); addStat(WheelStat_t::MITIGATION, m_playerBonusData.mitigation * 100); addStat(WheelStat_t::DAMAGE, m_playerBonusData.stats.damage); addStat(WheelStat_t::HEALING, m_playerBonusData.stats.healing); @@ -1865,14 +1970,13 @@ void PlayerWheel::registerPlayerBonusData() { for (int i = 0; i < m_playerBonusData.stages.divineEmpowerment; ++i) { setSpellInstant("Divine Empowerment", true); } + WheelSpells::Bonus bonus; + bonus.decrease.cooldown = 4 * 1000; + if (m_playerBonusData.stages.divineEmpowerment >= 2) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 4000; addSpellBonus("Divine Empowerment", bonus); } if (m_playerBonusData.stages.divineEmpowerment >= 3) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 4000; addSpellBonus("Divine Empowerment", bonus); } } else { @@ -1885,12 +1989,12 @@ void PlayerWheel::registerPlayerBonusData() { } if (m_playerBonusData.stages.divineGrenade >= 2) { WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 4000; + bonus.decrease.cooldown = 4 * 1000; addSpellBonus("Divine Grenade", bonus); } if (m_playerBonusData.stages.divineGrenade >= 3) { WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 6000; + bonus.decrease.cooldown = 6 * 1000; addSpellBonus("Divine Grenade", bonus); } } else { @@ -1905,9 +2009,21 @@ void PlayerWheel::registerPlayerBonusData() { setSpellInstant("Drain Body", false); } if (m_playerBonusData.stages.beamMastery > 0) { + m_beamMasterySpells.emplace("Energy Beam"); + m_beamMasterySpells.emplace("Great Death Beam"); + m_beamMasterySpells.emplace("Great Energy Beam"); for (int i = 0; i < m_playerBonusData.stages.beamMastery; ++i) { setSpellInstant("Beam Mastery", true); } + WheelSpells::Bonus deathBeamBonus; + deathBeamBonus.decrease.cooldown = 2 * 1000; + deathBeamBonus.increase.damage = 6; + if (m_playerBonusData.stages.beamMastery >= 2) { + addSpellBonus("Great Death Beam", deathBeamBonus); + } + if (m_playerBonusData.stages.beamMastery >= 3) { + addSpellBonus("Great Death Beam", deathBeamBonus); + } } else { setSpellInstant("Beam Mastery", false); } @@ -1916,6 +2032,17 @@ void PlayerWheel::registerPlayerBonusData() { for (int i = 0; i < m_playerBonusData.stages.twinBurst; ++i) { setSpellInstant("Twin Burst", true); } + WheelSpells::Bonus bonus; + bonus.decrease.cooldown = 4 * 1000; + bonus.decrease.secondaryGroupCooldown = 4 * 1000; + if (m_playerBonusData.stages.twinBurst >= 2) { + addSpellBonus("Ice Burst", bonus); + addSpellBonus("Terra Burst", bonus); + } + if (m_playerBonusData.stages.twinBurst >= 3) { + addSpellBonus("Ice Burst", bonus); + addSpellBonus("Terra Burst", bonus); + } } else { setSpellInstant("Twin Burst", false); } @@ -1933,14 +2060,13 @@ void PlayerWheel::registerPlayerBonusData() { for (int i = 0; i < m_playerBonusData.avatar.light; ++i) { setSpellInstant("Avatar of Light", true); } + WheelSpells::Bonus bonus; + bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes + if (m_playerBonusData.avatar.light >= 2) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Light", bonus); } if (m_playerBonusData.avatar.light >= 3) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Light", bonus); } } else { @@ -1951,14 +2077,13 @@ void PlayerWheel::registerPlayerBonusData() { for (int i = 0; i < m_playerBonusData.avatar.nature; ++i) { setSpellInstant("Avatar of Nature", true); } + WheelSpells::Bonus bonus; + bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes + if (m_playerBonusData.avatar.nature >= 2) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Nature", bonus); } if (m_playerBonusData.avatar.nature >= 3) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Nature", bonus); } } else { @@ -1969,14 +2094,12 @@ void PlayerWheel::registerPlayerBonusData() { for (int i = 0; i < m_playerBonusData.avatar.steel; ++i) { setSpellInstant("Avatar of Steel", true); } + WheelSpells::Bonus bonus; + bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes if (m_playerBonusData.avatar.steel >= 2) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Steel", bonus); } if (m_playerBonusData.avatar.steel >= 3) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Steel", bonus); } } else { @@ -1987,14 +2110,12 @@ void PlayerWheel::registerPlayerBonusData() { for (int i = 0; i < m_playerBonusData.avatar.storm; ++i) { setSpellInstant("Avatar of Storm", true); } + WheelSpells::Bonus bonus; + bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes if (m_playerBonusData.avatar.storm >= 2) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Storm", bonus); } if (m_playerBonusData.avatar.storm >= 3) { - WheelSpells::Bonus bonus; - bonus.decrease.cooldown = 30 * 60 * 1000; // 30 minutes addSpellBonus("Avatar of Storm", bonus); } } else { @@ -2161,10 +2282,10 @@ void PlayerWheel::printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonus g_logger().debug("mitigation: {}", bonusData.mitigation); } - auto &spellsVector = bonusData.spells; + const auto &spellsVector = bonusData.spells; if (!spellsVector.empty()) { g_logger().debug("Spells:"); - for (const auto &spell : bonusData.spells) { + for (const auto &spell : spellsVector) { g_logger().debug(" {}", spell); } } @@ -2174,7 +2295,7 @@ void PlayerWheel::printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonus void PlayerWheel::loadDedicationAndConvictionPerks() { using VocationBonusFunction = std::function &, uint16_t, uint8_t, PlayerWheelMethodsBonusData &)>; - auto wheelFunctions = g_game().getIOWheel()->getWheelMapFunctions(); + const auto &wheelFunctions = g_game().getIOWheel()->getWheelMapFunctions(); const auto vocationCipId = m_player.getPlayerVocationEnum(); if (vocationCipId < VOCATION_KNIGHT_CIP || vocationCipId > VOCATION_DRUID_CIP) { return; @@ -2239,7 +2360,7 @@ void PlayerWheel::processActiveGems() { if (count >= 3 && quality >= WheelGemQuality_t::Greater) { uint8_t grade = getGemGrade(WheelFragmentType_t::Greater, static_cast(supremeModifier)); std::string modifierName(magic_enum::enum_name(supremeModifier)); - g_logger().info("[{}] Adding supreme modifier {} to player {} from {} gem affinity {}", __FUNCTION__, modifierName, playerName, magic_enum::enum_name(quality), magic_enum::enum_name(affinity)); + g_logger().debug("[{}] Adding supreme modifier {} to player {} from {} gem affinity {}", __FUNCTION__, modifierName, playerName, magic_enum::enum_name(quality), magic_enum::enum_name(affinity)); m_modifierContext->addStrategies(supremeModifier, grade); } } @@ -2261,7 +2382,7 @@ void PlayerWheel::applyStageBonusForColor(const std::string &color) { return; } - auto [statsDamage, statsHealing] = g_game().getIOWheel()->getRevelationStatByStage(stageEnum); + const auto &[statsDamage, statsHealing] = g_game().getIOWheel()->getRevelationStatByStage(stageEnum); m_playerBonusData.stats.damage += statsDamage; m_playerBonusData.stats.healing += statsHealing; @@ -2339,7 +2460,6 @@ void PlayerWheel::applyBlueStageBonus(uint8_t stageValue, Vocation_t vocationEnu } else if (vocationEnum == Vocation_t::VOCATION_DRUID_CIP) { m_playerBonusData.stages.twinBurst = stageValue; for (uint8_t i = 1; i <= stageValue; ++i) { - addSpellToVector("Twin Burst"); addSpellToVector("Terra Burst"); addSpellToVector("Ice Burst"); } @@ -2423,7 +2543,7 @@ WheelStageEnum_t PlayerWheel::getPlayerSliceStage(const std::string &color) cons const auto modsSupremeIt = modsSupremePositionByVocation.find(vocationBaseId); if (modsSupremeIt != modsSupremePositionByVocation.end()) { - for (auto modPosition : modsSupremeIt->second.get()) { + for (const auto &modPosition : modsSupremeIt->second.get()) { const auto pos = static_cast(modPosition); uint8_t grade = 0; auto gradeKV = gemsGradeKV(WheelFragmentType_t::Greater, pos)->get("grade"); @@ -2553,7 +2673,8 @@ bool PlayerWheel::checkPositionalTatics() { break; } } - constexpr uint16_t magicSkill = 3; + constexpr uint16_t holyMagicSkill = 3; + constexpr uint16_t healingMagicSkill = 3; constexpr uint16_t distanceSkill = 3; if (creaturesNearby == 0) { m_creaturesNearby = creaturesNearby; @@ -2561,8 +2682,12 @@ bool PlayerWheel::checkPositionalTatics() { setMajorStat(WheelMajor_t::DISTANCE, distanceSkill); updateClient = true; } - if (getMajorStat(WheelMajor_t::MAGIC) != 0) { - setMajorStat(WheelMajor_t::MAGIC, 0); + if (getSpecializedMagic(COMBAT_HOLYDAMAGE) != 0) { + setSpecializedMagic(COMBAT_HOLYDAMAGE, 0); + updateClient = true; + } + if (getSpecializedMagic(COMBAT_HEALING) != 0) { + setSpecializedMagic(COMBAT_HEALING, 0); updateClient = true; } } else { @@ -2570,8 +2695,12 @@ bool PlayerWheel::checkPositionalTatics() { setMajorStat(WheelMajor_t::DISTANCE, 0); updateClient = true; } - if (getMajorStat(WheelMajor_t::MAGIC) != magicSkill) { - setMajorStat(WheelMajor_t::MAGIC, magicSkill); + if (getSpecializedMagic(COMBAT_HOLYDAMAGE) != holyMagicSkill) { + setSpecializedMagic(COMBAT_HOLYDAMAGE, holyMagicSkill); + updateClient = true; + } + if (getSpecializedMagic(COMBAT_HEALING) != healingMagicSkill) { + setSpecializedMagic(COMBAT_HEALING, healingMagicSkill); updateClient = true; } } @@ -2997,12 +3126,29 @@ void PlayerWheel::onThink(bool force /* = false*/) { void PlayerWheel::reduceAllSpellsCooldownTimer(int32_t value) const { for (const auto &condition : m_player.getConditionsByType(CONDITION_SPELLCOOLDOWN)) { - if (condition->getTicks() <= value) { - m_player.sendSpellCooldown(condition->getSubId(), 0); - condition->endCondition(m_player.getPlayer()); - } else { - condition->setTicks(condition->getTicks() - value); - m_player.sendSpellCooldown(condition->getSubId(), condition->getTicks()); + const auto spellId = condition->getSubId(); + const auto &spell = g_spells().getInstantSpellById(spellId); + const auto spellSecondaryGroup = spell->getSecondaryGroup(); + const auto &secondCondition = m_player.getCondition(CONDITION_SPELLGROUPCOOLDOWN, CONDITIONID_DEFAULT, spellSecondaryGroup); + + if (secondCondition) { + if (secondCondition->getTicks() <= value) { + m_player.sendSpellGroupCooldown(spellSecondaryGroup, 0); + secondCondition->endCondition(m_player.getPlayer()); + } else { + secondCondition->setTicks(secondCondition->getTicks() - value); + m_player.sendSpellGroupCooldown(spellSecondaryGroup, secondCondition->getTicks()); + } + } + + if (condition) { + if (condition->getTicks() <= value) { + m_player.sendSpellCooldown(spellId, 0); + condition->endCondition(m_player.getPlayer()); + } else { + condition->setTicks(condition->getTicks() - value); + m_player.sendSpellCooldown(spellId, condition->getTicks()); + } } } } @@ -3016,6 +3162,7 @@ void PlayerWheel::resetUpgradedSpells() { m_creaturesNearby = 0; m_spellsSelected.clear(); m_learnedSpellsSelected.clear(); + m_beamMasterySpells.clear(); for (int i = 0; i < static_cast(WheelMajor_t::TOTAL_COUNT); i++) { setMajorStat(static_cast(i), 0); } @@ -3081,17 +3228,15 @@ std::shared_ptr PlayerWheel::getCombatDataSpell(CombatDamage &damage) { damage.lifeLeechChance += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::LIFE_LEECH_CHANCE, spellGrade); } - if (m_spellsBonuses.contains(spellName)) { - damage.criticalDamage += (getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_DAMAGE) * 100); - damage.criticalChance += getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_CHANCE); - damage.damageMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE); - damage.damageReductionMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE_REDUCTION); - damage.healingMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::HEAL); - damage.manaLeech += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH); - damage.manaLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH_CHANCE); - damage.lifeLeech += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH); - damage.lifeLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH_CHANCE); - } + damage.criticalDamage += (getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_DAMAGE) * 100); + damage.criticalChance += getSpellBonus(spellName, WheelSpellBoost_t::CRITICAL_CHANCE); + damage.damageMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE); + damage.damageReductionMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::DAMAGE_REDUCTION); + damage.healingMultiplier += getSpellBonus(spellName, WheelSpellBoost_t::HEAL); + damage.manaLeech += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH); + damage.manaLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::MANA_LEECH_CHANCE); + damage.lifeLeech += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH); + damage.lifeLeechChance += getSpellBonus(spellName, WheelSpellBoost_t::LIFE_LEECH_CHANCE); } return spell; @@ -3125,6 +3270,15 @@ void PlayerWheel::setMajorStat(WheelMajor_t type, int32_t value) { } } +void PlayerWheel::setSpecializedMagic(CombatType_t type, int32_t value) { + auto enumValue = static_cast(type); + try { + m_specializedMagic.at(enumValue) = value; + } catch (const std::out_of_range &e) { + g_logger().error("[{}]. Type {} is out of range, value {}. Error message: {}", __FUNCTION__, enumValue, value, e.what()); + } +} + void PlayerWheel::setInstant(WheelInstant_t type, bool toggle) { auto enumValue = static_cast(type); try { @@ -3374,6 +3528,16 @@ int32_t PlayerWheel::getMajorStat(WheelMajor_t type) const { return 0; } +int32_t PlayerWheel::getSpecializedMagic(CombatType_t type) const { + auto enumValue = static_cast(type); + try { + return m_specializedMagic.at(enumValue); + } catch (const std::out_of_range &e) { + g_logger().error("[{}]. Instant type {}. Error message: {}", __FUNCTION__, enumValue, e.what()); + } + return 0; +} + int32_t PlayerWheel::getStat(WheelStat_t type) const { auto enumValue = static_cast(type); try { @@ -3593,7 +3757,7 @@ void PlayerWheel::setWheelBonusData(const PlayerWheelMethodsBonusData &newBonusD // Functions used to Manage Combat uint8_t PlayerWheel::getBeamAffectedTotal(const CombatDamage &tmpDamage) const { uint8_t beamAffectedTotal = 0; // Removed const - if (tmpDamage.runeSpellName == "Beam Mastery" && getInstant("Beam Mastery")) { + if (m_beamMasterySpells.contains(tmpDamage.instantSpellName) && getInstant("Beam Mastery")) { beamAffectedTotal = 3; } return beamAffectedTotal; @@ -3602,6 +3766,7 @@ uint8_t PlayerWheel::getBeamAffectedTotal(const CombatDamage &tmpDamage) const { void PlayerWheel::updateBeamMasteryDamage(CombatDamage &tmpDamage, uint8_t &beamAffectedTotal, uint8_t &beamAffectedCurrent) const { if (beamAffectedTotal > 0) { tmpDamage.damageMultiplier += checkBeamMasteryDamage(); + reduceAllSpellsCooldownTimer(1000); // Reduces all spell cooldown by 1 second per target hit (max 3 seconds) --beamAffectedTotal; beamAffectedCurrent++; } diff --git a/src/creatures/players/wheel/player_wheel.hpp b/src/creatures/players/wheel/player_wheel.hpp index 82730b76881..0ad3ed4ce59 100644 --- a/src/creatures/players/wheel/player_wheel.hpp +++ b/src/creatures/players/wheel/player_wheel.hpp @@ -101,6 +101,9 @@ class PlayerWheel { int getSpellAdditionalDuration(const std::string &spellName) const; bool getSpellAdditionalArea(const std::string &spellName) const; + bool handleTwinBurstsCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const; + bool handleBeamMasteryCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const; + /* * Functions for manage slots */ @@ -180,8 +183,8 @@ class PlayerWheel { */ uint8_t getOptions(uint32_t ownerId) const; - std::shared_ptr gemsKV() const; - std::shared_ptr gemsGradeKV(WheelFragmentType_t quality, uint8_t pos) const; + const std::shared_ptr &gemsKV() const; + const std::shared_ptr &gemsGradeKV(WheelFragmentType_t quality, uint8_t pos) const; uint8_t getGemGrade(WheelFragmentType_t quality, uint8_t pos) const; std::vector getRevealedGems() const; @@ -254,6 +257,16 @@ class PlayerWheel { */ void setMajorStat(WheelMajor_t type, int32_t value); + /** + * @brief Sets the value of a specific specialized magic in the Wheel of Destiny. + * + * This function sets the value of the specified specialized magic in the Wheel of Destiny to the provided value. + * + * @param type The type of the combat to set the specialized magic. + * @param value The value to set for the specialized magic. + */ + void setSpecializedMagic(CombatType_t type, int32_t value); + /** * @brief Sets the value of a specific instant in the Wheel of Destiny. * @@ -304,6 +317,7 @@ class PlayerWheel { uint8_t getStage(WheelStage_t type) const; WheelSpellGrade_t getSpellUpgrade(const std::string &name) const; int32_t getMajorStat(WheelMajor_t type) const; + int32_t getSpecializedMagic(CombatType_t type) const; int32_t getStat(WheelStat_t type) const; int32_t getResistance(CombatType_t type) const; int32_t getMajorStatConditional(const std::string &instant, WheelMajor_t major) const; @@ -373,63 +387,11 @@ class PlayerWheel { void toggleGemLock(uint16_t index) const; void setActiveGem(WheelGemAffinity_t affinity, uint16_t index) const; void removeActiveGem(WheelGemAffinity_t affinity) const; - void addRevelationBonus(WheelGemAffinity_t affinity, uint16_t points) { - m_bonusRevelationPoints[static_cast(affinity)] += points; - } - void resetRevelationBonus() { - m_bonusRevelationPoints = { 0, 0, 0, 0 }; - } - - void addSpellBonus(const std::string &spellName, const WheelSpells::Bonus &bonus) { - if (m_spellsBonuses.contains(spellName)) { - m_spellsBonuses[spellName].decrease.cooldown += bonus.decrease.cooldown; - m_spellsBonuses[spellName].decrease.manaCost += bonus.decrease.manaCost; - m_spellsBonuses[spellName].decrease.secondaryGroupCooldown += bonus.decrease.secondaryGroupCooldown; - m_spellsBonuses[spellName].increase.aditionalTarget += bonus.increase.aditionalTarget; - m_spellsBonuses[spellName].increase.area = bonus.increase.area; - m_spellsBonuses[spellName].increase.criticalChance += bonus.increase.criticalChance; - m_spellsBonuses[spellName].increase.criticalDamage += bonus.increase.criticalDamage; - m_spellsBonuses[spellName].increase.damage += bonus.increase.damage; - m_spellsBonuses[spellName].increase.damageReduction += bonus.increase.damageReduction; - m_spellsBonuses[spellName].increase.duration += bonus.increase.duration; - m_spellsBonuses[spellName].increase.heal += bonus.increase.heal; - m_spellsBonuses[spellName].leech.life += bonus.leech.life; - m_spellsBonuses[spellName].leech.mana += bonus.leech.mana; - return; - } - m_spellsBonuses[spellName] = bonus; - } - - int32_t getSpellBonus(const std::string &spellName, WheelSpellBoost_t boost) const { - if (!m_spellsBonuses.contains(spellName)) { - return 0; - } - auto [leech, increase, decrease] = m_spellsBonuses.at(spellName); - switch (boost) { - case WheelSpellBoost_t::COOLDOWN: - return decrease.cooldown; - case WheelSpellBoost_t::MANA: - return decrease.manaCost; - case WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN: - return decrease.secondaryGroupCooldown; - case WheelSpellBoost_t::CRITICAL_CHANCE: - return increase.criticalChance; - case WheelSpellBoost_t::CRITICAL_DAMAGE: - return increase.criticalDamage; - case WheelSpellBoost_t::DAMAGE: - return increase.damage; - case WheelSpellBoost_t::DAMAGE_REDUCTION: - return increase.damageReduction; - case WheelSpellBoost_t::HEAL: - return increase.heal; - case WheelSpellBoost_t::LIFE_LEECH: - return leech.life; - case WheelSpellBoost_t::MANA_LEECH: - return leech.mana; - default: - return 0; - } - } + void addRevelationBonus(WheelGemAffinity_t affinity, uint16_t points); + void resetRevelationBonus(); + void addSpellBonus(const std::string &spellName, const WheelSpells::Bonus &bonus); + + int32_t getSpellBonus(const std::string &spellName, WheelSpellBoost_t boost) const; WheelGemBasicModifier_t selectBasicModifier2(WheelGemBasicModifier_t modifier1) const; @@ -459,9 +421,11 @@ class PlayerWheel { std::array(WheelMajor_t::TOTAL_COUNT)> m_majorStats = { 0 }; std::array(WheelInstant_t::INSTANT_COUNT)> m_instant = { false }; std::array m_resistance = { 0 }; + std::array m_specializedMagic = { 0 }; int32_t m_creaturesNearby = 0; std::map m_spellsSelected; std::vector m_learnedSpellsSelected; std::unordered_map m_spellsBonuses; + std::unordered_set m_beamMasterySpells; }; diff --git a/src/creatures/players/wheel/wheel_definitions.hpp b/src/creatures/players/wheel/wheel_definitions.hpp index 5651b8dc216..acae0c22b14 100644 --- a/src/creatures/players/wheel/wheel_definitions.hpp +++ b/src/creatures/players/wheel/wheel_definitions.hpp @@ -284,7 +284,7 @@ namespace WheelSpells { struct Decrease { int cooldown = 0; int manaCost = 0; - uint8_t secondaryGroupCooldown = 0; + int secondaryGroupCooldown = 0; }; struct Leech { diff --git a/src/creatures/players/wheel/wheel_gems.cpp b/src/creatures/players/wheel/wheel_gems.cpp index 3ee884c077b..d9942833c48 100644 --- a/src/creatures/players/wheel/wheel_gems.cpp +++ b/src/creatures/players/wheel/wheel_gems.cpp @@ -237,16 +237,16 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin switch (modifier) { case WheelGemSupremeModifier_t::General_Dodge: - m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::DODGE, 25 * gradeMultiplier)); + m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::DODGE, 28 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_LifeLeech: - m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::LIFE_LEECH, 120 * gradeMultiplier)); + m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::LIFE_LEECH, 200 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_ManaLeech: - m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::MANA_LEECH, 40 * gradeMultiplier)); + m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::MANA_LEECH, 80 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_CriticalDamage: - m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::CRITICAL_DAMAGE, 150 * gradeMultiplier)); + m_strategies.emplace_back(std::make_unique(m_wheel, WheelStat_t::CRITICAL_DAMAGE, 200 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_RevelationMastery_GiftOfLife: m_strategies.emplace_back(std::make_unique(m_wheel, WheelGemAffinity_t::Green, 150 * gradeMultiplier)); @@ -254,7 +254,7 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin break; case WheelGemSupremeModifier_t::SorcererDruid_UltimateHealing: - bonus.increase.heal = 10 * gradeMultiplier; + bonus.increase.heal = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Ultimate Healing", bonus)); break; @@ -311,25 +311,25 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin break; case WheelGemSupremeModifier_t::Knight_AvatarOfSteel_Cooldown: - bonus.decrease.cooldown = 300 * 1000; + bonus.decrease.cooldown = 900 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Avatar of Steel", bonus)); break; case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_Cooldown: - bonus.decrease.cooldown = 1 * 1000; + bonus.decrease.cooldown = 2 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Executioner's Throw", bonus)); break; case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 6 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Executioner's Throw", bonus)); break; case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Executioner's Throw", bonus)); break; case WheelGemSupremeModifier_t::Knight_Fierce_Berserk_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Fierce Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Fierce_Berserk_CriticalExtraDamage: @@ -337,35 +337,35 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin m_strategies.emplace_back(std::make_unique(m_wheel, "Fierce Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Berserk_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Berserk_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Front_Sweep_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Front Sweep", bonus)); break; case WheelGemSupremeModifier_t::Knight_Front_Sweep_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 8 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Front Sweep", bonus)); break; case WheelGemSupremeModifier_t::Knight_Groundshaker_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = static_cast(std::round(6.5 * gradeMultiplier)); m_strategies.emplace_back(std::make_unique(m_wheel, "Groundshaker", bonus)); break; case WheelGemSupremeModifier_t::Knight_Groundshaker_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Groundshaker", bonus)); break; case WheelGemSupremeModifier_t::Knight_Annihilation_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 15 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Annihilation", bonus)); break; case WheelGemSupremeModifier_t::Knight_Annihilation_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Annihilation", bonus)); break; case WheelGemSupremeModifier_t::Knight_FairWoundCleansing_HealingIncrease: @@ -374,72 +374,72 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin break; case WheelGemSupremeModifier_t::Paladin_AvatarOfLight_Cooldown: - bonus.decrease.cooldown = 300 * 1000; + bonus.decrease.cooldown = 900 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Avatar of Light", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineDazzle_Cooldown: - bonus.decrease.cooldown = 2 * 1000; + bonus.decrease.cooldown = 4 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Dazzle", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineGrenade_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 6 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Grenade", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineGrenade_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Grenade", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineCaldera_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Caldera", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineCaldera_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Caldera", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineMissile_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 8 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Missile", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineMissile_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Missile", bonus)); break; case WheelGemSupremeModifier_t::Paladin_EtherealSpear_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 10 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_EtherealSpear_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 15 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 8 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Strong Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Strong Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineEmpowerment_Cooldown: - bonus.decrease.cooldown = 3 * 1000; + bonus.decrease.cooldown = 6 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Empowerment", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineGrenade_Cooldown: - bonus.decrease.cooldown = 1 * 1000; + bonus.decrease.cooldown = 2 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Divine Grenade", bonus)); break; case WheelGemSupremeModifier_t::Paladin_Salvation_HealingIncrease: - bonus.increase.heal = 10 * gradeMultiplier; + bonus.increase.heal = 6 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Salvation", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_AvatarOfStorm_Cooldown: - bonus.decrease.cooldown = 300 * 1000; + bonus.decrease.cooldown = 900 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Avatar of Storm", bonus)); break; @@ -449,31 +449,31 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin m_strategies.emplace_back(std::make_unique(m_wheel, "Energy Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 10 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Great Death Beam", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 15 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Great Death Beam", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_HellsCore_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 8 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Hell's Core", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_HellsCore_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Hell's Core", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_EnergyWave_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Energy Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_EnergyWave_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Energy Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatFireWave_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Great Fire Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatFireWave_CriticalExtraDamage: @@ -481,24 +481,24 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin m_strategies.emplace_back(std::make_unique(m_wheel, "Great Fire Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_RageOfTheSkies_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 8 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Rage of the Skies", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_RageOfTheSkies_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Rage of the Skies", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatEnergyBeam_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 10 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Great Energy Beam", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatEnergyBeam_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 15 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Great Energy Beam", bonus)); break; case WheelGemSupremeModifier_t::Druid_AvatarOfNature_Cooldown: - bonus.decrease.cooldown = 300 * 1000; + bonus.decrease.cooldown = 900 * 1000; wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.emplace_back(std::make_unique(m_wheel, "Avatar of Nature", bonus)); break; @@ -508,51 +508,51 @@ void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uin m_strategies.emplace_back(std::make_unique(m_wheel, "Nature's Embrace", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraBurst_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 7 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Terra Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraBurst_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Terra Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_IceBurst_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 7 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Ice Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_IceBurst_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Ice Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_EternalWinter_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Eternal Winter", bonus)); break; case WheelGemSupremeModifier_t::Druid_EternalWinter_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 8 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Eternal Winter", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraWave_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Terra Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraWave_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 12 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Terra Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_StrongIceWave_DamageIncrease: - bonus.increase.damage = 25 * gradeMultiplier; + bonus.increase.damage = 8 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Strong Ice Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_StrongIceWave_CriticalExtraDamage: - bonus.increase.criticalDamage = 8 * gradeMultiplier; + bonus.increase.criticalDamage = 15 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Strong Ice Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_HealFriend_HealingIncrease: - bonus.increase.heal = 10 * gradeMultiplier; + bonus.increase.heal = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Heal Friend", bonus)); break; case WheelGemSupremeModifier_t::Druid_MassHealing_HealingIncrease: - bonus.increase.heal = 10 * gradeMultiplier; + bonus.increase.heal = 5 * gradeMultiplier; m_strategies.emplace_back(std::make_unique(m_wheel, "Mass Healing", bonus)); break; default: diff --git a/src/game/game.cpp b/src/game/game.cpp index b4ce04f7644..d972a296dad 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -6959,7 +6959,7 @@ void Game::applyWheelOfDestinyEffectsToDamage(CombatDamage &damage, const std::s if (damage.secondary.value != 0) { damage.secondary.value -= attackerPlayer->wheel()->getStat(WheelStat_t::DAMAGE); } - if (damage.instantSpellName == "Twin Burst") { + if (damage.instantSpellName == "Ice Burst" || damage.instantSpellName == "Terra Burst") { int32_t damageBonus = attackerPlayer->wheel()->checkTwinBurstByTarget(target); if (damageBonus != 0) { damage.primary.value += (damage.primary.value * damageBonus) / 100.; @@ -9776,7 +9776,7 @@ void Game::playerSaveWheel(uint32_t playerId, NetworkMessage &msg) { return; } - if (player->isUIExhausted()) { + if (player->isUIExhausted(1000)) { player->sendCancelMessage(RETURNVALUE_YOUAREEXHAUSTED); return; } diff --git a/src/io/io_wheel.cpp b/src/io/io_wheel.cpp index 72d5e207d4c..5f7084d2b48 100644 --- a/src/io/io_wheel.cpp +++ b/src/io/io_wheel.cpp @@ -181,7 +181,7 @@ const VocationBonusMap &IOWheel::getWheelMapFunctions() const { std::pair IOWheel::getRevelationStatByStage(WheelStageEnum_t stageType) const { // Let's remove one, because the std::array starts with 0 and the stages with 1 - auto array = m_wheelBonusData.revelation.stats[static_cast(stageType) - 1]; + const auto &array = m_wheelBonusData.revelation.stats[static_cast(stageType) - 1]; return std::make_pair(array.damage, array.healing); } @@ -222,32 +222,32 @@ void IOWheel::initializeMapData() { void IOWheel::initializeDruidSpells() { m_wheelBonusData.spells.druid[0].name = "Strong Ice Wave"; m_wheelBonusData.spells.druid[0].grade[1].leech.mana = 3; - m_wheelBonusData.spells.druid[0].grade[2].increase.damage = 30; + m_wheelBonusData.spells.druid[0].grade[2].increase.damage = 10; m_wheelBonusData.spells.druid[1].name = "Mass Healing"; - m_wheelBonusData.spells.druid[1].grade[1].increase.heal = 10; + m_wheelBonusData.spells.druid[1].grade[1].increase.heal = 4; m_wheelBonusData.spells.druid[1].grade[2].increase.area = true; m_wheelBonusData.spells.druid[2].name = "Nature's Embrace"; - m_wheelBonusData.spells.druid[2].grade[1].increase.heal = 10; + m_wheelBonusData.spells.druid[2].grade[1].increase.heal = 11; m_wheelBonusData.spells.druid[2].grade[2].decrease.cooldown = 10; m_wheelBonusData.spells.druid[3].name = "Terra Wave"; - m_wheelBonusData.spells.druid[3].grade[1].increase.damage = 25; + m_wheelBonusData.spells.druid[3].grade[1].increase.damage = static_cast(std::round(6.5)); m_wheelBonusData.spells.druid[3].grade[2].leech.life = 5; m_wheelBonusData.spells.druid[4].name = "Heal Friend"; m_wheelBonusData.spells.druid[4].grade[1].decrease.manaCost = 10; - m_wheelBonusData.spells.druid[4].grade[2].increase.heal = 10; + m_wheelBonusData.spells.druid[4].grade[2].increase.heal = static_cast(std::round(5.5)); } void IOWheel::initializeKnightSpells() { m_wheelBonusData.spells.knight[0].name = "Front Sweep"; m_wheelBonusData.spells.knight[0].grade[1].leech.life = 5; - m_wheelBonusData.spells.knight[0].grade[2].increase.damage = 30; + m_wheelBonusData.spells.knight[0].grade[2].increase.damage = 14; m_wheelBonusData.spells.knight[1].name = "Groundshaker"; - m_wheelBonusData.spells.knight[1].grade[1].increase.damage = 25; + m_wheelBonusData.spells.knight[1].grade[1].increase.damage = static_cast(std::round(12.5)); m_wheelBonusData.spells.knight[1].grade[2].decrease.cooldown = 2; m_wheelBonusData.spells.knight[2].name = "Chivalrous Challenge"; @@ -255,12 +255,12 @@ void IOWheel::initializeKnightSpells() { m_wheelBonusData.spells.knight[2].grade[2].increase.aditionalTarget = 1; m_wheelBonusData.spells.knight[3].name = "Intense Wound Cleansing"; - m_wheelBonusData.spells.knight[3].grade[1].increase.heal = 10; + m_wheelBonusData.spells.knight[3].grade[1].increase.heal = 125; m_wheelBonusData.spells.knight[3].grade[2].decrease.cooldown = 300; m_wheelBonusData.spells.knight[4].name = "Fierce Berserk"; m_wheelBonusData.spells.knight[4].grade[1].decrease.manaCost = 30; - m_wheelBonusData.spells.knight[4].grade[2].increase.damage = 25; + m_wheelBonusData.spells.knight[4].grade[2].increase.damage = 10; } void IOWheel::initializePaladinSpells() { @@ -270,7 +270,7 @@ void IOWheel::initializePaladinSpells() { m_wheelBonusData.spells.paladin[1].name = "Strong Ethereal Spear"; m_wheelBonusData.spells.paladin[1].grade[1].decrease.cooldown = 2; - m_wheelBonusData.spells.paladin[1].grade[2].increase.damage = 25; + m_wheelBonusData.spells.paladin[1].grade[2].increase.damage = 380; m_wheelBonusData.spells.paladin[2].name = "Divine Dazzle"; m_wheelBonusData.spells.paladin[2].grade[1].increase.aditionalTarget = 1; @@ -283,7 +283,7 @@ void IOWheel::initializePaladinSpells() { m_wheelBonusData.spells.paladin[4].name = "Divine Caldera"; m_wheelBonusData.spells.paladin[4].grade[1].decrease.manaCost = 20; - m_wheelBonusData.spells.paladin[4].grade[2].increase.damage = 25; + m_wheelBonusData.spells.paladin[4].grade[2].increase.damage = static_cast(std::round(8.5)); } void IOWheel::initializeSorcererSpells() { @@ -292,19 +292,19 @@ void IOWheel::initializeSorcererSpells() { m_wheelBonusData.spells.sorcerer[1].name = "Sap Strength"; m_wheelBonusData.spells.sorcerer[1].grade[1].increase.area = true; - m_wheelBonusData.spells.sorcerer[1].grade[2].increase.damageReduction = 10; + m_wheelBonusData.spells.sorcerer[1].grade[2].increase.damageReduction = 1; m_wheelBonusData.spells.sorcerer[2].name = "Energy Wave"; - m_wheelBonusData.spells.sorcerer[2].grade[1].increase.damage = 25; + m_wheelBonusData.spells.sorcerer[2].grade[1].increase.damage = 5; m_wheelBonusData.spells.sorcerer[2].grade[2].increase.area = true; m_wheelBonusData.spells.sorcerer[3].name = "Great Fire Wave"; m_wheelBonusData.spells.sorcerer[3].grade[1].increase.criticalDamage = 15; m_wheelBonusData.spells.sorcerer[3].grade[1].increase.criticalChance = 10; - m_wheelBonusData.spells.sorcerer[3].grade[2].increase.damage = 25; + m_wheelBonusData.spells.sorcerer[3].grade[2].increase.damage = 5; m_wheelBonusData.spells.sorcerer[4].name = "Any_Focus_Mage_Spell"; - m_wheelBonusData.spells.sorcerer[4].grade[1].increase.damage = 25; + m_wheelBonusData.spells.sorcerer[4].grade[1].increase.damage = 5; m_wheelBonusData.spells.sorcerer[4].grade[2].decrease.cooldown = 4; m_wheelBonusData.spells.sorcerer[4].grade[2].decrease.secondaryGroupCooldown = 4; } diff --git a/src/utils/tools.cpp b/src/utils/tools.cpp index 301d2c61cf8..d83656bab40 100644 --- a/src/utils/tools.cpp +++ b/src/utils/tools.cpp @@ -1580,6 +1580,12 @@ SpellGroup_t stringToSpellGroup(const std::string &value) { if (tmpStr == "ultimatestrikes" || tmpStr == "8") { return SPELLGROUP_ULTIMATESTRIKES; } + if (tmpStr == "burstsofnature" || tmpStr == "9") { + return SPELLGROUP_BURSTS_OF_NATURE; + } + if (tmpStr == "greatbeams" || tmpStr == "10") { + return SPELLGROUP_GREAT_BEAMS; + } return SPELLGROUP_NONE; } From 8c481ef4eb961d77b7e1bd230a2b1213c9781190 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 3 Nov 2024 05:16:10 +0000 Subject: [PATCH 02/13] Code format - (Clang-format) --- src/creatures/players/wheel/player_wheel.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creatures/players/wheel/player_wheel.hpp b/src/creatures/players/wheel/player_wheel.hpp index 0ad3ed4ce59..1f12f982f4c 100644 --- a/src/creatures/players/wheel/player_wheel.hpp +++ b/src/creatures/players/wheel/player_wheel.hpp @@ -257,7 +257,7 @@ class PlayerWheel { */ void setMajorStat(WheelMajor_t type, int32_t value); - /** + /** * @brief Sets the value of a specific specialized magic in the Wheel of Destiny. * * This function sets the value of the specified specialized magic in the Wheel of Destiny to the provided value. From 8602ef60ab11e0cd6f9ba5efc86f2e279e088dd3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 3 Nov 2024 05:16:10 +0000 Subject: [PATCH 03/13] Code format - (Clang-format) --- src/creatures/players/wheel/player_wheel.cpp | 2 +- src/creatures/players/wheel/player_wheel.hpp | 2 +- src/game/game.cpp | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 0db8f9461ef..634237d0c4c 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -1272,7 +1272,7 @@ void PlayerWheel::toggleGemLock(uint16_t index) const { } void PlayerWheel::setActiveGem(WheelGemAffinity_t affinity, uint16_t index) const { - const auto gem = getGem(index); + auto gem = getGem(index); if (gem.uuid.empty()) { g_logger().error("[{}] Failed to load gem with index {}", __FUNCTION__, index); return; diff --git a/src/creatures/players/wheel/player_wheel.hpp b/src/creatures/players/wheel/player_wheel.hpp index 0ad3ed4ce59..1f12f982f4c 100644 --- a/src/creatures/players/wheel/player_wheel.hpp +++ b/src/creatures/players/wheel/player_wheel.hpp @@ -257,7 +257,7 @@ class PlayerWheel { */ void setMajorStat(WheelMajor_t type, int32_t value); - /** + /** * @brief Sets the value of a specific specialized magic in the Wheel of Destiny. * * This function sets the value of the specified specialized magic in the Wheel of Destiny to the provided value. diff --git a/src/game/game.cpp b/src/game/game.cpp index d972a296dad..ffcf56e78cb 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -9766,6 +9766,7 @@ void Game::playerOpenWheel(uint32_t playerId, uint32_t ownerId) { return; } + player->wheel()->clearDestroyedGems(); player->wheel()->sendOpenWheelWindow(ownerId); player->updateUIExhausted(); } From 2148caf49daf13165ed44a9d811acedb11145fe8 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 3 Nov 2024 07:09:50 +0000 Subject: [PATCH 04/13] Lua code format - (Stylua) --- data/scripts/spells/attack/great_death_beam.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/scripts/spells/attack/great_death_beam.lua b/data/scripts/spells/attack/great_death_beam.lua index 31fba671d56..84c75132d76 100644 --- a/data/scripts/spells/attack/great_death_beam.lua +++ b/data/scripts/spells/attack/great_death_beam.lua @@ -34,7 +34,7 @@ function spell.onCastSpell(creature, var) return false end - return combat[grade]:execute(creature, var) + return combat[grade]:execute(creature, var) end spell:group("attack", "greatbeams") From 3114db6f1136b7558fa04b94fb54c35c9f41161f Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Mon, 4 Nov 2024 15:29:43 -0300 Subject: [PATCH 05/13] refactor: misspelling and function improvement --- src/creatures/players/player.cpp | 6 +- src/creatures/players/wheel/player_wheel.cpp | 140 ++++++++---------- src/creatures/players/wheel/player_wheel.hpp | 2 +- .../players/wheel/wheel_definitions.hpp | 6 +- src/io/io_wheel.cpp | 2 +- 5 files changed, 66 insertions(+), 90 deletions(-) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 2b71983cd13..40f1bcab6e4 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -6344,7 +6344,7 @@ uint32_t Player::getMagicLevel() const { uint32_t magic = std::max(0, getLoyaltyMagicLevel() + varStats[STAT_MAGICPOINTS]); // Wheel of destiny magic bonus magic += m_wheelPlayer->getStat(WheelStat_t::MAGIC); // Regular bonus - magic += m_wheelPlayer->getMajorStatConditional("Positional Tatics", WheelMajor_t::MAGIC); // Revelation bonus + magic += m_wheelPlayer->getMajorStatConditional("Positional Tactics", WheelMajor_t::MAGIC); // Revelation bonus return magic; } @@ -6402,12 +6402,12 @@ uint16_t Player::getSkillLevel(skills_t skill) const { skillLevel += m_wheelPlayer->getStat(WheelStat_t::MELEE); skillLevel += m_wheelPlayer->getMajorStatConditional("Battle Instinct", WheelMajor_t::MELEE); } else if (skill == SKILL_DISTANCE) { - skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tatics", WheelMajor_t::DISTANCE); + skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tactics", WheelMajor_t::DISTANCE); skillLevel += m_wheelPlayer->getStat(WheelStat_t::DISTANCE); } else if (skill == SKILL_SHIELD) { skillLevel += m_wheelPlayer->getMajorStatConditional("Battle Instinct", WheelMajor_t::SHIELD); } else if (skill == SKILL_MAGLEVEL) { - skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tatics", WheelMajor_t::MAGIC); + skillLevel += m_wheelPlayer->getMajorStatConditional("Positional Tactics", WheelMajor_t::MAGIC); skillLevel += m_wheelPlayer->getStat(WheelStat_t::MAGIC); } else if (skill == SKILL_LIFE_LEECH_AMOUNT) { skillLevel += m_wheelPlayer->getStat(WheelStat_t::LIFE_LEECH); diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 97e057f12bf..b72cc99e506 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -1325,30 +1325,32 @@ void PlayerWheel::addSpellBonus(const std::string &spellName, const WheelSpells: } int32_t PlayerWheel::getSpellBonus(const std::string &spellName, WheelSpellBoost_t boost) const { + using enum WheelSpellBoost_t; + if (!m_spellsBonuses.contains(spellName)) { return 0; } const auto &[leech, increase, decrease] = m_spellsBonuses.at(spellName); switch (boost) { - case WheelSpellBoost_t::COOLDOWN: + case COOLDOWN: return decrease.cooldown; - case WheelSpellBoost_t::MANA: + case MANA: return decrease.manaCost; - case WheelSpellBoost_t::SECONDARY_GROUP_COOLDOWN: + case SECONDARY_GROUP_COOLDOWN: return decrease.secondaryGroupCooldown; - case WheelSpellBoost_t::CRITICAL_CHANCE: + case CRITICAL_CHANCE: return increase.criticalChance; - case WheelSpellBoost_t::CRITICAL_DAMAGE: + case CRITICAL_DAMAGE: return increase.criticalDamage; - case WheelSpellBoost_t::DAMAGE: + case DAMAGE: return increase.damage; - case WheelSpellBoost_t::DAMAGE_REDUCTION: + case DAMAGE_REDUCTION: return increase.damageReduction; - case WheelSpellBoost_t::HEAL: + case HEAL: return increase.heal; - case WheelSpellBoost_t::LIFE_LEECH: + case LIFE_LEECH: return leech.life; - case WheelSpellBoost_t::MANA_LEECH: + case MANA_LEECH: return leech.mana; default: return 0; @@ -1941,7 +1943,7 @@ void PlayerWheel::registerPlayerBonusData() { // Instant setSpellInstant("Battle Instinct", m_playerBonusData.instant.battleInstinct); setSpellInstant("Battle Healing", m_playerBonusData.instant.battleHealing); - setSpellInstant("Positional Tatics", m_playerBonusData.instant.positionalTatics); + setSpellInstant("Positional Tactics", m_playerBonusData.instant.positionalTactics); setSpellInstant("Ballistic Mastery", m_playerBonusData.instant.ballisticMastery); setSpellInstant("Healing Link", m_playerBonusData.instant.healingLink); setSpellInstant("Runic Mastery", m_playerBonusData.instant.runicMastery); @@ -2221,8 +2223,8 @@ void PlayerWheel::printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonus if (bonusData.instant.battleHealing) { g_logger().debug(" battleHealing: {}", bonusData.instant.battleHealing); } - if (bonusData.instant.positionalTatics) { - g_logger().debug(" positionalTatics: {}", bonusData.instant.positionalTatics); + if (bonusData.instant.positionalTactics) { + g_logger().debug(" positionalTactics: {}", bonusData.instant.positionalTactics); } if (bonusData.instant.ballisticMastery) { g_logger().debug(" ballisticMastery: {}", bonusData.instant.ballisticMastery); @@ -2585,7 +2587,7 @@ void PlayerWheel::checkAbilities() { if (getInstant("Battle Instinct") && getOnThinkTimer(WheelOnThink_t::BATTLE_INSTINCT) < OTSYS_TIME() && checkBattleInstinct()) { reloadClient = true; } - if (getInstant("Positional Tatics") && getOnThinkTimer(WheelOnThink_t::POSITIONAL_TATICS) < OTSYS_TIME() && checkPositionalTatics()) { + if (getInstant("Positional Tactics") && getOnThinkTimer(WheelOnThink_t::POSITIONAL_TACTICS) < OTSYS_TIME() && checkPositionalTactics()) { reloadClient = true; } if (getInstant("Ballistic Mastery") && getOnThinkTimer(WheelOnThink_t::BALLISTIC_MASTERY) < OTSYS_TIME() && checkBallisticMastery()) { @@ -2650,8 +2652,8 @@ bool PlayerWheel::checkBattleInstinct() { return updateClient; } -bool PlayerWheel::checkPositionalTatics() { - setOnThinkTimer(WheelOnThink_t::POSITIONAL_TATICS, OTSYS_TIME() + 2000); +bool PlayerWheel::checkPositionalTactics() { + setOnThinkTimer(WheelOnThink_t::POSITIONAL_TACTICS, OTSYS_TIME() + 2000); m_creaturesNearby = 0; bool updateClient = false; uint16_t creaturesNearby = 0; @@ -3083,7 +3085,7 @@ void PlayerWheel::onThink(bool force /* = false*/) { if (getGiftOfCooldown() > 0 /*getInstant("Gift of Life")*/ && getOnThinkTimer(WheelOnThink_t::GIFT_OF_LIFE) <= OTSYS_TIME()) { decreaseGiftOfCooldown(1); } - if (!m_player.hasCondition(CONDITION_INFIGHT) || m_player.getZoneType() == ZONE_PROTECTION || (!getInstant("Battle Instinct") && !getInstant("Positional Tatics") && !getInstant("Ballistic Mastery") && !getInstant("Gift of Life") && !getInstant("Combat Mastery") && !getInstant("Divine Empowerment") && getGiftOfCooldown() == 0)) { + if (!m_player.hasCondition(CONDITION_INFIGHT) || m_player.getZoneType() == ZONE_PROTECTION || (!getInstant("Battle Instinct") && !getInstant("Positional Tactics") && !getInstant("Ballistic Mastery") && !getInstant("Gift of Life") && !getInstant("Combat Mastery") && !getInstant("Divine Empowerment") && getGiftOfCooldown() == 0)) { bool mustReset = false; for (int i = 0; i < static_cast(WheelMajor_t::TOTAL_COUNT); i++) { if (getMajorStat(static_cast(i)) != 0) { @@ -3108,8 +3110,8 @@ void PlayerWheel::onThink(bool force /* = false*/) { if (getInstant("Battle Instinct") && (force || getOnThinkTimer(WheelOnThink_t::BATTLE_INSTINCT) < OTSYS_TIME()) && checkBattleInstinct()) { updateClient = true; } - // Positional Tatics - if (getInstant("Positional Tatics") && (force || getOnThinkTimer(WheelOnThink_t::POSITIONAL_TATICS) < OTSYS_TIME()) && checkPositionalTatics()) { + // Positional Tactics + if (getInstant("Positional Tactics") && (force || getOnThinkTimer(WheelOnThink_t::POSITIONAL_TACTICS) < OTSYS_TIME()) && checkPositionalTactics()) { updateClient = true; } // Ballistic Mastery @@ -3321,9 +3323,9 @@ void PlayerWheel::setSpellInstant(const std::string &name, bool value) { } } else if (name == "Battle Healing") { setInstant(WheelInstant_t::BATTLE_HEALING, value); - } else if (name == "Positional Tatics") { - setInstant(WheelInstant_t::POSITIONAL_TATICS, value); - if (!getInstant(WheelInstant_t::POSITIONAL_TATICS)) { + } else if (name == "Positional Tactics") { + setInstant(WheelInstant_t::POSITIONAL_TACTICS, value); + if (!getInstant(WheelInstant_t::POSITIONAL_TACTICS)) { setMajorStat(WheelMajor_t::MAGIC, 0); setMajorStat(WheelMajor_t::HOLY_RESISTANCE, 0); } @@ -3456,8 +3458,8 @@ uint8_t PlayerWheel::getStage(std::string_view name) const { if (name == "Battle Healing") { return PlayerWheel::getInstant(BATTLE_HEALING); } - if (name == "Positional Tatics") { - return PlayerWheel::getInstant(POSITIONAL_TATICS); + if (name == "Positional Tactics") { + return PlayerWheel::getInstant(POSITIONAL_TACTICS); } if (name == "Ballistic Mastery") { return PlayerWheel::getInstant(BALLISTIC_MASTERY); @@ -3604,65 +3606,39 @@ int64_t PlayerWheel::getOnThinkTimer(WheelOnThink_t type) const { bool PlayerWheel::getInstant(std::string_view name) const { using enum WheelInstant_t; - if (name == "Battle Instinct") { - return PlayerWheel::getInstant(BATTLE_INSTINCT); - } - if (name == "Battle Healing") { - return PlayerWheel::getInstant(BATTLE_HEALING); - } - if (name == "Positional Tatics") { - return PlayerWheel::getInstant(POSITIONAL_TATICS); - } - if (name == "Ballistic Mastery") { - return PlayerWheel::getInstant(BALLISTIC_MASTERY); - } - if (name == "Healing Link") { - return PlayerWheel::getInstant(HEALING_LINK); - } - if (name == "Runic Mastery") { - return PlayerWheel::getInstant(RUNIC_MASTERY); - } - if (name == "Focus Mastery") { - return PlayerWheel::getInstant(FOCUS_MASTERY); - } - if (name == "Beam Mastery") { - return PlayerWheel::getStage(WheelStage_t::BEAM_MASTERY); - } - if (name == "Combat Mastery") { - return PlayerWheel::getStage(WheelStage_t::COMBAT_MASTERY); - } - if (name == "Gift of Life") { - return PlayerWheel::getStage(WheelStage_t::GIFT_OF_LIFE); - } - if (name == "Blessing of the Grove") { - return PlayerWheel::getStage(WheelStage_t::BLESSING_OF_THE_GROVE); - } - if (name == "Drain Body") { - return PlayerWheel::getStage(WheelStage_t::DRAIN_BODY); - } - if (name == "Divine Empowerment") { - return PlayerWheel::getStage(WheelStage_t::DIVINE_EMPOWERMENT); - } - if (name == "Divine Grenade") { - return PlayerWheel::getStage(WheelStage_t::DIVINE_GRENADE); - } - if (name == "Twin Burst") { - return PlayerWheel::getStage(WheelStage_t::TWIN_BURST); - } - if (name == "Executioner's Throw") { - return PlayerWheel::getStage(WheelStage_t::EXECUTIONERS_THROW); - } - if (name == "Avatar of Light") { - return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_LIGHT); - } - if (name == "Avatar of Nature") { - return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_NATURE); - } - if (name == "Avatar of Steel") { - return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_STEEL); + using enum WheelStage_t; + + static const std::unordered_map instantMapping = { + { "Battle Instinct", BATTLE_INSTINCT }, + { "Battle Healing", BATTLE_HEALING }, + { "Positional Tactics", POSITIONAL_TACTICS }, + { "Ballistic Mastery", BALLISTIC_MASTERY }, + { "Healing Link", HEALING_LINK }, + { "Runic Mastery", RUNIC_MASTERY }, + { "Focus Mastery", FOCUS_MASTERY } + }; + + static const std::unordered_map stageMapping = { + { "Beam Mastery", BEAM_MASTERY }, + { "Combat Mastery", COMBAT_MASTERY }, + { "Gift of Life", GIFT_OF_LIFE }, + { "Blessing of the Grove", BLESSING_OF_THE_GROVE }, + { "Drain Body", DRAIN_BODY }, + { "Divine Empowerment", DIVINE_EMPOWERMENT }, + { "Divine Grenade", DIVINE_GRENADE }, + { "Twin Burst", TWIN_BURST }, + { "Executioner's Throw", EXECUTIONERS_THROW }, + { "Avatar of Light", AVATAR_OF_LIGHT }, + { "Avatar of Nature", AVATAR_OF_NATURE }, + { "Avatar of Steel", AVATAR_OF_STEEL }, + { "Avatar of Storm", AVATAR_OF_STORM } + }; + + if (auto it = instantMapping.find(name); it != instantMapping.end()) { + return PlayerWheel::getInstant(it->second); } - if (name == "Avatar of Storm") { - return PlayerWheel::getStage(WheelStage_t::AVATAR_OF_STORM); + if (auto it = stageMapping.find(name); it != stageMapping.end()) { + return PlayerWheel::getStage(it->second); } return false; diff --git a/src/creatures/players/wheel/player_wheel.hpp b/src/creatures/players/wheel/player_wheel.hpp index 8024d9f58a0..de0f08debeb 100644 --- a/src/creatures/players/wheel/player_wheel.hpp +++ b/src/creatures/players/wheel/player_wheel.hpp @@ -212,7 +212,7 @@ class PlayerWheel { void checkAbilities(); void checkGiftOfLife(); bool checkBattleInstinct(); - bool checkPositionalTatics(); + bool checkPositionalTactics(); bool checkBallisticMastery(); bool checkCombatMastery(); bool checkDivineEmpowerment(); diff --git a/src/creatures/players/wheel/wheel_definitions.hpp b/src/creatures/players/wheel/wheel_definitions.hpp index 87f7fc28d6b..a136bd620d3 100644 --- a/src/creatures/players/wheel/wheel_definitions.hpp +++ b/src/creatures/players/wheel/wheel_definitions.hpp @@ -97,7 +97,7 @@ enum class WheelStage_t : uint8_t { enum class WheelOnThink_t : uint8_t { BATTLE_INSTINCT = 0, - POSITIONAL_TATICS = 1, + POSITIONAL_TACTICS = 1, BALLISTIC_MASTERY = 2, COMBAT_MASTERY = 3, FOCUS_MASTERY = 4, @@ -148,7 +148,7 @@ enum class WheelMajor_t : uint8_t { enum class WheelInstant_t : uint8_t { BATTLE_INSTINCT = 0, BATTLE_HEALING = 1, - POSITIONAL_TATICS = 2, + POSITIONAL_TACTICS = 2, BALLISTIC_MASTERY = 3, HEALING_LINK = 4, RUNIC_MASTERY = 5, @@ -217,7 +217,7 @@ struct PlayerWheelMethodsBonusData { struct Instant { bool battleInstinct = false; // Knight bool battleHealing = false; // Knight - bool positionalTatics = false; // Paladin + bool positionalTactics = false; // Paladin bool ballisticMastery = false; // Paladin bool healingLink = false; // Druid bool runicMastery = false; // Druid/sorcerer diff --git a/src/io/io_wheel.cpp b/src/io/io_wheel.cpp index 5f7084d2b48..2e1b57c79bc 100644 --- a/src/io/io_wheel.cpp +++ b/src/io/io_wheel.cpp @@ -399,7 +399,7 @@ void IOWheel::slotGreen200(const std::shared_ptr &player, uint16_t point bonusData.stats.health += 2 * points; bonusData.stats.mana += 3 * points; if (pointsInSlot) { - bonusData.instant.positionalTatics = true; + bonusData.instant.positionalTactics = true; } } else { bonusData.stats.health += 1 * points; From 765e79d73536e23b8bab45d8a550a603fc8b23a5 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Mon, 4 Nov 2024 22:46:52 -0300 Subject: [PATCH 06/13] fix: sonar duplicated code --- src/creatures/players/wheel/player_wheel.cpp | 89 +++++++------------- 1 file changed, 31 insertions(+), 58 deletions(-) diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index b72cc99e506..63790220c36 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -3452,65 +3452,38 @@ bool PlayerWheel::getInstant(WheelInstant_t type) const { uint8_t PlayerWheel::getStage(std::string_view name) const { using enum WheelInstant_t; using enum WheelStage_t; - if (name == "Battle Instinct") { - return PlayerWheel::getInstant(BATTLE_INSTINCT); - } - if (name == "Battle Healing") { - return PlayerWheel::getInstant(BATTLE_HEALING); - } - if (name == "Positional Tactics") { - return PlayerWheel::getInstant(POSITIONAL_TACTICS); - } - if (name == "Ballistic Mastery") { - return PlayerWheel::getInstant(BALLISTIC_MASTERY); - } - if (name == "Healing Link") { - return PlayerWheel::getInstant(HEALING_LINK); - } - if (name == "Runic Mastery") { - return PlayerWheel::getInstant(RUNIC_MASTERY); - } - if (name == "Focus Mastery") { - return PlayerWheel::getInstant(FOCUS_MASTERY); - } - if (name == "Beam Mastery") { - return PlayerWheel::getStage(BEAM_MASTERY); - } - if (name == "Combat Mastery") { - return PlayerWheel::getStage(COMBAT_MASTERY); - } - if (name == "Gift of Life") { - return PlayerWheel::getStage(GIFT_OF_LIFE); - } - if (name == "Blessing of the Grove") { - return PlayerWheel::getStage(BLESSING_OF_THE_GROVE); - } - if (name == "Drain Body") { - return PlayerWheel::getStage(DRAIN_BODY); - } - if (name == "Divine Empowerment") { - return PlayerWheel::getStage(DIVINE_EMPOWERMENT); - } - if (name == "Divine Grenade") { - return PlayerWheel::getStage(DIVINE_GRENADE); - } - if (name == "Twin Burst") { - return PlayerWheel::getStage(TWIN_BURST); - } - if (name == "Executioner's Throw") { - return PlayerWheel::getStage(EXECUTIONERS_THROW); - } - if (name == "Avatar of Light") { - return PlayerWheel::getStage(AVATAR_OF_LIGHT); - } - if (name == "Avatar of Nature") { - return PlayerWheel::getStage(AVATAR_OF_NATURE); - } - if (name == "Avatar of Steel") { - return PlayerWheel::getStage(AVATAR_OF_STEEL); + + static const std::unordered_map instantMapping = { + { "Battle Instinct", BATTLE_INSTINCT }, + { "Battle Healing", BATTLE_HEALING }, + { "Positional Tatics", POSITIONAL_TACTICS }, + { "Ballistic Mastery", BALLISTIC_MASTERY }, + { "Healing Link", HEALING_LINK }, + { "Runic Mastery", RUNIC_MASTERY }, + { "Focus Mastery", FOCUS_MASTERY } + }; + + static const std::unordered_map stageMapping = { + { "Beam Mastery", BEAM_MASTERY }, + { "Combat Mastery", COMBAT_MASTERY }, + { "Gift of Life", GIFT_OF_LIFE }, + { "Blessing of the Grove", BLESSING_OF_THE_GROVE }, + { "Drain Body", DRAIN_BODY }, + { "Divine Empowerment", DIVINE_EMPOWERMENT }, + { "Divine Grenade", DIVINE_GRENADE }, + { "Twin Burst", TWIN_BURST }, + { "Executioner's Throw", EXECUTIONERS_THROW }, + { "Avatar of Light", AVATAR_OF_LIGHT }, + { "Avatar of Nature", AVATAR_OF_NATURE }, + { "Avatar of Steel", AVATAR_OF_STEEL }, + { "Avatar of Storm", AVATAR_OF_STORM } + }; + + if (auto it = instantMapping.find(name); it != instantMapping.end()) { + return PlayerWheel::getInstant(it->second); } - if (name == "Avatar of Storm") { - return PlayerWheel::getStage(AVATAR_OF_STORM); + if (auto it = stageMapping.find(name); it != stageMapping.end()) { + return PlayerWheel::getStage(it->second); } return false; From 3700faee624f355ca625797498e0914486db6cbb Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Mon, 4 Nov 2024 22:53:39 -0300 Subject: [PATCH 07/13] fix: return temporary ref --- src/creatures/players/wheel/player_wheel.cpp | 4 ++-- src/creatures/players/wheel/player_wheel.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 63790220c36..c50406d0d71 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -1020,11 +1020,11 @@ void PlayerWheel::addPromotionScrolls(NetworkMessage &msg) const { } } -const std::shared_ptr &PlayerWheel::gemsKV() const { +std::shared_ptr PlayerWheel::gemsKV() const { return m_player.kv()->scoped("wheel-of-destiny")->scoped("gems"); } -const std::shared_ptr &PlayerWheel::gemsGradeKV(WheelFragmentType_t type, uint8_t pos) const { +std::shared_ptr PlayerWheel::gemsGradeKV(WheelFragmentType_t type, uint8_t pos) const { return gemsKV()->scoped(std::string(magic_enum::enum_name(type)))->scoped(std::to_string(pos)); } diff --git a/src/creatures/players/wheel/player_wheel.hpp b/src/creatures/players/wheel/player_wheel.hpp index de0f08debeb..7c3bd2348a6 100644 --- a/src/creatures/players/wheel/player_wheel.hpp +++ b/src/creatures/players/wheel/player_wheel.hpp @@ -189,8 +189,8 @@ class PlayerWheel { */ uint8_t getOptions(uint32_t ownerId) const; - const std::shared_ptr &gemsKV() const; - const std::shared_ptr &gemsGradeKV(WheelFragmentType_t quality, uint8_t pos) const; + std::shared_ptr gemsKV() const; + std::shared_ptr gemsGradeKV(WheelFragmentType_t quality, uint8_t pos) const; uint8_t getGemGrade(WheelFragmentType_t quality, uint8_t pos) const; std::vector getRevealedGems() const; From 626a284efd9b2e0e4cd3a578f9fc9d72227b614b Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Tue, 5 Nov 2024 00:16:17 -0300 Subject: [PATCH 08/13] fix: remove unused function --- src/game/game.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 2e932c102d8..05f9f87046e 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -9831,7 +9831,6 @@ void Game::playerOpenWheel(uint32_t playerId, uint32_t ownerId) { return; } - player->wheel()->clearDestroyedGems(); player->wheel()->sendOpenWheelWindow(ownerId); player->updateUIExhausted(); } From a399a28575095178e5a164ffe014daa6aa43c345 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Tue, 5 Nov 2024 00:31:41 -0300 Subject: [PATCH 09/13] fix: executioners throw --- .../spells/attack/executioners_throw.lua | 23 +++---------------- src/creatures/players/wheel/player_wheel.cpp | 8 +++++++ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/data/scripts/spells/attack/executioners_throw.lua b/data/scripts/spells/attack/executioners_throw.lua index 2f2220625c5..08d700bfe54 100644 --- a/data/scripts/spells/attack/executioners_throw.lua +++ b/data/scripts/spells/attack/executioners_throw.lua @@ -40,28 +40,11 @@ function spell.onCastSpell(creature, var) local grade = creature:revelationStageWOD("Executioner's Throw") if grade == 0 then - creature:sendCancelMessage("You cannot cast this spell") + creature:sendCancelMessage("You need to learn this spell first") creature:getPosition():sendMagicEffect(CONST_ME_POFF) return false end - - local cooldown = 0 - if grade >= 3 then - cooldown = 10 - elseif grade >= 2 then - cooldown = 14 - elseif grade >= 1 then - cooldown = 18 - end - - var.instantName = "Executioner's Throw" - if combat:execute(creature, var) then - local condition = Condition(CONDITION_SPELLCOOLDOWN, CONDITIONID_DEFAULT, 261) - condition:setTicks((cooldown * 1000) / configManager.getFloat(configKeys.RATE_SPELL_COOLDOWN)) - creature:addCondition(condition) - return true - end - return false + return combat:execute(creature, var) end spell:group("attack") @@ -75,7 +58,7 @@ spell:range(5) spell:needTarget(true) spell:blockWalls(true) spell:needWeapon(true) -spell:cooldown(1000) -- Cooldown is calculated on the casting +spell:cooldown(18 * 1000) spell:groupCooldown(2 * 1000) spell:needLearn(true) spell:vocation("knight;true", "elite knight;true") diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index c50406d0d71..ce411b03e97 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -2059,6 +2059,14 @@ void PlayerWheel::registerPlayerBonusData() { for (int i = 0; i < m_playerBonusData.stages.executionersThrow; ++i) { setSpellInstant("Executioner's Throw", true); } + WheelSpells::Bonus bonus; + bonus.decrease.cooldown = 4 * 1000; + if (m_playerBonusData.stages.executionersThrow >= 2) { + addSpellBonus("Executioner's Throw", bonus); + } + if (m_playerBonusData.stages.executionersThrow >= 3) { + addSpellBonus("Executioner's Throw", bonus); + } } else { setSpellInstant("Executioner's Throw", false); } From daaf348b162567d31ced6f6cedb38ee76e536fcd Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Sat, 9 Nov 2024 18:49:13 -0300 Subject: [PATCH 10/13] improve: simplify function logic and check nullpointers --- src/creatures/players/wheel/player_wheel.cpp | 57 ++++++++++---------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index ce411b03e97..361a5b45512 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -958,42 +958,39 @@ int PlayerWheel::getSpellAdditionalDuration(const std::string &spellName) const } bool PlayerWheel::handleTwinBurstsCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const { - bool applyCondition = false; - uint16_t spellId = 0; - if (spellName == "Terra Burst") { - const auto &spell = g_spells().getSpellByName("Ice Burst"); - spellId = spell->getSpellId(); - applyCondition = true; - } else if (spellName == "Ice Burst") { - const auto &spell = g_spells().getSpellByName("Terra Burst"); - spellId = spell->getSpellId(); - applyCondition = true; - } + // Map of spell pairs for Twin Bursts + static const std::unordered_map spellPairs = { + {"Terra Burst", "Ice Burst"}, + {"Ice Burst", "Terra Burst"} + }; - if (applyCondition) { - const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId); - return player->addCondition(condition); + auto it = spellPairs.find(spellName); + if (it != spellPairs.end()) { + const auto &spell = g_spells().getSpellByName(it->second); + if (spell) { + const auto spellId = spell->getSpellId(); + const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId); + return player->addCondition(condition); + } } return false; } bool PlayerWheel::handleBeamMasteryCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const { - bool applyCondition = false; - uint16_t spellId = 0; - if (spellName == "Great Death Beam") { - const auto &spell = g_spells().getSpellByName("Great Energy Beam"); - spellId = spell->getSpellId(); - applyCondition = true; - } else if (spellName == "Great Energy Beam") { - const auto &spell = g_spells().getSpellByName("Great Death Beam"); - spellId = spell->getSpellId(); - applyCondition = true; - } + static const std::unordered_map spellPairs = { + {"Great Death Beam", "Great Energy Beam"}, + {"Great Energy Beam", "Great Death Beam"} + }; - if (applyCondition) { - const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId); - return player->addCondition(condition); + auto it = spellPairs.find(spellName); + if (it != spellPairs.end()) { + const auto &spell = g_spells().getSpellByName(it->second); + if (spell) { + const auto spellId = spell->getSpellId(); + const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_SPELLCOOLDOWN, spellCooldown / rateCooldown, 0, false, spellId); + return player->addCondition(condition); + } } return false; @@ -3144,6 +3141,10 @@ void PlayerWheel::reduceAllSpellsCooldownTimer(int32_t value) const { for (const auto &condition : m_player.getConditionsByType(CONDITION_SPELLCOOLDOWN)) { const auto spellId = condition->getSubId(); const auto &spell = g_spells().getInstantSpellById(spellId); + if (!spell) { + continue; + } + const auto spellSecondaryGroup = spell->getSecondaryGroup(); const auto &secondCondition = m_player.getCondition(CONDITION_SPELLGROUPCOOLDOWN, CONDITIONID_DEFAULT, spellSecondaryGroup); From 97dc21ba10693a75485c995ca11739e6124a0d5d Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 9 Nov 2024 21:49:49 +0000 Subject: [PATCH 11/13] Code format - (Clang-format) --- src/creatures/players/wheel/player_wheel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 361a5b45512..c8ab1b38f1c 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -960,8 +960,8 @@ int PlayerWheel::getSpellAdditionalDuration(const std::string &spellName) const bool PlayerWheel::handleTwinBurstsCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const { // Map of spell pairs for Twin Bursts static const std::unordered_map spellPairs = { - {"Terra Burst", "Ice Burst"}, - {"Ice Burst", "Terra Burst"} + { "Terra Burst", "Ice Burst" }, + { "Ice Burst", "Terra Burst" } }; auto it = spellPairs.find(spellName); @@ -979,8 +979,8 @@ bool PlayerWheel::handleTwinBurstsCooldown(const std::shared_ptr &player bool PlayerWheel::handleBeamMasteryCooldown(const std::shared_ptr &player, const std::string &spellName, int spellCooldown, int rateCooldown) const { static const std::unordered_map spellPairs = { - {"Great Death Beam", "Great Energy Beam"}, - {"Great Energy Beam", "Great Death Beam"} + { "Great Death Beam", "Great Energy Beam" }, + { "Great Energy Beam", "Great Death Beam" } }; auto it = spellPairs.find(spellName); From 70bee9f6c2b3c259355795dee64c07e773134c52 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Sun, 10 Nov 2024 22:43:01 -0300 Subject: [PATCH 12/13] perf: use spectators to get monsters within range --- src/creatures/players/wheel/player_wheel.cpp | 58 ++------------------ 1 file changed, 4 insertions(+), 54 deletions(-) diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index c8ab1b38f1c..aa7989c255e 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -9,6 +9,8 @@ #include "creatures/players/wheel/player_wheel.hpp" +#include "map/spectators.hpp" +#include "creatures/monsters/monster.hpp" #include "config/configmanager.hpp" #include "creatures/combat/condition.hpp" #include "creatures/combat/spells.hpp" @@ -2609,35 +2611,7 @@ bool PlayerWheel::checkBattleInstinct() { setOnThinkTimer(WheelOnThink_t::BATTLE_INSTINCT, OTSYS_TIME() + 2000); bool updateClient = false; m_creaturesNearby = 0; - uint16_t creaturesNearby = 0; - for (int offsetX = -1; offsetX <= 1; offsetX++) { - if (creaturesNearby >= 8) { - break; - } - for (int offsetY = -1; offsetY <= 1; offsetY++) { - if (creaturesNearby >= 8) { - break; - } - - const auto playerPositionOffSet = Position( - m_player.getPosition().x + offsetX, - m_player.getPosition().y + offsetY, - m_player.getPosition().z - ); - const auto &tile = g_game().map.getTile(playerPositionOffSet); - if (!tile) { - continue; - } - - const auto &creature = tile->getTopVisibleCreature(m_player.getPlayer()); - if (!creature || creature == m_player.getPlayer() || (creature->getMaster() && creature->getMaster()->getPlayer() == m_player.getPlayer())) { - continue; - } - - creaturesNearby++; - } - } - + uint16_t creaturesNearby = Spectators().find(m_player.getPosition(), false, 1, 1, 1, 1).excludePlayerMaster().size(); if (creaturesNearby >= 5) { m_creaturesNearby = creaturesNearby; creaturesNearby -= 4; @@ -2661,31 +2635,7 @@ bool PlayerWheel::checkPositionalTactics() { setOnThinkTimer(WheelOnThink_t::POSITIONAL_TACTICS, OTSYS_TIME() + 2000); m_creaturesNearby = 0; bool updateClient = false; - uint16_t creaturesNearby = 0; - for (int offsetX = -1; offsetX <= 1; offsetX++) { - if (creaturesNearby > 0) { - break; - } - for (int offsetY = -1; offsetY <= 1; offsetY++) { - const auto playerPositionOffSet = Position( - m_player.getPosition().x + offsetX, - m_player.getPosition().y + offsetY, - m_player.getPosition().z - ); - const auto &tile = g_game().map.getTile(playerPositionOffSet); - if (!tile) { - continue; - } - - const auto &creature = tile->getTopVisibleCreature(m_player.getPlayer()); - if (!creature || creature == m_player.getPlayer() || !creature->getMonster() || (creature->getMaster() && creature->getMaster()->getPlayer())) { - continue; - } - - creaturesNearby++; - break; - } - } + uint16_t creaturesNearby = Spectators().find(m_player.getPosition(), false, 1, 1, 1, 1).excludePlayerMaster().size(); constexpr uint16_t holyMagicSkill = 3; constexpr uint16_t healingMagicSkill = 3; constexpr uint16_t distanceSkill = 3; From 4ee9e55e5c1d1f4672954064c051dea8c2a12fa7 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Tue, 12 Nov 2024 19:07:16 -0300 Subject: [PATCH 13/13] fix: bad behaviour when saving the wheel without points added --- src/creatures/players/wheel/player_wheel.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index aa7989c255e..7d39720dc4d 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -1704,9 +1704,6 @@ bool PlayerWheel::saveDBPlayerSlotPointsOnLogout() const { const auto wheelSlots = getSlots(); for (uint8_t i = 1; i < wheelSlots.size(); ++i) { auto value = wheelSlots[i]; - if (value == 0) { - continue; - } stream.write(i); stream.write(value);