From 21f0a50388b10c06041ab073eebb93935fb14072 Mon Sep 17 00:00:00 2001 From: mattyx14 Date: Thu, 28 Nov 2024 14:53:04 -0600 Subject: [PATCH] fix loops and others from otserv --- .../ferumbras_ascension/bosses/shulgrax.lua | 1 - .../the_secret_library/bosses/ghulosh.lua | 1 - .../quests/the_secret_library/lokathmor.lua | 1 - data/libs/functions/boss_lever.lua | 2 +- src/creatures/combat/combat.cpp | 12 +- src/creatures/combat/spells.cpp | 3 - src/creatures/combat/spells.hpp | 6 +- src/creatures/creature.cpp | 50 ++++---- src/creatures/players/player.cpp | 22 +++- src/creatures/players/player.hpp | 2 + src/creatures/players/wheel/player_wheel.cpp | 11 +- src/game/game.cpp | 119 +++++++++++------- src/game/movement/teleport.cpp | 20 ++- src/io/functions/iologindata_load_player.cpp | 12 +- src/io/io_wheel.cpp | 4 +- src/io/iomarket.cpp | 6 +- src/items/containers/container.cpp | 19 ++- src/items/containers/mailbox/mailbox.cpp | 4 +- src/items/weapons/weapons.cpp | 30 +---- .../functions/core/game/config_functions.cpp | 2 +- src/lua/functions/lua_functions_loader.hpp | 4 +- src/lua/scripts/luascript.cpp | 2 +- src/map/house/house.cpp | 5 +- src/pch.hpp | 15 --- src/server/network/protocol/protocolgame.cpp | 29 +++-- .../network/protocol/protocolstatus.cpp | 2 +- src/utils/definitions.hpp | 2 + src/utils/pugicast.hpp | 6 +- 28 files changed, 211 insertions(+), 181 deletions(-) diff --git a/data-otxserver/monster/quests/ferumbras_ascension/bosses/shulgrax.lua b/data-otxserver/monster/quests/ferumbras_ascension/bosses/shulgrax.lua index 1eef0866c..2168dcc3b 100644 --- a/data-otxserver/monster/quests/ferumbras_ascension/bosses/shulgrax.lua +++ b/data-otxserver/monster/quests/ferumbras_ascension/bosses/shulgrax.lua @@ -81,7 +81,6 @@ monster.loot = { { id = 6558, chance = 10000 }, -- flask of demonic blood { id = 6558, chance = 10000 }, -- flask of demonic blood { id = 6558, chance = 10000 }, -- flask of demonic blood - { id = 17838, chance = 1800 }, -- unknown item { id = 3019, chance = 1000 }, -- demonbone amulet { id = 3026, chance = 12000, maxCount = 8 }, -- white pearl { id = 3029, chance = 12000, maxCount = 9 }, -- small sapphire diff --git a/data-otxserver/monster/quests/the_secret_library/bosses/ghulosh.lua b/data-otxserver/monster/quests/the_secret_library/bosses/ghulosh.lua index 607170459..fe80352ff 100644 --- a/data-otxserver/monster/quests/the_secret_library/bosses/ghulosh.lua +++ b/data-otxserver/monster/quests/the_secret_library/bosses/ghulosh.lua @@ -95,7 +95,6 @@ monster.loot = { { name = "butcher's axe", chance = 1000 }, { name = "dreaded cleaver", chance = 1000 }, { name = "mercenary sword", chance = 1000 }, - { id = 28341, chance = 1000 }, -- tessellated wall { name = "slightly rusted shield", chance = 5880 }, { name = "slightly rusted helmet", chance = 35290 }, { name = "epaulette", chance = 500 }, diff --git a/data-otxserver/monster/quests/the_secret_library/lokathmor.lua b/data-otxserver/monster/quests/the_secret_library/lokathmor.lua index 7df232587..8ef0357fc 100644 --- a/data-otxserver/monster/quests/the_secret_library/lokathmor.lua +++ b/data-otxserver/monster/quests/the_secret_library/lokathmor.lua @@ -100,7 +100,6 @@ monster.loot = { { name = "dreaded cleaver", chance = 30000 }, { name = "slightly rusted shield", chance = 26670 }, { name = "wand of inferno", chance = 30000 }, - { id = 28341, chance = 1000 }, -- tessellated wall { name = "sturdy book", chance = 1000 }, } diff --git a/data/libs/functions/boss_lever.lua b/data/libs/functions/boss_lever.lua index 40bc8e0b4..ae8a89d0e 100644 --- a/data/libs/functions/boss_lever.lua +++ b/data/libs/functions/boss_lever.lua @@ -177,7 +177,7 @@ function BossLever:onUse(player) return true end - local isAccountNormal = creature:getAccountType() == ACCOUNT_TYPE_NORMAL + local isAccountNormal = creature:getAccountType() < ACCOUNT_TYPE_GAMEMASTER if isAccountNormal and creature:getLevel() < self.requiredLevel then local message = "All players need to be level " .. self.requiredLevel .. " or higher." creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, message) diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 34a28398e..6b7667a71 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -1066,7 +1066,7 @@ void Combat::setupChain(const std::shared_ptr &weapon) { } bool Combat::doCombatChain(const std::shared_ptr &caster, const std::shared_ptr &target, bool aggressive) const { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (!params.chainCallback) { return false; } @@ -1469,7 +1469,7 @@ void Combat::setRuneSpellName(const std::string &value) { std::vector>> Combat::pickChainTargets(const std::shared_ptr &caster, const CombatParams ¶ms, uint8_t chainDistance, uint8_t maxTargets, bool backtracking, bool aggressive, const std::shared_ptr &initialTarget /* = nullptr */) { Benchmark bm_pickChain; - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (!caster) { return {}; } @@ -1512,7 +1512,7 @@ std::vector>> Combat::pickChainTargets } if (closestSpectator) { - g_logger().trace("[{}] closestSpectator: {}", __METHOD_NAME__, closestSpectator->getName()); + g_logger().trace("[{}] closestSpectator: {}", __FUNCTION__, closestSpectator->getName()); bool found = false; for (auto &[pos, vec] : resultMap) { @@ -1531,7 +1531,7 @@ std::vector>> Combat::pickChainTargets continue; } if (backtracking) { - g_logger().debug("[{}] backtracking", __METHOD_NAME__); + g_logger().debug("[{}] backtracking", __FUNCTION__); targets.pop_back(); backtrackingAttempts--; continue; @@ -1539,7 +1539,7 @@ std::vector>> Combat::pickChainTargets break; } - g_logger().debug("[{}] resultMap: {} in {} ms", __METHOD_NAME__, resultMap.size(), bm_pickChain.duration()); + g_logger().debug("[{}] resultMap: {} in {} ms", __FUNCTION__, resultMap.size(), bm_pickChain.duration()); return resultMap; } @@ -2221,7 +2221,7 @@ void MagicField::onStepInField(const std::shared_ptr &creature) { } void Combat::applyExtensions(const std::shared_ptr &caster, const std::shared_ptr &target, CombatDamage &damage, const CombatParams ¶ms) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (damage.extension || !caster || damage.primary.type == COMBAT_HEALING) { return; } diff --git a/src/creatures/combat/spells.cpp b/src/creatures/combat/spells.cpp index 327d97f32..f522eac86 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 5d9edb70d..56ff1a330 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/creature.cpp b/src/creatures/creature.cpp index 2081b0572..32f3c598b 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -35,7 +35,7 @@ Creature::~Creature() { } bool Creature::canSee(const Position &myPos, const Position &pos, int32_t viewRangeX, int32_t viewRangeY) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (myPos.z <= MAP_INIT_SURFACE_LAYER) { // we are on ground level or above (7 -> 0) // view is from 7 -> 0 @@ -95,7 +95,7 @@ int32_t Creature::getWalkSize() { } void Creature::onThink(uint32_t interval) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &followCreature = getFollowCreature(); const auto &master = getMaster(); @@ -168,7 +168,7 @@ void Creature::onCreatureWalk() { checkingWalkCreature = true; - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); g_dispatcher().addWalkEvent([self = getCreature(), this] { checkingWalkCreature = false; @@ -287,7 +287,7 @@ void Creature::stopEventWalk() { } void Creature::onCreatureAppear(const std::shared_ptr &creature, bool isLogin) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (creature.get() == this) { if (isLogin) { setLastPosition(getPosition()); @@ -296,7 +296,7 @@ void Creature::onCreatureAppear(const std::shared_ptr &creature, bool } void Creature::onRemoveCreature(const std::shared_ptr &creature, bool) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); onCreatureDisappear(creature, true); // Update player from monster target list (avoid memory usage after clean) @@ -307,7 +307,7 @@ void Creature::onRemoveCreature(const std::shared_ptr &creature, bool) } void Creature::onCreatureDisappear(const std::shared_ptr &creature, bool isLogout) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (getAttackedCreature() == creature) { setAttackedCreature(nullptr); onAttackedCreatureDisappear(isLogout); @@ -320,7 +320,7 @@ void Creature::onCreatureDisappear(const std::shared_ptr &creature, bo } void Creature::onChangeZone(ZoneType_t zone) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &attackedCreature = getAttackedCreature(); if (attackedCreature && zone == ZONE_PROTECTION) { onCreatureDisappear(attackedCreature, false); @@ -328,7 +328,7 @@ void Creature::onChangeZone(ZoneType_t zone) { } void Creature::onAttackedCreatureChangeZone(ZoneType_t zone) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (zone == ZONE_PROTECTION) { const auto &attackedCreature = getAttackedCreature(); if (attackedCreature) { @@ -338,7 +338,7 @@ void Creature::onAttackedCreatureChangeZone(ZoneType_t zone) { } void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (hasSummons()) { std::vector> despawnMonsterList; for (const auto &summon : getSummons()) { @@ -385,7 +385,7 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { } void Creature::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (creature.get() == this) { lastStep = OTSYS_TIME(); lastStepCost = 1; @@ -447,7 +447,7 @@ void Creature::onCreatureMove(const std::shared_ptr &creature, const s } void Creature::onDeath() { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); bool lastHitUnjustified = false; bool mostDamageUnjustified = false; const auto &lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); @@ -585,7 +585,7 @@ void Creature::onDeath() { } bool Creature::dropCorpse(const std::shared_ptr &lastHitCreature, const std::shared_ptr &mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (!lootDrop && getMonster()) { if (getMaster()) { // Scripting event onDeath @@ -882,7 +882,7 @@ void Creature::goToFollowCreature_async(std::function &&onComplete) { } void Creature::goToFollowCreature() { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &followCreature = getFollowCreature(); if (!followCreature) { return; @@ -937,7 +937,7 @@ bool Creature::canFollowMaster() const { } bool Creature::setFollowCreature(const std::shared_ptr &creature) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (creature) { if (getFollowCreature() == creature) { return true; @@ -1086,7 +1086,7 @@ void Creature::onAttackedCreatureDrainHealth(const std::shared_ptr &ta } void Creature::onAttackedCreatureKilled(const std::shared_ptr &target) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (target != getCreature()) { uint64_t gainExp = target->getGainedExperience(static_self_cast()); onGainExperience(gainExp, target); @@ -1094,7 +1094,7 @@ void Creature::onAttackedCreatureKilled(const std::shared_ptr &target) } bool Creature::deprecatedOnKilledCreature(const std::shared_ptr &target, bool lastHit) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &master = getMaster(); if (master) { master->deprecatedOnKilledCreature(target, lastHit); @@ -1109,7 +1109,7 @@ bool Creature::deprecatedOnKilledCreature(const std::shared_ptr &targe } void Creature::onGainExperience(uint64_t gainExp, const std::shared_ptr &target) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &master = getMaster(); if (gainExp == 0 || !master) { return; @@ -1140,7 +1140,7 @@ void Creature::onGainExperience(uint64_t gainExp, const std::shared_ptr &newMaster, bool reloadCreature /* = false*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); // Persists if this creature has ever been a summon this->summoned = true; const auto &oldMaster = getMaster(); @@ -1173,7 +1173,7 @@ bool Creature::setMaster(const std::shared_ptr &newMaster, bool reload } bool Creature::addCondition(const std::shared_ptr &condition, bool attackerPlayer /* = false*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (condition == nullptr) { return false; } @@ -1211,7 +1211,7 @@ bool Creature::addCombatCondition(const std::shared_ptr &condition, b } void Creature::removeCondition(ConditionType_t type) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); auto it = conditions.begin(), end = conditions.end(); while (it != end) { std::shared_ptr condition = *it; @@ -1229,7 +1229,7 @@ void Creature::removeCondition(ConditionType_t type) { } void Creature::removeCondition(ConditionType_t conditionType, ConditionId_t conditionId, bool force /* = false*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); auto it = conditions.begin(); const auto end = conditions.end(); while (it != end) { @@ -1292,7 +1292,7 @@ std::shared_ptr Creature::getCondition(ConditionType_t type) const { } std::shared_ptr Creature::getCondition(ConditionType_t type, ConditionId_t conditionId, uint32_t subId /* = 0*/) const { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); for (const auto &condition : conditions) { if (condition->getType() == type && condition->getId() == conditionId && condition->getSubId() == subId) { return condition; @@ -1312,7 +1312,7 @@ std::vector> Creature::getConditionsByType(ConditionT } void Creature::executeConditions(uint32_t interval) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); auto it = conditions.begin(), end = conditions.end(); while (it != end) { std::shared_ptr condition = *it; @@ -1331,7 +1331,7 @@ void Creature::executeConditions(uint32_t interval) { } bool Creature::hasCondition(ConditionType_t type, uint32_t subId /* = 0*/) const { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (isSuppress(type, false)) { return false; } @@ -1607,7 +1607,7 @@ ZoneType_t Creature::getZoneType() { } bool Creature::getPathTo(const Position &targetPos, std::vector &dirList, const FindPathParams &fpp) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (fpp.maxSearchDist != 0 || fpp.keepDistance) { return g_game().map.getPathMatchingCond(getCreature(), targetPos, dirList, FrozenPathingConditionCall(targetPos), fpp); } diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index d838f8b96..4335db2bd 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); @@ -5031,10 +5039,14 @@ ItemsTierCountList Player::getDepotInboxItemsId() const { ItemsTierCountList itemMap; const auto &inboxPtr = getInbox(); - const auto &container = inboxPtr->getContainer(); + const auto &container = inboxPtr ? inboxPtr->getContainer() : nullptr; if (container) { for (ContainerIterator it = container->iterator(); it.hasNext(); it.advance()) { const auto &item = *it; + if (!item) { + continue; + } + (itemMap[item->getID()])[item->getTier()] += Item::countByType(item, -1); } } @@ -6323,9 +6335,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 { @@ -9065,7 +9077,7 @@ void Player::forgeFuseItems(ForgeAction_t actionType, uint16_t firstItemId, uint returnValue = g_game().internalAddItem(static_self_cast(), exaltationContainer, INDEX_WHEREEVER); if (returnValue != RETURNVALUE_NOERROR) { - g_logger().error("Failed to add exaltation chest to player with name {}", fmt::underlying(ITEM_EXALTATION_CHEST), getName()); + g_logger().error("Failed to add exaltation chest to player with name {}", getName()); sendCancelMessage(getReturnMessage(returnValue)); sendForgeError(RETURNVALUE_CONTACTADMINISTRATOR); return; diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 03f248cfa..6ab3be4ca 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/creatures/players/wheel/player_wheel.cpp b/src/creatures/players/wheel/player_wheel.cpp index 7d39720dc..165a43f06 100644 --- a/src/creatures/players/wheel/player_wheel.cpp +++ b/src/creatures/players/wheel/player_wheel.cpp @@ -1448,8 +1448,13 @@ void PlayerWheel::improveGemGrade(WheelFragmentType_t fragmentType, uint8_t pos) return; } + if (value == 0 && quantity == 0) { + g_logger().error("[{}] Player {} trying to upgrade gem to grade greater than 3", std::source_location::current().function_name(), m_player.getName()); + return; + } + if (!m_player.hasItemCountById(fragmentId, quantity, true)) { - g_logger().error("[{}] Player {} does not have the required {} fragments with id {}", __FUNCTION__, m_player.getName(), quantity, fragmentId); + g_logger().error("[{}] Player {} does not have the required {} fragments with id {}", std::source_location::current().function_name(), m_player.getName(), quantity, fragmentId); return; } @@ -1477,7 +1482,7 @@ std::tuple PlayerWheel::getLesserGradeCost(uint8_t grade) const { case 3: return std::make_tuple(30000000, 30); default: - throw std::invalid_argument("Invalid level for Lesser Fragment."); + return {}; } } @@ -1490,7 +1495,7 @@ std::tuple PlayerWheel::getGreaterGradeCost(uint8_t grade) const { case 3: return std::make_tuple(75000000, 30); default: - throw std::invalid_argument("Invalid level for Greater Fragment."); + return {}; } } diff --git a/src/game/game.cpp b/src/game/game.cpp index 77a277c69..e69654a47 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1161,7 +1161,7 @@ bool Game::internalPlaceCreature(const std::shared_ptr &creature, cons } bool Game::placeCreature(const std::shared_ptr &creature, const Position &pos, bool extendedPos /*=false*/, bool forced /*= false*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (!internalPlaceCreature(creature, pos, extendedPos, forced)) { return false; } @@ -1188,7 +1188,7 @@ bool Game::placeCreature(const std::shared_ptr &creature, const Positi } bool Game::removeCreature(const std::shared_ptr &creature, bool isLogout /* = true*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (!creature || creature->isRemoved()) { return false; } @@ -1256,7 +1256,7 @@ bool Game::removeCreature(const std::shared_ptr &creature, bool isLogo } void Game::executeDeath(uint32_t creatureId) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); std::shared_ptr creature = getCreatureByID(creatureId); if (creature && !creature->isRemoved()) { afterCreatureZoneChange(creature, creature->getZones(), {}); @@ -1265,7 +1265,7 @@ void Game::executeDeath(uint32_t creatureId) { } void Game::playerTeleport(uint32_t playerId, const Position &newPosition) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &player = getPlayerByID(playerId); if (!player || !player->hasFlag(PlayerFlags_t::CanMapClickTeleport)) { return; @@ -1278,7 +1278,7 @@ void Game::playerTeleport(uint32_t playerId, const Position &newPosition) { } void Game::playerInspectItem(const std::shared_ptr &player, const Position &pos) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const std::shared_ptr &thing = internalGetThing(player, pos, 0, 0, STACKPOS_TOPDOWN_ITEM); if (!thing) { player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE); @@ -1295,7 +1295,7 @@ void Game::playerInspectItem(const std::shared_ptr &player, const Positi } void Game::playerInspectItem(const std::shared_ptr &player, uint16_t itemId, uint8_t itemCount, bool cyclopedia) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); player->sendItemInspection(itemId, itemCount, nullptr, cyclopedia); } @@ -1349,7 +1349,7 @@ FILELOADER_ERRORS Game::loadAppearanceProtobuf(const std::string &file) { } void Game::playerMoveThing(uint32_t playerId, const Position &fromPos, uint16_t itemId, uint8_t fromStackPos, const Position &toPos, uint8_t count) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &player = getPlayerByID(playerId); if (!player) { return; @@ -1434,7 +1434,7 @@ void Game::playerMoveCreatureByID(uint32_t playerId, uint32_t movingCreatureId, } void Game::playerMoveCreature(const std::shared_ptr &player, const std::shared_ptr &movingCreature, const Position &movingCreatureOrigPos, const std::shared_ptr &toTile) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); g_dispatcher().addWalkEvent([=, this] { if (!player->canDoAction()) { @@ -1590,7 +1590,7 @@ ReturnValue Game::internalMoveCreature(const std::shared_ptr &creature } ReturnValue Game::internalMoveCreature(const std::shared_ptr &creature, const std::shared_ptr &toTile, uint32_t flags /*= 0*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (creature->hasCondition(CONDITION_ROOTED)) { return RETURNVALUE_NOTPOSSIBLE; } @@ -2009,7 +2009,7 @@ ReturnValue Game::checkMoveItemToCylinder(const std::shared_ptr &player, } ReturnValue Game::internalMoveItem(std::shared_ptr fromCylinder, std::shared_ptr toCylinder, int32_t index, const std::shared_ptr &item, uint32_t count, std::shared_ptr* movedItem, uint32_t flags /*= 0*/, const std::shared_ptr &actor /*=nullptr*/, const std::shared_ptr &tradeItem /* = nullptr*/, bool checkTile /* = true*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (fromCylinder == nullptr) { g_logger().error("[{}] fromCylinder is nullptr", __FUNCTION__); return RETURNVALUE_NOTPOSSIBLE; @@ -2271,7 +2271,7 @@ ReturnValue Game::internalAddItem(std::shared_ptr toCylinder, const st } ReturnValue Game::internalAddItem(std::shared_ptr toCylinder, const std::shared_ptr &item, int32_t index, uint32_t flags, bool test, uint32_t &remainderCount) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (toCylinder == nullptr) { g_logger().error("[{}] fromCylinder is nullptr", __FUNCTION__); return RETURNVALUE_NOTPOSSIBLE; @@ -2359,7 +2359,7 @@ ReturnValue Game::internalAddItem(std::shared_ptr toCylinder, const st ReturnValue Game::internalRemoveItem(const std::shared_ptr &items, int32_t count /*= -1*/, bool test /*= false*/, uint32_t flags /*= 0*/, bool force /*= false*/) { auto item = items; - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (item == nullptr) { g_logger().debug("{} - Item is nullptr", __FUNCTION__); return RETURNVALUE_NOTPOSSIBLE; @@ -2439,7 +2439,7 @@ std::tuple Game::addItemBatch(const std::shared return std::make_tuple(ret, totalAdded, containersCreated); } - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &player = toCylinder->getPlayer(); bool dropping = false; auto setupDestination = [&]() -> std::shared_ptr { @@ -2519,7 +2519,7 @@ std::tuple Game::addItemBatch(const std::shared } std::tuple Game::createItemBatch(const std::shared_ptr &toCylinder, const std::vector> &itemCounts, uint32_t flags /* = 0 */, bool dropOnMap /* = true */, uint32_t autoContainerId /* = 0 */) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); std::vector> items; for (const auto &[itemId, count, subType] : itemCounts) { const auto &itemType = Item::items[itemId]; @@ -2553,7 +2553,7 @@ std::tuple Game::createItem(const std::shared_p } ReturnValue Game::internalPlayerAddItem(const std::shared_ptr &player, const std::shared_ptr &item, bool dropOnMap /*= true*/, Slots_t slot /*= CONST_SLOT_WHEREEVER*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); uint32_t remainderCount = 0; ReturnValue ret; if (slot == CONST_SLOT_WHEREEVER) { @@ -2585,7 +2585,7 @@ ReturnValue Game::internalPlayerAddItem(const std::shared_ptr &player, c } std::shared_ptr Game::findItemOfType(const std::shared_ptr &cylinder, uint16_t itemId, bool depthSearch /*= true*/, int32_t subType /*= -1*/) const { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (cylinder == nullptr) { g_logger().error("[{}] Cylinder is nullptr", __FUNCTION__); return nullptr; @@ -2751,7 +2751,7 @@ void Game::addMoney(const std::shared_ptr &cylinder, uint64_t money, u } std::shared_ptr Game::transformItem(std::shared_ptr item, uint16_t newId, int32_t newCount /*= -1*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (item->getID() == newId && (newCount == -1 || (newCount == item->getSubType() && newCount != 0))) { // chargeless item placed on map = infinite return item; } @@ -2889,7 +2889,7 @@ std::shared_ptr Game::transformItem(std::shared_ptr item, uint16_t n } ReturnValue Game::internalTeleport(const std::shared_ptr &thing, const Position &newPos, bool pushMove /* = true*/, uint32_t flags /*= 0*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (thing == nullptr) { g_logger().error("[{}] thing is nullptr", __FUNCTION__); return RETURNVALUE_NOTPOSSIBLE; @@ -3409,18 +3409,22 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* = const auto &slotItem = player->getInventoryItem(slot); const auto &equipItem = searchForItem(backpack, it.id, hasTier, tier); ReturnValue ret = RETURNVALUE_NOERROR; + if (slotItem && slotItem->getID() == it.id && (!it.stackable || slotItem->getItemCount() == slotItem->getStackSize() || !equipItem)) { ret = internalMoveItem(slotItem->getParent(), player, CONST_SLOT_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr); g_logger().debug("Item {} was unequipped", slotItem->getName()); } else if (equipItem) { // Shield slot item const auto &rightItem = player->getInventoryItem(CONST_SLOT_RIGHT); + // Check Ammo item if (it.weaponType == WEAPON_AMMO) { if (rightItem && rightItem->isQuiver()) { ret = internalMoveItem(equipItem->getParent(), rightItem->getContainer(), 0, equipItem, equipItem->getItemCount(), nullptr); } } else { + const auto &leftItem = player->getInventoryItem(CONST_SLOT_LEFT); + const int32_t &slotPosition = equipItem->getSlotPosition(); // Checks if a two-handed item is being equipped in the left slot when the right slot is already occupied and move to backpack if ( @@ -3429,10 +3433,35 @@ void Game::playerEquipItem(uint32_t playerId, uint16_t itemId, bool hasTier /* = && rightItem && !(it.weaponType == WEAPON_DISTANCE) && !rightItem->isQuiver() + && (!leftItem || leftItem->getWeaponType() != WEAPON_DISTANCE) ) { ret = internalCollectManagedItems(player, rightItem, getObjectCategory(rightItem), false); } + // Check if trying to equip a quiver while another quiver is already equipped in the right slot + if (slot == CONST_SLOT_RIGHT && rightItem && rightItem->isQuiver() && it.isQuiver()) { + // Replace the existing quiver with the new one + ret = internalMoveItem(rightItem->getParent(), player, INDEX_WHEREEVER, rightItem, rightItem->getItemCount(), nullptr); + if (ret == RETURNVALUE_NOERROR) { + g_logger().debug("Quiver {} was unequipped to equip new quiver", rightItem->getName()); + } else { + player->sendCancelMessage(ret); + return; + } + } else { + // Check if trying to equip a shield while a two-handed weapon is equipped in the left slot + if (slot == CONST_SLOT_RIGHT && leftItem && leftItem->getSlotPosition() & SLOTP_TWO_HAND) { + // Unequip the two-handed weapon from the left slot + ret = internalMoveItem(leftItem->getParent(), player, INDEX_WHEREEVER, leftItem, leftItem->getItemCount(), nullptr); + if (ret == RETURNVALUE_NOERROR) { + g_logger().debug("Two-handed weapon {} was unequipped to equip shield", leftItem->getName()); + } else { + player->sendCancelMessage(ret); + return; + } + } + } + if (slotItem) { ret = internalMoveItem(slotItem->getParent(), player, INDEX_WHEREEVER, slotItem, slotItem->getItemCount(), nullptr); g_logger().debug("Item {} was moved back to player", slotItem->getName()); @@ -3676,7 +3705,7 @@ void Game::playerStopAutoWalk(uint32_t playerId) { } void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t fromStackPos, uint16_t fromItemId, const Position &toPos, uint8_t toStackPos, uint16_t toItemId) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &player = getPlayerByID(playerId); if (!player) { return; @@ -3821,7 +3850,7 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f } void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPos, uint8_t index, uint16_t itemId) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &player = getPlayerByID(playerId); if (!player) { return; @@ -3931,7 +3960,7 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo } void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uint8_t fromStackPos, uint32_t creatureId, uint16_t itemId) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &player = getPlayerByID(playerId); if (!player) { return; @@ -5285,7 +5314,7 @@ void Game::internalCloseTrade(const std::shared_ptr &player) { } void Game::playerBuyItem(uint32_t playerId, uint16_t itemId, uint8_t count, uint16_t amount, bool ignoreCap /* = false*/, bool inBackpacks /* = false*/) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (amount == 0) { return; } @@ -5341,7 +5370,7 @@ void Game::playerBuyItem(uint32_t playerId, uint16_t itemId, uint8_t count, uint } void Game::playerSellItem(uint32_t playerId, uint16_t itemId, uint8_t count, uint16_t amount, bool ignoreEquipped) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (amount == 0) { return; } @@ -6445,14 +6474,14 @@ void Game::addCreatureCheck(const std::shared_ptr &creature) { } void Game::removeCreatureCheck(const std::shared_ptr &creature) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); if (creature->inCheckCreaturesVector.load()) { creature->creatureCheck.store(false); } } void Game::checkCreatures() { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); static size_t index = 0; std::erase_if(checkCreatureLists[index], [this](const std::shared_ptr creature) { @@ -7428,10 +7457,6 @@ bool Game::combatChangeHealth(const std::shared_ptr &attacker, const s target->drainHealth(attacker, realDamage); if (realDamage > 0 && targetMonster) { - if (attackerPlayer && attackerPlayer->getPlayer()) { - attackerPlayer->updateImpactTracker(damage.secondary.type, damage.secondary.value); - } - if (targetMonster->israndomStepping()) { targetMonster->setIgnoreFieldDamage(true); } @@ -9000,7 +9025,7 @@ void Game::playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t ite return; } - std::shared_ptr depotLocker = player->getDepotLocker(player->getLastDepotId()); + const std::shared_ptr &depotLocker = player->getDepotLocker(player->getLastDepotId()); if (depotLocker == nullptr) { offerStatus << "Depot locker is nullptr for player " << player->getName(); return; @@ -9083,6 +9108,7 @@ void Game::playerCancelMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 return; } + const auto &playerInbox = player->getInbox(); if (offer.type == MARKETACTION_BUY) { player->setBankBalance(player->getBankBalance() + offer.price * offer.amount); g_metrics().addCounter("balance_decrease", offer.price * offer.amount, { { "player", player->getName() }, { "context", "market_purchase" } }); @@ -9099,10 +9125,11 @@ void Game::playerCancelMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 player->getAccount()->addCoins(CoinType::Transferable, offer.amount, ""); } else if (it.stackable) { uint16_t tmpAmount = offer.amount; + while (tmpAmount > 0) { int32_t stackCount = std::min(it.stackSize, tmpAmount); const auto &item = Item::CreateItem(it.id, stackCount); - if (internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { + if (internalAddItem(playerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { break; } @@ -9122,7 +9149,7 @@ void Game::playerCancelMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 for (uint16_t i = 0; i < offer.amount; ++i) { const auto &item = Item::CreateItem(it.id, subType); - if (internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { + if (internalAddItem(playerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { break; } @@ -9180,35 +9207,41 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 return; } + const auto &playerInbox = player->getInbox(); + uint64_t totalPrice = offer.price * amount; // The player has an offer to by something and someone is going to sell to item type // so the market action is 'buy' as who created the offer is buying. if (offer.type == MARKETACTION_BUY) { - std::shared_ptr depotLocker = player->getDepotLocker(player->getLastDepotId()); + const std::shared_ptr &depotLocker = player->getDepotLocker(player->getLastDepotId()); if (depotLocker == nullptr) { offerStatus << "Depot locker is nullptr"; return; } - std::shared_ptr buyerPlayer = getPlayerByGUID(offer.playerId, true); + const std::shared_ptr &buyerPlayer = getPlayerByGUID(offer.playerId, true); if (!buyerPlayer) { offerStatus << "Failed to load buyer player " << player->getName(); return; } - if (!buyerPlayer->getAccount()) { + const auto &buyerPlayerAccount = buyerPlayer->getAccount(); + if (!buyerPlayerAccount) { player->sendTextMessage(MESSAGE_MARKET, "Cannot accept offer."); return; } - if (player == buyerPlayer || player->getAccount() == buyerPlayer->getAccount()) { + const auto &playerAccount = player->getAccount(); + if (player == buyerPlayer || playerAccount == buyerPlayerAccount) { player->sendTextMessage(MESSAGE_MARKET, "You cannot accept your own offer."); return; } + const auto &buyerPlayerInbox = buyerPlayer->getInbox(); + if (it.id == ITEM_STORE_COIN) { - auto [transferableCoins, error] = player->getAccount()->getCoins(CoinType::Transferable); + auto [transferableCoins, error] = playerAccount->getCoins(CoinType::Transferable); if (error != AccountErrors_t::Ok) { offerStatus << "Failed to load transferable coins for player " << player->getName(); @@ -9220,7 +9253,7 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 return; } - player->getAccount()->removeCoins( + playerAccount->removeCoins( CoinType::Transferable, amount, "Sold on Market" @@ -9255,7 +9288,7 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 while (tmpAmount > 0) { uint16_t stackCount = std::min(it.stackSize, tmpAmount); const auto &item = Item::CreateItem(it.id, stackCount); - if (internalAddItem(buyerPlayer->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { + if (internalAddItem(buyerPlayerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { offerStatus << "Failed to add player inbox stackable item for buy offer for player " << player->getName(); break; @@ -9277,7 +9310,7 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 for (uint16_t i = 0; i < amount; ++i) { const auto &item = Item::CreateItem(it.id, subType); - if (internalAddItem(buyerPlayer->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { + if (internalAddItem(buyerPlayerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { offerStatus << "Failed to add player inbox item for buy offer for player " << player->getName(); break; @@ -9328,7 +9361,7 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 const auto &item = Item::CreateItem(it.id, stackCount); if ( // Init-statement - auto ret = internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT); + auto ret = internalAddItem(playerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT); // Condition ret != RETURNVALUE_NOERROR ) { @@ -9356,7 +9389,7 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 const auto &item = Item::CreateItem(it.id, subType); if ( // Init-statement - auto ret = internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT); + auto ret = internalAddItem(playerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT); // Condition ret != RETURNVALUE_NOERROR ) { @@ -9481,7 +9514,7 @@ void Game::playerAnswerModalWindow(uint32_t playerId, uint32_t modalWindowId, ui } void Game::playerForgeFuseItems(uint32_t playerId, ForgeAction_t actionType, uint16_t firstItemId, uint8_t tier, uint16_t secondItemId, bool usedCore, bool reduceTierLoss, bool convergence) { - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); const auto &player = getPlayerByID(playerId); if (!player) { return; diff --git a/src/game/movement/teleport.cpp b/src/game/movement/teleport.cpp index 368bcf6e4..d11552220 100644 --- a/src/game/movement/teleport.cpp +++ b/src/game/movement/teleport.cpp @@ -80,29 +80,27 @@ void Teleport::addThing(int32_t, const std::shared_ptr &thing) { // Prevent infinity loop if (checkInfinityLoop(destTile)) { const Position &pos = getPosition(); - g_logger().warn("[Teleport:addThing] - " - "Infinity loop teleport at position: {}", - pos.toString()); + g_logger().warn("[Teleport:addThing] - Infinity loop teleport at position: {}", pos.toString()); return; } const MagicEffectClasses effect = Item::items[id].magicEffect; - if (const std::shared_ptr &creature = thing->getCreature()) { + if (const auto &creature = thing->getCreature()) { Position origPos = creature->getPosition(); g_game().internalCreatureTurn(creature, origPos.x > destPos.x ? DIRECTION_WEST : DIRECTION_EAST); - g_dispatcher().addWalkEvent([=] { - g_game().map.moveCreature(creature, destTile); - if (effect != CONST_ME_NONE) { - g_game().addMagicEffect(origPos, effect); - g_game().addMagicEffect(destTile->getPosition(), effect); - } - }); + g_game().map.moveCreature(creature, destTile); + + if (effect != CONST_ME_NONE) { + g_game().addMagicEffect(origPos, effect); + g_game().addMagicEffect(destTile->getPosition(), effect); + } } else if (const auto &item = thing->getItem()) { if (effect != CONST_ME_NONE) { g_game().addMagicEffect(destTile->getPosition(), effect); g_game().addMagicEffect(item->getPosition(), effect); } + g_game().internalMoveItem(getTile(), destTile, INDEX_WHEREEVER, item, item->getItemCount(), nullptr); } } diff --git a/src/io/functions/iologindata_load_player.cpp b/src/io/functions/iologindata_load_player.cpp index 7cb08a7b9..e724d0ced 100644 --- a/src/io/functions/iologindata_load_player.cpp +++ b/src/io/functions/iologindata_load_player.cpp @@ -679,8 +679,14 @@ void IOLoginDataLoad::loadPlayerInboxItems(const std::shared_ptr &player ItemsMap inboxItems; loadItems(inboxItems, result, player); - for (auto it = inboxItems.rbegin(), end = inboxItems.rend(); it != end; ++it) { - const std::pair, int32_t> &pair = it->second; + const auto &playerInbox = player->getInbox(); + if (!playerInbox) { + g_logger().warn("[{}] - Player inbox nullptr", __FUNCTION__); + return; + } + + for (const auto &it : std::ranges::reverse_view(inboxItems)) { + const std::pair, int32_t> &pair = it.second; const auto &item = pair.first; if (!item) { continue; @@ -688,7 +694,7 @@ void IOLoginDataLoad::loadPlayerInboxItems(const std::shared_ptr &player int32_t pid = pair.second; if (pid >= 0 && pid < 100) { - player->getInbox()->internalAddThing(item); + playerInbox->internalAddThing(item); item->startDecaying(); } else { auto inboxIt = inboxItems.find(pid); diff --git a/src/io/io_wheel.cpp b/src/io/io_wheel.cpp index 2e1b57c79..cfcf65930 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/io/iomarket.cpp b/src/io/iomarket.cpp index ff2f9595d..fe91b3f6d 100644 --- a/src/io/iomarket.cpp +++ b/src/io/iomarket.cpp @@ -175,12 +175,14 @@ void IOMarket::processExpiredOffers(const DBResult_ptr &result, bool) { continue; } + const auto &playerInbox = player->getInbox(); + if (itemType.stackable) { uint16_t tmpAmount = amount; while (tmpAmount > 0) { uint16_t stackCount = std::min(100, tmpAmount); const auto &item = Item::CreateItem(itemType.id, stackCount); - if (g_game().internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { + if (g_game().internalAddItem(playerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { g_logger().error("[{}] Ocurred an error to add item with id {} to player {}", __FUNCTION__, itemType.id, player->getName()); break; @@ -202,7 +204,7 @@ void IOMarket::processExpiredOffers(const DBResult_ptr &result, bool) { for (uint16_t i = 0; i < amount; ++i) { const auto &item = Item::CreateItem(itemType.id, subType); - if (g_game().internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { + if (g_game().internalAddItem(playerInbox, item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) { break; } diff --git a/src/items/containers/container.cpp b/src/items/containers/container.cpp index 70ad1cbab..77a37942e 100644 --- a/src/items/containers/container.cpp +++ b/src/items/containers/container.cpp @@ -78,9 +78,9 @@ std::shared_ptr Container::createBrowseField(const std::shared_ptrgetTile(); + const auto &tile = parent->getTile(); if (tile) { auto browseField = g_game().browseFields.find(tile); if (browseField != g_game().browseFields.end()) { @@ -385,7 +385,12 @@ uint32_t Container::getContainerHoldingCount() { bool Container::isHoldingItem(const std::shared_ptr &item) { for (ContainerIterator it = iterator(); it.hasNext(); it.advance()) { - if (*it == item) { + const auto &compareItem = *it; + if (!compareItem || !item) { + continue; + } + + if (compareItem == item) { return true; } } @@ -395,6 +400,10 @@ bool Container::isHoldingItem(const std::shared_ptr &item) { bool Container::isHoldingItemWithId(const uint16_t id) { for (ContainerIterator it = iterator(); it.hasNext(); it.advance()) { const auto &item = *it; + if (!item) { + continue; + } + if (item && item->getID() == id) { return true; } @@ -1024,9 +1033,9 @@ void ContainerIterator::advance() { return; } - auto currentItem = container->itemlist[top.index]; + const auto ¤tItem = container->itemlist[top.index]; if (currentItem) { - auto subContainer = currentItem->getContainer(); + const auto &subContainer = currentItem->getContainer(); if (subContainer && !subContainer->itemlist.empty()) { size_t newDepth = top.depth + 1; if (newDepth <= maxTraversalDepth) { diff --git a/src/items/containers/mailbox/mailbox.cpp b/src/items/containers/mailbox/mailbox.cpp index 9abe6d0f6..27562e92d 100644 --- a/src/items/containers/mailbox/mailbox.cpp +++ b/src/items/containers/mailbox/mailbox.cpp @@ -98,7 +98,9 @@ bool Mailbox::sendItem(const std::shared_ptr &item) const { text = item->getAttribute(ItemAttribute_t::TEXT); } if (player && item) { - if (g_game().internalMoveItem(item->getParent(), player->getInbox(), INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT) == RETURNVALUE_NOERROR) { + const auto &playerInbox = player->getInbox(); + const auto &itemParent = item->getParent(); + if (g_game().internalMoveItem(itemParent, playerInbox, INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT) == RETURNVALUE_NOERROR) { const auto &newItem = g_game().transformItem(item, item->getID() + 1); if (newItem && newItem->getID() == ITEM_LETTER_STAMPED && !writer.empty()) { newItem->setAttribute(ItemAttribute_t::WRITER, writer); diff --git a/src/items/weapons/weapons.cpp b/src/items/weapons/weapons.cpp index 4eb84d246..2ec09945f 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/lua/functions/core/game/config_functions.cpp b/src/lua/functions/core/game/config_functions.cpp index 045ea7519..029895a43 100644 --- a/src/lua/functions/core/game/config_functions.cpp +++ b/src/lua/functions/core/game/config_functions.cpp @@ -83,7 +83,7 @@ int ConfigFunctions::luaConfigManagerGetFloat(lua_State* L) { float value = g_configManager().getFloat(key); double finalValue = shouldRound ? static_cast(std::round(value * 100.0) / 100.0) : value; - g_logger().debug("[{}] key: {}, finalValue: {}, shouldRound: {}", __METHOD_NAME__, magic_enum::enum_name(key), finalValue, shouldRound); + g_logger().debug("[{}] key: {}, finalValue: {}, shouldRound: {}", __FUNCTION__, magic_enum::enum_name(key), finalValue, shouldRound); lua_pushnumber(L, finalValue); return 1; } diff --git a/src/lua/functions/lua_functions_loader.hpp b/src/lua/functions/lua_functions_loader.hpp index fffc7e5b3..68cfeb45c 100644 --- a/src/lua/functions/lua_functions_loader.hpp +++ b/src/lua/functions/lua_functions_loader.hpp @@ -63,7 +63,7 @@ class Lua { static void setCreatureMetatable(lua_State* L, int32_t index, const std::shared_ptr &creature); template - static T getNumber(lua_State* L, int32_t arg) { + static T getNumber(lua_State* L, int32_t arg, std::source_location location = std::source_location::current()) { auto number = lua_tonumber(L, arg); if constexpr (std::is_enum_v) { @@ -73,7 +73,7 @@ class Lua { if constexpr (std::is_integral_v) { if constexpr (std::is_unsigned_v) { if (number < 0) { - g_logger().debug("[{}] overflow, setting to default unsigned value (0)", __FUNCTION__); + g_logger().debug("[{}] overflow, setting to default unsigned value (0), called line: {}:{}, in {}", __FUNCTION__, location.line(), location.column(), location.function_name()); return T(0); } } diff --git a/src/lua/scripts/luascript.cpp b/src/lua/scripts/luascript.cpp index 7c0ce2c09..9bb926b56 100644 --- a/src/lua/scripts/luascript.cpp +++ b/src/lua/scripts/luascript.cpp @@ -237,7 +237,7 @@ bool LuaScriptInterface::closeState() { std::string LuaScriptInterface::getMetricsScope() const { #ifdef FEATURE_METRICS - metrics::method_latency measure(__METHOD_NAME__); + metrics::method_latency measure(__METRICS_METHOD_NAME__); int32_t scriptId; int32_t callbackId; bool timerEvent; diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index 4d6cd59df..6d9356117 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -849,7 +849,7 @@ void Houses::payHouses(RentPeriod_t rentPeriod) const { if (house->getPayRentWarnings() < 7) { const int32_t daysLeft = 7 - house->getPayRentWarnings(); - std::shared_ptr letter = Item::CreateItem(ITEM_LETTER_STAMPED); + const std::shared_ptr &letter = Item::CreateItem(ITEM_LETTER_STAMPED); std::string period; switch (rentPeriod) { @@ -876,7 +876,8 @@ void Houses::payHouses(RentPeriod_t rentPeriod) const { std::ostringstream ss; ss << "Warning! \nThe " << period << " rent of " << house->getRent() << " gold for your house \"" << house->getName() << "\" is payable. Have it within " << daysLeft << " days or you will lose this house."; letter->setAttribute(ItemAttribute_t::TEXT, ss.str()); - g_game().internalAddItem(player->getInbox(), letter, INDEX_WHEREEVER, FLAG_NOLIMIT); + const auto &playerInbox = player->getInbox(); + g_game().internalAddItem(playerInbox, letter, INDEX_WHEREEVER, FLAG_NOLIMIT); house->setPayRentWarnings(house->getPayRentWarnings() + 1); } else { house->setOwner(0, true, player); diff --git a/src/pch.hpp b/src/pch.hpp index 79f14433f..d66b5fc10 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -170,20 +170,5 @@ format_as(E e) { #include "lua/global/shared_object.hpp" -constexpr std::string_view methodName(const char* s) { - const std::string_view prettyFunction(s); - const size_t bracket = prettyFunction.rfind('('); - const size_t space = prettyFunction.rfind(' ', bracket) + 1; - return prettyFunction.substr(space, bracket - space); -} - -#if defined(__GNUC__) || defined(__clang__) - #define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__) -#elif defined(_MSC_VER) - #define __METHOD_NAME__ methodName(__FUNCSIG__) -#else - #error "Compiler not supported" -#endif - #include "account/account_info.hpp" #include "config/config_enums.hpp" diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 727c1cc00..2f7ff9e24 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) { diff --git a/src/server/network/protocol/protocolstatus.cpp b/src/server/network/protocol/protocolstatus.cpp index fbf7c9a04..1ef74fc9e 100644 --- a/src/server/network/protocol/protocolstatus.cpp +++ b/src/server/network/protocol/protocolstatus.cpp @@ -18,7 +18,7 @@ std::string ProtocolStatus::SERVER_NAME = "OTX Server"; std::string ProtocolStatus::SERVER_VERSION = "6"; -std::string ProtocolStatus::SERVER_DEVELOPERS = "OpenTibiaBR Organization. Based on: Canary (4.0). And data edited by: Mattyx14"; +std::string ProtocolStatus::SERVER_DEVELOPERS = "OpenTibiaBR Organization. Based on: Canary (3.5). And data edited by: Mattyx14"; std::map ProtocolStatus::ipConnectMap; const uint64_t ProtocolStatus::start = OTSYS_TIME(true); diff --git a/src/utils/definitions.hpp b/src/utils/definitions.hpp index d557896f3..24a6b7d13 100644 --- a/src/utils/definitions.hpp +++ b/src/utils/definitions.hpp @@ -13,6 +13,8 @@ #define __FUNCTION__ __func__ #endif +#define __METRICS_METHOD_NAME__ std::source_location::current().function_name() + #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif diff --git a/src/utils/pugicast.hpp b/src/utils/pugicast.hpp index b59e95d37..910435966 100644 --- a/src/utils/pugicast.hpp +++ b/src/utils/pugicast.hpp @@ -38,14 +38,12 @@ namespace pugi { // If the string could not be parsed as the specified type if (errorCode == std::errc::invalid_argument) { // Throw an exception indicating that the argument is invalid - logError(fmt::format("Invalid argument {}", str)); - throw std::invalid_argument("Invalid argument: " + std::string(str)); + logError(fmt::format("[{}] Invalid argument {}", __FUNCTION__, str)); } // If the parsed value is out of range for the specified type else if (errorCode == std::errc::result_out_of_range) { // Throw an exception indicating that the result is out of range - logError(fmt::format("Result out of range: {}", str)); - throw std::out_of_range("Result out of range: " + std::string(str)); + logError(fmt::format("[{}] Result out of range: {}", __FUNCTION__, str)); } // Return a default value if no exception is thrown