diff --git a/data-otservbr-global/npc/ahmet.lua b/data-otservbr-global/npc/ahmet.lua index 8a3db7e2d97..1e1795f6af9 100644 --- a/data-otservbr-global/npc/ahmet.lua +++ b/data-otservbr-global/npc/ahmet.lua @@ -30,6 +30,7 @@ npcConfig.shop = { -- Sellable items { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2881, buy = 2 }, { itemName = "deed of ownership", clientId = 7866, buy = 1000 }, { itemName = "document", clientId = 2818, buy = 12 }, diff --git a/data-otservbr-global/npc/asphota.lua b/data-otservbr-global/npc/asphota.lua index 13e9b83f6c4..c470cfc554d 100644 --- a/data-otservbr-global/npc/asphota.lua +++ b/data-otservbr-global/npc/asphota.lua @@ -60,6 +60,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, { itemName = "hand auger", clientId = 31334, buy = 25 }, { itemName = "inkwell", clientId = 3509, sell = 8 }, diff --git a/data-otservbr-global/npc/bashira.lua b/data-otservbr-global/npc/bashira.lua index 6a1f987cc2a..d818e5769bf 100644 --- a/data-otservbr-global/npc/bashira.lua +++ b/data-otservbr-global/npc/bashira.lua @@ -74,6 +74,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2881, buy = 2 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, diff --git a/data-otservbr-global/npc/beatrice.lua b/data-otservbr-global/npc/beatrice.lua index 89fe93286dc..17d07a56ce5 100644 --- a/data-otservbr-global/npc/beatrice.lua +++ b/data-otservbr-global/npc/beatrice.lua @@ -99,6 +99,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, { itemName = "hand auger", clientId = 31334, buy = 25 }, { itemName = "inkwell", clientId = 3509, sell = 8 }, diff --git a/data-otservbr-global/npc/bertha.lua b/data-otservbr-global/npc/bertha.lua index 339b91aae7e..add1d0aa3eb 100644 --- a/data-otservbr-global/npc/bertha.lua +++ b/data-otservbr-global/npc/bertha.lua @@ -103,6 +103,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2884, buy = 2 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, diff --git a/data-otservbr-global/npc/bezil.lua b/data-otservbr-global/npc/bezil.lua index 39f366ef309..61fd7854eaf 100644 --- a/data-otservbr-global/npc/bezil.lua +++ b/data-otservbr-global/npc/bezil.lua @@ -59,6 +59,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 40, sell = 40 }, { itemName = "grey backpack", clientId = 2870, buy = 10 }, diff --git a/data-otservbr-global/npc/gladys.lua b/data-otservbr-global/npc/gladys.lua index d9911e3f55b..d455de501e0 100644 --- a/data-otservbr-global/npc/gladys.lua +++ b/data-otservbr-global/npc/gladys.lua @@ -57,6 +57,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, { itemName = "fox paw", clientId = 27462, sell = 100 }, { itemName = "fur armor", clientId = 22085, sell = 5000 }, diff --git a/data-otservbr-global/npc/gorn.lua b/data-otservbr-global/npc/gorn.lua index 0d875652da9..64967e6251f 100644 --- a/data-otservbr-global/npc/gorn.lua +++ b/data-otservbr-global/npc/gorn.lua @@ -124,6 +124,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2884, buy = 2 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, diff --git a/data-otservbr-global/npc/gree_dee.lua b/data-otservbr-global/npc/gree_dee.lua index 287edb79a1b..2997ffb7f55 100644 --- a/data-otservbr-global/npc/gree_dee.lua +++ b/data-otservbr-global/npc/gree_dee.lua @@ -62,6 +62,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2881, buy = 2 }, { itemName = "deed of ownership", clientId = 7866, buy = 1000 }, { itemName = "document", clientId = 2818, buy = 12 }, diff --git a/data-otservbr-global/npc/halif.lua b/data-otservbr-global/npc/halif.lua index 27317ec6692..99947d4bb3c 100644 --- a/data-otservbr-global/npc/halif.lua +++ b/data-otservbr-global/npc/halif.lua @@ -60,6 +60,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2881, buy = 2 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 40, sell = 40 }, diff --git a/data-otservbr-global/npc/lubo.lua b/data-otservbr-global/npc/lubo.lua index 2c1d7ab661b..20d1b2eba64 100644 --- a/data-otservbr-global/npc/lubo.lua +++ b/data-otservbr-global/npc/lubo.lua @@ -169,6 +169,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, { itemName = "hand auger", clientId = 31334, buy = 25 }, { itemName = "machete", clientId = 3308, buy = 35, sell = 6 }, diff --git a/data-otservbr-global/npc/maro.lua b/data-otservbr-global/npc/maro.lua index 7ba549262f7..adb5eb417b5 100644 --- a/data-otservbr-global/npc/maro.lua +++ b/data-otservbr-global/npc/maro.lua @@ -58,6 +58,7 @@ npcConfig.shop = { { itemName = "cleaver", clientId = 3471, buy = 15 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2881, buy = 2 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, { itemName = "fork", clientId = 3467, buy = 10 }, diff --git a/data-otservbr-global/npc/maun.lua b/data-otservbr-global/npc/maun.lua index 9e57ca6b862..1bce8918562 100644 --- a/data-otservbr-global/npc/maun.lua +++ b/data-otservbr-global/npc/maun.lua @@ -66,6 +66,7 @@ npcConfig.shop = { { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crossbow", clientId = 3349, buy = 500, sell = 120 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "crystalline arrow", clientId = 15793, buy = 20 }, { itemName = "desintegrate rune", clientId = 3197, buy = 26 }, { itemName = "diamond arrow", clientId = 35901, buy = 100 }, diff --git a/data-otservbr-global/npc/nezil.lua b/data-otservbr-global/npc/nezil.lua index 260a01bce4e..d9b509045bc 100644 --- a/data-otservbr-global/npc/nezil.lua +++ b/data-otservbr-global/npc/nezil.lua @@ -59,6 +59,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 40, sell = 40 }, { itemName = "grey backpack", clientId = 2870, buy = 10 }, diff --git a/data-otservbr-global/npc/perod.lua b/data-otservbr-global/npc/perod.lua index 7d3f32d6ad3..098117839de 100644 --- a/data-otservbr-global/npc/perod.lua +++ b/data-otservbr-global/npc/perod.lua @@ -105,6 +105,7 @@ npcConfig.shop = { { itemName = "closed trap", clientId = 3481, buy = 280 }, { itemName = "crossbow", clientId = 3349, buy = 500, sell = 500 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "crystalline arrow", clientId = 15793, buy = 20 }, { itemName = "cup", clientId = 2884, buy = 2 }, { itemName = "diamond arrow", clientId = 35901, buy = 100 }, diff --git a/data-otservbr-global/npc/red_lilly.lua b/data-otservbr-global/npc/red_lilly.lua index b744fae905d..637dee9c180 100644 --- a/data-otservbr-global/npc/red_lilly.lua +++ b/data-otservbr-global/npc/red_lilly.lua @@ -68,6 +68,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2881, buy = 2 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, diff --git a/data-otservbr-global/npc/rock_in_a_hard_place.lua b/data-otservbr-global/npc/rock_in_a_hard_place.lua index 7abec0e60d1..4d4c6b1ee10 100644 --- a/data-otservbr-global/npc/rock_in_a_hard_place.lua +++ b/data-otservbr-global/npc/rock_in_a_hard_place.lua @@ -109,6 +109,7 @@ local itemsTable = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "deepling axe", clientId = 13991, sell = 40000 }, { itemName = "deepling squelcher", clientId = 14250, sell = 7000 }, { itemName = "deepling staff", clientId = 13987, sell = 4000 }, diff --git a/data-otservbr-global/npc/sarina.lua b/data-otservbr-global/npc/sarina.lua index 3429b5f6d35..bcc13ada91e 100644 --- a/data-otservbr-global/npc/sarina.lua +++ b/data-otservbr-global/npc/sarina.lua @@ -98,6 +98,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2881, buy = 3 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, diff --git a/data-otservbr-global/npc/shiantis.lua b/data-otservbr-global/npc/shiantis.lua index 08493c2cf2e..a268b8dd8e8 100644 --- a/data-otservbr-global/npc/shiantis.lua +++ b/data-otservbr-global/npc/shiantis.lua @@ -104,6 +104,7 @@ npcConfig.shop = { { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "coal basin kit", clientId = 3513, buy = 25 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cuckoo clock", clientId = 2664, buy = 40 }, { itemName = "document", clientId = 2834, buy = 12 }, { itemName = "empty goldfish bowl", clientId = 5928, buy = 50 }, diff --git a/data-otservbr-global/npc/timur.lua b/data-otservbr-global/npc/timur.lua index f2a23509601..f3788c60494 100644 --- a/data-otservbr-global/npc/timur.lua +++ b/data-otservbr-global/npc/timur.lua @@ -74,6 +74,7 @@ npcConfig.shop = { { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crossbow", clientId = 3349, sell = 160 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, { itemName = "hand auger", clientId = 31334, buy = 25 }, diff --git a/data-otservbr-global/npc/zora.lua b/data-otservbr-global/npc/zora.lua index f9b3a458d52..e6f271a2699 100644 --- a/data-otservbr-global/npc/zora.lua +++ b/data-otservbr-global/npc/zora.lua @@ -98,6 +98,7 @@ npcConfig.shop = { { itemName = "candlestick", clientId = 2917, buy = 2 }, { itemName = "closed trap", clientId = 3481, buy = 280, sell = 75 }, { itemName = "crowbar", clientId = 3304, buy = 260, sell = 50 }, + { itemName = "crusher", clientId = 46627, buy = 500 }, { itemName = "cup", clientId = 2884, buy = 2 }, { itemName = "document", clientId = 2818, buy = 12 }, { itemName = "fishing rod", clientId = 3483, buy = 150, sell = 40 }, diff --git a/data/items/items.xml b/data/items/items.xml index df8ba8c122d..79f122afb9a 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -76351,5 +76351,15 @@ Granted by TibiaGoals.com"/> + + + + + + + + + + diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index cdd8af8a40f..5a6c4cbf6cc 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -13,6 +13,7 @@ #include "creatures/monsters/monsters.hpp" #include "creatures/players/player.hpp" #include "creatures/players/wheel/player_wheel.hpp" +#include "creatures/players/wheel/wheel_gems.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" #include "creatures/players/cyclopedia/player_cyclopedia.hpp" @@ -5385,7 +5386,7 @@ uint32_t Player::getCapacity() const { } else if (hasFlag(PlayerFlags_t::HasInfiniteCapacity)) { return std::numeric_limits::max(); } - return capacity + bonusCapacity + varStats[STAT_CAPACITY] + m_wheelPlayer->getStat(WheelStat_t::CAPACITY); + return capacity + bonusCapacity + varStats[STAT_CAPACITY] + (m_wheelPlayer->getStat(WheelStat_t::CAPACITY) * 100); } int32_t Player::getMaxHealth() const { @@ -6716,11 +6717,13 @@ bool Player::isCreatureUnlockedOnTaskHunting(const std::shared_ptr void Player::triggerMomentum() { auto item = getInventoryItem(CONST_SLOT_HEAD); - if (item == nullptr) { - return; + + double_t chance = 0; + if (item) { + chance += item->getMomentumChance(); } - double_t chance = item->getMomentumChance(); + chance += m_wheelPlayer->getBonusData().momentum; double_t randomChance = uniform_random(0, 10000) / 100.; if (getZoneType() != ZONE_PROTECTION && hasCondition(CONDITION_INFIGHT) && ((OTSYS_TIME() / 1000) % 2) == 0 && chance > 0 && randomChance < chance) { bool triggered = false; diff --git a/src/creatures/players/vocations/vocation.cpp b/src/creatures/players/vocations/vocation.cpp index 5e497f18d44..0217cabe7db 100644 --- a/src/creatures/players/vocations/vocation.cpp +++ b/src/creatures/players/vocations/vocation.cpp @@ -11,6 +11,7 @@ #include "utils/pugicast.hpp" #include "utils/tools.hpp" +#include "enums/player_wheel.hpp" bool Vocations::reload() { vocationsMap.clear(); diff --git a/src/creatures/players/vocations/vocation.hpp b/src/creatures/players/vocations/vocation.hpp index f4f35082cfc..6bd8d9a2ebc 100644 --- a/src/creatures/players/vocations/vocation.hpp +++ b/src/creatures/players/vocations/vocation.hpp @@ -12,7 +12,9 @@ #include "declarations.hpp" #include "items/item.hpp" #include "lib/di/container.hpp" -#include "creatures/players/wheel/wheel_gems.hpp" + +enum class WheelGemQuality_t : uint8_t; +enum class WheelGemSupremeModifier_t : uint8_t; class Vocation { public: diff --git a/src/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 6e79ff65274..b577e998651 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -9,6 +9,7 @@ #include "creatures/players/wheel/player_wheel.hpp" +#include "enums/player_wheel.hpp" #include "config/configmanager.hpp" #include "io/io_wheel.hpp" #include "game/game.hpp" @@ -74,6 +75,175 @@ const static std::vector wheelGemBasicSlot2Allowed = { WheelGemBasicModifier_t::General_MitigationMultiplier, }; +const static std::vector modsBasicPosition = { + WheelGemBasicModifier_t::General_PhysicalResistance, + WheelGemBasicModifier_t::General_HolyResistance, + WheelGemBasicModifier_t::General_DeathResistance, + WheelGemBasicModifier_t::General_FireResistance, + WheelGemBasicModifier_t::General_EarthResistance, + WheelGemBasicModifier_t::General_IceResistance, + WheelGemBasicModifier_t::General_EnergyResistance, + + WheelGemBasicModifier_t::General_HolyResistance_DeathWeakness, + WheelGemBasicModifier_t::General_DeathResistance_HolyWeakness, + WheelGemBasicModifier_t::General_FireResistance_EarthResistance, + WheelGemBasicModifier_t::General_FireResistance_IceResistance, + WheelGemBasicModifier_t::General_FireResistance_EnergyResistance, + WheelGemBasicModifier_t::General_EarthResistance_IceResistance, + WheelGemBasicModifier_t::General_EarthResistance_EnergyResistance, + WheelGemBasicModifier_t::General_IceResistance_EnergyResistance, + + WheelGemBasicModifier_t::General_FireResistance_EarthWeakness, + WheelGemBasicModifier_t::General_FireResistance_IceWeakness, + WheelGemBasicModifier_t::General_FireResistance_EnergyWeakness, + WheelGemBasicModifier_t::General_EarthResistance_FireWeakness, + WheelGemBasicModifier_t::General_EarthResistance_IceWeakness, + WheelGemBasicModifier_t::General_EarthResistance_EnergyWeakness, + WheelGemBasicModifier_t::General_IceResistance_EarthWeakness, + WheelGemBasicModifier_t::General_IceResistance_FireWeakness, + WheelGemBasicModifier_t::General_IceResistance_EnergyWeakness, + WheelGemBasicModifier_t::General_EnergyResistance_EarthWeakness, + WheelGemBasicModifier_t::General_EnergyResistance_IceWeakness, + WheelGemBasicModifier_t::General_EnergyResistance_FireWeakness, + WheelGemBasicModifier_t::General_ManaDrainResistance, + WheelGemBasicModifier_t::General_LifeDrainResistance, + WheelGemBasicModifier_t::General_ManaDrainResistance_LifeDrainResistance, + WheelGemBasicModifier_t::General_MitigationMultiplier, + + WheelGemBasicModifier_t::Vocation_Health, + WheelGemBasicModifier_t::Vocation_Mana_FireResistance, + WheelGemBasicModifier_t::Vocation_Mana_EnergyResistance, + WheelGemBasicModifier_t::Vocation_Mana_Earth_Resistance, + WheelGemBasicModifier_t::Vocation_Mana_Ice_Resistance, + WheelGemBasicModifier_t::Vocation_Mana, + WheelGemBasicModifier_t::Vocation_Health_FireResistance, + WheelGemBasicModifier_t::Vocation_Health_EnergyResistance, + WheelGemBasicModifier_t::Vocation_Health_EarthResistance, + WheelGemBasicModifier_t::Vocation_Health_IceResistance, + + WheelGemBasicModifier_t::Vocation_Capacity_FireResistance, + WheelGemBasicModifier_t::Vocation_Capacity_EnergyResistance, + WheelGemBasicModifier_t::Vocation_Capacity_EarthResistance, + WheelGemBasicModifier_t::Vocation_Capacity_IceResistance, + WheelGemBasicModifier_t::Vocation_Capacity, +}; + +const static std::vector modsSupremeKnightPosition = { + WheelGemSupremeModifier_t::General_Dodge, + WheelGemSupremeModifier_t::General_CriticalDamage, + WheelGemSupremeModifier_t::General_LifeLeech, + WheelGemSupremeModifier_t::General_ManaLeech, + WheelGemSupremeModifier_t::General_RevelationMastery_GiftOfLife, + + WheelGemSupremeModifier_t::Knight_AvatarOfSteel_Cooldown, + WheelGemSupremeModifier_t::Knight_ExecutionersThrow_Cooldown, + WheelGemSupremeModifier_t::Knight_ExecutionersThrow_DamageIncrease, + WheelGemSupremeModifier_t::Knight_ExecutionersThrow_CriticalExtraDamage, + WheelGemSupremeModifier_t::Knight_Fierce_Berserk_DamageIncrease, + WheelGemSupremeModifier_t::Knight_Fierce_Berserk_CriticalExtraDamage, + WheelGemSupremeModifier_t::Knight_Berserk_DamageIncrease, + WheelGemSupremeModifier_t::Knight_Berserk_CriticalExtraDamage, + WheelGemSupremeModifier_t::Knight_Front_Sweep_CriticalExtraDamage, + WheelGemSupremeModifier_t::Knight_Front_Sweep_DamageIncrease, + WheelGemSupremeModifier_t::Knight_Groundshaker_DamageIncrease, + WheelGemSupremeModifier_t::Knight_Groundshaker_CriticalExtraDamage, + WheelGemSupremeModifier_t::Knight_Annihilation_CriticalExtraDamage, + WheelGemSupremeModifier_t::Knight_Annihilation_DamageIncrease, + WheelGemSupremeModifier_t::Knight_FairWoundCleansing_HealingIncrease, + WheelGemSupremeModifier_t::Knight_RevelationMastery_AvatarOfSteel, + WheelGemSupremeModifier_t::Knight_RevelationMastery_ExecutionersThrow, + WheelGemSupremeModifier_t::Knight_RevelationMastery_CombatMastery, +}; + +const static std::vector modsSupremePaladinPosition = { + WheelGemSupremeModifier_t::General_Dodge, + WheelGemSupremeModifier_t::General_CriticalDamage, + WheelGemSupremeModifier_t::General_LifeLeech, + WheelGemSupremeModifier_t::General_ManaLeech, + WheelGemSupremeModifier_t::General_RevelationMastery_GiftOfLife, + + WheelGemSupremeModifier_t::Paladin_AvatarOfLight_Cooldown, + WheelGemSupremeModifier_t::Paladin_DivineDazzle_Cooldown, + WheelGemSupremeModifier_t::Paladin_DivineGrenade_DamageIncrease, + WheelGemSupremeModifier_t::Paladin_DivineGrenade_CriticalExtraDamage, + WheelGemSupremeModifier_t::Paladin_DivineCaldera_DamageIncrease, + WheelGemSupremeModifier_t::Paladin_DivineCaldera_CriticalExtraDamage, + WheelGemSupremeModifier_t::Paladin_DivineMissile_DamageIncrease, + WheelGemSupremeModifier_t::Paladin_DivineMissile_CriticalExtraDamage, + WheelGemSupremeModifier_t::Paladin_EtherealSpear_DamageIncrease, + WheelGemSupremeModifier_t::Paladin_EtherealSpear_CriticalExtraDamage, + WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_DamageIncrease, + WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_CriticalExtraDamage, + WheelGemSupremeModifier_t::Paladin_DivineEmpowerment_Cooldown, + WheelGemSupremeModifier_t::Paladin_DivineGrenade_Cooldown, + WheelGemSupremeModifier_t::Paladin_Salvation_HealingIncrease, + WheelGemSupremeModifier_t::Paladin_RevelationMastery_AvatarOfLight, + WheelGemSupremeModifier_t::Paladin_RevelationMastery_DivineGrenade, + WheelGemSupremeModifier_t::Paladin_RevelationMastery_DivineEmpowerment, +}; + +const static std::vector modsSupremeSorcererPosition = { + WheelGemSupremeModifier_t::General_Dodge, + WheelGemSupremeModifier_t::General_CriticalDamage, + WheelGemSupremeModifier_t::General_LifeLeech, + WheelGemSupremeModifier_t::General_ManaLeech, + WheelGemSupremeModifier_t::SorcererDruid_UltimateHealing, + WheelGemSupremeModifier_t::General_RevelationMastery_GiftOfLife, + + WheelGemSupremeModifier_t::Sorcerer_AvatarOfStorm_Cooldown, + WheelGemSupremeModifier_t::Sorcerer_EnergyWave_Cooldown, + WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_DamageIncrease, + WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_CriticalExtraDamage, + WheelGemSupremeModifier_t::Sorcerer_HellsCore_DamageIncrease, + WheelGemSupremeModifier_t::Sorcerer_HellsCore_CriticalExtraDamage, + WheelGemSupremeModifier_t::Sorcerer_EnergyWave_DamageIncrease, + WheelGemSupremeModifier_t::Sorcerer_EnergyWave_CriticalExtraDamage, + WheelGemSupremeModifier_t::Sorcerer_GreatFireWave_DamageIncrease, + WheelGemSupremeModifier_t::Sorcerer_GreatFireWave_CriticalExtraDamage, + WheelGemSupremeModifier_t::Sorcerer_RageOfTheSkies_DamageIncrease, + WheelGemSupremeModifier_t::Sorcerer_RageOfTheSkies_CriticalExtraDamage, + WheelGemSupremeModifier_t::Sorcerer_GreatEnergyBeam_DamageIncrease, + WheelGemSupremeModifier_t::Sorcerer_GreatEnergyBeam_CriticalExtraDamage, + WheelGemSupremeModifier_t::Sorcerer_RevelationMastery_AvatarOfStorm, + WheelGemSupremeModifier_t::Sorcerer_RevelationMastery_BeamMastery, + WheelGemSupremeModifier_t::Sorcerer_RevelationMastery_DrainBody, +}; + +const static std::vector modsSupremeDruidPosition = { + WheelGemSupremeModifier_t::General_Dodge, + WheelGemSupremeModifier_t::General_CriticalDamage, + WheelGemSupremeModifier_t::General_LifeLeech, + WheelGemSupremeModifier_t::General_ManaLeech, + WheelGemSupremeModifier_t::SorcererDruid_UltimateHealing, + WheelGemSupremeModifier_t::General_RevelationMastery_GiftOfLife, + + WheelGemSupremeModifier_t::Druid_AvatarOfNature_Cooldown, + WheelGemSupremeModifier_t::Druid_NaturesEmbrace_Cooldown, + WheelGemSupremeModifier_t::Druid_TerraBurst_DamageIncrease, + WheelGemSupremeModifier_t::Druid_TerraBurst_CriticalExtraDamage, + WheelGemSupremeModifier_t::Druid_IceBurst_DamageIncrease, + WheelGemSupremeModifier_t::Druid_IceBurst_CriticalExtraDamage, + WheelGemSupremeModifier_t::Druid_EternalWinter_CriticalExtraDamage, + WheelGemSupremeModifier_t::Druid_EternalWinter_DamageIncrease, + WheelGemSupremeModifier_t::Druid_TerraWave_DamageIncrease, + WheelGemSupremeModifier_t::Druid_TerraWave_CriticalExtraDamage, + WheelGemSupremeModifier_t::Druid_StrongIceWave_DamageIncrease, + WheelGemSupremeModifier_t::Druid_StrongIceWave_CriticalExtraDamage, + WheelGemSupremeModifier_t::Druid_HealFriend_HealingIncrease, + WheelGemSupremeModifier_t::Druid_MassHealing_HealingIncrease, + WheelGemSupremeModifier_t::Druid_RevelationMastery_AvatarOfNature, + WheelGemSupremeModifier_t::Druid_RevelationMastery_BlessingOfTheGrove, + WheelGemSupremeModifier_t::Druid_RevelationMastery_TwinBursts, +}; + +// Using reference wrapper to avoid copying the vector to the map +const static std::unordered_map>> modsSupremePositionByVocation = { + { 1, std::cref(modsSupremeSorcererPosition) }, + { 2, std::cref(modsSupremeDruidPosition) }, + { 3, std::cref(modsSupremePaladinPosition) }, + { 4, std::cref(modsSupremeKnightPosition) } +}; + // To avoid conflict in other files that might use a function with the same name // Here are built-in helper functions namespace { @@ -669,10 +839,42 @@ bool PlayerWheel::canPlayerSelectPointOnSlot(WheelSlots_t slot, bool recursive) uint16_t PlayerWheel::getUnusedPoints() const { auto totalPoints = getWheelPoints(); + if (totalPoints == 0) { return 0; } + const auto vocationBaseId = m_player.getVocation()->getBaseId(); + const auto modsSupremeIt = modsSupremePositionByVocation.find(vocationBaseId); + + for (const auto &modPosition : modsBasicPosition) { + const auto pos = static_cast(modPosition); + uint8_t grade = 0; + auto gradeKV = gemsGradeKV(WheelFragmentType_t::Lesser, pos)->get("grade"); + + if (gradeKV.has_value()) { + grade = static_cast(gradeKV->get()); + } + + totalPoints += grade == 3 ? 1 : 0; + } + + if (modsSupremeIt != modsSupremePositionByVocation.end()) { + 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"); + + if (gradeKV.has_value()) { + grade = gradeKV->get(); + } + + totalPoints += grade == 3 ? 1 : 0; + } + } else { + g_logger().error("[{}] supreme modifications not found for vocation base id: {}", std::source_location::current().function_name(), vocationBaseId); + } + for (uint8_t i = WheelSlots_t::SLOT_FIRST; i <= WheelSlots_t::SLOT_LAST; ++i) { totalPoints -= getPointsBySlotType(static_cast(i)); } @@ -765,6 +967,20 @@ 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 { + 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"); + + if (gradeKV.has_value()) { + grade = static_cast(gradeKV->get()); + } + return grade; +} + std::vector PlayerWheel::getRevealedGems() const { std::vector unlockedGems; auto unlockedGemUUIDs = gemsKV()->scoped("revealed")->keys(); @@ -924,10 +1140,55 @@ uint16_t PlayerWheel::getGemIndex(const std::string &uuid) const { void PlayerWheel::destroyGem(uint16_t index) { auto gem = getGem(index); if (gem.locked) { - g_logger().error("[{}] Player {} trying to destroy locked gem with index {}", __FUNCTION__, m_player.getName(), index); + g_logger().error("[{}] Player {} destroyed locked gem with index {}", std::source_location::current().function_name(), m_player.getName(), index); return; } + + const auto &backpack = m_player.getInventoryItem(CONST_SLOT_BACKPACK); + const auto &mainBackpack = backpack ? backpack->getContainer() : nullptr; + + uint8_t lesserFragments = 0; + uint8_t greaterFragments = 0; + + switch (gem.quality) { + case WheelGemQuality_t::Lesser: + lesserFragments = normal_random(1, 5); + break; + case WheelGemQuality_t::Regular: + lesserFragments = normal_random(2, 10); + break; + case WheelGemQuality_t::Greater: + greaterFragments = normal_random(1, 5); + break; + } + + if (lesserFragments > 0) { + const auto &fragmentsItem = Item::CreateItem(ITEM_LESSER_FRAGMENT, lesserFragments); + auto returnValue = g_game().internalPlayerAddItem(m_player.getPlayer(), fragmentsItem, false, CONST_SLOT_WHEREEVER); + if (returnValue != RETURNVALUE_NOERROR) { + g_logger().error("Failed to add {} lesser fragments to player with name {}", lesserFragments, m_player.getName()); + m_player.sendCancelMessage(getReturnMessage(RETURNVALUE_CONTACTADMINISTRATOR)); + return; + } + g_logger().debug("[{}] Player {} destroyed a gem and received {} lesser fragments", std::source_location::current().function_name(), m_player.getName(), lesserFragments); + } + + 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); + 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)); + return; + } + g_logger().debug("[{}] Player {} destroyed a gem and received {} greater fragments", std::source_location::current().function_name(), m_player.getName(), greaterFragments); + } + 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)); + sendOpenWheelWindow(m_player.getID()); } @@ -1002,24 +1263,132 @@ void PlayerWheel::addGems(NetworkMessage &msg) const { msg.addByte(static_cast(gem.supremeModifier)); } } +} + +void PlayerWheel::addGradeModifiers(NetworkMessage &msg) const { + msg.addByte(0x2E); // Modifiers for all Vocations + for (const auto &modPosition : modsBasicPosition) { + const auto pos = static_cast(modPosition); + msg.addByte(pos); + uint8_t grade = 0; + auto gradeKV = gemsGradeKV(WheelFragmentType_t::Lesser, pos)->get("grade"); + + if (gradeKV.has_value()) { + grade = static_cast(gradeKV->get()); + } + msg.addByte(grade); + } + + msg.addByte(0x17); // Modifiers for specific per Vocations + + const auto vocationBaseId = m_player.getVocation()->getBaseId(); + const auto modsSupremeIt = modsSupremePositionByVocation.find(vocationBaseId); + + if (modsSupremeIt != modsSupremePositionByVocation.end()) { + for (const auto &modPosition : modsSupremeIt->second.get()) { + const auto pos = static_cast(modPosition); + msg.addByte(pos); + uint8_t grade = 0; + auto gradeKV = gemsGradeKV(WheelFragmentType_t::Greater, pos)->get("grade"); + + if (gradeKV.has_value()) { + grade = gradeKV->get(); + } + msg.addByte(grade); + } + } else { + g_logger().error("[{}] vocation base id: {}", std::source_location::current().function_name(), m_player.getVocation()->getBaseId()); + } +} + +void PlayerWheel::improveGemGrade(WheelFragmentType_t fragmentType, uint8_t pos) { + uint16_t fragmentId = 0; + uint32_t value = 0; + uint8_t quantity = 0; + uint8_t grade = 0; + + auto gradeKV = gemsGradeKV(fragmentType, pos)->get("grade"); + if (gradeKV.has_value()) { + grade = gradeKV->get(); + } + + ++grade; + + switch (fragmentType) { + case WheelFragmentType_t::Lesser: + fragmentId = ITEM_LESSER_FRAGMENT; + std::tie(value, quantity) = getLesserGradeCost(grade); + break; + case WheelFragmentType_t::Greater: + fragmentId = ITEM_GREATER_FRAGMENT; + std::tie(value, quantity) = getGreaterGradeCost(grade); + break; + default: + g_logger().error("[{}] Invalid Fragment Type: {}", std::source_location::current().function_name(), static_cast(fragmentType)); + return; + } - msg.addByte(0); // Lesser gems - msg.addByte(0); // Greater gems + if (!m_player.hasItemCountById(fragmentId, quantity, false)) { + g_logger().error("[{}] Player {} does not have the required {} fragments with id {}", __FUNCTION__, m_player.getName(), quantity, fragmentId); + return; + } + + if (!g_game().removeMoney(m_player.getPlayer(), value, 0, true)) { + g_logger().error("[{}] Failed to remove {} gold from player {}", std::source_location::current().function_name(), value, m_player.getName()); + return; + } + + if (!m_player.removeItemCountById(fragmentId, quantity, false)) { + g_logger().error("[{}] Failed to remove {} fragments with id {} from player {}", std::source_location::current().function_name(), quantity, fragmentId, m_player.getName()); + return; + } + + gemsGradeKV(fragmentType, pos)->set("grade", grade); + loadPlayerBonusData(); + sendOpenWheelWindow(m_player.getID()); } -void PlayerWheel::sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId) const { +std::tuple PlayerWheel::getLesserGradeCost(uint8_t grade) const { + switch (grade) { + case 1: + return std::make_tuple(2000000, 5); + case 2: + return std::make_tuple(5000000, 15); + case 3: + return std::make_tuple(30000000, 30); + default: + throw std::invalid_argument("Invalid level for Lesser Fragment."); + } +} + +std::tuple PlayerWheel::getGreaterGradeCost(uint8_t grade) const { + switch (grade) { + case 1: + return std::make_tuple(5000000, 5); + case 2: + return std::make_tuple(12000000, 15); + case 3: + return std::make_tuple(75000000, 30); + default: + throw std::invalid_argument("Invalid level for Greater Fragment."); + } +} + +void PlayerWheel::sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId) { if (m_player.client && m_player.client->oldProtocol) { return; } msg.addByte(0x5F); bool canUse = canOpenWheel(); + msg.add(ownerId); // Player ID msg.addByte(canUse ? 1 : 0); // Can Use if (!canUse) { return; } + addInitialGems(); msg.addByte(getOptions(ownerId)); // Options msg.addByte(m_player.getPlayerVocationEnum()); // Vocation id @@ -1030,6 +1399,7 @@ void PlayerWheel::sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId) con } addPromotionScrolls(msg); addGems(msg); + addGradeModifiers(msg); // TODO: read items from inventory auto voc = m_player.getVocation(); m_player.client->sendResourceBalance(RESOURCE_BANK, m_player.getBankBalance()); @@ -1037,6 +1407,8 @@ void PlayerWheel::sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId) con 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)); } void PlayerWheel::sendGiftOfLifeCooldown() const { @@ -1268,6 +1640,35 @@ uint16_t PlayerWheel::getWheelPoints(bool includeExtraPoints /* = true*/) const return totalPoints; } +void PlayerWheel::addInitialGems() { + auto initialsGems = gemsKV()->get("initialGems"); + + if (!initialsGems.has_value()) { + for (auto gemAffinity : magic_enum::enum_values()) { + for (auto gemQuality : magic_enum::enum_values()) { + if (gemQuality == WheelGemQuality_t::Greater) { + continue; + } + + PlayerWheelGem gem; + gem.uuid = KV::generateUUID(); + gem.locked = false; + gem.affinity = gemAffinity; + gem.quality = gemQuality; + + gem.basicModifier1 = wheelGemBasicSlot1Allowed[uniform_random(0, wheelGemBasicSlot1Allowed.size() - 1)]; + gem.basicModifier2 = {}; + gem.supremeModifier = {}; + if (gemQuality >= WheelGemQuality_t::Regular) { + gem.basicModifier2 = selectBasicModifier2(gem.basicModifier1); + } + gem.save(gemsKV()); + } + } + gemsKV()->set("initialGems", true); + } +} + bool PlayerWheel::canOpenWheel() const { // Vocation check if (m_player.getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) { @@ -1735,6 +2136,10 @@ void PlayerWheel::printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonus g_logger().debug(" storm: {}", bonusData.avatar.storm); } + if (bonusData.momentum > 0) { + g_logger().debug("bonus: {}", bonusData.momentum); + } + if (bonusData.mitigation > 0) { g_logger().debug("mitigation: {}", bonusData.mitigation); } @@ -1803,19 +2208,22 @@ void PlayerWheel::processActiveGems() { auto count = m_playerBonusData.unlockedVesselResonances[static_cast(affinity)]; if (count >= 1) { + uint8_t grade = getGemGrade(WheelFragmentType_t::Lesser, static_cast(basicModifier1)); std::string modifierName(magic_enum::enum_name(basicModifier1)); g_logger().debug("[{}] Adding basic modifier 1 {} to player {} from {} gem affinity {}", __FUNCTION__, modifierName, playerName, magic_enum::enum_name(quality), magic_enum::enum_name(affinity)); - m_modifierContext->addStrategies(basicModifier1); + m_modifierContext->addStrategies(basicModifier1, grade); } if (count >= 2 && quality >= WheelGemQuality_t::Regular) { + uint8_t grade = getGemGrade(WheelFragmentType_t::Lesser, static_cast(basicModifier2)); std::string modifierName(magic_enum::enum_name(basicModifier2)); g_logger().debug("[{}] Adding basic modifier 2 {} to player {} from {} gem affinity {}", __FUNCTION__, modifierName, playerName, magic_enum::enum_name(quality), magic_enum::enum_name(affinity)); - m_modifierContext->addStrategies(basicModifier2); + m_modifierContext->addStrategies(basicModifier2, grade); } 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)); - m_modifierContext->addStrategies(supremeModifier); + m_modifierContext->addStrategies(supremeModifier, grade); } } @@ -1994,6 +2402,25 @@ WheelStageEnum_t PlayerWheel::getPlayerSliceStage(const std::string &color) cons } } + const auto vocationBaseId = m_player.getVocation()->getBaseId(); + const auto modsSupremeIt = modsSupremePositionByVocation.find(vocationBaseId); + + if (modsSupremeIt != modsSupremePositionByVocation.end()) { + for (auto modPosition : modsSupremeIt->second.get()) { + const auto pos = static_cast(modPosition); + uint8_t grade = 0; + auto gradeKV = gemsGradeKV(WheelFragmentType_t::Greater, pos)->get("grade"); + + if (gradeKV.has_value()) { + grade = gradeKV->get(); + } + + totalPoints += grade == 3 ? 1 : 0; + } + } else { + g_logger().error("[{}] supreme modifications not found for vocation base id: {}", std::source_location::current().function_name(), vocationBaseId); + } + if (totalPoints >= static_cast(WheelStagePointsEnum_t::THREE)) { return WheelStageEnum_t::THREE; } else if (totalPoints >= static_cast(WheelStagePointsEnum_t::TWO)) { @@ -2609,8 +3036,10 @@ std::shared_ptr PlayerWheel::getCombatDataSpell(CombatDamage &damage) { spell = g_spells().getRuneSpellByName(damage.runeSpellName); } if (spell) { + const auto &spellName = spell->getName(); + damage.damageMultiplier += checkFocusMasteryDamage(); - if (getHealingLinkUpgrade(spell->getName())) { + if (getHealingLinkUpgrade(spellName)) { damage.healingLink += 10; } if (spell->getSecondaryGroup() == SPELLGROUP_FOCUS && getInstant("Focus Mastery")) { @@ -2618,15 +3047,27 @@ std::shared_ptr PlayerWheel::getCombatDataSpell(CombatDamage &damage) { } if (spell->getWheelOfDestinyUpgraded()) { - damage.criticalDamage += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::CRITICAL_DAMAGE, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::CRITICAL_DAMAGE); - damage.criticalChance += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::CRITICAL_CHANCE, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::CRITICAL_CHANCE); - damage.damageMultiplier += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::DAMAGE, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::DAMAGE); - damage.damageReductionMultiplier += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::DAMAGE_REDUCTION, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::DAMAGE_REDUCTION); - damage.healingMultiplier += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::HEAL, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::HEAL); - damage.manaLeech += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::MANA_LEECH, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::MANA_LEECH); - damage.manaLeechChance += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::LIFE_LEECH_CHANCE, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::LIFE_LEECH_CHANCE); - damage.lifeLeech += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::LIFE_LEECH, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::LIFE_LEECH); - damage.lifeLeechChance += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::LIFE_LEECH_CHANCE, spellGrade) + getSpellBonus(spell->getName(), WheelSpellBoost_t::LIFE_LEECH_CHANCE); + damage.criticalDamage += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::CRITICAL_DAMAGE, spellGrade) * 100; + damage.criticalChance += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::CRITICAL_CHANCE, spellGrade); + damage.damageMultiplier += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::DAMAGE, spellGrade); + damage.damageReductionMultiplier += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::DAMAGE_REDUCTION, spellGrade); + damage.healingMultiplier += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::HEAL, spellGrade); + damage.manaLeech += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::MANA_LEECH, spellGrade); + damage.manaLeechChance += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::MANA_LEECH_CHANCE, spellGrade); + damage.lifeLeech += spell->getWheelOfDestinyBoost(WheelSpellBoost_t::LIFE_LEECH, spellGrade); + 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); } } @@ -3180,6 +3621,10 @@ WheelGemBasicModifier_t PlayerWheel::selectBasicModifier2(WheelGemBasicModifier_ return modifier; } +std::string PlayerWheelGem::toString() const { + return fmt::format("[PlayerWheelGem] uuid: {}, locked: {}, affinity: {}, quality: {}, basicModifier1: {}, basicModifier2: {}, supremeModifier: {}", uuid, locked, static_cast(affinity), static_cast(quality), static_cast(basicModifier1), static_cast(basicModifier2), static_cast(supremeModifier)); +} + void PlayerWheelGem::save(const std::shared_ptr &kv) const { kv->scoped("revealed")->set(uuid, serialize()); } diff --git a/src/creatures/players/wheel/player_wheel.hpp b/src/creatures/players/wheel/player_wheel.hpp index 46968c2d7f7..a99b3dac49a 100644 --- a/src/creatures/players/wheel/player_wheel.hpp +++ b/src/creatures/players/wheel/player_wheel.hpp @@ -9,17 +9,22 @@ #pragma once -#include "utils/utils_definitions.hpp" -#include "enums/player_wheel.hpp" #include "creatures/players/wheel/wheel_definitions.hpp" -#include "kv/kv_definitions.hpp" -class Spell; -class Player; class Creature; -class NetworkMessage; +class IOWheel; class KV; +class NetworkMessage; +class Player; +class Spell; class WheelModifierContext; +class ValueWrapper; + +enum class WheelFragmentType_t : uint8_t; +enum class WheelGemAffinity_t : uint8_t; +enum class WheelGemBasicModifier_t : uint8_t; +enum class WheelGemQuality_t : uint8_t; +enum class WheelGemSupremeModifier_t : uint8_t; struct PlayerWheelGem { std::string uuid; @@ -30,9 +35,7 @@ struct PlayerWheelGem { WheelGemBasicModifier_t basicModifier2; WheelGemSupremeModifier_t supremeModifier; - std::string toString() const { - return fmt::format("[PlayerWheelGem] uuid: {}, locked: {}, affinity: {}, quality: {}, basicModifier1: {}, basicModifier2: {}, supremeModifier: {}", uuid, locked, static_cast(affinity), static_cast(quality), static_cast(basicModifier1), static_cast(basicModifier2), static_cast(supremeModifier)); - } + std::string toString() const; void save(const std::shared_ptr &kv) const; @@ -81,7 +84,9 @@ class PlayerWheel { void saveSlotPointsOnPressSaveButton(NetworkMessage &msg); void addPromotionScrolls(NetworkMessage &msg) const; void addGems(NetworkMessage &msg) const; - void sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId) const; + void addGradeModifiers(NetworkMessage &msg) const; + void improveGemGrade(WheelFragmentType_t fragmentType, uint8_t pos); + void sendOpenWheelWindow(NetworkMessage &msg, uint32_t ownerId); void sendGiftOfLifeCooldown() const; /* @@ -141,9 +146,13 @@ class PlayerWheel { WheelStageEnum_t getPlayerSliceStage(const std::string &color) const; + std::tuple getLesserGradeCost(uint8_t grade) const; + std::tuple getGreaterGradeCost(uint8_t grade) const; + void printPlayerWheelMethodsBonusData(const PlayerWheelMethodsBonusData &bonusData) const; private: + void addInitialGems(); /* * Open wheel functions helpers */ @@ -172,6 +181,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; + uint8_t getGemGrade(WheelFragmentType_t quality, uint8_t pos) const; std::vector getRevealedGems() const; std::vector getActiveGems() const; diff --git a/src/creatures/players/wheel/wheel_definitions.hpp b/src/creatures/players/wheel/wheel_definitions.hpp index c23d2adf53f..8fc3783b4cb 100644 --- a/src/creatures/players/wheel/wheel_definitions.hpp +++ b/src/creatures/players/wheel/wheel_definitions.hpp @@ -253,6 +253,7 @@ struct PlayerWheelMethodsBonusData { Stages stages; Avatar avatar; + float momentum = 0; float mitigation = 0; std::vector spells; }; diff --git a/src/creatures/players/wheel/wheel_gems.cpp b/src/creatures/players/wheel/wheel_gems.cpp index 186a6939186..fb77643913a 100644 --- a/src/creatures/players/wheel/wheel_gems.cpp +++ b/src/creatures/players/wheel/wheel_gems.cpp @@ -28,184 +28,193 @@ void GemModifierSpellBonusStrategy::execute() { m_wheel.addSpellBonus(m_spellName, m_bonus); } -void WheelModifierContext::addStrategies(WheelGemBasicModifier_t modifier) { +void WheelModifierContext::addStrategies(WheelGemBasicModifier_t modifier, uint8_t grade) { + float gradeMultiplier = 1.0; + if (grade == 1) { + gradeMultiplier = 1.1; + } else if (grade == 2) { + gradeMultiplier = 1.2; + } else if (grade == 3) { + gradeMultiplier = 1.5; + } + switch (modifier) { case WheelGemBasicModifier_t::General_PhysicalResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_PHYSICALDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_PHYSICALDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_HolyResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_HOLYDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_HOLYDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_DeathResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_DEATHDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_DEATHDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_FireResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 200)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 200 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_EarthResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 200)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 200 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_IceResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 200)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 200 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_EnergyResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 200)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 200 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_HolyResistance_DeathWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_HOLYDAMAGE, 150)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_HOLYDAMAGE, 150 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_DEATHDAMAGE, -100)); break; case WheelGemBasicModifier_t::General_DeathResistance_HolyWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_DEATHDAMAGE, 150)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_DEATHDAMAGE, 150 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_HOLYDAMAGE, -100)); break; case WheelGemBasicModifier_t::General_FireResistance_EarthResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100)); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100 * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_FireResistance_IceResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100)); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100 * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_FireResistance_EnergyResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100)); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100 * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_EarthResistance_IceResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100)); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100 * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_EarthResistance_EnergyResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100)); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100 * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_IceResistance_EnergyResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100)); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100 * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_FireResistance_EarthWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_FireResistance_IceWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_FireResistance_EnergyWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_EarthResistance_FireWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_EarthResistance_IceWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_EarthResistance_EnergyWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_IceResistance_EarthWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_IceResistance_FireWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_IceResistance_EnergyWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_EnergyResistance_EarthWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_EnergyResistance_IceWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_EnergyResistance_FireWeakness: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 300 * gradeMultiplier)); m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, -200)); break; case WheelGemBasicModifier_t::General_ManaDrainResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_MANADRAIN, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_MANADRAIN, 300 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_LifeDrainResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_LIFEDRAIN, 300)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_LIFEDRAIN, 300 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_ManaDrainResistance_LifeDrainResistance: - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_MANADRAIN, 150)); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_LIFEDRAIN, 150)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_MANADRAIN, 150 * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_LIFEDRAIN, 150 * gradeMultiplier)); break; case WheelGemBasicModifier_t::General_MitigationMultiplier: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MITIGATION, 500)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MITIGATION, 500 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Health: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, getHealthValue(m_vocation, modifier))); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, WheelGemUtils::getHealthValue(m_vocation, modifier) * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Mana_FireResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, getManaValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, WheelGemUtils::getManaValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Mana_EnergyResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, getManaValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, WheelGemUtils::getManaValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Mana_Earth_Resistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, getManaValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, WheelGemUtils::getManaValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Mana_Ice_Resistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, getManaValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, WheelGemUtils::getManaValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Mana: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, getManaValue(m_vocation, modifier))); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, WheelGemUtils::getManaValue(m_vocation, modifier) * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Health_FireResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, getHealthValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, WheelGemUtils::getHealthValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Health_EnergyResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, getHealthValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, WheelGemUtils::getHealthValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Health_EarthResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, getHealthValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, WheelGemUtils::getHealthValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Health_IceResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, getHealthValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, WheelGemUtils::getHealthValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Mixed: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, getHealthValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, getManaValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, getCapacityValue(m_vocation, modifier))); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::HEALTH, WheelGemUtils::getHealthValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA, WheelGemUtils::getManaValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, WheelGemUtils::getCapacityValue(m_vocation, modifier) * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Capacity_FireResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, getCapacityValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, WheelGemUtils::getCapacityValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_FIREDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Capacity_EnergyResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, getCapacityValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, WheelGemUtils::getCapacityValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ENERGYDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Capacity_EarthResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, getCapacityValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, WheelGemUtils::getCapacityValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_EARTHDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Capacity_IceResistance: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, getCapacityValue(m_vocation, modifier))); - m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, WheelGemUtils::getCapacityValue(m_vocation, modifier) * gradeMultiplier)); + m_strategies.push_back(std::make_unique(m_wheel, CombatType_t::COMBAT_ICEDAMAGE, 100 * gradeMultiplier)); break; case WheelGemBasicModifier_t::Vocation_Capacity: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, getCapacityValue(m_vocation, modifier))); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CAPACITY, WheelGemUtils::getCapacityValue(m_vocation, modifier) * gradeMultiplier)); break; default: @@ -213,304 +222,337 @@ void WheelModifierContext::addStrategies(WheelGemBasicModifier_t modifier) { } } -void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier) { +void WheelModifierContext::addStrategies(WheelGemSupremeModifier_t modifier, uint8_t grade) { WheelSpells::Bonus bonus; + auto &wheelBonus = m_wheel.getBonusData(); + + float gradeMultiplier = 1.0; + if (grade == 1) { + gradeMultiplier = 1.1; + } else if (grade == 2) { + gradeMultiplier = 1.2; + } else if (grade == 3) { + gradeMultiplier = 1.5; + } switch (modifier) { case WheelGemSupremeModifier_t::General_Dodge: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::DODGE, 25)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::DODGE, 25 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_LifeLeech: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::LIFE_LEECH, 120)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::LIFE_LEECH, 120 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_ManaLeech: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA_LEECH, 40)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::MANA_LEECH, 40 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_CriticalDamage: - m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CRITICAL_DAMAGE, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelStat_t::CRITICAL_DAMAGE, 150 * gradeMultiplier)); break; case WheelGemSupremeModifier_t::General_RevelationMastery_GiftOfLife: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Green, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Green, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Green, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::SorcererDruid_UltimateHealing: - bonus.increase.heal = 10; + bonus.increase.heal = 10 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Ultimate Healing", bonus)); break; case WheelGemSupremeModifier_t::Knight_RevelationMastery_ExecutionersThrow: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Red, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Knight_RevelationMastery_AvatarOfSteel: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Purple, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Knight_RevelationMastery_CombatMastery: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Blue, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Paladin_RevelationMastery_DivineGrenade: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Red, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Paladin_RevelationMastery_AvatarOfLight: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Purple, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Paladin_RevelationMastery_DivineEmpowerment: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Blue, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Druid_RevelationMastery_BlessingOfTheGrove: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Red, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Druid_RevelationMastery_AvatarOfNature: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Purple, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Druid_RevelationMastery_TwinBursts: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Blue, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Sorcerer_RevelationMastery_BeamMastery: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Red, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Red, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Sorcerer_RevelationMastery_AvatarOfStorm: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Purple, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Purple, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Sorcerer_RevelationMastery_DrainBody: - m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150)); + m_strategies.push_back(std::make_unique(m_wheel, WheelGemAffinity_t::Blue, 150 * gradeMultiplier)); + m_wheel.addRevelationBonus(WheelGemAffinity_t::Blue, 150 * gradeMultiplier); break; case WheelGemSupremeModifier_t::Knight_AvatarOfSteel_Cooldown: bonus.decrease.cooldown = 300 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Avatar of Steel", bonus)); break; case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_Cooldown: bonus.decrease.cooldown = 1 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Executioner's Throw", bonus)); break; case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Executioner's Throw", bonus)); break; case WheelGemSupremeModifier_t::Knight_ExecutionersThrow_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Executioner's Throw", bonus)); break; case WheelGemSupremeModifier_t::Knight_Fierce_Berserk_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Fierce Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Fierce_Berserk_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Fierce Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Berserk_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Berserk_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Berserk", bonus)); break; case WheelGemSupremeModifier_t::Knight_Front_Sweep_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Front Sweep", bonus)); break; case WheelGemSupremeModifier_t::Knight_Front_Sweep_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Front Sweep", bonus)); break; case WheelGemSupremeModifier_t::Knight_Groundshaker_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Groundshaker", bonus)); break; case WheelGemSupremeModifier_t::Knight_Groundshaker_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Groundshaker", bonus)); break; case WheelGemSupremeModifier_t::Knight_Annihilation_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Annihilation", bonus)); break; case WheelGemSupremeModifier_t::Knight_Annihilation_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Annihilation", bonus)); break; case WheelGemSupremeModifier_t::Knight_FairWoundCleansing_HealingIncrease: - bonus.increase.heal = 10; + bonus.increase.heal = 10 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Fair Wound Cleansing", bonus)); break; case WheelGemSupremeModifier_t::Paladin_AvatarOfLight_Cooldown: bonus.decrease.cooldown = 300 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Avatar of Light", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineDazzle_Cooldown: bonus.decrease.cooldown = 2 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Divine Dazzle", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineGrenade_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Divine Grenade", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineGrenade_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Divine Grenade", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineCaldera_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Divine Caldera", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineCaldera_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Divine Caldera", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineMissile_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Divine Missile", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineMissile_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Divine Missile", bonus)); break; case WheelGemSupremeModifier_t::Paladin_EtherealSpear_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_EtherealSpear_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Strong Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_StrongEtherealSpear_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Strong Ethereal Spear", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineEmpowerment_Cooldown: bonus.decrease.cooldown = 3 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Divine Empowerment", bonus)); break; case WheelGemSupremeModifier_t::Paladin_DivineGrenade_Cooldown: bonus.decrease.cooldown = 1 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Divine Grenade", bonus)); break; case WheelGemSupremeModifier_t::Paladin_Salvation_HealingIncrease: - bonus.increase.heal = 10; + bonus.increase.heal = 10 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Salvation", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_AvatarOfStorm_Cooldown: bonus.decrease.cooldown = 300 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Avatar of Storm", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_EnergyWave_Cooldown: bonus.decrease.cooldown = 1 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Energy Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Great Death Beam", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatDeathBeam_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Great Death Beam", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_HellsCore_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Hell's Core", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_HellsCore_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Hell's Core", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_EnergyWave_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Energy Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_EnergyWave_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Energy Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatFireWave_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Great Fire Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatFireWave_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Great Fire Wave", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_RageOfTheSkies_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Rage of the Skies", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_RageOfTheSkies_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Rage of the Skies", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatEnergyBeam_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Great Energy Beam", bonus)); break; case WheelGemSupremeModifier_t::Sorcerer_GreatEnergyBeam_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Great Energy Beam", bonus)); break; case WheelGemSupremeModifier_t::Druid_AvatarOfNature_Cooldown: bonus.decrease.cooldown = 300 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Avatar of Nature", bonus)); break; case WheelGemSupremeModifier_t::Druid_NaturesEmbrace_Cooldown: bonus.decrease.cooldown = 5 * 1000; + wheelBonus.momentum += grade < 3 ? 0.33 * grade : 1; m_strategies.push_back(std::make_unique(m_wheel, "Nature's Embrace", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraBurst_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Terra Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraBurst_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Terra Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_IceBurst_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Ice Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_IceBurst_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Ice Burst", bonus)); break; case WheelGemSupremeModifier_t::Druid_EternalWinter_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Eternal Winter", bonus)); break; case WheelGemSupremeModifier_t::Druid_EternalWinter_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Eternal Winter", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraWave_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Terra Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_TerraWave_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Terra Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_StrongIceWave_DamageIncrease: - bonus.increase.damage = 25; + bonus.increase.damage = 25 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Strong Ice Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_StrongIceWave_CriticalExtraDamage: - bonus.increase.criticalDamage = 8; + bonus.increase.criticalDamage = 8 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Strong Ice Wave", bonus)); break; case WheelGemSupremeModifier_t::Druid_HealFriend_HealingIncrease: - bonus.increase.heal = 10; + bonus.increase.heal = 10 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Heal Friend", bonus)); break; case WheelGemSupremeModifier_t::Druid_MassHealing_HealingIncrease: - bonus.increase.heal = 10; + bonus.increase.heal = 10 * gradeMultiplier; m_strategies.push_back(std::make_unique(m_wheel, "Mass Healing", bonus)); break; default: @@ -523,3 +565,230 @@ void WheelModifierContext::executeStrategies() { strategy->execute(); } } + +int32_t WheelGemUtils::getHealthValue(Vocation_t vocation, WheelGemBasicModifier_t modifier) { + static const std::unordered_map> stats = { + { + WheelGemBasicModifier_t::Vocation_Health, + { + { Vocation_t::VOCATION_KNIGHT, 300 }, + { Vocation_t::VOCATION_PALADIN, 200 }, + { Vocation_t::VOCATION_SORCERER, 100 }, + { Vocation_t::VOCATION_DRUID, 100 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Health_FireResistance, + { + { Vocation_t::VOCATION_KNIGHT, 150 }, + { Vocation_t::VOCATION_PALADIN, 100 }, + { Vocation_t::VOCATION_SORCERER, 50 }, + { Vocation_t::VOCATION_DRUID, 50 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Health_EnergyResistance, + { + { Vocation_t::VOCATION_KNIGHT, 150 }, + { Vocation_t::VOCATION_PALADIN, 100 }, + { Vocation_t::VOCATION_SORCERER, 50 }, + { Vocation_t::VOCATION_DRUID, 50 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Health_EarthResistance, + { + { Vocation_t::VOCATION_KNIGHT, 150 }, + { Vocation_t::VOCATION_PALADIN, 100 }, + { Vocation_t::VOCATION_SORCERER, 50 }, + { Vocation_t::VOCATION_DRUID, 50 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Health_IceResistance, + { + { Vocation_t::VOCATION_KNIGHT, 150 }, + { Vocation_t::VOCATION_PALADIN, 100 }, + { Vocation_t::VOCATION_SORCERER, 50 }, + { Vocation_t::VOCATION_DRUID, 50 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mixed, + { + { Vocation_t::VOCATION_KNIGHT, 150 }, + { Vocation_t::VOCATION_PALADIN, 100 }, + { Vocation_t::VOCATION_SORCERER, 50 }, + { Vocation_t::VOCATION_DRUID, 50 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mixed2, + { + { Vocation_t::VOCATION_KNIGHT, 150 }, + { Vocation_t::VOCATION_PALADIN, 100 }, + { Vocation_t::VOCATION_SORCERER, 50 }, + { Vocation_t::VOCATION_DRUID, 50 }, + }, + }, + }; + + auto modifierIt = stats.find(modifier); + if (modifierIt != stats.end()) { + auto vocationIt = modifierIt->second.find(vocation); + if (vocationIt != modifierIt->second.end()) { + return vocationIt->second; + } + } + return 0; +} + +int32_t WheelGemUtils::getManaValue(Vocation_t vocation, WheelGemBasicModifier_t modifier) { + static const std::unordered_map> stats = { + { + WheelGemBasicModifier_t::Vocation_Mana_FireResistance, + { + { Vocation_t::VOCATION_KNIGHT, 50 }, + { Vocation_t::VOCATION_PALADIN, 150 }, + { Vocation_t::VOCATION_SORCERER, 300 }, + { Vocation_t::VOCATION_DRUID, 300 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mana_EnergyResistance, + { + { Vocation_t::VOCATION_KNIGHT, 50 }, + { Vocation_t::VOCATION_PALADIN, 150 }, + { Vocation_t::VOCATION_SORCERER, 300 }, + { Vocation_t::VOCATION_DRUID, 300 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mana_Earth_Resistance, + { + { Vocation_t::VOCATION_KNIGHT, 50 }, + { Vocation_t::VOCATION_PALADIN, 150 }, + { Vocation_t::VOCATION_SORCERER, 300 }, + { Vocation_t::VOCATION_DRUID, 300 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mana_Ice_Resistance, + { + { Vocation_t::VOCATION_KNIGHT, 50 }, + { Vocation_t::VOCATION_PALADIN, 150 }, + { Vocation_t::VOCATION_SORCERER, 300 }, + { Vocation_t::VOCATION_DRUID, 300 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mana, + { + { Vocation_t::VOCATION_KNIGHT, 100 }, + { Vocation_t::VOCATION_PALADIN, 300 }, + { Vocation_t::VOCATION_SORCERER, 600 }, + { Vocation_t::VOCATION_DRUID, 600 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mixed, + { + { Vocation_t::VOCATION_PALADIN, 100 }, + { Vocation_t::VOCATION_SORCERER, 150 }, + { Vocation_t::VOCATION_DRUID, 150 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Capacity, + { + { Vocation_t::VOCATION_KNIGHT, 50 }, + { Vocation_t::VOCATION_PALADIN, 150 }, + { Vocation_t::VOCATION_SORCERER, 300 }, + { Vocation_t::VOCATION_DRUID, 300 }, + }, + } + }; + + auto modifierIt = stats.find(modifier); + if (modifierIt != stats.end()) { + auto vocationIt = modifierIt->second.find(vocation); + if (vocationIt != modifierIt->second.end()) { + return vocationIt->second; + } + } + return 0; +} + +int32_t WheelGemUtils::getCapacityValue(Vocation_t vocation, WheelGemBasicModifier_t modifier) { + static const std::unordered_map> stats = { + { + WheelGemBasicModifier_t::Vocation_Capacity_FireResistance, + { + { Vocation_t::VOCATION_KNIGHT, 250 }, + { Vocation_t::VOCATION_PALADIN, 200 }, + { Vocation_t::VOCATION_SORCERER, 100 }, + { Vocation_t::VOCATION_DRUID, 100 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Capacity_EnergyResistance, + { + { Vocation_t::VOCATION_KNIGHT, 250 }, + { Vocation_t::VOCATION_PALADIN, 200 }, + { Vocation_t::VOCATION_SORCERER, 100 }, + { Vocation_t::VOCATION_DRUID, 100 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Capacity_EarthResistance, + { + { Vocation_t::VOCATION_KNIGHT, 250 }, + { Vocation_t::VOCATION_PALADIN, 200 }, + { Vocation_t::VOCATION_SORCERER, 100 }, + { Vocation_t::VOCATION_DRUID, 100 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Capacity_IceResistance, + { + { Vocation_t::VOCATION_KNIGHT, 250 }, + { Vocation_t::VOCATION_PALADIN, 200 }, + { Vocation_t::VOCATION_SORCERER, 100 }, + { Vocation_t::VOCATION_DRUID, 100 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Capacity, + { + { Vocation_t::VOCATION_KNIGHT, 500 }, + { Vocation_t::VOCATION_PALADIN, 400 }, + { Vocation_t::VOCATION_SORCERER, 200 }, + { Vocation_t::VOCATION_DRUID, 200 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mixed, + { + { Vocation_t::VOCATION_KNIGHT, 125 }, + }, + }, + { + WheelGemBasicModifier_t::Vocation_Mixed2, + { + { Vocation_t::VOCATION_KNIGHT, 250 }, + { Vocation_t::VOCATION_PALADIN, 200 }, + { Vocation_t::VOCATION_SORCERER, 100 }, + { Vocation_t::VOCATION_DRUID, 100 }, + }, + } + }; + + auto modifierIt = stats.find(modifier); + if (modifierIt != stats.end()) { + auto vocationIt = modifierIt->second.find(vocation); + if (vocationIt != modifierIt->second.end()) { + return vocationIt->second; + } + } + return 0; +} diff --git a/src/creatures/players/wheel/wheel_gems.hpp b/src/creatures/players/wheel/wheel_gems.hpp index 994f4b9d148..dee64225183 100644 --- a/src/creatures/players/wheel/wheel_gems.hpp +++ b/src/creatures/players/wheel/wheel_gems.hpp @@ -9,12 +9,18 @@ #pragma once -#include "creatures/creatures_definitions.hpp" -#include "wheel_definitions.hpp" -#include "enums/player_wheel.hpp" +#include "creatures/players/wheel/wheel_definitions.hpp" class PlayerWheel; +enum CombatType_t : uint8_t; +enum Vocation_t : uint16_t; + +enum class WheelGemAffinity_t : uint8_t; +enum class WheelGemBasicModifier_t : uint8_t; +enum class WheelGemSupremeModifier_t : uint8_t; +enum class WheelStat_t : uint8_t; + class GemModifierStrategy { public: explicit GemModifierStrategy(PlayerWheel &wheel) : @@ -87,8 +93,8 @@ class WheelModifierContext { explicit WheelModifierContext(PlayerWheel &wheel, Vocation_t vocation) : m_wheel(wheel), m_vocation(vocation) { } - void addStrategies(WheelGemBasicModifier_t modifier); - void addStrategies(WheelGemSupremeModifier_t modifier); + void addStrategies(WheelGemBasicModifier_t modifier, uint8_t grade); + void addStrategies(WheelGemSupremeModifier_t modifier, uint8_t grade); void resetStrategies() { m_strategies.clear(); @@ -102,229 +108,9 @@ class WheelModifierContext { Vocation_t m_vocation; }; -[[maybe_unused]] static int32_t getHealthValue(Vocation_t vocation, WheelGemBasicModifier_t modifier) { - static const std::unordered_map> stats = { - { - WheelGemBasicModifier_t::Vocation_Health, - { - { Vocation_t::VOCATION_KNIGHT, 300 }, - { Vocation_t::VOCATION_PALADIN, 200 }, - { Vocation_t::VOCATION_SORCERER, 100 }, - { Vocation_t::VOCATION_DRUID, 100 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Health_FireResistance, - { - { Vocation_t::VOCATION_KNIGHT, 150 }, - { Vocation_t::VOCATION_PALADIN, 100 }, - { Vocation_t::VOCATION_SORCERER, 50 }, - { Vocation_t::VOCATION_DRUID, 50 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Health_EnergyResistance, - { - { Vocation_t::VOCATION_KNIGHT, 150 }, - { Vocation_t::VOCATION_PALADIN, 100 }, - { Vocation_t::VOCATION_SORCERER, 50 }, - { Vocation_t::VOCATION_DRUID, 50 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Health_EarthResistance, - { - { Vocation_t::VOCATION_KNIGHT, 150 }, - { Vocation_t::VOCATION_PALADIN, 100 }, - { Vocation_t::VOCATION_SORCERER, 50 }, - { Vocation_t::VOCATION_DRUID, 50 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Health_IceResistance, - { - { Vocation_t::VOCATION_KNIGHT, 150 }, - { Vocation_t::VOCATION_PALADIN, 100 }, - { Vocation_t::VOCATION_SORCERER, 50 }, - { Vocation_t::VOCATION_DRUID, 50 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mixed, - { - { Vocation_t::VOCATION_KNIGHT, 150 }, - { Vocation_t::VOCATION_PALADIN, 100 }, - { Vocation_t::VOCATION_SORCERER, 50 }, - { Vocation_t::VOCATION_DRUID, 50 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mixed2, - { - { Vocation_t::VOCATION_KNIGHT, 150 }, - { Vocation_t::VOCATION_PALADIN, 100 }, - { Vocation_t::VOCATION_SORCERER, 50 }, - { Vocation_t::VOCATION_DRUID, 50 }, - }, - }, - }; - - auto modifierIt = stats.find(modifier); - if (modifierIt != stats.end()) { - auto vocationIt = modifierIt->second.find(vocation); - if (vocationIt != modifierIt->second.end()) { - return vocationIt->second; - } - } - return 0; -} - -[[maybe_unused]] static int32_t getManaValue(Vocation_t vocation, WheelGemBasicModifier_t modifier) { - static const std::unordered_map> stats = { - { - WheelGemBasicModifier_t::Vocation_Mana_FireResistance, - { - { Vocation_t::VOCATION_KNIGHT, 50 }, - { Vocation_t::VOCATION_PALADIN, 150 }, - { Vocation_t::VOCATION_SORCERER, 300 }, - { Vocation_t::VOCATION_DRUID, 300 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mana_EnergyResistance, - { - { Vocation_t::VOCATION_KNIGHT, 50 }, - { Vocation_t::VOCATION_PALADIN, 150 }, - { Vocation_t::VOCATION_SORCERER, 300 }, - { Vocation_t::VOCATION_DRUID, 300 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mana_Earth_Resistance, - { - { Vocation_t::VOCATION_KNIGHT, 50 }, - { Vocation_t::VOCATION_PALADIN, 150 }, - { Vocation_t::VOCATION_SORCERER, 300 }, - { Vocation_t::VOCATION_DRUID, 300 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mana_Ice_Resistance, - { - { Vocation_t::VOCATION_KNIGHT, 50 }, - { Vocation_t::VOCATION_PALADIN, 150 }, - { Vocation_t::VOCATION_SORCERER, 300 }, - { Vocation_t::VOCATION_DRUID, 300 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mana, - { - { Vocation_t::VOCATION_KNIGHT, 100 }, - { Vocation_t::VOCATION_PALADIN, 300 }, - { Vocation_t::VOCATION_SORCERER, 600 }, - { Vocation_t::VOCATION_DRUID, 600 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mixed, - { - { Vocation_t::VOCATION_PALADIN, 100 }, - { Vocation_t::VOCATION_SORCERER, 150 }, - { Vocation_t::VOCATION_DRUID, 150 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Capacity, - { - { Vocation_t::VOCATION_KNIGHT, 50 }, - { Vocation_t::VOCATION_PALADIN, 150 }, - { Vocation_t::VOCATION_SORCERER, 300 }, - { Vocation_t::VOCATION_DRUID, 300 }, - }, - } - }; - - auto modifierIt = stats.find(modifier); - if (modifierIt != stats.end()) { - auto vocationIt = modifierIt->second.find(vocation); - if (vocationIt != modifierIt->second.end()) { - return vocationIt->second; - } - } - return 0; -} - -[[maybe_unused]] static int32_t getCapacityValue(Vocation_t vocation, WheelGemBasicModifier_t modifier) { - static const std::unordered_map> stats = { - { - WheelGemBasicModifier_t::Vocation_Capacity_FireResistance, - { - { Vocation_t::VOCATION_KNIGHT, 250 }, - { Vocation_t::VOCATION_PALADIN, 200 }, - { Vocation_t::VOCATION_SORCERER, 100 }, - { Vocation_t::VOCATION_DRUID, 100 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Capacity_EnergyResistance, - { - { Vocation_t::VOCATION_KNIGHT, 250 }, - { Vocation_t::VOCATION_PALADIN, 200 }, - { Vocation_t::VOCATION_SORCERER, 100 }, - { Vocation_t::VOCATION_DRUID, 100 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Capacity_EarthResistance, - { - { Vocation_t::VOCATION_KNIGHT, 250 }, - { Vocation_t::VOCATION_PALADIN, 200 }, - { Vocation_t::VOCATION_SORCERER, 100 }, - { Vocation_t::VOCATION_DRUID, 100 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Capacity_IceResistance, - { - { Vocation_t::VOCATION_KNIGHT, 250 }, - { Vocation_t::VOCATION_PALADIN, 200 }, - { Vocation_t::VOCATION_SORCERER, 100 }, - { Vocation_t::VOCATION_DRUID, 100 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Capacity, - { - { Vocation_t::VOCATION_KNIGHT, 250 }, - { Vocation_t::VOCATION_PALADIN, 200 }, - { Vocation_t::VOCATION_SORCERER, 100 }, - { Vocation_t::VOCATION_DRUID, 100 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mixed, - { - { Vocation_t::VOCATION_KNIGHT, 125 }, - }, - }, - { - WheelGemBasicModifier_t::Vocation_Mixed2, - { - { Vocation_t::VOCATION_KNIGHT, 250 }, - { Vocation_t::VOCATION_PALADIN, 200 }, - { Vocation_t::VOCATION_SORCERER, 100 }, - { Vocation_t::VOCATION_DRUID, 100 }, - }, - } - }; - - auto modifierIt = stats.find(modifier); - if (modifierIt != stats.end()) { - auto vocationIt = modifierIt->second.find(vocation); - if (vocationIt != modifierIt->second.end()) { - return vocationIt->second; - } - } - return 0; -} +class WheelGemUtils { +public: + [[maybe_unused]] static int32_t getHealthValue(Vocation_t vocation, WheelGemBasicModifier_t modifier); + [[maybe_unused]] static int32_t getManaValue(Vocation_t vocation, WheelGemBasicModifier_t modifier); + [[maybe_unused]] static int32_t getCapacityValue(Vocation_t vocation, WheelGemBasicModifier_t modifier); +}; diff --git a/src/enums/player_wheel.hpp b/src/enums/player_wheel.hpp index 81cde57f651..6133f191581 100644 --- a/src/enums/player_wheel.hpp +++ b/src/enums/player_wheel.hpp @@ -18,6 +18,19 @@ enum class WheelGemAction_t : uint8_t { Reveal, SwitchDomain, ToggleLock, + ImproveGrade +}; + +enum class WheelImproveGemGrade_t : uint8_t { + Grade1, + Grade2, + Grade3, + Grade4, +}; + +enum class WheelFragmentType_t : uint8_t { + Greater, + Lesser, }; enum class WheelGemAffinity_t : uint8_t { @@ -69,8 +82,8 @@ enum class WheelGemBasicModifier_t : uint8_t { General_MitigationMultiplier, Vocation_Health, - Vocation_Capacity, - Vocation_Mana_FireResistance, + // Vocation_Mana_Capacity = 32, INVALID MODIFIER, WILL BE DISPLAYED AS (UNKNOWN) + Vocation_Mana_FireResistance = 33, Vocation_Mana_EnergyResistance, Vocation_Mana_Earth_Resistance, Vocation_Mana_Ice_Resistance, @@ -85,6 +98,7 @@ enum class WheelGemBasicModifier_t : uint8_t { Vocation_Capacity_EnergyResistance, Vocation_Capacity_EarthResistance, Vocation_Capacity_IceResistance, + Vocation_Capacity, }; enum class WheelGemSupremeModifier_t : uint8_t { @@ -103,12 +117,12 @@ enum class WheelGemSupremeModifier_t : uint8_t { Knight_Fierce_Berserk_CriticalExtraDamage, Knight_Berserk_DamageIncrease, Knight_Berserk_CriticalExtraDamage, - Knight_Front_Sweep_CriticalExtraDamage, Knight_Front_Sweep_DamageIncrease, + Knight_Front_Sweep_CriticalExtraDamage, Knight_Groundshaker_DamageIncrease, Knight_Groundshaker_CriticalExtraDamage, - Knight_Annihilation_CriticalExtraDamage, Knight_Annihilation_DamageIncrease, + Knight_Annihilation_CriticalExtraDamage, Knight_FairWoundCleansing_HealingIncrease, Knight_RevelationMastery_AvatarOfSteel, Knight_RevelationMastery_ExecutionersThrow, @@ -157,8 +171,8 @@ enum class WheelGemSupremeModifier_t : uint8_t { Druid_TerraBurst_CriticalExtraDamage, Druid_IceBurst_DamageIncrease, Druid_IceBurst_CriticalExtraDamage, - Druid_EternalWinter_CriticalExtraDamage, Druid_EternalWinter_DamageIncrease, + Druid_EternalWinter_CriticalExtraDamage, Druid_TerraWave_DamageIncrease, Druid_TerraWave_CriticalExtraDamage, Druid_StrongIceWave_DamageIncrease, diff --git a/src/game/game.cpp b/src/game/game.cpp index 482823c89ed..c6ba09311d5 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -34,6 +34,7 @@ #include "items/weapons/weapons.hpp" #include "creatures/players/imbuements/imbuements.hpp" #include "creatures/players/wheel/player_wheel.hpp" +#include "enums/player_wheel.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" #include "creatures/players/cyclopedia/player_cyclopedia.hpp" @@ -9785,8 +9786,9 @@ void Game::playerWheelGemAction(uint32_t playerId, NetworkMessage &msg) { return; } - auto action = msg.get(); - auto param = msg.get(); + const auto action = msg.getByte(); + const auto param = msg.getByte(); + uint8_t pos = 0; switch (static_cast(action)) { case WheelGemAction_t::Destroy: @@ -9801,6 +9803,10 @@ void Game::playerWheelGemAction(uint32_t playerId, NetworkMessage &msg) { case WheelGemAction_t::ToggleLock: player->wheel()->toggleGemLock(param); break; + case WheelGemAction_t::ImproveGrade: + pos = msg.getByte(); + player->wheel()->improveGemGrade(static_cast(param), pos); + break; default: g_logger().error("[{}] player {} is trying to do invalid action {} on wheel", __FUNCTION__, player->getName(), action); break; diff --git a/src/io/io_wheel.cpp b/src/io/io_wheel.cpp index 1d2a7884e82..72d5e207d4c 100644 --- a/src/io/io_wheel.cpp +++ b/src/io/io_wheel.cpp @@ -9,6 +9,7 @@ #include "io/io_wheel.hpp" +#include "enums/player_wheel.hpp" #include "kv/kv.hpp" #include "creatures/players/wheel/player_wheel.hpp" #include "creatures/players/player.hpp" diff --git a/src/server/server_definitions.hpp b/src/server/server_definitions.hpp index 79dd89df511..2a8d55e2c89 100644 --- a/src/server/server_definitions.hpp +++ b/src/server/server_definitions.hpp @@ -67,6 +67,8 @@ enum Resource_t : uint8_t { RESOURCE_LESSER_GEMS = 0x51, RESOURCE_REGULAR_GEMS = 0x52, RESOURCE_GREATER_GEMS = 0x53, + RESOURCE_LESSER_FRAGMENT = 0x54, + RESOURCE_GREATER_FRAGMENT = 0x55, RESOURCE_WHEEL_OF_DESTINY = 0x56 }; diff --git a/src/utils/utils_definitions.hpp b/src/utils/utils_definitions.hpp index 4e5279fe47e..6eae663daca 100644 --- a/src/utils/utils_definitions.hpp +++ b/src/utils/utils_definitions.hpp @@ -631,6 +631,9 @@ enum ItemID_t : uint16_t { ITEM_BATHTUB_FILLED = 26077, ITEM_BATHTUB_FILLED_NOTMOVABLE = 26100, + ITEM_LESSER_FRAGMENT = 46625, + ITEM_GREATER_FRAGMENT = 46626, + ITEM_NONE = 0 };