From 9d3309600b66520b17c3274123c772f800a95413 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Mon, 1 Jan 2024 11:31:00 -0800 Subject: [PATCH 1/3] feat: min delay between conditions --- config.lua.dist | 1 + src/config/config_definitions.hpp | 1 + src/config/configmanager.cpp | 1 + src/creatures/combat/combat.cpp | 2 +- src/creatures/creature.cpp | 10 ++++++---- src/creatures/creature.hpp | 4 ++-- src/creatures/creatures_definitions.hpp | 22 ++++++++++++++++++++++ src/creatures/players/player.cpp | 10 +++++++++- src/creatures/players/player.hpp | 20 ++++++++++++++++++++ 9 files changed, 63 insertions(+), 8 deletions(-) diff --git a/config.lua.dist b/config.lua.dist index 55a211267e6..0ac1e831a94 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -370,6 +370,7 @@ coinPacketSize = 25 coinImagesURL = "http://127.0.0.1/images/store/" classicAttackSpeed = false showScriptsLogInConsole = false +minDelayBetweenConditions = 0 -- time to suppress negative conditions after being affected by them (ms) -- configure maximum value of critical imbuement criticalChance = 10 inventoryGlowOnFiveBless = false diff --git a/src/config/config_definitions.hpp b/src/config/config_definitions.hpp index 31aa4659e06..80b9492cbf9 100644 --- a/src/config/config_definitions.hpp +++ b/src/config/config_definitions.hpp @@ -145,6 +145,7 @@ enum ConfigKey_t : uint16_t { METRICS_ENABLE_PROMETHEUS, METRICS_OSTREAM_INTERVAL, METRICS_PROMETHEUS_ADDRESS, + MIN_DELAY_BETWEEN_CONDITIONS, MIN_ELEMENTAL_RESISTANCE, MONTH_KILLS_TO_RED, MULTIPLIER_ATTACKONFIST, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index 1afbc0295ae..ec977460fe2 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -117,6 +117,7 @@ bool ConfigManager::load() { loadBoolConfig(L, CLEAN_PROTECTION_ZONES, "cleanProtectionZones", false); loadBoolConfig(L, GLOBAL_SERVER_SAVE_SHUTDOWN, "globalServerSaveShutdown", true); loadBoolConfig(L, PUSH_WHEN_ATTACKING, "pushWhenAttacking", false); + loadIntConfig(L, MIN_DELAY_BETWEEN_CONDITIONS, "minDelayBetweenConditions", 0); loadBoolConfig(L, WEATHER_RAIN, "weatherRain", false); loadBoolConfig(L, WEATHER_THUNDER, "thunderEffect", false); diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index e3211a1f52e..1142763ef5a 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -744,7 +744,7 @@ void Combat::CombatConditionFunc(std::shared_ptr caster, std::shared_p // TODO: infight condition until all aggressive conditions has ended if (target) { - target->addCombatCondition(conditionCopy); + target->addCombatCondition(conditionCopy, caster && caster->getPlayer() != nullptr); } } } diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 8e2e748c004..95c11b16888 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -1334,12 +1334,14 @@ bool Creature::setMaster(std::shared_ptr newMaster, bool reloadCreatur return true; } -bool Creature::addCondition(std::shared_ptr condition) { +bool Creature::addCondition(std::shared_ptr condition, bool attackerPlayer /* = false*/) { metrics::method_latency measure(__METHOD_NAME__); if (condition == nullptr) { return false; } - + if (isSuppress(condition->getType(), attackerPlayer)) { + return false; + } std::shared_ptr prevCond = getCondition(condition->getType(), condition->getId(), condition->getSubId()); if (prevCond) { prevCond->addCondition(getCreature(), condition); @@ -1355,11 +1357,11 @@ bool Creature::addCondition(std::shared_ptr condition) { return false; } -bool Creature::addCombatCondition(std::shared_ptr condition) { +bool Creature::addCombatCondition(std::shared_ptr condition, bool attackerPlayer /* = false*/) { // Caution: condition variable could be deleted after the call to addCondition ConditionType_t type = condition->getType(); - if (!addCondition(condition)) { + if (!addCondition(condition, attackerPlayer)) { return false; } diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index cbbdc94e3ac..0c1872416d2 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -388,8 +388,8 @@ class Creature : virtual public Thing, public SharedObject { return SPEECHBUBBLE_NONE; } - bool addCondition(std::shared_ptr condition); - bool addCombatCondition(std::shared_ptr condition); + bool addCondition(std::shared_ptr condition, bool attackerPlayer = false); + bool addCombatCondition(std::shared_ptr condition, bool attackerPlayer = false); void removeCondition(ConditionType_t conditionType, ConditionId_t conditionId, bool force = false); void removeCondition(ConditionType_t type); void removeCondition(std::shared_ptr condition); diff --git a/src/creatures/creatures_definitions.hpp b/src/creatures/creatures_definitions.hpp index 39ada8745a5..2c74895db42 100644 --- a/src/creatures/creatures_definitions.hpp +++ b/src/creatures/creatures_definitions.hpp @@ -112,6 +112,28 @@ enum ConditionType_t : uint8_t { CONDITION_COUNT = 39 }; +// constexpr definiting suppressible conditions +constexpr bool IsConditionSuppressible(ConditionType_t condition) { + constexpr ConditionType_t suppressibleConditions[] = { + CONDITION_POISON, + CONDITION_FIRE, + CONDITION_ENERGY, + CONDITION_BLEEDING, + CONDITION_PARALYZE, + CONDITION_DROWN, + CONDITION_FREEZING, + CONDITION_CURSED, + }; + + for (const auto &suppressibleCondition : suppressibleConditions) { + if (condition == suppressibleCondition) { + return true; + } + } + + return false; +} + enum ConditionParam_t { CONDITION_PARAM_OWNER = 1, CONDITION_PARAM_TICKS = 2, diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 0b5da33dc41..b3fa5b674db 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -215,7 +215,12 @@ std::shared_ptr Player::getInventoryItem(Slots_t slot) const { return inventory[slot]; } -bool Player::isSuppress(ConditionType_t conditionType) const { +bool Player::isSuppress(ConditionType_t conditionType, bool attackerPlayer) const { + auto minDelay = g_configManager().getNumber(MIN_DELAY_BETWEEN_CONDITIONS, __FUNCTION__); + if (IsConditionSuppressible(conditionType) && checkLastConditionTimeWithin(conditionType, minDelay)) { + return true; + } + return m_conditionSuppressions[static_cast(conditionType)]; } @@ -4422,6 +4427,9 @@ void Player::onAddCondition(ConditionType_t type) { } void Player::onAddCombatCondition(ConditionType_t type) { + if (IsConditionSuppressible(type)) { + updateLastConditionTime(type); + } switch (type) { case CONDITION_POISON: sendTextMessage(MESSAGE_FAILURE, "You are poisoned."); diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 9d7a555b050..1b12ebf571d 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -899,6 +899,25 @@ class Player final : public Creature, public Cylinder, public Bankable { return lastAttackBlockType; } + uint64_t getLastConditionTime(ConditionType_t type) const { + if (!lastConditionTime.contains(static_cast(type))) { + return 0; + } + return lastConditionTime.at(static_cast(type)); + } + + void updateLastConditionTime(ConditionType_t type) { + lastConditionTime[static_cast(type)] = OTSYS_TIME(); + } + + bool checkLastConditionTimeWithin(ConditionType_t type, uint32_t interval) const { + if (!lastConditionTime.contains(static_cast(type))) { + return false; + } + auto last = lastConditionTime.at(static_cast(type)); + return last > 0 && ((OTSYS_TIME() - last) < interval); + } + std::shared_ptr getWeapon(Slots_t slot, bool ignoreAmmo) const; std::shared_ptr getWeapon(bool ignoreAmmo = false) const; WeaponType_t getWeaponType() const; @@ -2680,6 +2699,7 @@ class Player final : public Creature, public Cylinder, public Bankable { uint64_t experience = 0; uint64_t manaSpent = 0; uint64_t lastAttack = 0; + std::unordered_map lastConditionTime; uint64_t bankBalance = 0; uint64_t lastQuestlogUpdate = 0; uint64_t preyCards = 0; From d58aafdd574a9716f605f9463760b4b5bf186649 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Mon, 1 Jan 2024 12:40:28 -0800 Subject: [PATCH 2/3] Update config.lua.dist --- config.lua.dist | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config.lua.dist b/config.lua.dist index 0ac1e831a94..b5027874bc7 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -370,7 +370,8 @@ coinPacketSize = 25 coinImagesURL = "http://127.0.0.1/images/store/" classicAttackSpeed = false showScriptsLogInConsole = false -minDelayBetweenConditions = 0 -- time to suppress negative conditions after being affected by them (ms) +-- time to suppress negative conditions after being affected by them (ms) +minDelayBetweenConditions = 0 -- configure maximum value of critical imbuement criticalChance = 10 inventoryGlowOnFiveBless = false From ce5ecd492cfb9a7bd35a7e1dce122d6d63702442 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Mon, 1 Jan 2024 15:18:54 -0800 Subject: [PATCH 3/3] missing file changes --- src/creatures/combat/condition.cpp | 5 +++-- src/creatures/creature.cpp | 2 +- src/creatures/creature.hpp | 2 +- src/creatures/players/player.cpp | 2 +- src/creatures/players/player.hpp | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index 8b8ddff7ca4..c1693aae2bf 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -1644,7 +1644,9 @@ bool ConditionDamage::getNextDamage(int32_t &damage) { } bool ConditionDamage::doDamage(std::shared_ptr creature, int32_t healthChange) { - if (creature->isSuppress(getType())) { + auto attacker = g_game().getPlayerByGUID(owner) ? g_game().getPlayerByGUID(owner)->getCreature() : g_game().getCreatureByID(owner); + bool isPlayer = attacker && attacker->getPlayer(); + if (creature->isSuppress(getType(), isPlayer)) { return true; } @@ -1653,7 +1655,6 @@ bool ConditionDamage::doDamage(std::shared_ptr creature, int32_t healt damage.primary.value = healthChange; damage.primary.type = Combat::ConditionToDamageType(conditionType); - std::shared_ptr attacker = g_game().getCreatureByID(owner); if (field && creature->getPlayer() && attacker && attacker->getPlayer()) { damage.primary.value = static_cast(std::round(damage.primary.value / 2.)); } diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 95c11b16888..eaaf4ca64ea 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -1492,7 +1492,7 @@ void Creature::executeConditions(uint32_t interval) { bool Creature::hasCondition(ConditionType_t type, uint32_t subId /* = 0*/) const { metrics::method_latency measure(__METHOD_NAME__); - if (isSuppress(type)) { + if (isSuppress(type, false)) { return false; } diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index 0c1872416d2..a21403edcef 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -406,7 +406,7 @@ class Creature : virtual public Thing, public SharedObject { virtual bool isImmune(ConditionType_t type) const { return false; } - virtual bool isSuppress(ConditionType_t type) const { + virtual bool isSuppress(ConditionType_t type, bool attackerPlayer) const { return false; }; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index b3fa5b674db..65c86f9d7d6 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -455,7 +455,7 @@ float Player::getDefenseFactor() const { uint32_t Player::getClientIcons() { uint32_t icons = 0; for (const auto &condition : conditions) { - if (!isSuppress(condition->getType())) { + if (!isSuppress(condition->getType(), false)) { icons |= condition->getIcons(); } } diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 1b12ebf571d..36aafef1cd3 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -2920,7 +2920,7 @@ class Player final : public Creature, public Cylinder, public Bankable { return skillLoss ? static_cast(experience * getLostPercent()) : 0; } - bool isSuppress(ConditionType_t conditionType) const override; + bool isSuppress(ConditionType_t conditionType, bool attackerPlayer) const override; void addConditionSuppression(const std::array &addConditions); uint16_t getLookCorpse() const override;