diff --git a/data/XML/imbuements.xml b/data/XML/imbuements.xml index fa1c3312..6b686fcd 100644 --- a/data/XML/imbuements.xml +++ b/data/XML/imbuements.xml @@ -22,6 +22,7 @@ + @@ -427,4 +428,23 @@ + + + + + + + + + + + + + + + + + + + diff --git a/data/items/items.xml b/data/items/items.xml index dd615d64..34bdf938 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -2660,7 +2660,9 @@ - + + + @@ -2727,6 +2729,7 @@ + @@ -2740,7 +2743,9 @@ - + + + @@ -2755,6 +2760,7 @@ + @@ -7219,7 +7225,9 @@ - + + + @@ -11072,6 +11080,7 @@ + @@ -11082,6 +11091,7 @@ + @@ -11103,6 +11113,7 @@ + @@ -12116,7 +12127,9 @@ - + + + @@ -14889,6 +14902,7 @@ + @@ -20503,7 +20517,9 @@ - + + + @@ -23911,6 +23927,7 @@ + @@ -26833,7 +26850,9 @@ - + + + @@ -27126,7 +27145,9 @@ - + + + @@ -34164,6 +34185,7 @@ + @@ -41800,6 +41822,7 @@ + @@ -43447,7 +43470,9 @@ Awarded by TibiaMagazine.com.ve"/> - + + + @@ -43871,6 +43896,7 @@ Awarded by TibiaMagazine.com.ve"/> + @@ -45232,6 +45258,7 @@ Awarded by TibiaMisterios.com.br"/> + @@ -55525,6 +55552,7 @@ hands of its owner. Granted by TibiaRoyal.com"/> + @@ -57239,7 +57267,9 @@ hands of its owner. Granted by TibiaRoyal.com"/> - + + + @@ -59255,6 +59285,7 @@ hands of its owner. Granted by TibiaRoyal.com"/> + @@ -61707,6 +61738,7 @@ hands of its owner. Granted by TibiaRoyal.com"/> + @@ -64267,6 +64299,7 @@ hands of its owner. Granted by TibiaRoyal.com"/> + @@ -64282,6 +64315,7 @@ hands of its owner. Granted by TibiaRoyal.com"/> + @@ -65935,6 +65969,7 @@ former students at the Noodles Academy. Awarded by TibiaLabs.com"/> + @@ -65950,6 +65985,7 @@ former students at the Noodles Academy. Awarded by TibiaLabs.com"/> + @@ -70551,6 +70587,7 @@ Granted by TibiaGoals.com"/> + @@ -71532,6 +71569,7 @@ Granted by TibiaGoals.com"/> + @@ -71586,6 +71624,7 @@ Granted by TibiaGoals.com"/> + @@ -73950,6 +73989,7 @@ Granted by TibiaGoals.com"/> + @@ -73965,6 +74005,7 @@ Granted by TibiaGoals.com"/> + @@ -76102,6 +76143,7 @@ Granted by TibiaGoals.com"/> + @@ -76205,6 +76247,7 @@ Granted by TibiaGoals.com"/> + diff --git a/data/scripts/talkactions/god/deflect_condition.lua b/data/scripts/talkactions/god/deflect_condition.lua new file mode 100644 index 00000000..ddc36997 --- /dev/null +++ b/data/scripts/talkactions/god/deflect_condition.lua @@ -0,0 +1,81 @@ +-- talkActions to help test deflect condition + +local addDeflect = TalkAction("/adddeflect") + +function addDeflect.onSay(player, words, param) + local split = param:split(",") + if #split ~= 4 then + player:sendCancelMessage("Insufficient parameters. Usage: /adddeflect , , , ") + return true + end + + local playerName = split[1]:trimSpace() + local targetPlayer = Player(playerName) + if not targetPlayer then + player:sendCancelMessage("Player " .. playerName .. " not found.") + return true + end + + local source = split[2]:trimSpace() + + local conditionId = split[3]:trimSpace() + conditionId = tonumber(conditionId) + if not conditionId then + player:sendCancelMessage(" must be a number.") + return true + end + + local deflectChance = split[4]:trimSpace() + deflectChance = tonumber(deflectChance) + if not deflectChance then + player:sendCancelMessage(" must be a number.") + return true + end + + targetPlayer:addDeflectCondition(source, conditionId, deflectChance) + return true +end + +addDeflect:separator(" ") +addDeflect:groupType("god") +addDeflect:register() + +local removeDeflect = TalkAction("/removedeflect") + +function removeDeflect.onSay(player, words, param) + local split = param:split(",") + if #split ~= 4 then + player:sendCancelMessage("Insufficient parameters. Usage: /removedeflect , , , ") + return true + end + + local playerName = split[1]:trimSpace() + local targetPlayer = Player(playerName) + if not targetPlayer then + player:sendCancelMessage("Player " .. playerName .. " not found.") + return true + end + + local source = split[2]:trimSpace() + + local conditionId = split[3]:trimSpace() + conditionId = tonumber(conditionId) + if not conditionId then + player:sendCancelMessage(" must be a number.") + return true + end + + local deflectChance = split[4]:trimSpace() + deflectChance = tonumber(deflectChance) + if not deflectChance then + player:sendCancelMessage(" must be a number.") + return true + end + + targetPlayer:removeDeflectCondition(source, conditionId, deflectChance) + return true +end + +removeDeflect:separator(" ") +removeDeflect:groupType("god") +removeDeflect:register() diff --git a/markdowns/CHANGELOG.md b/markdowns/CHANGELOG.md index 5c9f257f..a95e5a0a 100644 --- a/markdowns/CHANGELOG.md +++ b/markdowns/CHANGELOG.md @@ -115,7 +115,6 @@ - Players can enable the chain system using the `!chain` command. ([Tryller](https://github.com/jprzimba)). - Updated npc data-global/npc/hireling.lua, now it sell imbuement packages and also buy all loots inside Loot Pouch ([Tryller](https://github.com/jprzimba)). - Cyclopedia item summary ([phacUFPE](https://github.com/phacUFPE)) -- Add Vibrancy imbuement ([pennaor](https://github.com/pennaor)) - Badge system ([elsongabriel](https://github.com/elsongabriel)) - Screenshots configurable in config.lua enableScreenshots ([Tryller](https://github.com/jprzimba)). - Augments system ([phacUFPE](https://github.com/phacUFPE)). diff --git a/src/core.hpp b/src/core.hpp index e324895a..eff9c42b 100644 --- a/src/core.hpp +++ b/src/core.hpp @@ -18,7 +18,7 @@ #pragma once static constexpr auto SOFTWARE_NAME = "Crystal Server"; -static constexpr auto SOFTWARE_VERSION = "4.1.2"; +static constexpr auto SOFTWARE_VERSION = "4.1.3"; static constexpr auto SOFTWARE_DEVELOPERS = "Crystal Server Contributors"; static constexpr auto AUTHENTICATOR_DIGITS = 6U; diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index e8584884..8e8089e1 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -821,7 +821,6 @@ void Combat::CombatConditionFunc(const std::shared_ptr &caster, const if (condition->getType() == CONDITION_ROOTED && !checkRootConditionAffected(player)) { return; } - } if (caster == target || (target && !target->isImmune(condition->getType()))) { diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index 57fc4238..346fc27e 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -336,10 +336,15 @@ Condition::Condition(ConditionId_t initId, ConditionType_t initType, int32_t ini endTime(initTicks == -1 ? std::numeric_limits::max() : 0), subId(initSubId), ticks(initTicks), conditionType(initType), id(initId), isBuff(initBuff), m_isPersistent(isPersistent) { } -bool Condition::startCondition(std::shared_ptr) { +bool Condition::startCondition(std::shared_ptr creature) { + if (creatureCanDeflect(creature)) { + return false; + } + if (ticks > 0) { endTime = ticks + OTSYS_TIME(); } + return true; } @@ -411,7 +416,19 @@ int32_t Condition::getTicks() const { return ticks; } -bool Condition::updateCondition(const std::shared_ptr &addCondition) { +// Determines whether a creature can prevent the condition from being added or updated +bool Condition::creatureCanDeflect(std::shared_ptr creature) const { + if (!creature) { + return false; + } + auto player = creature->getPlayer(); + if (player) { + return player->getDeflectConditionChance(conditionType) >= uniform_random(1, 100); + } + return false; +} + +bool Condition::updateCondition(const std::shared_ptr &addCondition, std::shared_ptr creature /*= nullptr*/) { if (conditionType != addCondition->getType()) { return false; } @@ -424,6 +441,10 @@ bool Condition::updateCondition(const std::shared_ptr &addCondition) return false; } + if (creatureCanDeflect(creature)) { + return false; + } + return true; } @@ -447,7 +468,7 @@ void ConditionGeneric::endCondition(std::shared_ptr) { } void ConditionGeneric::addCondition(std::shared_ptr creature, const std::shared_ptr addCondition) { - if (updateCondition(addCondition)) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); if (creature && addSound != SoundEffect_t::SILENCE) { @@ -511,7 +532,7 @@ void ConditionAttributes::addCondition(std::shared_ptr creature, const return; } - if (updateCondition(addCondition)) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); const std::shared_ptr &conditionAttrs = addCondition->static_self_cast(); @@ -1228,7 +1249,7 @@ void ConditionRegeneration::endCondition(std::shared_ptr creature) { } void ConditionRegeneration::addCondition(std::shared_ptr creature, const std::shared_ptr addCondition) { - if (updateCondition(addCondition)) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); const auto &conditionRegen = addCondition->static_self_cast(); @@ -1476,8 +1497,8 @@ std::unordered_set ConditionManaShield::getIcons() const { ConditionSoul::ConditionSoul(ConditionId_t initId, ConditionType_t initType, int32_t iniTicks, bool initBuff, uint32_t initSubId) : ConditionGeneric(initId, initType, iniTicks, initBuff, initSubId) { } -void ConditionSoul::addCondition(std::shared_ptr, const std::shared_ptr addCondition) { - if (updateCondition(addCondition)) { +void ConditionSoul::addCondition(std::shared_ptr creature, const std::shared_ptr addCondition) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); const auto &conditionSoul = addCondition->static_self_cast(); @@ -1635,7 +1656,11 @@ void ConditionDamage::serialize(PropWriteStream &propWriteStream) { } } -bool ConditionDamage::updateCondition(const std::shared_ptr &addCondition) { +bool ConditionDamage::updateCondition(const std::shared_ptr &addCondition, std::shared_ptr creature /*= nullptr*/) { + if (creatureCanDeflect(creature)) { + return false; + } + const auto &conditionDamage = addCondition->static_self_cast(); if (conditionDamage->doForceUpdate()) { return true; @@ -1824,7 +1849,7 @@ void ConditionDamage::addCondition(std::shared_ptr creature, const std return; } - if (!updateCondition(addCondition)) { + if (!updateCondition(addCondition, creature)) { return; } @@ -2215,8 +2240,8 @@ void ConditionFeared::endCondition(std::shared_ptr creature) { } } -void ConditionFeared::addCondition(std::shared_ptr, const std::shared_ptr addCondition) { - if (updateCondition(addCondition)) { +void ConditionFeared::addCondition(std::shared_ptr creature, const std::shared_ptr addCondition) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); } } @@ -2252,8 +2277,8 @@ bool ConditionRooted::executeCondition(const std::shared_ptr &creature return Condition::executeCondition(creature, interval); } -void ConditionRooted::addCondition(std::shared_ptr, const std::shared_ptr addCondition) { - if (updateCondition(addCondition)) { +void ConditionRooted::addCondition(std::shared_ptr creature, const std::shared_ptr addCondition) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); } } @@ -2387,6 +2412,10 @@ void ConditionSpeed::addCondition(std::shared_ptr creature, const std: return; } + if (creatureCanDeflect(creature)) { + return; + } + setTicks(addCondition->getTicks()); const auto &conditionSpeed = addCondition->static_self_cast(); @@ -2529,7 +2558,7 @@ void ConditionOutfit::addCondition(std::shared_ptr creature, const std return; } - if (updateCondition(addCondition)) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); const auto &conditionOutfit = addCondition->static_self_cast(); @@ -2595,7 +2624,7 @@ void ConditionLight::endCondition(std::shared_ptr creature) { } void ConditionLight::addCondition(std::shared_ptr creature, const std::shared_ptr condition) { - if (updateCondition(condition)) { + if (updateCondition(condition, creature)) { setTicks(condition->getTicks()); const auto &conditionLight = condition->static_self_cast(); @@ -2685,7 +2714,7 @@ void ConditionLight::serialize(PropWriteStream &propWriteStream) { */ void ConditionSpellCooldown::addCondition(std::shared_ptr creature, const std::shared_ptr addCondition) { - if (updateCondition(addCondition)) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); if (subId != 0 && ticks > 0) { @@ -2723,7 +2752,7 @@ bool ConditionSpellCooldown::startCondition(std::shared_ptr creature) */ void ConditionSpellGroupCooldown::addCondition(std::shared_ptr creature, const std::shared_ptr addCondition) { - if (updateCondition(addCondition)) { + if (updateCondition(addCondition, creature)) { setTicks(addCondition->getTicks()); if (subId != 0 && ticks > 0) { diff --git a/src/creatures/combat/condition.hpp b/src/creatures/combat/condition.hpp index 939e50c6..d3f2d837 100644 --- a/src/creatures/combat/condition.hpp +++ b/src/creatures/combat/condition.hpp @@ -62,6 +62,8 @@ class Condition : public SharedObject { bool isPersistent() const; bool isRemovableOnDeath() const; + bool creatureCanDeflect(std::shared_ptr creature) const; + protected: uint8_t drainBodyStage = 0; int64_t endTime {}; @@ -72,7 +74,7 @@ class Condition : public SharedObject { bool isBuff {}; bool m_isPersistent {}; - virtual bool updateCondition(const std::shared_ptr &addCondition); + virtual bool updateCondition(const std::shared_ptr &addCondition, std::shared_ptr creature = nullptr); private: SoundEffect_t tickSound = SoundEffect_t::SILENCE; @@ -286,7 +288,7 @@ class ConditionDamage final : public Condition { bool getNextDamage(int32_t &damage); bool doDamage(const std::shared_ptr &creature, int32_t healthChange) const; - bool updateCondition(const std::shared_ptr &addCondition) override; + bool updateCondition(const std::shared_ptr &addCondition, std::shared_ptr creature = nullptr) override; }; class ConditionFeared final : public Condition { @@ -327,17 +329,17 @@ class ConditionFeared final : public Condition { }; class ConditionRooted final : public Condition { -public: - ConditionRooted() = default; - ConditionRooted(ConditionId_t initId, ConditionType_t initType, int32_t initTicks, bool initBuff, uint32_t initSubId); - - bool startCondition(std::shared_ptr creature) override; - bool executeCondition(const std::shared_ptr &creature, int32_t interval) override; - void endCondition(std::shared_ptr creature) override; - void addCondition(std::shared_ptr creature, std::shared_ptr condition) override; - std::unordered_set getIcons() const override; - - std::shared_ptr clone() const override; +public: + ConditionRooted() = default; + ConditionRooted(ConditionId_t initId, ConditionType_t initType, int32_t initTicks, bool initBuff, uint32_t initSubId); + + bool startCondition(std::shared_ptr creature) override; + bool executeCondition(const std::shared_ptr &creature, int32_t interval) override; + void endCondition(std::shared_ptr creature) override; + void addCondition(std::shared_ptr creature, std::shared_ptr condition) override; + std::unordered_set getIcons() const override; + + std::shared_ptr clone() const override; }; class ConditionSpeed final : public Condition { diff --git a/src/creatures/players/imbuements/imbuements.cpp b/src/creatures/players/imbuements/imbuements.cpp index fd7ce409..d925ebb4 100644 --- a/src/creatures/players/imbuements/imbuements.cpp +++ b/src/creatures/players/imbuements/imbuements.cpp @@ -316,6 +316,26 @@ bool Imbuements::loadFromXml(bool /* reloading */) { } imbuement.capacity = pugi::cast(attr.value()); + } else if (strcasecmp(effecttype.c_str(), "deflect") == 0) { + if (!(attr = childNode.attribute("chance"))) { + g_logger().warn("Missing deflect chance for imbuement name {}", imbuement.name); + continue; + } + auto deflectChance = pugi::cast(attr.value()); + if (deflectChance <= 0 || deflectChance > 100) { + g_logger().warn("Invalid deflect chance for imbuement name {}", imbuement.name); + continue; + } + if (!(attr = childNode.attribute("conditionid"))) { + g_logger().warn("Missing deflect condition id for imbuement name {}", imbuement.name); + continue; + } + auto conditionId = pugi::cast(attr.value()); + if (conditionId <= 0 || conditionId >= CONDITION_COUNT) { + g_logger().warn("Invalid deflect condition id for imbuement name {}", imbuement.name); + continue; + } + imbuement.deflectConditions[static_cast(conditionId)] = deflectChance; } } } diff --git a/src/creatures/players/imbuements/imbuements.hpp b/src/creatures/players/imbuements/imbuements.hpp index f01ae8ae..0006c21c 100644 --- a/src/creatures/players/imbuements/imbuements.hpp +++ b/src/creatures/players/imbuements/imbuements.hpp @@ -116,6 +116,8 @@ class Imbuement { CombatType_t combatType = COMBAT_NONE; + std::unordered_map deflectConditions; + protected: friend class Imbuements; friend class Item; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index f3aaaa6b..84e1e947 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -2854,6 +2854,11 @@ void Player::addItemImbuementStats(const Imbuement* imbuement) { bonusCapacity = (capacity * imbuement->capacity) / 100; } + // Add imbuement deflect conditions + for (const auto &[condition, chance] : imbuement->deflectConditions) { + addDeflectCondition("imbuement", condition, chance); + } + if (requestUpdate) { sendStats(); sendSkills(); @@ -2893,6 +2898,13 @@ void Player::removeItemImbuementStats(const Imbuement* imbuement) { bonusCapacity = 0; } + // Remove imbuement deflect conditions + if (getDeflectConditions().size() > 0) { + for (const auto &[condition, chance] : imbuement->deflectConditions) { + removeDeflectCondition("imbuement", condition, chance); + } + } + if (requestUpdate) { sendStats(); sendSkills(); @@ -10797,3 +10809,29 @@ uint16_t Player::getPlayerVocationEnum() const { return Vocation_t::VOCATION_NONE; } + +// Deflect Condition +uint8_t Player::getDeflectConditionChance(const ConditionType_t &conditionType) const { + uint8_t maxChance = 0; + for (const auto &dc : deflectConditions) { + if (conditionType == dc.condition && dc.chance > maxChance) { + maxChance = dc.chance; + } + } + + return maxChance; +} + +void Player::removeDeflectCondition(const std::string_view &source, const ConditionType_t &conditionType, const uint8_t &chance) { + auto it = std::find_if(deflectConditions.begin(), deflectConditions.end(), [source, conditionType, chance](const DeflectCondition &dc) { + return source == dc.source && conditionType == dc.condition && chance == dc.chance; + }); + + if (it != deflectConditions.end()) { + deflectConditions.erase(it); + } +} + +void Player::addDeflectCondition(std::string source, ConditionType_t conditionType, uint8_t chance) { + deflectConditions.emplace_back(source, conditionType, chance); +} diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 2b081e0a..b8c39b4d 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -1283,6 +1283,32 @@ class Player final : public Creature, public Cylinder, public Bankable { uint16_t getPlayerVocationEnum() const; + /******************************************************************************* + * Deflect Condition + * Responsible for defining the conditions that when trying to be + * added to the player or being updated, there is a chance to prevent these actions + ******************************************************************************/ + struct DeflectCondition { + DeflectCondition(std::string source, ConditionType_t condition, uint8_t chance) : + source(source), condition(condition), chance(chance) { } + std::string source; + uint8_t chance = 0; + ConditionType_t condition = CONDITION_NONE; + }; + + const std::vector &getDeflectConditions() const { + return deflectConditions; + } + + // Searches according to a conditionType the higest chance found among the player's + // deflect conditions. Return defaults to 0 if no condition is met. + uint8_t getDeflectConditionChance(const ConditionType_t &conditionType) const; + + // Removes a deflect condition from a player from a given source + void removeDeflectCondition(const std::string_view &source, const ConditionType_t &conditionType, const uint8_t &chance); + + void addDeflectCondition(std::string source, ConditionType_t conditionType, uint8_t chance); + private: friend class PlayerLock; std::mutex mutex; @@ -1675,4 +1701,11 @@ class Player final : public Creature, public Cylinder, public Bankable { int32_t getMarriageSpouse() const { return marriageSpouse; } + + // Stores of conditions to be deflected from various sources, including from "imbuements". + // Different DeflectCondition containing the same data may be present. + // This is allowed because, for example, if armor and boots have a common imbument, + // unequipping the armor does not influence the boot's imbuement. + // When present simultaneously, the one with the greatest chance of occurrence will prevail. + std::vector deflectConditions; }; diff --git a/src/items/functions/item/item_parse.hpp b/src/items/functions/item/item_parse.hpp index 80ccf7de..23987e67 100644 --- a/src/items/functions/item/item_parse.hpp +++ b/src/items/functions/item/item_parse.hpp @@ -255,7 +255,8 @@ const phmap::flat_hash_map ImbuementsTypeMap = { { "skillboost shielding", IMBUEMENT_SKILLBOOST_SHIELDING }, { "skillboost distance", IMBUEMENT_SKILLBOOST_DISTANCE }, { "skillboost magic level", IMBUEMENT_SKILLBOOST_MAGIC_LEVEL }, - { "increase capacity", IMBUEMENT_INCREASE_CAPACITY } + { "increase capacity", IMBUEMENT_INCREASE_CAPACITY }, + { "paralysis removal", IMBUEMENT_PARALYSIS_REMOVAL }, }; const phmap::flat_hash_map AugmentWithoutValueDescriptionDefaultKeys = { diff --git a/src/items/items_definitions.hpp b/src/items/items_definitions.hpp index 22e6c99c..719ab50b 100644 --- a/src/items/items_definitions.hpp +++ b/src/items/items_definitions.hpp @@ -276,7 +276,8 @@ enum ImbuementTypes_t : int64_t { IMBUEMENT_SKILLBOOST_SHIELDING = 14, IMBUEMENT_SKILLBOOST_DISTANCE = 15, IMBUEMENT_SKILLBOOST_MAGIC_LEVEL = 16, - IMBUEMENT_INCREASE_CAPACITY = 17 + IMBUEMENT_INCREASE_CAPACITY = 17, + IMBUEMENT_PARALYSIS_REMOVAL = 18 }; enum class Augment_t : uint8_t { diff --git a/src/lua/functions/creatures/player/player_functions.cpp b/src/lua/functions/creatures/player/player_functions.cpp index 5ac00417..1268d53c 100644 --- a/src/lua/functions/creatures/player/player_functions.cpp +++ b/src/lua/functions/creatures/player/player_functions.cpp @@ -396,6 +396,9 @@ void PlayerFunctions::init(lua_State* L) { Lua::registerMethod(L, "Player", "addAchievementPoints", PlayerFunctions::luaPlayerAddAchievementPoints); Lua::registerMethod(L, "Player", "removeAchievementPoints", PlayerFunctions::luaPlayerRemoveAchievementPoints); + Lua::registerMethod(L, "Player", "addDeflectCondition", PlayerFunctions::luaPlayerAddDeflectCondition); + Lua::registerMethod(L, "Player", "removeDeflectCondition", PlayerFunctions::luaPlayerRemoveDeflectCondition); + // Badge Functions Lua::registerMethod(L, "Player", "addBadge", PlayerFunctions::luaPlayerAddBadge); @@ -4879,3 +4882,33 @@ int PlayerFunctions::luaPlayerSendCreatureAppear(lua_State* L) { Lua::pushBoolean(L, true); return 1; } + +int PlayerFunctions::luaPlayerAddDeflectCondition(lua_State* L) { + // player:addDeflectCondition(source, conditionType, deflectChance) + const auto &player = Lua::getUserdataShared(L, 1); + if (!player) { + Lua::reportErrorFunc(Lua::getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + return 1; + } + auto source = Lua::getString(L, 2); + auto conditionType = Lua::getNumber(L, 3); + auto deflectChance = Lua::getNumber(L, 4); + player->addDeflectCondition(source, conditionType, deflectChance); + Lua::pushBoolean(L, true); + return 1; +} + +int PlayerFunctions::luaPlayerRemoveDeflectCondition(lua_State* L) { + // player:removeDeflectCondition(source, conditionType, deflectChance) + const auto &player = Lua::getUserdataShared(L, 1); + if (!player) { + Lua::reportErrorFunc(Lua::getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + return 1; + } + auto source = Lua::getString(L, 2); + auto conditionType = Lua::getNumber(L, 3); + auto deflectChance = Lua::getNumber(L, 4); + player->removeDeflectCondition(source, conditionType, deflectChance); + Lua::pushBoolean(L, true); + return 1; +} diff --git a/src/lua/functions/creatures/player/player_functions.hpp b/src/lua/functions/creatures/player/player_functions.hpp index 339a36b1..83744b65 100644 --- a/src/lua/functions/creatures/player/player_functions.hpp +++ b/src/lua/functions/creatures/player/player_functions.hpp @@ -378,6 +378,9 @@ class PlayerFunctions { static int luaPlayerAddAchievementPoints(lua_State* L); static int luaPlayerRemoveAchievementPoints(lua_State* L); + static int luaPlayerAddDeflectCondition(lua_State* L); + static int luaPlayerRemoveDeflectCondition(lua_State* L); + static int luaPlayerAddBadge(lua_State* L); static int luaPlayerAddTitle(lua_State* L); diff --git a/src/utils/tools.cpp b/src/utils/tools.cpp index 5881c58a..df5bd070 100644 --- a/src/utils/tools.cpp +++ b/src/utils/tools.cpp @@ -890,7 +890,8 @@ const ImbuementTypeNames imbuementTypeNames = { { "skillboost shielding", IMBUEMENT_SKILLBOOST_SHIELDING }, { "skillboost distance", IMBUEMENT_SKILLBOOST_DISTANCE }, { "skillboost magic level", IMBUEMENT_SKILLBOOST_MAGIC_LEVEL }, - { "increase capacity", IMBUEMENT_INCREASE_CAPACITY } + { "increase capacity", IMBUEMENT_INCREASE_CAPACITY }, + { "paralysis removal", IMBUEMENT_PARALYSIS_REMOVAL }, }; /**