diff --git a/data-canary/scripts/actions/other/destroy.lua b/data-canary/scripts/actions/other/destroy.lua index 587df2f5ea7..62af94ab101 100644 --- a/data-canary/scripts/actions/other/destroy.lua +++ b/data-canary/scripts/actions/other/destroy.lua @@ -250,7 +250,7 @@ local setting = { local destroy = Action() function destroy.onUse(player, item, fromPosition, target, toPosition, isHotkey) - return ActionsLib.destroyItem(player, target, toPosition) + return destroyItem(player, target, toPosition) end for index, value in ipairs(setting) do diff --git a/data-canary/scripts/actions/other/sewer.lua b/data-canary/scripts/actions/other/sewer.lua deleted file mode 100644 index 2868e887ae5..00000000000 --- a/data-canary/scripts/actions/other/sewer.lua +++ /dev/null @@ -1,12 +0,0 @@ -local sewer = Action() - -function sewer.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if item:getId() == 435 then - fromPosition.z = fromPosition.z + 1 - end - player:teleportTo(fromPosition, false) - return true -end - -sewer:id(435) -sewer:register() diff --git a/data-otservbr-global/lib/quests/soul_war.lua b/data-otservbr-global/lib/quests/soul_war.lua index f5b2d75f5ba..a6058bc4715 100644 --- a/data-otservbr-global/lib/quests/soul_war.lua +++ b/data-otservbr-global/lib/quests/soul_war.lua @@ -1455,7 +1455,7 @@ function Player:getSoulWarZoneMonster() return zoneMonsterName end -function Player:isInBoatSpot() +function Creature:isInBoatSpot() -- Get ebb and flow zone and check if player is in zone local zone = SoulWarQuest.ebbAndFlow.getZone() local tile = Tile(self:getPosition()) @@ -1464,11 +1464,11 @@ function Player:isInBoatSpot() groundId = tile:getGround():getId() end if zone and zone:isInZone(self:getPosition()) and tile and groundId == SoulWarQuest.ebbAndFlow.boatId then - logger.trace("Player {} is in boat spot", self:getName()) + logger.trace("Creature {} is in boat spot", self:getName()) return true end - logger.trace("Player {} is not in boat spot", self:getName()) + logger.trace("Creature {} is not in boat spot", self:getName()) return false end diff --git a/data-otservbr-global/scripts/actions/other/teleport.lua b/data-otservbr-global/scripts/actions/other/teleport.lua deleted file mode 100644 index 7e763f00594..00000000000 --- a/data-otservbr-global/scripts/actions/other/teleport.lua +++ /dev/null @@ -1,19 +0,0 @@ -local ladderTable = Game.getLadderIds() - -local upFloorIds = ladderTable - -local teleport = Action() - -function teleport.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if table.contains(upFloorIds, item.itemid) then - fromPosition:moveUpstairs() - else - fromPosition.z = fromPosition.z + 1 - end - player:teleportTo(fromPosition, false) - return true -end - -teleport:id(435) -teleport:id(unpack(ladderTable)) -teleport:register() diff --git a/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua b/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua index 91273ac4cbd..e5166038db2 100644 --- a/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua +++ b/data-otservbr-global/scripts/quests/soul_war/globalevent-ebb_and_flow_change_maps.lua @@ -18,17 +18,25 @@ local function updateWaterPoolsSize() end local function loadMapEmpty() - if SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then - local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() - for _, player in ipairs(players) do - if player:getPosition().z == 8 then - if player:isInBoatSpot() then - local teleportPosition = player:getPosition() - teleportPosition.z = 9 - player:teleportTo(teleportPosition) - logger.trace("Teleporting player to down.") + local playersInZone = SoulWarQuest.ebbAndFlow.getZone():countPlayers() + local monstersInZone = SoulWarQuest.ebbAndFlow.getZone():countMonsters() + if playersInZone > 0 or monstersInZone > 0 then + local creatures = SoulWarQuest.ebbAndFlow.getZone():getCreatures() + for _, creature in ipairs(creatures) do + local creatureMaster = creature:getMaster() + local player = creature:getPlayer() + if creature:isPlayer() or (creature:isMonster() and creatureMaster and creatureMaster:getPlayer()) then + if creature:getPosition().z == 8 then + if creature:isInBoatSpot() then + local teleportPosition = creature:getPosition() + teleportPosition.z = 9 + creature:teleportTo(teleportPosition) + logger.trace("Teleporting player to down.") + end + if player then + player:sendCreatureAppear() + end end - player:sendCreatureAppear() end end end @@ -72,22 +80,30 @@ local function findNearestRoomPosition(playerPosition) end local function loadMapInundate() - if SoulWarQuest.ebbAndFlow.getZone():countPlayers() > 0 then - local players = SoulWarQuest.ebbAndFlow.getZone():getPlayers() - for _, player in ipairs(players) do - local playerPosition = player:getPosition() - if playerPosition.z == 9 then - if player:isInBoatSpot() then - local nearestCenterPosition = findNearestRoomPosition(playerPosition) - player:teleportTo(nearestCenterPosition) - logger.trace("Teleporting player to the near center position room and updating tile.") - else - player:teleportTo(SoulWarQuest.ebbAndFlow.waitPosition) - logger.trace("Teleporting player to wait position and updating tile.") + local playersInZone = SoulWarQuest.ebbAndFlow.getZone():countPlayers() + local monstersInZone = SoulWarQuest.ebbAndFlow.getZone():countMonsters() + if playersInZone > 0 or monstersInZone > 0 then + local creatures = SoulWarQuest.ebbAndFlow.getZone():getCreatures() + for _, creature in ipairs(creatures) do + local creatureMaster = creature:getMaster() + local player = creature:getPlayer() + if creature:isPlayer() or (creature:isMonster() and creatureMaster and creatureMaster:getPlayer()) then + local creaturePosition = creature:getPosition() + if creaturePosition.z == 9 then + if creature:isInBoatSpot() then + local nearestCenterPosition = findNearestRoomPosition(creaturePosition) + creature:teleportTo(nearestCenterPosition) + logger.trace("Teleporting player to the near center position room and updating tile.") + else + creature:teleportTo(SoulWarQuest.ebbAndFlow.waitPosition) + logger.trace("Teleporting player to wait position and updating tile.") + end + creaturePosition:sendMagicEffect(CONST_ME_TELEPORT) + end + if player then + player:sendCreatureAppear() end - playerPosition:sendMagicEffect(CONST_ME_TELEPORT) end - player:sendCreatureAppear() end end diff --git a/data-canary/scripts/actions/other/ladder_up.lua b/data/scripts/actions/items/ladder_up.lua similarity index 71% rename from data-canary/scripts/actions/other/ladder_up.lua rename to data/scripts/actions/items/ladder_up.lua index 80d811fa741..5ec5f7c5b67 100644 --- a/data-canary/scripts/actions/other/ladder_up.lua +++ b/data/scripts/actions/items/ladder_up.lua @@ -1,9 +1,9 @@ -local setting = { 1948, 1968, 5542, 20474, 20475, 28656, 31262 } +local ladderTable = Game.getLadderIds() local ladder = Action() function ladder.onUse(player, item, fromPosition, target, toPosition, isHotkey) - if table.contains(setting, item.itemid) then + if table.contains(ladderTable, item.itemid) then fromPosition:moveUpstairs() else fromPosition.z = fromPosition.z + 1 @@ -18,8 +18,5 @@ function ladder.onUse(player, item, fromPosition, target, toPosition, isHotkey) return true end -for index, value in ipairs(setting) do - ladder:id(value) -end - +ladder:id(435, unpack(ladderTable)) ladder:register() diff --git a/data/scripts/spells/support/sharpshooter.lua b/data/scripts/spells/support/sharpshooter.lua index 568fec86e00..e5111781562 100644 --- a/data/scripts/spells/support/sharpshooter.lua +++ b/data/scripts/spells/support/sharpshooter.lua @@ -4,9 +4,9 @@ local combat = Combat() combat:setParameter(COMBAT_PARAM_EFFECT, CONST_ME_MAGIC_GREEN) combat:setParameter(COMBAT_PARAM_AGGRESSIVE, false) -local speed = Condition(CONDITION_HASTE) +local speed = Condition(CONDITION_PARALYZE) speed:setParameter(CONDITION_PARAM_TICKS, spellDuration) -speed:setFormula(0.7, 0, 0.7, 0) +speed:setFormula(0.7, 56, 0.7, 56) combat:addCondition(speed) local exhaustHealGroup = Condition(CONDITION_SPELLGROUPCOOLDOWN) diff --git a/src/creatures/combat/spells.cpp b/src/creatures/combat/spells.cpp index 327d97f3284..f522eac86a6 100644 --- a/src/creatures/combat/spells.cpp +++ b/src/creatures/combat/spells.cpp @@ -23,9 +23,6 @@ #include "lua/scripts/scripts.hpp" #include "lib/di/container.hpp" -std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyRegularBoost = { 0 }; -std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyUpgradedBoost = { 0 }; - Spells::Spells() = default; Spells::~Spells() = default; diff --git a/src/creatures/combat/spells.hpp b/src/creatures/combat/spells.hpp index 5d9edb70dd6..56ff1a330de 100644 --- a/src/creatures/combat/spells.hpp +++ b/src/creatures/combat/spells.hpp @@ -10,9 +10,7 @@ #pragma once #include "lua/creature/actions.hpp" - -enum class WheelSpellBoost_t : uint8_t; -enum class WheelSpellGrade_t : uint8_t; +#include "creatures/players/wheel/wheel_definitions.hpp" class InstantSpell; class RuneSpell; @@ -256,6 +254,8 @@ class Spell : public BaseSpell { bool pzLocked = false; bool whellOfDestinyUpgraded = false; + std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyRegularBoost = { 0 }; + std::array(WheelSpellBoost_t::TOTAL_COUNT)> wheelOfDestinyUpgradedBoost = { 0 }; private: uint32_t mana = 0; diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index d838f8b96a0..3ef1d64e982 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -2739,6 +2739,10 @@ uint16_t Player::getGrindingXpBoost() const { return grindingXpBoost; } +uint16_t Player::getDisplayGrindingXpBoost() const { + return std::clamp(grindingXpBoost * (baseXpGain / 100), 0, std::numeric_limits::max()); +} + void Player::setGrindingXpBoost(uint16_t value) { grindingXpBoost = std::min(std::numeric_limits::max(), value); } @@ -2747,6 +2751,10 @@ uint16_t Player::getXpBoostPercent() const { return xpBoostPercent; } +uint16_t Player::getDisplayXpBoostPercent() const { + return std::clamp(xpBoostPercent * (baseXpGain / 100), 0, std::numeric_limits::max()); +} + void Player::setXpBoostPercent(uint16_t percent) { xpBoostPercent = percent; } @@ -3517,7 +3525,7 @@ void Player::death(const std::shared_ptr &lastHitCreature) { } // Level loss - auto expLoss = static_cast(std::ceil((experience * deathLossPercent) / 100.)); + auto expLoss = static_cast(std::ceil(experience * deathLossPercent)); g_logger().debug("[{}] - experience lost {}", __FUNCTION__, expLoss); g_events().eventPlayerOnLoseExperience(static_self_cast(), expLoss); @@ -6323,9 +6331,9 @@ double Player::getLostPercent() const { g_logger().debug("[{}] - after promotion {}", __FUNCTION__, percentReduction); } - g_logger().debug("[{}] - total lost percent {}", __FUNCTION__, lossPercent - (lossPercent * percentReduction)); + g_logger().debug("[{}] - total lost percent {}", __FUNCTION__, (lossPercent * (1 - percentReduction)) / 100.); - return lossPercent - (lossPercent * percentReduction); + return (lossPercent * (1 - percentReduction)) / 100.; } [[nodiscard]] const std::string &Player::getGuildNick() const { diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 03f248cfa2f..6ab3be4ca7a 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -972,8 +972,10 @@ class Player final : public Creature, public Cylinder, public Bankable { uint16_t getVoucherXpBoost() const; void setVoucherXpBoost(uint16_t value); uint16_t getGrindingXpBoost() const; + uint16_t getDisplayGrindingXpBoost() const; void setGrindingXpBoost(uint16_t value); uint16_t getXpBoostPercent() const; + uint16_t getDisplayXpBoostPercent() const; void setXpBoostPercent(uint16_t percent); uint16_t getStaminaXpBoost() const; void setStaminaXpBoost(uint16_t value); diff --git a/src/io/io_wheel.cpp b/src/io/io_wheel.cpp index 2e1b57c79bc..cfcf6593010 100644 --- a/src/io/io_wheel.cpp +++ b/src/io/io_wheel.cpp @@ -58,7 +58,7 @@ namespace InternalPlayerWheel { return; } - auto spell = g_spells().getInstantSpellByName(name); + const auto &spell = g_spells().getInstantSpellByName(name); if (spell) { g_logger().trace("[{}] registering instant spell with name {}", __FUNCTION__, spell->getName()); // Increase data @@ -127,7 +127,7 @@ bool IOWheel::initializeGlobalData(bool reload /* = false*/) { // Register spells for druid for (const auto &data : getWheelBonusData().spells.druid) { for (size_t i = 1; i < 3; ++i) { - const auto grade = data.grade[i]; + const auto &grade = data.grade[i]; InternalPlayerWheel::registerWheelSpellTable(grade, data.name, static_cast(i)); } } diff --git a/src/items/weapons/weapons.cpp b/src/items/weapons/weapons.cpp index 4eb84d246c6..2ec09945f36 100644 --- a/src/items/weapons/weapons.cpp +++ b/src/items/weapons/weapons.cpp @@ -942,35 +942,7 @@ void WeaponWand::configureWeapon(const ItemType &it) { } int32_t WeaponWand::getWeaponDamage(const std::shared_ptr &player, const std::shared_ptr &, const std::shared_ptr &, bool maxDamage /* = false*/) const { - if (!g_configManager().getBoolean(TOGGLE_CHAIN_SYSTEM)) { - // Returns maximum damage or a random value between minChange and maxChange - return maxDamage ? -maxChange : -normal_random(minChange, maxChange); - } - - // If chain system is enabled, calculates magic-based damage - int32_t attackSkill = 0; - int32_t attackValue = 0; - float attackFactor = 0.0; - [[maybe_unused]] int16_t elementAttack = 0; - [[maybe_unused]] CombatDamage combatDamage; - calculateSkillFormula(player, attackSkill, attackValue, attackFactor, elementAttack, combatDamage); - - const auto magLevel = player->getMagicLevel(); - const auto level = player->getLevel(); - - // Check if level is greater than zero before performing division - const auto levelDivision = level > 0 ? level / 5.0 : 0.0; - - const auto totalAttackValue = magLevel + attackValue; - - // Check if magLevel is greater than zero before performing division - const auto magicLevelDivision = totalAttackValue > 0 ? totalAttackValue / 3.0 : 0.0; - - const double min = levelDivision + magicLevelDivision; - const double max = levelDivision + totalAttackValue; - - // Returns the calculated maximum damage or a random value between the calculated minimum and maximum - return maxDamage ? -max : -normal_random(min, max); + return maxDamage ? -maxChange : -normal_random(minChange, maxChange); } int16_t WeaponWand::getElementDamageValue() const { diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 727c1cc0097..2f7ff9e2479 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -3480,8 +3480,8 @@ void ProtocolGame::sendCyclopediaCharacterGeneralStats() { msg.add(player->getLevel()); msg.addByte(player->getLevelPercent()); msg.add(player->getBaseXpGain()); // BaseXPGainRate - msg.add(player->getGrindingXpBoost()); // LowLevelBonus - msg.add(player->getXpBoostPercent()); // XPBoost + msg.add(player->getDisplayGrindingXpBoost()); // LowLevelBonus + msg.add(player->getDisplayXpBoostPercent()); // XPBoost msg.add(player->getStaminaXpBoost()); // StaminaMultiplier(100=x1.0) msg.add(player->getXpBoostTime()); // xpBoostRemainingTime msg.addByte(player->getXpBoostTime() > 0 ? 0x00 : 0x01); // canBuyXpBoost @@ -5745,14 +5745,23 @@ void ProtocolGame::sendForgeHistory(uint8_t page) { page = page + 1; auto historyVector = player->getForgeHistory(); auto historyVectorLen = historyVector.size(); - uint16_t lastPage = (1 < std::floor((historyVectorLen - 1) / 9) + 1) ? static_cast(std::floor((historyVectorLen - 1) / 9) + 1) : 1; - uint16_t currentPage = (lastPage < page) ? lastPage : page; + + uint16_t currentPage = 1; + uint16_t lastPage = 1; + uint16_t pageFirstEntry = 0; + uint16_t pageLastEntry = 0; std::vector historyPerPage; - uint16_t pageFirstEntry = (0 < historyVectorLen - (currentPage - 1) * 9) ? historyVectorLen - (currentPage - 1) * 9 : 0; - uint16_t pageLastEntry = (0 < historyVectorLen - currentPage * 9) ? historyVectorLen - currentPage * 9 : 0; - for (uint16_t entry = pageFirstEntry; entry > pageLastEntry; --entry) { - historyPerPage.emplace_back(historyVector[entry - 1]); + if (historyVectorLen > 0) { + lastPage = std::clamp(std::floor((historyVectorLen - 1) / 9) + 1, 0, std::numeric_limits::max()); + currentPage = (lastPage < page) ? lastPage : page; + + pageFirstEntry = std::clamp(historyVectorLen - (currentPage - 1) * 9, 0, std::numeric_limits::max()); + pageLastEntry = historyVectorLen > currentPage * 9 ? std::clamp(historyVectorLen - currentPage * 9, 0, std::numeric_limits::max()) : 0; + + for (uint16_t entry = pageFirstEntry; entry > pageLastEntry; --entry) { + historyPerPage.emplace_back(historyVector[entry - 1]); + } } auto historyPageToSend = historyPerPage.size(); @@ -7840,8 +7849,8 @@ void ProtocolGame::AddPlayerStats(NetworkMessage &msg) { msg.add(player->getVoucherXpBoost()); // xp voucher } - msg.add(player->getGrindingXpBoost()); // low level bonus - msg.add(player->getXpBoostPercent()); // xp boost + msg.add(player->getDisplayGrindingXpBoost()); // low level bonus + msg.add(player->getDisplayXpBoostPercent()); // xp boost msg.add(player->getStaminaXpBoost()); // stamina multiplier (100 = 1.0x) if (!oldProtocol) {