From 6410b20e03b16dff3708feeda080ab75ad2131cb Mon Sep 17 00:00:00 2001 From: Matt Gomez Date: Fri, 5 Jul 2024 21:00:29 -0600 Subject: [PATCH] update : https://github.com/opentibiabr/canary/commit/3aeb3e75d567f94a1e865630c3ed496b819e45b3 --- data-otxserver/lib/core/storages.lua | 9 + .../grave_danger/bosses/lord_azaram.lua | 4 +- .../the_dream_courts/bosses/faceless_bane.lua | 19 +- .../monster/faceless_bane_immunity.lua | 47 +++ .../quests/grimvale/feroxa_transform.lua | 39 +++ data/libs/functions/boss_lever.lua | 32 +- data/libs/systems/hireling.lua | 4 +- data/modules/scripts/blessings/blessings.lua | 4 +- .../scripts/daily_reward/daily_reward.lua | 2 +- data/modules/scripts/gamestore/gamestore.lua | 4 +- data/modules/scripts/gamestore/init.lua | 58 ++-- data/npclib/npc_system/npc_handler.lua | 1 - .../player/offline_training.lua | 15 +- data/scripts/eventcallbacks/README.md | 33 +- .../creature/on_area_combat.lua | 2 +- .../scripts/eventcallbacks/player/on_look.lua | 7 +- data/scripts/talkactions/god/create_npc.lua | 38 ++- data/scripts/talkactions/player/reward.lua | 2 +- schema.sql | 6 - src/canary_server.cpp | 8 +- src/creatures/CMakeLists.txt | 1 + src/creatures/appearance/outfit/outfit.cpp | 4 +- src/creatures/combat/combat.cpp | 55 ++-- src/creatures/combat/condition.cpp | 2 +- src/creatures/combat/spells.cpp | 20 +- src/creatures/creature.cpp | 4 +- src/creatures/creatures_definitions.hpp | 12 +- src/creatures/interactions/chat.cpp | 16 +- src/creatures/monsters/monster.cpp | 28 +- src/creatures/monsters/monster.hpp | 6 +- src/creatures/monsters/monsters.cpp | 20 +- src/creatures/npcs/npc.cpp | 41 ++- src/creatures/npcs/npc.hpp | 14 +- .../achievement/player_achievement.cpp | 17 +- .../achievement/player_achievement.hpp | 6 +- .../players/cyclopedia/player_badge.cpp | 2 +- .../players/cyclopedia/player_cyclopedia.cpp | 185 ++++++++++++ .../players/cyclopedia/player_cyclopedia.hpp | 46 +++ .../players/cyclopedia/player_title.cpp | 5 +- src/creatures/players/grouping/familiars.cpp | 2 +- src/creatures/players/grouping/groups.cpp | 2 +- src/creatures/players/grouping/party.hpp | 2 +- .../players/imbuements/imbuements.cpp | 6 +- src/creatures/players/player.cpp | 82 ++--- src/creatures/players/player.hpp | 77 ++--- src/creatures/players/vip/player_vip.cpp | 4 +- src/creatures/players/vocations/vocation.cpp | 12 +- src/database/databasemanager.cpp | 4 +- src/enums/player_cyclopedia.hpp | 24 ++ src/game/game.cpp | 281 +++++++----------- src/game/game.hpp | 13 +- src/game/game_definitions.hpp | 11 + src/game/movement/teleport.cpp | 4 +- src/game/scheduling/dispatcher.cpp | 55 ++-- src/game/scheduling/dispatcher.hpp | 19 ++ src/game/scheduling/task.hpp | 3 +- src/io/functions/iologindata_load_player.cpp | 7 +- src/io/io_bosstiary.cpp | 6 +- src/io/iobestiary.cpp | 6 +- src/io/iomap.cpp | 54 ++-- src/io/ioprey.cpp | 6 +- src/items/containers/container.cpp | 4 + src/items/decay/decay.cpp | 8 +- src/items/functions/item/item_parse.cpp | 4 +- src/items/item.cpp | 32 +- src/items/items.cpp | 8 +- src/items/tile.cpp | 2 +- src/items/weapons/weapons.cpp | 4 +- src/lua/callbacks/event_callback.cpp | 230 +++++++------- src/lua/callbacks/events_callbacks.hpp | 26 ++ src/lua/creature/actions.cpp | 10 +- src/lua/creature/actions.hpp | 8 +- src/lua/creature/creatureevent.cpp | 60 ++-- src/lua/creature/events.cpp | 194 ++++++------ src/lua/creature/movement.cpp | 32 +- src/lua/creature/movement.hpp | 8 +- src/lua/creature/raids.cpp | 104 +++---- src/lua/creature/talkaction.cpp | 4 +- .../functions/core/game/game_functions.cpp | 5 +- .../creatures/combat/spell_functions.cpp | 22 +- .../creatures/creature_functions.cpp | 2 +- .../creatures/monster/loot_functions.cpp | 12 +- .../monster/monster_type_functions.cpp | 12 +- .../functions/creatures/npc/npc_functions.cpp | 10 +- .../creatures/npc/shop_functions.cpp | 12 +- .../creatures/player/player_functions.cpp | 43 ++- .../creatures/player/player_functions.hpp | 5 + src/lua/functions/events/action_functions.cpp | 2 +- .../events/creature_event_functions.cpp | 4 +- .../events/global_event_functions.cpp | 14 +- .../functions/events/move_event_functions.cpp | 8 +- src/lua/functions/items/item_functions.cpp | 2 +- src/lua/functions/items/weapon_functions.cpp | 16 +- src/lua/functions/lua_functions_loader.cpp | 4 +- src/lua/global/baseevents.cpp | 6 +- src/lua/global/globalevent.cpp | 16 +- src/lua/scripts/lua_environment.cpp | 4 +- src/lua/scripts/scripts.cpp | 2 +- src/map/house/house.cpp | 4 +- src/map/house/housetile.cpp | 6 +- src/map/map.cpp | 28 +- src/map/mapcache.cpp | 2 +- src/map/spectators.cpp | 61 ++-- src/map/spectators.hpp | 49 ++- src/server/network/connection/connection.cpp | 2 +- src/server/network/message/networkmessage.cpp | 4 +- src/server/network/message/networkmessage.hpp | 15 +- src/server/network/protocol/protocol.cpp | 4 +- src/server/network/protocol/protocol.hpp | 2 +- src/server/network/protocol/protocolgame.cpp | 270 ++++++++++++----- src/server/network/protocol/protocolgame.hpp | 2 + src/server/network/protocol/protocollogin.cpp | 2 +- .../network/protocol/protocolstatus.cpp | 4 +- src/server/server.hpp | 8 +- src/server/signals.cpp | 4 +- src/utils/simd.hpp | 2 +- src/utils/tools.cpp | 25 ++ src/utils/tools.hpp | 2 + src/utils/utils_definitions.hpp | 11 - start.sh | 8 +- vcproj/otxserver.vcxproj | 2 + 121 files changed, 1820 insertions(+), 1134 deletions(-) create mode 100644 data-otxserver/scripts/creaturescripts/monster/faceless_bane_immunity.lua create mode 100644 data-otxserver/scripts/creaturescripts/quests/grimvale/feroxa_transform.lua create mode 100644 src/creatures/players/cyclopedia/player_cyclopedia.cpp create mode 100644 src/creatures/players/cyclopedia/player_cyclopedia.hpp diff --git a/data-otxserver/lib/core/storages.lua b/data-otxserver/lib/core/storages.lua index fce8059f7..2b8d9a778 100644 --- a/data-otxserver/lib/core/storages.lua +++ b/data-otxserver/lib/core/storages.lua @@ -3079,6 +3079,15 @@ GlobalStorage = { DarashiaWest = 60193, }, }, + TheDreamCourts = { + -- Reserved storage from 60194 - 60196 + FacelessBane = { + -- Global + StepsOn = 60194, + Deaths = 60195, + ResetSteps = 60196, + }, + }, FuryGates = 65000, Yakchal = 65001, PitsOfInfernoLevers = 65002, diff --git a/data-otxserver/monster/quests/grave_danger/bosses/lord_azaram.lua b/data-otxserver/monster/quests/grave_danger/bosses/lord_azaram.lua index 701a0b6f9..8507c3a0c 100644 --- a/data-otxserver/monster/quests/grave_danger/bosses/lord_azaram.lua +++ b/data-otxserver/monster/quests/grave_danger/bosses/lord_azaram.lua @@ -17,8 +17,8 @@ monster.events = { "GraveDangerBossDeath", } -monster.health = 75000 -monster.maxHealth = 75000 +monster.health = 300000 +monster.maxHealth = 300000 monster.race = "venom" monster.corpse = 31599 monster.speed = 125 diff --git a/data-otxserver/monster/quests/the_dream_courts/bosses/faceless_bane.lua b/data-otxserver/monster/quests/the_dream_courts/bosses/faceless_bane.lua index e4d8553c4..868fe08e7 100644 --- a/data-otxserver/monster/quests/the_dream_courts/bosses/faceless_bane.lua +++ b/data-otxserver/monster/quests/the_dream_courts/bosses/faceless_bane.lua @@ -2,7 +2,7 @@ local mType = Game.createMonsterType("Faceless Bane") local monster = {} monster.description = "Faceless Bane" -monster.experience = 30000 +monster.experience = 20000 monster.outfit = { lookType = 1119, lookHead = 0, @@ -22,7 +22,11 @@ monster.manaCost = 0 monster.changeTarget = { interval = 4000, - chance = 10, + chance = 20, +} + +monster.reflects = { + { type = COMBAT_DEATHDAMAGE, percent = 90 }, } monster.bosstiary = { @@ -131,11 +135,7 @@ monster.elements = { { type = COMBAT_DROWNDAMAGE, percent = 0 }, { type = COMBAT_ICEDAMAGE, percent = 0 }, { type = COMBAT_HOLYDAMAGE, percent = 0 }, - { type = COMBAT_DEATHDAMAGE, percent = 99 }, -} - -monster.heals = { - { type = COMBAT_DEATHDAMAGE, percent = 100 }, + { type = COMBAT_DEATHDAMAGE, percent = 50 }, } monster.immunities = { @@ -149,6 +149,11 @@ mType.onThink = function(monster, interval) end mType.onAppear = function(monster, creature) if monster:getType():isRewardBoss() then + -- reset global storage state to default / ensure sqm's reset for the next team + Game.setStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.Deaths, -1) + Game.setStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.StepsOn, -1) + Game.setStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.ResetSteps, 1) + monster:registerEvent("facelessBaneImmunity") monster:setReward(true) end end diff --git a/data-otxserver/scripts/creaturescripts/monster/faceless_bane_immunity.lua b/data-otxserver/scripts/creaturescripts/monster/faceless_bane_immunity.lua new file mode 100644 index 000000000..36e1ecd11 --- /dev/null +++ b/data-otxserver/scripts/creaturescripts/monster/faceless_bane_immunity.lua @@ -0,0 +1,47 @@ +local bossName = "Faceless Bane" + +local function healBoss(creature) + if creature then + creature:addHealth(creature:getMaxHealth()) + creature:getPosition():sendMagicEffect(CONST_ME_BLOCKHIT) + end +end + +local function createSummons(creature) + if creature then + local pos = creature:getPosition() + Game.createMonster("Gazer Spectre", pos, true, false, creature) + Game.createMonster("Ripper Spectre", pos, true, false, creature) + Game.createMonster("Burster Spectre", pos, true, false, creature) + end +end + +local function resetBoss(creature, deaths) + if creature then + healBoss(creature) + createSummons(creature) + Game.setStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.Deaths, deaths + 1) + Game.setStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.StepsOn, 0) + Game.setStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.ResetSteps, 1) + end +end + +local facelessBaneImmunity = CreatureEvent("facelessBaneImmunity") + +function facelessBaneImmunity.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType) + if creature and creature:isMonster() and creature:getName() == bossName then + local creatureHealthPercent = (creature:getHealth() * 100) / creature:getMaxHealth() + local facelessBaneDeathsStorage = Game.getStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.Deaths) + + if creatureHealthPercent <= 20 and facelessBaneDeathsStorage < 1 then + resetBoss(creature, facelessBaneDeathsStorage) + return true + elseif Game.getStorageValue(GlobalStorage.TheDreamCourts.FacelessBane.StepsOn) < 1 then + healBoss(creature) + return true + end + end + return primaryDamage, primaryType, secondaryDamage, secondaryType +end + +facelessBaneImmunity:register() diff --git a/data-otxserver/scripts/creaturescripts/quests/grimvale/feroxa_transform.lua b/data-otxserver/scripts/creaturescripts/quests/grimvale/feroxa_transform.lua new file mode 100644 index 000000000..ac7cd6f2b --- /dev/null +++ b/data-otxserver/scripts/creaturescripts/quests/grimvale/feroxa_transform.lua @@ -0,0 +1,39 @@ +local feroxaTransform = CreatureEvent("FeroxaTransform") +function feroxaTransform.onThink(creature) + if creature:getName():lower() ~= "feroxa" then + return true + end + if creature:getMaxHealth() == 100000 then + if creature:getHealth() <= 50000 then + creature:getPosition():sendMagicEffect(CONST_ME_POFF) + Game.createMonster("feroxa2", creature:getPosition(), true, true) + creature:remove() + end + end + if creature:getMaxHealth() == 50000 then + if creature:getHealth() <= 25000 then + creature:getPosition():sendMagicEffect(CONST_ME_POFF) + local feroxas = { + [1] = { name = "feroxa3" }, + [2] = { name = "feroxa4" }, + } + Game.createMonster(feroxas[math.random(#feroxas)].name, creature:getPosition(), true, true) + creature:remove() + end + end +end + +feroxaTransform:register() + +local feroxaDeath = CreatureEvent("FeroxaDeath") +function feroxaDeath.onDeath(creature, corpse, deathList) + if creature and creature:getMonster() then + local pool = Tile(creature:getPosition()):getItemById(2886) + if pool then + pool:remove() + end + Game.createMonster("Feroxa5", creature:getPosition(), true, true) + end +end + +feroxaDeath:register() diff --git a/data/libs/functions/boss_lever.lua b/data/libs/functions/boss_lever.lua index 3792cdf62..b95bf7211 100644 --- a/data/libs/functions/boss_lever.lua +++ b/data/libs/functions/boss_lever.lua @@ -174,24 +174,36 @@ function BossLever:onUse(player) end if creature:getLevel() < self.requiredLevel then - creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "All the players need to be level " .. self.requiredLevel .. " or higher.") + local message = "All players need to be level " .. self.requiredLevel .. " or higher." + creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, message) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, message) return false end - if self:lastEncounterTime(creature) > os.time() then - local info = lever:getInfoPositions() - for _, v in pairs(info) do - local newPlayer = v.creature - if newPlayer then - local timeLeft = self:lastEncounterTime(newPlayer) - os.time() - newPlayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You or a member in your team have to wait " .. getTimeInWords(timeLeft) .. " to face " .. self.name .. " again!") - if self:lastEncounterTime(newPlayer) > os.time() then - newPlayer:getPosition():sendMagicEffect(CONST_ME_POFF) + if creature:getGroup():getId() < GROUP_TYPE_GOD and self:lastEncounterTime(creature) > os.time() then + local infoPositions = lever:getInfoPositions() + for _, posInfo in pairs(infoPositions) do + local currentPlayer = posInfo.creature + if currentPlayer then + local lastEncounter = self:lastEncounterTime(currentPlayer) + local currentTime = os.time() + if lastEncounter and currentTime < lastEncounter then + local timeLeft = lastEncounter - currentTime + local timeMessage = getTimeInWords(timeLeft) .. " to face " .. self.name .. " again!" + local message = "You have to wait " .. timeMessage + + if currentPlayer ~= player then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "A member in your team has to wait " .. timeMessage) + end + + currentPlayer:sendTextMessage(MESSAGE_EVENT_ADVANCE, message) + currentPlayer:getPosition():sendMagicEffect(CONST_ME_POFF) end end end return false end + self.onUseExtra(creature) return true end) diff --git a/data/libs/systems/hireling.lua b/data/libs/systems/hireling.lua index 8b5784759..30134cd7c 100644 --- a/data/libs/systems/hireling.lua +++ b/data/libs/systems/hireling.lua @@ -361,7 +361,7 @@ function Hireling:returnToLamp(player_id) local inbox = owner:getStoreInbox() local inboxItems = inbox:getItems() - if not inbox or #inboxItems > inbox:getMaxCapacity() then + if not inbox or #inboxItems >= inbox:getMaxCapacity() then owner:getPosition():sendMagicEffect(CONST_ME_POFF) return owner:sendTextMessage(MESSAGE_FAILURE, "You don't have enough room in your inbox.") end @@ -556,7 +556,7 @@ function Player:addNewHireling(name, sex) local inbox = self:getStoreInbox() local inboxItems = inbox:getItems() - if not inbox or #inboxItems > inbox:getMaxCapacity() then + if not inbox or #inboxItems >= inbox:getMaxCapacity() then self:getPosition():sendMagicEffect(CONST_ME_POFF) self:sendTextMessage(MESSAGE_FAILURE, "You don't have enough room in your inbox.") return false diff --git a/data/modules/scripts/blessings/blessings.lua b/data/modules/scripts/blessings/blessings.lua index adfa364e7..e061501a3 100644 --- a/data/modules/scripts/blessings/blessings.lua +++ b/data/modules/scripts/blessings/blessings.lua @@ -21,7 +21,7 @@ Blessings.Credits = { Blessings.Config = { AdventurerBlessingLevel = configManager.getNumber(configKeys.ADVENTURERSBLESSING_LEVEL), -- Free full bless until level - HasToF = false, -- Enables/disables twist of fate + HasToF = not configManager.getBoolean(configKeys.TOGGLE_SERVER_IS_RETRO), -- Enables/disables twist of fate InquisitonBlessPriceMultiplier = 1.1, -- Bless price multiplied by henricus SkulledDeathLoseStoreItem = configManager.getBoolean(configKeys.SKULLED_DEATH_LOSE_STORE_ITEM), -- Destroy all items on store when dying with red/blackskull InventoryGlowOnFiveBless = configManager.getBoolean(configKeys.INVENTORY_GLOW), -- Glow in yellow inventory items when the player has 5 or more bless, @@ -142,7 +142,7 @@ Blessings.sendBlessDialog = function(player) msg:addU16(Blessings.BitWiseTable[v.id]) msg:addByte(player:getBlessingCount(v.id)) if player:getClient().version > 1200 then - msg:addByte(0) -- Store Blessings Count + msg:addByte(player:getBlessingCount(v.id, true)) -- Store Blessings Count end end end diff --git a/data/modules/scripts/daily_reward/daily_reward.lua b/data/modules/scripts/daily_reward/daily_reward.lua index 09b927ced..b6a7c1699 100644 --- a/data/modules/scripts/daily_reward/daily_reward.lua +++ b/data/modules/scripts/daily_reward/daily_reward.lua @@ -454,7 +454,7 @@ function Player.selectDailyReward(self, msg) -- Adding items to store inbox local inbox = self:getStoreInbox() local inboxItems = inbox:getItems() - if not inbox or #inboxItems > inbox:getMaxCapacity() then + if not inbox or #inboxItems >= inbox:getMaxCapacity() then self:sendError("You do not have enough space in your store inbox.") return false end diff --git a/data/modules/scripts/gamestore/gamestore.lua b/data/modules/scripts/gamestore/gamestore.lua index f000c4079..ed17c456c 100644 --- a/data/modules/scripts/gamestore/gamestore.lua +++ b/data/modules/scripts/gamestore/gamestore.lua @@ -135,7 +135,7 @@ GameStore.Categories = { icons = { "Blood_of_the_Mountain.png" }, name = "Blood of the Mountain", price = 25, - blessid = 8, + blessid = 7, count = 1, id = GameStore.SubActions.BLESSING_BLOOD, description = "Reduces your character's chance to lose any items as well as the amount of your character's experience and skill loss upon death:\n\n• 1 blessing = 8.00% less Skill / XP loss, 30% equipment protection\n• 2 blessing = 16.00% less Skill / XP loss, 55% equipment protection\n• 3 blessing = 24.00% less Skill / XP loss, 75% equipment protection\n• 4 blessing = 32.00% less Skill / XP loss, 90% equipment protection\n• 5 blessing = 40.00% less Skill / XP loss, 100% equipment protection\n• 6 blessing = 48.00% less Skill / XP loss, 100% equipment protection\n• 7 blessing = 56.00% less Skill / XP loss, 100% equipment protection\n\n{character} \n{limit|5} \n{info} added directly to the Record of Blessings \n{info} characters with a red or black skull will always lose all equipment upon death", @@ -154,7 +154,7 @@ GameStore.Categories = { icons = { "Heart_of_the_Mountain.png" }, name = "Heart of the Mountain", price = 25, - blessid = 7, + blessid = 8, count = 1, id = GameStore.SubActions.BLESSING_HEART, description = "Reduces your character's chance to lose any items as well as the amount of your character's experience and skill loss upon death:\n\n• 1 blessing = 8.00% less Skill / XP loss, 30% equipment protection\n• 2 blessing = 16.00% less Skill / XP loss, 55% equipment protection\n• 3 blessing = 24.00% less Skill / XP loss, 75% equipment protection\n• 4 blessing = 32.00% less Skill / XP loss, 90% equipment protection\n• 5 blessing = 40.00% less Skill / XP loss, 100% equipment protection\n• 6 blessing = 48.00% less Skill / XP loss, 100% equipment protection\n• 7 blessing = 56.00% less Skill / XP loss, 100% equipment protection\n\n{character} \n{limit|5} \n{info} added directly to the Record of Blessings \n{info} characters with a red or black skull will always lose all equipment upon death", diff --git a/data/modules/scripts/gamestore/init.lua b/data/modules/scripts/gamestore/init.lua index ba7398d9d..433abf344 100644 --- a/data/modules/scripts/gamestore/init.lua +++ b/data/modules/scripts/gamestore/init.lua @@ -47,8 +47,8 @@ GameStore.SubActions = { BLESSING_SUNS = 6, BLESSING_SPIRITUAL = 7, BLESSING_EMBRACE = 8, - BLESSING_HEART = 9, - BLESSING_BLOOD = 10, + BLESSING_BLOOD = 9, + BLESSING_HEART = 10, BLESSING_ALL_PVE = 11, BLESSING_ALL_PVP = 12, CHARM_EXPANSION = 13, @@ -247,6 +247,11 @@ function onRecvbyte(player, msg, byte) return player:sendCancelMessage("Store don't have offers for rookgaard citizen.") end + if player:isUIExhausted(250) then + player:sendCancelMessage("You are exhausted.") + return + end + if byte == GameStore.RecivedPackets.C_StoreEvent then elseif byte == GameStore.RecivedPackets.C_TransferCoins then parseTransferableCoins(player:getId(), msg) @@ -262,12 +267,6 @@ function onRecvbyte(player, msg, byte) parseRequestTransactionHistory(player:getId(), msg) end - if player:isUIExhausted(250) then - player:sendCancelMessage("You are exhausted.") - return false - end - - player:updateUIExhausted() return true end @@ -306,6 +305,7 @@ function parseTransferableCoins(playerId, msg) GameStore.insertHistory(accountId, GameStore.HistoryTypes.HISTORY_TYPE_NONE, player:getName() .. " transferred you this amount.", amount, GameStore.CoinType.Transferable) GameStore.insertHistory(player:getAccountId(), GameStore.HistoryTypes.HISTORY_TYPE_NONE, "You transferred this amount to " .. reciver, -1 * amount, GameStore.CoinType.Transferable) openStore(playerId) + player:updateUIExhausted() end function parseOpenStore(playerId, msg) @@ -396,6 +396,18 @@ function parseRequestStoreOffers(playerId, msg) addPlayerEvent(sendShowStoreOffers, 250, playerId, searchResultsCategory) end + player:updateUIExhausted() +end + +-- Used on cyclopedia store summary +local function insertPlayerTransactionSummary(player, offer) + local id = offer.id + if offer.type == GameStore.OfferTypes.OFFER_TYPE_HOUSE then + id = offer.itemtype + elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_BLESSINGS then + id = offer.blessid + end + player:createTransactionSummary(offer.type, math.max(1, offer.count or 1), id) end function parseBuyStoreOffer(playerId, msg) @@ -449,9 +461,7 @@ function parseBuyStoreOffer(playerId, msg) -- Handled errors are thrown to indicate that the purchase has failed; -- Handled errors have a code index and unhandled errors do not local pcallOk, pcallError = pcall(function() - if offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM then - GameStore.processItemPurchase(player, offer.itemtype, offer.count or 1, offer.movable, offer.setOwner) - elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_UNIQUE then + if offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM or offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_UNIQUE then GameStore.processItemPurchase(player, offer.itemtype, offer.count or 1, offer.movable, offer.setOwner) elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_INSTANT_REWARD_ACCESS then GameStore.processInstantRewardAccess(player, offer.count) @@ -465,11 +475,9 @@ function parseBuyStoreOffer(playerId, msg) GameStore.processPremiumPurchase(player, offer.id) elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_STACKABLE then GameStore.processStackablePurchase(player, offer.itemtype, offer.count, offer.name, offer.movable, offer.setOwner) - elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_HOUSE then + elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_HOUSE or offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_BED then GameStore.processHouseRelatedPurchase(player, offer) - elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT then - GameStore.processOutfitPurchase(player, offer.sexId, offer.addon) - elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT_ADDON then + elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT or offer.type == GameStore.OfferTypes.OFFER_TYPE_OUTFIT_ADDON then GameStore.processOutfitPurchase(player, offer.sexId, offer.addon) elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_MOUNT then GameStore.processMountPurchase(player, offer.id) @@ -503,8 +511,6 @@ function parseBuyStoreOffer(playerId, msg) GameStore.processHirelingSkillPurchase(player, offer) elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_HIRELING_OUTFIT then GameStore.processHirelingOutfitPurchase(player, offer) - elseif offer.type == GameStore.OfferTypes.OFFER_TYPE_ITEM_BED then - GameStore.processHouseRelatedPurchase(player, offer) else -- This should never happen by our convention, but just in case the guarding condition is messed up... error({ code = 0, message = "This offer is unavailable [2]" }) @@ -522,6 +528,9 @@ function parseBuyStoreOffer(playerId, msg) return queueSendStoreAlertToUser(alertMessage, 500, playerId) end + if table.contains({ GameStore.OfferTypes.OFFER_TYPE_HOUSE, GameStore.OfferTypes.OFFER_TYPE_EXPBOOST, GameStore.OfferTypes.OFFER_TYPE_PREYBONUS, GameStore.OfferTypes.OFFER_TYPE_BLESSINGS, GameStore.OfferTypes.OFFER_TYPE_ALLBLESSINGS, GameStore.OfferTypes.OFFER_TYPE_INSTANT_REWARD_ACCESS }, offer.type) then + insertPlayerTransactionSummary(player, offer) + end local configure = useOfferConfigure(offer.type) if configure ~= GameStore.ConfigureOffers.SHOW_CONFIGURE then if not player:makeCoinTransaction(offer) then @@ -532,19 +541,33 @@ function parseBuyStoreOffer(playerId, msg) sendUpdatedStoreBalances(playerId) return addPlayerEvent(sendStorePurchaseSuccessful, 650, playerId, message) end + + player:updateUIExhausted() return true end -- Both functions use same formula! function parseOpenTransactionHistory(playerId, msg) + local player = Player(playerId) + if not player then + return + end + local page = 1 GameStore.DefaultValues.DEFAULT_VALUE_ENTRIES_PER_PAGE = msg:getByte() sendStoreTransactionHistory(playerId, page, GameStore.DefaultValues.DEFAULT_VALUE_ENTRIES_PER_PAGE) + player:updateUIExhausted() end function parseRequestTransactionHistory(playerId, msg) + local player = Player(playerId) + if not player then + return + end + local page = msg:getU32() sendStoreTransactionHistory(playerId, page + 1, GameStore.DefaultValues.DEFAULT_VALUE_ENTRIES_PER_PAGE) + player:updateUIExhausted() end local function getCategoriesRook() @@ -1812,6 +1835,7 @@ function GameStore.processHirelingPurchase(player, offer, productType, hirelingN player:makeCoinTransaction(offer, hirelingName) local message = "You have successfully bought " .. hirelingName + player:createTransactionSummary(offer.type, 1) return addPlayerEvent(sendStorePurchaseSuccessful, 650, player:getId(), message) -- If not, we ask him to do! else diff --git a/data/npclib/npc_system/npc_handler.lua b/data/npclib/npc_system/npc_handler.lua index 8f4d5f2ca..31aaa88fa 100644 --- a/data/npclib/npc_system/npc_handler.lua +++ b/data/npclib/npc_system/npc_handler.lua @@ -480,7 +480,6 @@ if NpcHandler == nil then -- If is npc shop, send shop window and parse default message (if not have callback on the npc) if npc:isMerchant() then - npc:closeShopWindow(player) npc:openShopWindow(player) self:say(msg, npc, player) end diff --git a/data/scripts/creaturescripts/player/offline_training.lua b/data/scripts/creaturescripts/player/offline_training.lua index 4466c6ee0..7d08f07ef 100644 --- a/data/scripts/creaturescripts/player/offline_training.lua +++ b/data/scripts/creaturescripts/player/offline_training.lua @@ -55,18 +55,23 @@ function offlineTraining.onLogin(player) local vocation = player:getVocation() local promotion = vocation:getPromotion() local topVocation = not promotion and vocation or promotion - local updateSkills = false + local tries = nil if table.contains({ SKILL_CLUB, SKILL_SWORD, SKILL_AXE, SKILL_DISTANCE }, offlineTrainingSkill) then - local modifier = topVocation:getBaseAttackSpeed() / 1000 / configManager.getFloat(configKeys.RATE_OFFLINE_TRAINING_SPEED) - updateSkills = player:addOfflineTrainingTries(offlineTrainingSkill, (trainingTime / modifier) / (offlineTrainingSkill == SKILL_DISTANCE and 4 or 2)) + local modifier = topVocation:getBaseAttackSpeed() / 1000 + tries = (trainingTime / modifier) / (offlineTrainingSkill == SKILL_DISTANCE and 4 or 2) elseif offlineTrainingSkill == SKILL_MAGLEVEL then - local gainTicks = topVocation:getManaGainTicks() * 2 + local gainTicks = topVocation:getManaGainTicks() / 1000 if gainTicks == 0 then gainTicks = 1 end - updateSkills = player:addOfflineTrainingTries(SKILL_MAGLEVEL, trainingTime * (vocation:getManaGainAmount() / gainTicks)) + tries = trainingTime * (vocation:getManaGainAmount() / gainTicks) + end + + local updateSkills = false + if tries then + updateSkills = player:addOfflineTrainingTries(offlineTrainingSkill, tries * configManager.getFloat(configKeys.RATE_OFFLINE_TRAINING_SPEED)) end if updateSkills then diff --git a/data/scripts/eventcallbacks/README.md b/data/scripts/eventcallbacks/README.md index 601653574..ae5de046b 100644 --- a/data/scripts/eventcallbacks/README.md +++ b/data/scripts/eventcallbacks/README.md @@ -14,8 +14,8 @@ Event callbacks are available for several categories of game entities, such as ` ### These are the functions available to use - `(bool)` `creatureOnChangeOutfit` -- `(bool)` `creatureOnAreaCombat` -- `(bool)` `creatureOnTargetCombat` +- `(ReturnValue)` `creatureOnAreaCombat` +- `(ReturnValue)` `creatureOnTargetCombat` - `(void)` `creatureOnHear` - `(void)` `creatureOnDrainHealth` - `(bool)` `partyOnJoin` @@ -66,7 +66,7 @@ local callback = EventCallback() function callback.creatureOnAreaCombat(creature, tile, isAggressive) -- custom behavior when a creature enters combat area - return true + return RETURNVALUE_NOERROR end callback:register() @@ -131,14 +131,36 @@ Here is an example of a boolean event callback: ```lua local callback = EventCallback() +function callback.playerOnMoveItem(player, item, count, fromPos, toPos, fromCylinder, toCylinder) + if item:getId() == ITEM_PARCEL then + --Custom behavior when the player moves a parcel. + return false + end + return true +end + +callback:register() +``` + +### In this example, when a player moves an item, the function checks if the item is a parcel and apply a custom behaviour, returning false making it impossible to move, stopping the associated function on the C++ side. + +## ReturnValue Event Callbacks + +Some event callbacks are expected to return a enum value, in this case, the enum ReturnValue. If the return is different of RETURNVALUE_NOERROR, it will stop the execution of the next callbacks. + +Here is an example of a ReturnValue event callback: + +```lua +local callback = EventCallback() + function callback.creatureOnAreaCombat(creature, tile, isAggressive) -- if the creature is not aggressive, stop the execution of the C++ function if not isAggressive then - return false + return RETURNVALUE_NOTPOSSIBLE end -- custom behavior when an aggressive creature enters a combat area - return true + return RETURNVALUE_NOERROR end callback:register() @@ -146,6 +168,7 @@ callback:register() ### In this example, when a non-aggressive creature enters a combat area, the creatureOnAreaCombat function returns false, stopping the associated function on the C++ side. + ## Multiple Callbacks for the Same Event You can define multiple callbacks for the same event type. This allows you to encapsulate different behaviors in separate callbacks, making your code more modular and easier to manage. diff --git a/data/scripts/eventcallbacks/creature/on_area_combat.lua b/data/scripts/eventcallbacks/creature/on_area_combat.lua index a6295074d..f68cc95cc 100644 --- a/data/scripts/eventcallbacks/creature/on_area_combat.lua +++ b/data/scripts/eventcallbacks/creature/on_area_combat.lua @@ -1,7 +1,7 @@ local callback = EventCallback() function callback.creatureOnAreaCombat(creature, tile, isAggressive) - return true + return RETURNVALUE_NOERROR end callback:register() diff --git a/data/scripts/eventcallbacks/player/on_look.lua b/data/scripts/eventcallbacks/player/on_look.lua index 90d308905..022aebbcc 100644 --- a/data/scripts/eventcallbacks/player/on_look.lua +++ b/data/scripts/eventcallbacks/player/on_look.lua @@ -60,11 +60,12 @@ function callback.playerOnLook(player, thing, position, distance) description = string.format("%s\nDecays to: %d", description, decayId) end elseif thing:isCreature() then - local str = "%s\nHealth: %d / %d" + local str, pId = "%s\n%s\nHealth: %d / %d" if thing:isPlayer() and thing:getMaxMana() > 0 then + pId = string.format("Player ID: %i", thing:getGuid()) str = string.format("%s, Mana: %d / %d", str, thing:getMana(), thing:getMaxMana()) end - description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "." + description = string.format(str, description, pId, thing:getHealth(), thing:getMaxHealth()) end description = string.format("%s\nPosition: (%d, %d, %d)", description, position.x, position.y, position.z) @@ -76,7 +77,7 @@ function callback.playerOnLook(player, thing, position, distance) description = string.format("%s\nSpeed: %d", description, speed) if thing:isPlayer() then - description = string.format("%s\nIP: %s.", description, Game.convertIpToString(thing:getIp())) + description = string.format("%s\nIP: %s", description, Game.convertIpToString(thing:getIp())) end end end diff --git a/data/scripts/talkactions/god/create_npc.lua b/data/scripts/talkactions/god/create_npc.lua index 4aeec3dde..b6d0412d3 100644 --- a/data/scripts/talkactions/god/create_npc.lua +++ b/data/scripts/talkactions/god/create_npc.lua @@ -1,3 +1,6 @@ +-- To summon a temporary npc use /n npcname +-- To summon a permanent npc use /n npcname,true + local createNpc = TalkAction("/n") function createNpc.onSay(player, words, param) @@ -9,11 +12,44 @@ function createNpc.onSay(player, words, param) return true end + local split = param:split(",") + local name = split[1] + local permanentStr = split[2] + local position = player:getPosition() - local npc = Game.createNpc(param, position) + local npc = Game.createNpc(name, position) if npc then npc:setMasterPos(position) position:sendMagicEffect(CONST_ME_MAGIC_RED) + + if permanentStr and permanentStr == "true" then + local mapName = configManager.getString(configKeys.MAP_NAME) + local mapNpcsPath = mapName .. "-npc.xml" + local filePath = string.format("%s/world/%s", DATA_DIRECTORY, mapNpcsPath) + local npcsFile = io.open(filePath, "r") + if not npcsFile then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error when trying to add permanent NPC. NPC File not found.") + return true + end + local fileContent = npcsFile:read("*all") + npcsFile:close() + local endTag = "" + if not fileContent:find(endTag, 1, true) then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error when trying to add permanent NPC. The NPC file format is incorrect. Missing end tag " .. endTag .. ".") + return true + end + local textToAdd = string.format('\t\n\t\t\n\t', position.x, position.y, position.z, name, position.z) + local newFileContent = fileContent:gsub(endTag, textToAdd .. "\n" .. endTag) + npcsFile = io.open(filePath, "w") + if not npcsFile then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error when trying to write to the NPC file.") + return true + end + npcsFile:write(newFileContent) + npcsFile:close() + + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Permanent NPC added successfully.") + end else player:sendCancelMessage("There is not enough room.") position:sendMagicEffect(CONST_ME_POFF) diff --git a/data/scripts/talkactions/player/reward.lua b/data/scripts/talkactions/player/reward.lua index d198f60ef..687a1df91 100644 --- a/data/scripts/talkactions/player/reward.lua +++ b/data/scripts/talkactions/player/reward.lua @@ -26,7 +26,7 @@ local function sendExerciseRewardModal(player) local inbox = player:getStoreInbox() local inboxItems = inbox:getItems() - if inbox and #inboxItems <= inbox:getMaxCapacity() and player:getFreeCapacity() >= iType:getWeight() then + if inbox and #inboxItems < inbox:getMaxCapacity() and player:getFreeCapacity() >= iType:getWeight() then local item = inbox:addItem(it.id, it.charges) if item then item:setActionId(IMMOVABLE_ACTION_ID) diff --git a/schema.sql b/schema.sql index 2fbc7dd64..af2450670 100644 --- a/schema.sql +++ b/schema.sql @@ -850,9 +850,3 @@ INSERT INTO `players` (4, 'Paladin Sample', 1, 1, 8, 3, 185, 185, 4200, 113, 115, 95, 39, 129, 0, 90, 90, 0, 8, '', 470, 1, 10, 0, 10, 0, 10, 0, 10, 0), (5, 'Knight Sample', 1, 1, 8, 4, 185, 185, 4200, 113, 115, 95, 39, 129, 0, 90, 90, 0, 8, '', 470, 1, 10, 0, 10, 0, 10, 0, 10, 0), (6, 'GOD', 6, 1, 2, 0, 155, 155, 100, 113, 115, 95, 39, 75, 0, 60, 60, 0, 8, '', 410, 1, 10, 0, 10, 0, 10, 0, 10, 0); - --- Create vip groups for GOD account -INSERT INTO `account_vipgroups` (`name`, `account_id`, `customizable`) VALUES -('Friends', 1, 0), -('Enemies', 1, 0), -('Trading Partners', 1, 0); diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 17cd75c6a..28a2053b4 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -93,8 +93,8 @@ int CanaryServer::run() { #ifndef _WIN32 if (getuid() == 0 || geteuid() == 0) { logger.warn("{} has been executed as root user, " - "please consider running it as a normal user", - ProtocolStatus::SERVER_NAME); + "please consider running it as a normal user", + ProtocolStatus::SERVER_NAME); } #endif @@ -235,7 +235,7 @@ void CanaryServer::toggleForceCloseButton() { void CanaryServer::badAllocationHandler() { // Use functions that only use stack allocation g_logger().error("Allocation failed, server out of memory, " - "decrease the size of your map or compile in 64 bits mode"); + "decrease the size of your map or compile in 64 bits mode"); if (isatty(STDIN_FILENO)) { getchar(); @@ -319,7 +319,7 @@ void CanaryServer::initializeDatabase() { DatabaseManager::updateDatabase(); if (g_configManager().getBoolean(OPTIMIZE_DATABASE, __FUNCTION__) - && !DatabaseManager::optimizeTables()) { + && !DatabaseManager::optimizeTables()) { logger.debug("No tables were optimized"); } } diff --git a/src/creatures/CMakeLists.txt b/src/creatures/CMakeLists.txt index af6ba129e..c87a45a0a 100644 --- a/src/creatures/CMakeLists.txt +++ b/src/creatures/CMakeLists.txt @@ -23,6 +23,7 @@ target_sources(${PROJECT_NAME}_lib PRIVATE players/player.cpp players/achievement/player_achievement.cpp players/cyclopedia/player_badge.cpp + players/cyclopedia/player_cyclopedia.cpp players/cyclopedia/player_title.cpp players/wheel/player_wheel.cpp players/wheel/wheel_gems.cpp diff --git a/src/creatures/appearance/outfit/outfit.cpp b/src/creatures/appearance/outfit/outfit.cpp index 971206593..251bf7bde 100644 --- a/src/creatures/appearance/outfit/outfit.cpp +++ b/src/creatures/appearance/outfit/outfit.cpp @@ -58,8 +58,8 @@ bool Outfits::loadFromXml() { } if (auto lookType = pugi::cast(lookTypeAttribute.value()); - g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0 - && !g_game().isLookTypeRegistered(lookType)) { + g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0 + && !g_game().isLookTypeRegistered(lookType)) { g_logger().warn("[Outfits::loadFromXml] An unregistered creature looktype type with id '{}' was ignored to prevent client crash.", lookType); continue; } diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 2aaadac4d..87f7500d0 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -21,6 +21,8 @@ #include "items/weapons/weapons.hpp" #include "map/spectators.hpp" #include "lib/metrics/metrics.hpp" +#include "lua/callbacks/event_callback.hpp" +#include "lua/callbacks/events_callbacks.hpp" int32_t Combat::getLevelFormula(std::shared_ptr player, const std::shared_ptr wheelSpell, const CombatDamage &damage) const { if (!player) { @@ -273,8 +275,11 @@ ReturnValue Combat::canDoCombat(std::shared_ptr caster, std::shared_pt } } } - - return g_events().eventCreatureOnAreaCombat(caster, tile, aggressive); + ReturnValue ret = g_events().eventCreatureOnAreaCombat(caster, tile, aggressive); + if (ret == RETURNVALUE_NOERROR) { + ret = g_callbacks().checkCallbackWithReturnValue(EventCallback_t::creatureOnTargetCombat, &EventCallback::creatureOnAreaCombat, caster, tile, aggressive); + } + return ret; } bool Combat::isInPvpZone(std::shared_ptr attacker, std::shared_ptr target) { @@ -409,7 +414,11 @@ ReturnValue Combat::canDoCombat(std::shared_ptr attacker, std::shared_ } } } - return g_events().eventCreatureOnTargetCombat(attacker, target); + ReturnValue ret = g_events().eventCreatureOnTargetCombat(attacker, target); + if (ret == RETURNVALUE_NOERROR) { + ret = g_callbacks().checkCallbackWithReturnValue(EventCallback_t::creatureOnTargetCombat, &EventCallback::creatureOnTargetCombat, attacker, target); + } + return ret; } void Combat::setPlayerCombatValues(formulaType_t newFormulaType, double newMina, double newMinb, double newMaxa, double newMaxb) { @@ -648,8 +657,8 @@ CombatDamage Combat::applyImbuementElementalDamage(std::shared_ptr attac } if (imbuementInfo.imbuement->combatType == COMBAT_NONE - || damage.primary.type == COMBAT_HEALING - || damage.secondary.type == COMBAT_HEALING) { + || damage.primary.type == COMBAT_HEALING + || damage.secondary.type == COMBAT_HEALING) { continue; } @@ -1247,8 +1256,8 @@ void Combat::doCombatHealth(std::shared_ptr caster, std::shared_ptr caster, std::shared_ptr target, const Position &origin, CombatDamage &damage, const CombatParams ¶ms) { bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target, params.aggressive) == RETURNVALUE_NOERROR); if ((caster && target) - && (caster == target || canCombat) - && (params.impactEffect != CONST_ME_NONE)) { + && (caster == target || canCombat) + && (params.impactEffect != CONST_ME_NONE)) { g_game().addMagicEffect(target->getPosition(), params.impactEffect); } @@ -1291,8 +1300,8 @@ void Combat::doCombatMana(std::shared_ptr caster, std::shared_ptr caster, std::shared_ptr target, const Position &origin, CombatDamage &damage, const CombatParams ¶ms) { bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target, params.aggressive) == RETURNVALUE_NOERROR); if ((caster && target) - && (caster == target || canCombat) - && (params.impactEffect != CONST_ME_NONE)) { + && (caster == target || canCombat) + && (params.impactEffect != CONST_ME_NONE)) { g_game().addMagicEffect(target->getPosition(), params.impactEffect); } @@ -1359,8 +1368,8 @@ void Combat::doCombatDispel(std::shared_ptr caster, const Position &po void Combat::doCombatDispel(std::shared_ptr caster, std::shared_ptr target, const CombatParams ¶ms) { bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target, params.aggressive) == RETURNVALUE_NOERROR); if ((caster && target) - && (caster == target || canCombat) - && (params.impactEffect != CONST_ME_NONE)) { + && (caster == target || canCombat) + && (params.impactEffect != CONST_ME_NONE)) { g_game().addMagicEffect(target->getPosition(), params.impactEffect); } @@ -1399,7 +1408,7 @@ void Combat::doCombatDefault(std::shared_ptr caster, std::shared_ptrgetPosition(), params.impactEffect); + g_game().addMagicEffect(target->getPosition(), params.impactEffect); } */ @@ -1531,8 +1540,8 @@ void ValueCallback::getMinMaxValues(std::shared_ptr player, CombatDamage // onGetPlayerMinMaxValues(...) if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[ValueCallback::getMinMaxValues - Player {} formula {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), fmt::underlying(type)); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), fmt::underlying(type)); return; } @@ -1624,8 +1633,8 @@ void TileCallback::onTileCombat(std::shared_ptr creature, std::shared_ // onTileCombat(creature, pos) if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[TileCallback::onTileCombat - Creature {} type {} on tile x: {} y: {} z: {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), fmt::underlying(type), (tile->getPosition()).getX(), (tile->getPosition()).getY(), (tile->getPosition()).getZ()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), fmt::underlying(type), (tile->getPosition()).getX(), (tile->getPosition()).getY(), (tile->getPosition()).getZ()); return; } @@ -1655,8 +1664,8 @@ void TargetCallback::onTargetCombat(std::shared_ptr creature, std::sha // onTargetCombat(creature, target) if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[TargetCallback::onTargetCombat - Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName()); return; } @@ -1715,8 +1724,8 @@ void ChainCallback::onChainCombat(std::shared_ptr creature, uint8_t &m // onChainCombat(creature) if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[ChainCallback::onTargetCombat - Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName()); return; } @@ -1757,8 +1766,8 @@ bool ChainPickerCallback::onChainCombat(std::shared_ptr creature, std: // onChainCombat(creature, target) if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[ChainPickerCallback::onTargetCombat - Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName()); return true; } @@ -2169,7 +2178,7 @@ void Combat::applyExtensions(std::shared_ptr caster, std::shared_ptrgetInventoryItem(CONST_SLOT_LEFT); - playerWeapon != nullptr && playerWeapon->getTier() > 0) { + playerWeapon != nullptr && playerWeapon->getTier() > 0) { double_t fatalChance = playerWeapon->getFatalChance(); double_t randomChance = uniform_random(0, 10000) / 100; if (fatalChance > 0 && randomChance < fatalChance) { diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index 7f477f1d8..b9603d010 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -2042,7 +2042,7 @@ bool ConditionFeared::executeCondition(std::shared_ptr creature, int32 g_dispatcher().addEvent([id = creature->getID(), listDir = listDir.data()] { g_game().forcePlayerAutoWalk(id, listDir); }, - "ConditionFeared::executeCondition"); + "ConditionFeared::executeCondition"); g_logger().debug("[ConditionFeared::executeCondition] Walking Scheduled"); } diff --git a/src/creatures/combat/spells.cpp b/src/creatures/combat/spells.cpp index dd4305de1..f8852c5e5 100644 --- a/src/creatures/combat/spells.cpp +++ b/src/creatures/combat/spells.cpp @@ -108,7 +108,7 @@ void Spells::clear() { bool Spells::hasInstantSpell(const std::string &word) const { if (auto iterate = instants.find(word); - iterate != instants.end()) { + iterate != instants.end()) { return true; } return false; @@ -127,8 +127,8 @@ bool Spells::registerInstantLuaEvent(const std::shared_ptr instant // Checks if there is any spell registered with the same name if (hasInstantSpell(words)) { g_logger().warn("[Spells::registerInstantLuaEvent] - " - "Duplicate registered instant spell with words: {}, on spell with name: {}", - words, instantName); + "Duplicate registered instant spell with words: {}, on spell with name: {}", + words, instantName); return false; } // Register spell word in the map @@ -166,7 +166,7 @@ std::list Spells::getSpellsByVocation(uint16_t vocationId) { vocSpellsIt = vocSpells.find(vocationId); if (vocSpellsIt != vocSpells.end() - && vocSpellsIt->second) { + && vocSpellsIt->second) { spellsList.push_back(it.second->getSpellId()); } } @@ -361,8 +361,8 @@ bool CombatSpell::executeCastSpell(std::shared_ptr creature, const Lua // onCastSpell(creature, var) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CombatSpell::executeCastSpell - Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName()); return false; } @@ -950,8 +950,8 @@ bool InstantSpell::executeCastSpell(std::shared_ptr creature, const Lu // onCastSpell(creature, var) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[InstantSpell::executeCastSpell - Creature {} words {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), getWords()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), getWords()); return false; } @@ -1095,8 +1095,8 @@ bool RuneSpell::executeCastSpell(std::shared_ptr creature, const LuaVa // onCastSpell(creature, var, isHotkey) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[RuneSpell::executeCastSpell - Creature {} runeId {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), getRuneItemId()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), getRuneItemId()); return false; } diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 7796863f0..c68ab4f35 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -259,7 +259,7 @@ void Creature::addEventWalk(bool firstStep) { self->eventWalk = g_dispatcher().scheduleEvent( static_cast(ticks), - [creatureId = self->getID()] { g_game().checkCreatureWalk(creatureId); }, "Creature::checkCreatureWalk" + [creatureId = self->getID()] { g_game().checkCreatureWalk(creatureId); }, "Game::checkCreatureWalk" ); }); } @@ -828,7 +828,7 @@ bool Creature::dropCorpse(std::shared_ptr lastHitCreature, std::shared g_dispatcher().addEvent([player, corpseContainer, corpsePosition = corpse->getPosition()] { g_game().playerQuickLootCorpse(player, corpseContainer, corpsePosition); }, - "Game::playerQuickLootCorpse"); + "Game::playerQuickLootCorpse"); } } } diff --git a/src/creatures/creatures_definitions.hpp b/src/creatures/creatures_definitions.hpp index 33f62dbd2..74ec6c5f2 100644 --- a/src/creatures/creatures_definitions.hpp +++ b/src/creatures/creatures_definitions.hpp @@ -1524,12 +1524,12 @@ using StashItemList = std::map; using ItemsTierCountList = std::map>; /* - > ItemsTierCountList structure: - |- [itemID] - |- [itemTier] - |- Count - | ... - | ... + > ItemsTierCountList structure: + |- [itemID] + |- [itemTier] + |- Count + | ... + | ... */ struct ProtocolFamiliars { diff --git a/src/creatures/interactions/chat.cpp b/src/creatures/interactions/chat.cpp index e16af670f..900247e45 100644 --- a/src/creatures/interactions/chat.cpp +++ b/src/creatures/interactions/chat.cpp @@ -145,8 +145,8 @@ bool ChatChannel::executeCanJoinEvent(const std::shared_ptr &player) { LuaScriptInterface* scriptInterface = g_chat().getScriptInterface(); if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[CanJoinChannelEvent::execute - Player {}, on channel {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), getName()); return false; } @@ -171,8 +171,8 @@ bool ChatChannel::executeOnJoinEvent(const std::shared_ptr &player) { LuaScriptInterface* scriptInterface = g_chat().getScriptInterface(); if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[OnJoinChannelEvent::execute - Player {}, on channel {}] " - "Call stack overflow. Too many lua script calls being nested", - player->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested", + player->getName(), getName()); return false; } @@ -197,8 +197,8 @@ bool ChatChannel::executeOnLeaveEvent(const std::shared_ptr &player) { LuaScriptInterface* scriptInterface = g_chat().getScriptInterface(); if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[OnLeaveChannelEvent::execute - Player {}, on channel {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), getName()); return false; } @@ -223,8 +223,8 @@ bool ChatChannel::executeOnSpeakEvent(const std::shared_ptr &player, Spe LuaScriptInterface* scriptInterface = g_chat().getScriptInterface(); if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[OnSpeakChannelEvent::execute - Player {}, type {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), fmt::underlying(type)); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), fmt::underlying(type)); return false; } diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index 5e0a7d16b..4b993cbab 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -50,8 +50,8 @@ Monster::Monster(const std::shared_ptr mType) : for (const std::string &scriptName : mType->info.scripts) { if (!registerCreatureEvent(scriptName)) { g_logger().warn("[Monster::Monster] - " - "Unknown event name: {}", - scriptName); + "Unknown event name: {}", + scriptName); } } } @@ -138,8 +138,8 @@ void Monster::onCreatureAppear(std::shared_ptr creature, bool isLogin) LuaScriptInterface* scriptInterface = mType->info.scriptInterface; if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[Monster::onCreatureAppear - Monster {} creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - getName(), creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + getName(), creature->getName()); return; } @@ -176,8 +176,8 @@ void Monster::onRemoveCreature(std::shared_ptr creature, bool isLogout LuaScriptInterface* scriptInterface = mType->info.scriptInterface; if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[Monster::onCreatureDisappear - Monster {} creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - getName(), creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + getName(), creature->getName()); return; } @@ -217,8 +217,8 @@ void Monster::onCreatureMove(const std::shared_ptr &creature, const st LuaScriptInterface* scriptInterface = mType->info.scriptInterface; if (!scriptInterface->reserveScriptEnv()) { g_logger().error("[Monster::onCreatureMove - Monster {} creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - getName(), creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + getName(), creature->getName()); return; } @@ -291,8 +291,8 @@ void Monster::onCreatureSay(std::shared_ptr creature, SpeakClasses typ LuaScriptInterface* scriptInterface = mType->info.scriptInterface; if (!scriptInterface->reserveScriptEnv()) { g_logger().error("Monster {} creature {}] Call stack overflow. Too many lua " - "script calls being nested.", - getName(), creature->getName()); + "script calls being nested.", + getName(), creature->getName()); return; } @@ -771,8 +771,8 @@ void Monster::onThink(uint32_t interval) { LuaScriptInterface* scriptInterface = mType->info.scriptInterface; if (!scriptInterface->reserveScriptEnv()) { g_logger().error("Monster {} Call stack overflow. Too many lua script calls " - "being nested.", - getName()); + "being nested.", + getName()); return; } @@ -2041,8 +2041,8 @@ void Monster::dropLoot(std::shared_ptr corpse, std::shared_ptr corpse, std::shared_ptr lastHitCreature) override; void getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) override; bool useCacheMap() const override { - return !randomStepping; + // return !randomStepping; + // As the map cache is done synchronously for each movement that a monster makes, it is better to disable it, + // as the pathfinder, which is one of the resources that uses this cache the most, + // is multithreding and thus the processing cost is divided between the threads. + return false; } friend class MonsterFunctions; diff --git a/src/creatures/monsters/monsters.cpp b/src/creatures/monsters/monsters.cpp index 3d457aa4d..78358f69d 100644 --- a/src/creatures/monsters/monsters.cpp +++ b/src/creatures/monsters/monsters.cpp @@ -97,7 +97,7 @@ bool Monsters::deserializeSpell(const std::shared_ptr spell, spell } if (std::string spellName = asLowerCaseString(spell->name); - spellName == "melee") { + spellName == "melee") { sb.isMelee = true; if (spell->attack > 0 && spell->skill > 0) { @@ -164,8 +164,8 @@ bool Monsters::deserializeSpell(const std::shared_ptr spell, spell condition->setOutfit(outfit); } else { g_logger().error("[Monsters::deserializeSpell] - " - "Missing outfit monster or item in outfit spell for: {}", - description); + "Missing outfit monster or item in outfit spell for: {}", + description); return false; } @@ -208,8 +208,8 @@ bool Monsters::deserializeSpell(const std::shared_ptr spell, spell } else if (spellName == "condition") { if (spell->conditionType == CONDITION_NONE) { g_logger().error("[Monsters::deserializeSpell] - " - "{} condition is not set for: {}", - description, spell->name); + "{} condition is not set for: {}", + description, spell->name); } } else if (spellName == "strength") { // @@ -217,8 +217,8 @@ bool Monsters::deserializeSpell(const std::shared_ptr spell, spell // } else { g_logger().error("[Monsters::deserializeSpell] - " - "{} unknown or missing parameter on spell with name: {}", - description, spell->name); + "{} unknown or missing parameter on spell with name: {}", + description, spell->name); } if (spell->shoot != CONST_ANI_NONE) { @@ -295,9 +295,9 @@ bool MonsterType::loadCallback(LuaScriptInterface* scriptInterface) { std::shared_ptr Monsters::getMonsterType(const std::string &name, bool silent /* = false*/) const { std::string lowerCaseName = asLowerCaseString(name); if (auto it = monsters.find(lowerCaseName); - it != monsters.end() - // We will only return the MonsterType if it match the exact name of the monster - && it->first.find(lowerCaseName) != it->first.npos) { + it != monsters.end() + // We will only return the MonsterType if it match the exact name of the monster + && it->first.find(lowerCaseName) != it->first.npos) { return it->second; } if (!silent) { diff --git a/src/creatures/npcs/npc.cpp b/src/creatures/npcs/npc.cpp index e445a58fc..fdbf58853 100644 --- a/src/creatures/npcs/npc.cpp +++ b/src/creatures/npcs/npc.cpp @@ -101,14 +101,13 @@ void Npc::onRemoveCreature(std::shared_ptr creature, bool isLogout) { } if (auto player = creature->getPlayer()) { + removeShopPlayer(player->getGUID()); onPlayerDisappear(player); } if (spawnNpc) { spawnNpc->startSpawnNpcCheck(); } - - shopPlayerMap.clear(); } void Npc::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { @@ -259,7 +258,7 @@ void Npc::onPlayerBuyItem(std::shared_ptr player, uint16_t itemId, uint8 } uint32_t buyPrice = 0; - const std::vector &shopVector = getShopItemVector(player->getGUID()); + const auto &shopVector = getShopItemVector(player->getGUID()); for (const ShopBlock &shopBlock : shopVector) { if (itemType.id == shopBlock.itemId && shopBlock.itemBuyPrice != 0) { buyPrice = shopBlock.itemBuyPrice; @@ -372,7 +371,7 @@ void Npc::onPlayerSellItem(std::shared_ptr player, uint16_t itemId, uint uint32_t sellPrice = 0; const ItemType &itemType = Item::items[itemId]; - const std::vector &shopVector = getShopItemVector(player->getGUID()); + const auto &shopVector = getShopItemVector(player->getGUID()); for (const ShopBlock &shopBlock : shopVector) { if (itemType.id == shopBlock.itemId && shopBlock.itemSellPrice != 0) { sellPrice = shopBlock.itemSellPrice; @@ -522,7 +521,7 @@ void Npc::onThinkWalk(uint32_t interval) { } if (Direction newDirection; - getRandomStep(newDirection)) { + getRandomStep(newDirection)) { listWalkDir.push_front(newDirection); addEventWalk(); } @@ -586,7 +585,7 @@ void Npc::setPlayerInteraction(uint32_t playerId, uint16_t topicId /*= 0*/) { void Npc::removePlayerInteraction(std::shared_ptr player) { if (playerInteractions.contains(player->getID())) { playerInteractions.erase(player->getID()); - player->closeShopWindow(true); + player->closeShopWindow(); } } @@ -634,7 +633,7 @@ bool Npc::getRandomStep(Direction &moveDirection) { std::ranges::shuffle(directionvector, getRandomGenerator()); for (const Position &creaturePos = getPosition(); - Direction direction : directionvector) { + Direction direction : directionvector) { if (canWalkTo(creaturePos, direction)) { moveDirection = direction; return true; @@ -643,30 +642,26 @@ bool Npc::getRandomStep(Direction &moveDirection) { return false; } -void Npc::addShopPlayer(const std::shared_ptr &player, const std::vector &shopItems /* = {}*/) { - if (!player) { - return; - } - - shopPlayerMap.try_emplace(player->getGUID(), shopItems); +bool Npc::isShopPlayer(uint32_t playerGUID) const { + return shopPlayers.find(playerGUID) != shopPlayers.end(); } -void Npc::removeShopPlayer(const std::shared_ptr &player) { - if (!player) { - return; - } +void Npc::addShopPlayer(uint32_t playerGUID, const std::vector &shopItems) { + shopPlayers.try_emplace(playerGUID, shopItems); +} - shopPlayerMap.erase(player->getGUID()); +void Npc::removeShopPlayer(uint32_t playerGUID) { + shopPlayers.erase(playerGUID); } void Npc::closeAllShopWindows() { - for (const auto &[playerGUID, playerPtr] : shopPlayerMap) { - auto shopPlayer = g_game().getPlayerByGUID(playerGUID); - if (shopPlayer) { - shopPlayer->closeShopWindow(); + for (const auto &[playerGUID, shopBlock] : shopPlayers) { + const auto &player = g_game().getPlayerByGUID(playerGUID); + if (player) { + player->closeShopWindow(); } } - shopPlayerMap.clear(); + shopPlayers.clear(); } void Npc::handlePlayerMove(std::shared_ptr player, const Position &newPos) { diff --git a/src/creatures/npcs/npc.hpp b/src/creatures/npcs/npc.hpp index 7e8be84c7..c246aa4b6 100644 --- a/src/creatures/npcs/npc.hpp +++ b/src/creatures/npcs/npc.hpp @@ -95,10 +95,10 @@ class Npc final : public Creature { npcType->info.currencyId = currency; } - std::vector getShopItemVector(uint32_t playerGUID) { + const std::vector &getShopItemVector(uint32_t playerGUID) const { if (playerGUID != 0) { - auto it = shopPlayerMap.find(playerGUID); - if (it != shopPlayerMap.end() && !it->second.empty()) { + auto it = shopPlayers.find(playerGUID); + if (it != shopPlayers.end() && !it->second.empty()) { return it->second; } } @@ -165,8 +165,10 @@ class Npc final : public Creature { internalLight = npcType->info.light; } - void addShopPlayer(const std::shared_ptr &player, const std::vector &shopItems = {}); - void removeShopPlayer(const std::shared_ptr &player); + bool isShopPlayer(uint32_t playerGUID) const; + + void addShopPlayer(uint32_t playerGUID, const std::vector &shopItems); + void removeShopPlayer(uint32_t playerGUID); void closeAllShopWindows(); static uint32_t npcAutoID; @@ -184,7 +186,7 @@ class Npc final : public Creature { std::map playerInteractions; - phmap::flat_hash_map> shopPlayerMap; + std::unordered_map> shopPlayers; std::shared_ptr npcType; std::shared_ptr spawnNpc; diff --git a/src/creatures/players/achievement/player_achievement.cpp b/src/creatures/players/achievement/player_achievement.cpp index 2db53dbe7..cd0735ab5 100644 --- a/src/creatures/players/achievement/player_achievement.cpp +++ b/src/creatures/players/achievement/player_achievement.cpp @@ -35,7 +35,7 @@ bool PlayerAchievement::add(uint16_t id, bool message /* = true*/, uint32_t time addPoints(achievement.points); int toSaveTimeStamp = timestamp != 0 ? timestamp : (OTSYS_TIME() / 1000); getUnlockedKV()->set(achievement.name, toSaveTimeStamp); - m_achievementsUnlocked.push_back({ achievement.id, toSaveTimeStamp }); + m_achievementsUnlocked.emplace_back(achievement.id, toSaveTimeStamp); m_achievementsUnlocked.shrink_to_fit(); return true; } @@ -53,7 +53,7 @@ bool PlayerAchievement::remove(uint16_t id) { if (auto it = std::find_if(m_achievementsUnlocked.begin(), m_achievementsUnlocked.end(), [id](auto achievement_it) { return achievement_it.first == id; }); - it != m_achievementsUnlocked.end()) { + it != m_achievementsUnlocked.end()) { getUnlockedKV()->remove(achievement.name); m_achievementsUnlocked.erase(it); removePoints(achievement.points); @@ -72,7 +72,7 @@ bool PlayerAchievement::isUnlocked(uint16_t id) const { if (auto it = std::find_if(m_achievementsUnlocked.begin(), m_achievementsUnlocked.end(), [id](auto achievement_it) { return achievement_it.first == id; }); - it != m_achievementsUnlocked.end()) { + it != m_achievementsUnlocked.end()) { return true; } @@ -80,7 +80,8 @@ bool PlayerAchievement::isUnlocked(uint16_t id) const { } uint16_t PlayerAchievement::getPoints() const { - return m_player.kv()->scoped("achievements")->get("points")->getNumber(); + auto kvScoped = m_player.kv()->scoped("achievements")->get("points"); + return kvScoped ? static_cast(kvScoped->getNumber()) : 0; } void PlayerAchievement::addPoints(uint16_t toAddPoints) { @@ -109,12 +110,12 @@ void PlayerAchievement::loadUnlockedAchievements() { g_logger().debug("[{}] - Achievement {} found for player {}.", __FUNCTION__, achievementName, m_player.getName()); - m_achievementsUnlocked.push_back({ achievement.id, getUnlockedKV()->get(achievementName)->getNumber() }); + m_achievementsUnlocked.emplace_back(achievement.id, getUnlockedKV()->get(achievementName)->getNumber()); } } void PlayerAchievement::sendUnlockedSecretAchievements() { - std::vector> m_achievementsUnlocked; + std::vector> achievementsUnlocked; uint16_t unlockedSecret = 0; for (const auto &[achievId, achievCreatedTime] : getUnlockedAchievements()) { Achievement achievement = g_game().getAchievementById(achievId); @@ -126,10 +127,10 @@ void PlayerAchievement::sendUnlockedSecretAchievements() { unlockedSecret++; } - m_achievementsUnlocked.push_back({ achievement, achievCreatedTime }); + achievementsUnlocked.emplace_back(achievement, achievCreatedTime); } - m_player.sendCyclopediaCharacterAchievements(unlockedSecret, m_achievementsUnlocked); + m_player.sendCyclopediaCharacterAchievements(unlockedSecret, achievementsUnlocked); } const std::shared_ptr &PlayerAchievement::getUnlockedKV() { diff --git a/src/creatures/players/achievement/player_achievement.hpp b/src/creatures/players/achievement/player_achievement.hpp index d1073a9bf..e0c027e58 100644 --- a/src/creatures/players/achievement/player_achievement.hpp +++ b/src/creatures/players/achievement/player_achievement.hpp @@ -31,11 +31,11 @@ class PlayerAchievement { explicit PlayerAchievement(Player &player); bool add(uint16_t id, bool message = true, uint32_t timestamp = 0); bool remove(uint16_t id); - bool isUnlocked(uint16_t id) const; - uint16_t getPoints() const; + [[nodiscard]] bool isUnlocked(uint16_t id) const; + [[nodiscard]] uint16_t getPoints() const; void addPoints(uint16_t toAddPoints); void removePoints(uint16_t toRemovePoints); - std::vector> getUnlockedAchievements() const; + [[nodiscard]] std::vector> getUnlockedAchievements() const; void loadUnlockedAchievements(); void sendUnlockedSecretAchievements(); const std::shared_ptr &getUnlockedKV(); diff --git a/src/creatures/players/cyclopedia/player_badge.cpp b/src/creatures/players/cyclopedia/player_badge.cpp index 9b892a616..639640b2f 100644 --- a/src/creatures/players/cyclopedia/player_badge.cpp +++ b/src/creatures/players/cyclopedia/player_badge.cpp @@ -26,7 +26,7 @@ bool PlayerBadge::hasBadge(uint8_t id) const { if (auto it = std::find_if(m_badgesUnlocked.begin(), m_badgesUnlocked.end(), [id](auto badge_it) { return badge_it.first.m_id == id; }); - it != m_badgesUnlocked.end()) { + it != m_badgesUnlocked.end()) { return true; } diff --git a/src/creatures/players/cyclopedia/player_cyclopedia.cpp b/src/creatures/players/cyclopedia/player_cyclopedia.cpp new file mode 100644 index 000000000..abbc920d3 --- /dev/null +++ b/src/creatures/players/cyclopedia/player_cyclopedia.cpp @@ -0,0 +1,185 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2024 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +#include "pch.hpp" + +#include "database/databasetasks.hpp" +#include "creatures/players/player.hpp" +#include "player_cyclopedia.hpp" +#include "game/game.hpp" +#include "kv/kv.hpp" + +PlayerCyclopedia::PlayerCyclopedia(Player &player) : + m_player(player) { } + +Summary PlayerCyclopedia::getSummary() { + return { getAmount(Summary_t::PREY_CARDS), + getAmount(Summary_t::INSTANT_REWARDS), + getAmount(Summary_t::HIRELINGS) }; +} + +void PlayerCyclopedia::loadSummaryData() { + DBResult_ptr result = g_database().storeQuery(fmt::format("SELECT COUNT(*) as `count` FROM `player_hirelings` WHERE `player_id` = {}", m_player.getGUID())); + auto kvScoped = m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(static_cast(Summary_t::HIRELINGS))); + if (result && !kvScoped->get("amount").has_value()) { + kvScoped->set("amount", result->getNumber("count")); + } +} + +void PlayerCyclopedia::loadDeathHistory(uint16_t page, uint16_t entriesPerPage) { + Benchmark bm_check; + uint32_t offset = static_cast(page - 1) * entriesPerPage; + auto query = fmt::format("SELECT `time`, `level`, `killed_by`, `mostdamage_by`, (select count(*) FROM `player_deaths` WHERE `player_id` = {}) as `entries` FROM `player_deaths` WHERE `player_id` = {} AND `time` >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY)) ORDER BY `time` DESC LIMIT {}, {}", m_player.getGUID(), m_player.getGUID(), offset, entriesPerPage); + + uint32_t playerID = m_player.getID(); + std::function callback = [playerID, page, entriesPerPage](const DBResult_ptr &result, bool) { + std::shared_ptr player = g_game().getPlayerByID(playerID); + if (!player) { + return; + } + + player->resetAsyncOngoingTask(PlayerAsyncTask_RecentDeaths); + if (!result) { + player->sendCyclopediaCharacterRecentDeaths(0, 0, {}); + return; + } + + auto pages = result->getNumber("entries"); + pages += entriesPerPage - 1; + pages /= entriesPerPage; + + std::vector entries; + entries.reserve(result->countResults()); + do { + std::string killed_by = result->getString("killed_by"); + std::string mostdamage_by = result->getString("mostdamage_by"); + + std::string cause = fmt::format("Died at Level {}", result->getNumber("level")); + + if (!killed_by.empty()) { + cause.append(fmt::format(" by{}", formatWithArticle(killed_by))); + } + + if (!mostdamage_by.empty()) { + cause.append(fmt::format("{}{}", !killed_by.empty() ? " and" : "", formatWithArticle(mostdamage_by))); + } + + entries.emplace_back(cause, result->getNumber("time")); + } while (result->next()); + player->sendCyclopediaCharacterRecentDeaths(page, static_cast(pages), entries); + }; + g_databaseTasks().store(query, callback); + m_player.addAsyncOngoingTask(PlayerAsyncTask_RecentDeaths); + + g_logger().debug("Loading death history from the player {} took {} milliseconds.", m_player.getName(), bm_check.duration()); +} + +void PlayerCyclopedia::loadRecentKills(uint16_t page, uint16_t entriesPerPage) { + Benchmark bm_check; + + const std::string &escapedName = g_database().escapeString(m_player.getName()); + uint32_t offset = static_cast(page - 1) * entriesPerPage; + auto query = fmt::format("SELECT `d`.`time`, `d`.`killed_by`, `d`.`mostdamage_by`, `d`.`unjustified`, `d`.`mostdamage_unjustified`, `p`.`name`, (select count(*) FROM `player_deaths` WHERE ((`killed_by` = {} AND `is_player` = 1) OR (`mostdamage_by` = {} AND `mostdamage_is_player` = 1))) as `entries` FROM `player_deaths` AS `d` INNER JOIN `players` AS `p` ON `d`.`player_id` = `p`.`id` WHERE ((`d`.`killed_by` = {} AND `d`.`is_player` = 1) OR (`d`.`mostdamage_by` = {} AND `d`.`mostdamage_is_player` = 1)) AND `time` >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 70 DAY)) ORDER BY `time` DESC LIMIT {}, {}", escapedName, escapedName, escapedName, escapedName, offset, entriesPerPage); + + uint32_t playerID = m_player.getID(); + std::function callback = [playerID, page, entriesPerPage](const DBResult_ptr &result, bool) { + std::shared_ptr player = g_game().getPlayerByID(playerID); + if (!player) { + return; + } + + player->resetAsyncOngoingTask(PlayerAsyncTask_RecentPvPKills); + if (!result) { + player->sendCyclopediaCharacterRecentPvPKills(0, 0, {}); + return; + } + + auto pages = result->getNumber("entries"); + pages += entriesPerPage - 1; + pages /= entriesPerPage; + + std::vector entries; + entries.reserve(result->countResults()); + do { + std::string cause1 = result->getString("killed_by"); + std::string cause2 = result->getString("mostdamage_by"); + std::string name = result->getString("name"); + + uint8_t status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_JUSTIFIED; + if (player->getName() == cause1) { + if (result->getNumber("unjustified") == 1) { + status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED; + } + } else if (player->getName() == cause2) { + if (result->getNumber("mostdamage_unjustified") == 1) { + status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED; + } + } + + entries.emplace_back(fmt::format("Killed {}.", name), result->getNumber("time"), status); + } while (result->next()); + player->sendCyclopediaCharacterRecentPvPKills(page, static_cast(pages), entries); + }; + g_databaseTasks().store(query, callback); + m_player.addAsyncOngoingTask(PlayerAsyncTask_RecentPvPKills); + + g_logger().debug("Loading recent kills from the player {} took {} milliseconds.", m_player.getName(), bm_check.duration()); +} + +void PlayerCyclopedia::updateStoreSummary(uint8_t type, uint16_t amount, const std::string &id) { + switch (type) { + case Summary_t::HOUSE_ITEMS: + case Summary_t::BLESSINGS: + insertValue(type, amount, id); + break; + case Summary_t::ALL_BLESSINGS: + for (int i = 1; i < 8; ++i) { + insertValue(static_cast(Summary_t::BLESSINGS), amount, fmt::format("{}", i)); + } + break; + default: + updateAmount(type, amount); + break; + } +} + +uint16_t PlayerCyclopedia::getAmount(uint8_t type) { + auto kvScope = m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type))->get("amount"); + return static_cast(kvScope ? kvScope->getNumber() : 0); +} + +void PlayerCyclopedia::updateAmount(uint8_t type, uint16_t amount) { + auto oldAmount = getAmount(type); + m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type))->set("amount", oldAmount + amount); +} + +std::map PlayerCyclopedia::getResult(uint8_t type) const { + auto kvScope = m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type)); + std::map result; // ID, amount + for (const auto &scope : kvScope->keys()) { + size_t pos = scope.find('.'); + if (pos == std::string::npos) { + g_logger().error("[{}] Invalid key format: {}", __FUNCTION__, scope); + continue; + } + std::string id = scope.substr(0, pos); + auto amount = kvScope->scoped(id)->get("amount"); + result.emplace(std::stoll(id), static_cast(amount ? amount->getNumber() : 0)); + } + return result; +} + +void PlayerCyclopedia::insertValue(uint8_t type, uint16_t amount, const std::string &id) { + auto result = getResult(type); + auto it = result.find(std::stoll(id)); + auto oldAmount = (it != result.end() ? it->second : 0); + auto newAmount = oldAmount + amount; + m_player.kv()->scoped("summary")->scoped(g_game().getSummaryKeyByType(type))->scoped(id)->set("amount", newAmount); + g_logger().debug("[{}] type: {}, id: {}, old amount: {}, added amount: {}, new amount: {}", __FUNCTION__, type, id, oldAmount, amount, newAmount); +} diff --git a/src/creatures/players/cyclopedia/player_cyclopedia.hpp b/src/creatures/players/cyclopedia/player_cyclopedia.hpp new file mode 100644 index 000000000..32c446cc3 --- /dev/null +++ b/src/creatures/players/cyclopedia/player_cyclopedia.hpp @@ -0,0 +1,46 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2024 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +#pragma once + +#include "creatures/creatures_definitions.hpp" +#include "enums/player_cyclopedia.hpp" + +class Player; +class KV; + +struct Summary { + uint16_t m_preyWildcards = 0; + uint16_t m_instantRewards = 0; + uint16_t m_hirelings = 0; + + [[maybe_unused]] Summary(uint16_t mPreyWildcards, uint16_t mInstantRewards, uint16_t mHirelings) : + m_preyWildcards(mPreyWildcards), m_instantRewards(mInstantRewards), m_hirelings(mHirelings) { } +}; + +class PlayerCyclopedia { +public: + explicit PlayerCyclopedia(Player &player); + + Summary getSummary(); + + void loadSummaryData(); + void loadDeathHistory(uint16_t page, uint16_t entriesPerPage); + void loadRecentKills(uint16_t page, uint16_t entriesPerPage); + + void updateStoreSummary(uint8_t type, uint16_t amount = 1, const std::string &id = ""); + uint16_t getAmount(uint8_t type); + void updateAmount(uint8_t type, uint16_t amount = 1); + + [[nodiscard]] std::map getResult(uint8_t type) const; + void insertValue(uint8_t type, uint16_t amount = 1, const std::string &id = ""); + +private: + Player &m_player; +}; diff --git a/src/creatures/players/cyclopedia/player_title.cpp b/src/creatures/players/cyclopedia/player_title.cpp index 624b03134..7c348cbf7 100644 --- a/src/creatures/players/cyclopedia/player_title.cpp +++ b/src/creatures/players/cyclopedia/player_title.cpp @@ -26,7 +26,7 @@ bool PlayerTitle::isTitleUnlocked(uint8_t id) const { if (auto it = std::find_if(m_titlesUnlocked.begin(), m_titlesUnlocked.end(), [id](auto title_it) { return title_it.first.m_id == id; }); - it != m_titlesUnlocked.end()) { + it != m_titlesUnlocked.end()) { return true; } @@ -84,7 +84,8 @@ const std::vector> &PlayerTitle::getUnlockedTitles() } uint8_t PlayerTitle::getCurrentTitle() const { - return static_cast(m_player.kv()->scoped("titles")->get("current-title")->getNumber()); + auto title = m_player.kv()->scoped("titles")->get("current-title"); + return title ? static_cast(title->getNumber()) : 0; } void PlayerTitle::setCurrentTitle(uint8_t id) { diff --git a/src/creatures/players/grouping/familiars.cpp b/src/creatures/players/grouping/familiars.cpp index 6e923b823..6312aaa28 100644 --- a/src/creatures/players/grouping/familiars.cpp +++ b/src/creatures/players/grouping/familiars.cpp @@ -77,7 +77,7 @@ std::shared_ptr Familiars::getFamiliarByLookType(uint16_t vocation, ui if (auto it = std::find_if(familiars[vocation].begin(), familiars[vocation].end(), [lookType](auto familiar_it) { return familiar_it->lookType == lookType; }); - it != familiars[vocation].end()) { + it != familiars[vocation].end()) { return *it; } return nullptr; diff --git a/src/creatures/players/grouping/groups.cpp b/src/creatures/players/grouping/groups.cpp index 937fa848f..c4dab4a90 100644 --- a/src/creatures/players/grouping/groups.cpp +++ b/src/creatures/players/grouping/groups.cpp @@ -103,7 +103,7 @@ std::shared_ptr Groups::getGroup(uint16_t id) const { if (auto it = std::find_if(groups_vector.begin(), groups_vector.end(), [id](auto group_it) { return group_it->id == id; }); - it != groups_vector.end()) { + it != groups_vector.end()) { return *it; } return nullptr; diff --git a/src/creatures/players/grouping/party.hpp b/src/creatures/players/grouping/party.hpp index 10663a278..6aaecc561 100644 --- a/src/creatures/players/grouping/party.hpp +++ b/src/creatures/players/grouping/party.hpp @@ -108,7 +108,7 @@ class Party : public SharedObject { if (auto it = std::find_if(membersData.begin(), membersData.end(), [playerId](const std::shared_ptr &preyIt) { return preyIt->id == playerId; }); - it != membersData.end()) { + it != membersData.end()) { return *it; } diff --git a/src/creatures/players/imbuements/imbuements.cpp b/src/creatures/players/imbuements/imbuements.cpp index ed312dbf8..4bfb0de83 100644 --- a/src/creatures/players/imbuements/imbuements.cpp +++ b/src/creatures/players/imbuements/imbuements.cpp @@ -347,9 +347,9 @@ std::vector Imbuements::getImbuements(std::shared_ptr player // Parse the storages for each imbuement in imbuements.xml and config.lua (enable/disable storage) if (g_configManager().getBoolean(TOGGLE_IMBUEMENT_SHRINE_STORAGE, __FUNCTION__) - && imbuement->getStorage() != 0 - && player->getStorageValue(imbuement->getStorage() == -1) - && imbuement->getBaseID() >= 1 && imbuement->getBaseID() <= 3) { + && imbuement->getStorage() != 0 + && player->getStorageValue(imbuement->getStorage() == -1) + && imbuement->getBaseID() >= 1 && imbuement->getBaseID() <= 3) { continue; } diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 2c92f6941..eddffa20a 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -17,6 +17,7 @@ #include "creatures/players/wheel/player_wheel.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" +#include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" #include "creatures/players/storages/storages.hpp" #include "game/game.hpp" @@ -53,6 +54,7 @@ Player::Player(ProtocolGame_ptr p) : m_wheelPlayer = std::make_unique(*this); m_playerAchievement = std::make_unique(*this); m_playerBadge = std::make_unique(*this); + m_playerCyclopedia = std::make_unique(*this); m_playerTitle = std::make_unique(*this); } @@ -284,7 +286,7 @@ std::shared_ptr Player::getQuiverAmmoOfType(const ItemType &it) const { std::shared_ptr quiver = inventory[CONST_SLOT_RIGHT]; for (std::shared_ptr container = quiver->getContainer(); - auto ammoItem : container->getItemList()) { + auto ammoItem : container->getItemList()) { if (ammoItem->getAmmoType() == it.ammoType) { if (level >= Item::items[ammoItem->getID()].minReqLevel) { return ammoItem; @@ -633,20 +635,6 @@ phmap::flat_hash_map> Player::getAllSlotItems() c return itemMap; } -phmap::flat_hash_map Player::getBlessingNames() const { - static phmap::flat_hash_map blessingNames = { - { TWIST_OF_FATE, "Twist of Fate" }, - { WISDOM_OF_SOLITUDE, "The Wisdom of Solitude" }, - { SPARK_OF_THE_PHOENIX, "The Spark of the Phoenix" }, - { FIRE_OF_THE_SUNS, "The Fire of the Suns" }, - { SPIRITUAL_SHIELDING, "The Spiritual Shielding" }, - { EMBRACE_OF_TIBIA, "The Embrace of Tibia" }, - { BLOOD_OF_THE_MOUNTAIN, "Blood of the Mountain" }, - { HEARTH_OF_THE_MOUNTAIN, "Heart of the Mountain" }, - }; - return blessingNames; -} - void Player::setTraining(bool value) { for (const auto &[key, player] : g_game().getPlayers()) { if (!this->isInGhostMode() || player->isAccessPlayer()) { @@ -1894,32 +1882,39 @@ void Player::onRemoveCreature(std::shared_ptr creature, bool isLogout) } } -bool Player::openShopWindow(std::shared_ptr npc) { +bool Player::openShopWindow(std::shared_ptr npc, const std::vector &shopItems) { + Benchmark brenchmark; if (!npc) { g_logger().error("[Player::openShopWindow] - Npc is wrong or nullptr"); return false; } + if (npc->isShopPlayer(getGUID())) { + g_logger().debug("[Player::openShopWindow] - Player {} is already in shop window", getName()); + return false; + } + + npc->addShopPlayer(getGUID(), shopItems); + setShopOwner(npc); sendShop(npc); std::map inventoryMap; sendSaleItemList(getAllSaleItemIdAndCount(inventoryMap)); + + g_logger().debug("[Player::openShopWindow] - Player {} has opened shop window in {} ms", getName(), brenchmark.duration()); return true; } -bool Player::closeShopWindow(bool sendCloseShopWindow /*= true*/) { +bool Player::closeShopWindow() { if (!shopOwner) { return false; } - shopOwner->removeShopPlayer(static_self_cast()); + shopOwner->removeShopPlayer(getGUID()); setShopOwner(nullptr); - if (sendCloseShopWindow) { - sendCloseShop(); - } - + sendCloseShop(); return true; } @@ -3828,7 +3823,7 @@ bool Player::hasItemCountById(uint16_t itemId, uint32_t itemAmount, bool checkSt // Check items from stash for (StashItemList stashToSend = getStashItems(); - auto [stashItemId, itemCount] : stashToSend) { + auto [stashItemId, itemCount] : stashToSend) { if (!checkStash) { break; } @@ -4293,7 +4288,7 @@ bool Player::hasShopItemForSale(uint16_t itemId, uint8_t subType) const { } const ItemType &itemType = Item::items[itemId]; - std::vector shoplist = shopOwner->getShopItemVector(getGUID()); + const auto &shoplist = shopOwner->getShopItemVector(getGUID()); return std::any_of(shoplist.begin(), shoplist.end(), [&](const ShopBlock &shopBlock) { return shopBlock.itemId == itemId && shopBlock.itemBuyPrice != 0 && (!itemType.isFluidContainer() || shopBlock.itemSubType == subType); }); @@ -5385,7 +5380,7 @@ uint16_t Player::getSkillLevel(skills_t skill) const { skillLevel = std::max(0, skillLevel + varSkills[skill]); if (auto it = maxValuePerSkill.find(skill); - it != maxValuePerSkill.end()) { + it != maxValuePerSkill.end()) { skillLevel = std::min(it->second, skillLevel); } @@ -6221,7 +6216,7 @@ std::pair Player::getForgeSliversAndCores() const { // Check items from stash for (StashItemList stashToSend = getStashItems(); - auto [itemId, itemCount] : stashToSend) { + auto [itemId, itemCount] : stashToSend) { if (itemId == ITEM_FORGE_SLIVER) { sliverCount += itemCount; } @@ -6612,12 +6607,12 @@ std::string Player::getBlessingsName() const { } }); - auto BlessingNames = getBlessingNames(); + auto BlessingNames = g_game().getBlessingNames(); std::ostringstream os; for (uint8_t i = 1; i <= 8; i++) { if (hasBlessing(i)) { if (auto blessName = BlessingNames.find(static_cast(i)); - blessName != BlessingNames.end()) { + blessName != BlessingNames.end()) { os << (*blessName).second; } else { continue; @@ -6810,7 +6805,7 @@ void Player::requestDepotSearchItem(uint16_t itemId, uint8_t tier) { uint32_t stashCount = 0; if (const ItemType &iType = Item::items[itemId]; - iType.stackable && iType.wareId > 0) { + iType.stackable && iType.wareId > 0) { stashCount = getStashItemCount(itemId); } @@ -6859,10 +6854,10 @@ void Player::retrieveAllItemsFromDepotSearch(uint16_t itemId, uint8_t tier, bool for (const std::shared_ptr &locker : depotLocker->getItemList()) { std::shared_ptr c = locker->getContainer(); if (!c || c->empty() || - // Retrieve from inbox. - (c->isInbox() && isDepot) || - // Retrieve from depot. - (!c->isInbox() && !isDepot)) { + // Retrieve from inbox. + (c->isInbox() && isDepot) || + // Retrieve from depot. + (!c->isInbox() && !isDepot)) { continue; } @@ -6928,7 +6923,7 @@ std::shared_ptr Player::getItemFromDepotSearch(uint16_t itemId, const Posi for (const std::shared_ptr &locker : depotLocker->getItemList()) { std::shared_ptr c = locker->getContainer(); if (!c || c->empty() || (c->isInbox() && pos.y != 0x21) || // From inbox. - (!c->isInbox() && pos.y != 0x20)) { // From depot. + (!c->isInbox() && pos.y != 0x20)) { // From depot. continue; } @@ -7112,7 +7107,7 @@ void Player::forgeFuseItems(ForgeAction_t actionType, uint16_t firstItemId, uint return; } if (returnValue = g_game().internalRemoveItem(secondForgingItem, 1); - returnValue != RETURNVALUE_NOERROR) { + returnValue != RETURNVALUE_NOERROR) { g_logger().error("[Log 2] Failed to remove forge item {} from player with name {}", secondItemId, getName()); sendCancelMessage(getReturnMessage(returnValue)); sendForgeError(RETURNVALUE_CONTACTADMINISTRATOR); @@ -7355,7 +7350,7 @@ void Player::forgeTransferItemTier(ForgeAction_t actionType, uint16_t donorItemI return; } if (returnValue = g_game().internalRemoveItem(receiveItem, 1); - returnValue != RETURNVALUE_NOERROR) { + returnValue != RETURNVALUE_NOERROR) { g_logger().error("[Log 2] Failed to remove transfer item {} from player with name {}", receiveItemId, getName()); sendCancelMessage(getReturnMessage(returnValue)); sendForgeError(RETURNVALUE_CONTACTADMINISTRATOR); @@ -7495,7 +7490,7 @@ void Player::forgeResourceConversion(ForgeAction_t actionType) { } if (std::shared_ptr item = Item::CreateItem(ITEM_FORGE_CORE, 1); - item) { + item) { returnValue = g_game().internalPlayerAddItem(static_self_cast(), item); } if (returnValue != RETURNVALUE_NOERROR) { @@ -7517,7 +7512,7 @@ void Player::forgeResourceConversion(ForgeAction_t actionType) { auto upgradeCost = dustLevel - 75; if (auto dusts = getForgeDusts(); - upgradeCost > dusts) { + upgradeCost > dusts) { g_logger().error("[{}] Not enough dust", __FUNCTION__); sendForgeError(RETURNVALUE_CONTACTADMINISTRATOR); return; @@ -8019,6 +8014,15 @@ const std::unique_ptr &Player::vip() const { return m_playerVIP; } +// Cyclopedia +std::unique_ptr &Player::cyclopedia() { + return m_playerCyclopedia; +} + +const std::unique_ptr &Player::cyclopedia() const { + return m_playerCyclopedia; +} + void Player::sendLootMessage(const std::string &message) const { auto party = getParty(); if (!party) { @@ -8093,7 +8097,7 @@ bool Player::hasPermittedConditionInPZ() const { uint16_t Player::getDodgeChance() const { uint16_t chance = 0; if (auto playerArmor = getInventoryItem(CONST_SLOT_ARMOR); - playerArmor != nullptr && playerArmor->getTier()) { + playerArmor != nullptr && playerArmor->getTier()) { chance += static_cast(playerArmor->getDodgeChance() * 100); } diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index d374bd599..627b640ad 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -36,6 +36,7 @@ #include "enums/object_category.hpp" #include "enums/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" +#include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" #include "creatures/players/vip/player_vip.hpp" @@ -54,6 +55,7 @@ class Spell; class PlayerWheel; class PlayerAchievement; class PlayerBadge; +class PlayerCyclopedia; class PlayerTitle; class PlayerVIP; class Spectators; @@ -475,13 +477,18 @@ class Player final : public Creature, public Cylinder, public Bankable { bool hasBlessing(uint8_t index) const { return blessings[index - 1] != 0; } - uint8_t getBlessingCount(uint8_t index) const { - if (index > 0 && index <= blessings.size()) { - return blessings[index - 1]; - } else { - g_logger().error("[{}] - index outside range 0-10.", __FUNCTION__); - return 0; + + uint8_t getBlessingCount(uint8_t index, bool storeCount = false) const { + if (!storeCount) { + if (index > 0 && index <= blessings.size()) { + return blessings[index - 1]; + } else { + g_logger().error("[{}] - index outside range 0-10.", __FUNCTION__); + return 0; + } } + auto amount = kv()->scoped("summary")->scoped("blessings")->scoped(fmt::format("{}", index))->get("amount"); + return amount ? static_cast(amount->getNumber()) : 0; } std::string getBlessingsName() const; @@ -850,8 +857,8 @@ class Player final : public Creature, public Cylinder, public Bankable { void onWalkComplete() override; void stopWalk(); - bool openShopWindow(std::shared_ptr npc); - bool closeShopWindow(bool sendCloseShopWindow = true); + bool openShopWindow(std::shared_ptr npc, const std::vector &shopItems = {}); + bool closeShopWindow(); bool updateSaleShopList(std::shared_ptr item); bool hasShopItemForSale(uint16_t itemId, uint8_t subType) const; @@ -1642,11 +1649,7 @@ class Player final : public Creature, public Cylinder, public Bankable { client->sendCyclopediaCharacterRecentDeaths(page, pages, entries); } } - void sendCyclopediaCharacterRecentPvPKills( - uint16_t page, uint16_t pages, - const std::vector< - RecentPvPKillEntry> &entries - ) { + void sendCyclopediaCharacterRecentPvPKills(uint16_t page, uint16_t pages, const std::vector &entries) { if (client) { client->sendCyclopediaCharacterRecentPvPKills(page, pages, entries); } @@ -1956,7 +1959,7 @@ class Player final : public Creature, public Cylinder, public Bankable { bool isImmuneCleanse(ConditionType_t conditiontype) { uint64_t timenow = OTSYS_TIME(); if ((cleanseCondition.first == conditiontype) - && (timenow <= cleanseCondition.second)) { + && (timenow <= cleanseCondition.second)) { return true; } return false; @@ -2154,7 +2157,7 @@ class Player final : public Creature, public Cylinder, public Bankable { if (auto it = std::find_if(preys.begin(), preys.end(), [slotid](const std::unique_ptr &preyIt) { return preyIt->id == slotid; }); - it != preys.end()) { + it != preys.end()) { return *it; } @@ -2221,7 +2224,7 @@ class Player final : public Creature, public Cylinder, public Bankable { if (auto it = std::find_if(preys.begin(), preys.end(), [raceId](const std::unique_ptr &it) { return it->selectedRaceId == raceId; }); - it != preys.end()) { + it != preys.end()) { return *it; } @@ -2252,7 +2255,7 @@ class Player final : public Creature, public Cylinder, public Bankable { if (auto it = std::find_if(taskHunting.begin(), taskHunting.end(), [slotid](const std::unique_ptr &itTask) { return itTask->id == slotid; }); - it != taskHunting.end()) { + it != taskHunting.end()) { return *it; } @@ -2321,7 +2324,7 @@ class Player final : public Creature, public Cylinder, public Bankable { if (auto it = std::find_if(taskHunting.begin(), taskHunting.end(), [raceId](const std::unique_ptr &itTask) { return itTask->selectedRaceId == raceId; }); - it != taskHunting.end()) { + it != taskHunting.end()) { return *it; } @@ -2562,8 +2565,7 @@ class Player final : public Creature, public Cylinder, public Bankable { } bool checkAutoLoot(bool isBoss) const { - const bool autoLoot = g_configManager().getBoolean(AUTOLOOT, __FUNCTION__); - if (!autoLoot) { + if (!g_configManager().getBoolean(AUTOLOOT, __FUNCTION__)) { return false; } if (g_configManager().getBoolean(VIP_SYSTEM_ENABLED, __FUNCTION__) && g_configManager().getBoolean(VIP_AUTOLOOT_VIP_ONLY, __FUNCTION__) && !isVip()) { @@ -2571,18 +2573,13 @@ class Player final : public Creature, public Cylinder, public Bankable { } auto featureKV = kv()->scoped("features")->get("autoloot"); - if (featureKV.has_value()) { - auto value = featureKV->getNumber(); - if (value == 2) { - return true; - } else if (value == 1) { - return !isBoss; - } else if (value == 0) { - return false; - } + auto value = featureKV.has_value() ? featureKV->getNumber() : 0; + if (value == 2) { + return true; + } else if (value == 1) { + return !isBoss; } - - return true; + return false; } QuickLootFilter_t getQuickLootFilter() const { @@ -2605,9 +2602,6 @@ class Player final : public Creature, public Cylinder, public Bankable { // This get all players slot items phmap::flat_hash_map> getAllSlotItems() const; - // This get all blessings - phmap::flat_hash_map getBlessingNames() const; - // Gets the equipped items with augment by type std::vector> getEquippedAugmentItemsByType(Augment_t augmentType) const; @@ -2637,6 +2631,10 @@ class Player final : public Creature, public Cylinder, public Bankable { std::unique_ptr &title(); const std::unique_ptr &title() const; + // Player summary interface + std::unique_ptr &cyclopedia(); + const std::unique_ptr &cyclopedia() const; + // Player vip interface std::unique_ptr &vip(); const std::unique_ptr &vip() const; @@ -2958,6 +2956,8 @@ class Player final : public Creature, public Cylinder, public Bankable { int32_t magicShieldCapacityFlat = 0; int32_t magicShieldCapacityPercent = 0; + int32_t marriageSpouse = -1; + void updateItemsLight(bool internal = false); uint16_t getStepSpeed() const override { return std::max(PLAYER_MIN_SPEED, std::min(PLAYER_MAX_SPEED, getSpeed())); @@ -3034,12 +3034,14 @@ class Player final : public Creature, public Cylinder, public Bankable { friend class IOLoginDataSave; friend class PlayerAchievement; friend class PlayerBadge; + friend class PlayerCyclopedia; friend class PlayerTitle; friend class PlayerVIP; std::unique_ptr m_wheelPlayer; std::unique_ptr m_playerAchievement; std::unique_ptr m_playerBadge; + std::unique_ptr m_playerCyclopedia; std::unique_ptr m_playerTitle; std::unique_ptr m_playerVIP; @@ -3065,4 +3067,11 @@ class Player final : public Creature, public Cylinder, public Bankable { bool hasOtherRewardContainerOpen(const std::shared_ptr container) const; void checkAndShowBlessingMessage(); + + void setMarriageSpouse(const int32_t spouseId) { + marriageSpouse = spouseId; + } + int32_t getMarriageSpouse() const { + return marriageSpouse; + } }; diff --git a/src/creatures/players/vip/player_vip.cpp b/src/creatures/players/vip/player_vip.cpp index b4b1642ec..95ebe91ad 100644 --- a/src/creatures/players/vip/player_vip.cpp +++ b/src/creatures/players/vip/player_vip.cpp @@ -143,13 +143,13 @@ std::shared_ptr PlayerVIP::getGroupByName(const std::string &name) con void PlayerVIP::addGroupInternal(uint8_t groupId, const std::string &name, bool customizable) { if (getGroupByName(name) != nullptr) { - g_logger().warn("{} - Group name already exists.", __FUNCTION__); + g_logger().debug("{} - Group name already exists.", __FUNCTION__); return; } const auto freeId = getFreeId(); if (freeId == 0) { - g_logger().warn("{} - No id available.", __FUNCTION__); + g_logger().debug("{} - No id available.", __FUNCTION__); return; } diff --git a/src/creatures/players/vocations/vocation.cpp b/src/creatures/players/vocations/vocation.cpp index 98dbaeb1b..6fec27251 100644 --- a/src/creatures/players/vocations/vocation.cpp +++ b/src/creatures/players/vocations/vocation.cpp @@ -129,13 +129,13 @@ bool Vocations::loadFromXml() { voc->skillMultipliers[skill_id] = pugi::cast(childNode.attribute("multiplier").value()); } else { g_logger().warn("[Vocations::loadFromXml] - " - "No valid skill id: {} for vocation: {}", - skill_id, voc->id); + "No valid skill id: {} for vocation: {}", + skill_id, voc->id); } } else { g_logger().warn("[Vocations::loadFromXml] - " - "Missing skill id for vocation: {}", - voc->id); + "Missing skill id for vocation: {}", + voc->id); } } else if (strcasecmp(childNode.name(), "mitigation") == 0) { pugi::xml_attribute factorAttribute = childNode.attribute("multiplier"); @@ -198,8 +198,8 @@ std::shared_ptr Vocations::getVocation(uint16_t id) { auto it = vocationsMap.find(id); if (it == vocationsMap.end()) { g_logger().warn("[Vocations::getVocation] - " - "Vocation {} not found", - id); + "Vocation {} not found", + id); return nullptr; } return it->second; diff --git a/src/database/databasemanager.cpp b/src/database/databasemanager.cpp index cbcc116dd..dfbb7d9a6 100644 --- a/src/database/databasemanager.cpp +++ b/src/database/databasemanager.cpp @@ -89,8 +89,8 @@ void DatabaseManager::updateDatabase() { ss << g_configManager().getString(DATA_DIRECTORY, __FUNCTION__) + "/migrations/" << version << ".lua"; if (luaL_dofile(L, ss.str().c_str()) != 0) { g_logger().error("DatabaseManager::updateDatabase - Version: {}" - "] {}", - version, lua_tostring(L, -1)); + "] {}", + version, lua_tostring(L, -1)); break; } diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index f0637011a..295e57398 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -36,3 +36,27 @@ enum CyclopediaTitle_t : uint8_t { MAP, OTHERS, }; + +enum Summary_t : uint8_t { + HOUSE_ITEMS = 9, + BOOSTS = 10, + PREY_CARDS = 12, + BLESSINGS = 14, + ALL_BLESSINGS = 17, + INSTANT_REWARDS = 18, + HIRELINGS = 20, +}; + +enum class CyclopediaMapData_t : uint8_t { + MinimapMarker = 0, + DiscoveryData = 1, + ActiveRaid = 2, + ImminentRaidMainArea = 3, + ImminentRaidSubArea = 4, + SetDiscoveryArea = 5, + Passage = 6, + SubAreaMonsters = 7, + MonsterBestiary = 8, + Donations = 9, + SetCurrentArea = 10, +}; diff --git a/src/game/game.cpp b/src/game/game.cpp index 57daddded..7ef6b7a90 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -38,6 +38,7 @@ #include "creatures/players/wheel/player_wheel.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" +#include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" #include "creatures/npcs/npc.hpp" #include "server/network/webhook/webhook.hpp" @@ -362,6 +363,45 @@ Game::Game() { HighscoreCategory("Fishing", static_cast(HighscoreCategories_t::FISHING)), HighscoreCategory("Magic Level", static_cast(HighscoreCategories_t::MAGIC_LEVEL)) }; + + m_blessingNames = { + { static_cast(TWIST_OF_FATE), "Twist of Fate" }, + { static_cast(WISDOM_OF_SOLITUDE), "The Wisdom of Solitude" }, + { static_cast(SPARK_OF_THE_PHOENIX), "The Spark of the Phoenix" }, + { static_cast(FIRE_OF_THE_SUNS), "The Fire of the Suns" }, + { static_cast(SPIRITUAL_SHIELDING), "The Spiritual Shielding" }, + { static_cast(EMBRACE_OF_TIBIA), "The Embrace of Tibia" }, + { static_cast(BLOOD_OF_THE_MOUNTAIN), "Blood of the Mountain" }, + { static_cast(HEARTH_OF_THE_MOUNTAIN), "Heart of the Mountain" }, + }; + + m_summaryCategories = { + { static_cast(Summary_t::HOUSE_ITEMS), "house-items" }, + { static_cast(Summary_t::BOOSTS), "xp-boosts" }, + { static_cast(Summary_t::PREY_CARDS), "prey-cards" }, + { static_cast(Summary_t::BLESSINGS), "blessings" }, + { static_cast(Summary_t::INSTANT_REWARDS), "instant-rewards" }, + { static_cast(Summary_t::HIRELINGS), "hirelings" }, + }; + + m_hirelingSkills = { + { 1001, "banker" }, + { 1002, "cooker" }, + { 1003, "steward" }, + { 1004, "trader" } + }; + + m_hirelingOutfits = { + { 2001, "banker" }, + { 2002, "cooker" }, + { 2003, "steward" }, + { 2004, "trader" }, + { 2005, "servant" }, + { 2006, "hydra" }, + { 2007, "ferumbras" }, + { 2008, "bonelord" }, + { 2009, "dragon" }, + }; } Game::~Game() = default; @@ -386,7 +426,7 @@ void Game::loadBoostedCreature() { const auto result = db.storeQuery("SELECT * FROM `boosted_creature`"); if (!result) { g_logger().warn("[Game::loadBoostedCreature] - " - "Failed to detect boosted creature database. (CODE 01)"); + "Failed to detect boosted creature database. (CODE 01)"); return; } @@ -423,15 +463,15 @@ void Game::loadBoostedCreature() { if (selectedMonster.raceId == 0) { g_logger().warn("[Game::loadBoostedCreature] - " - "It was not possible to generate a new boosted creature->"); + "It was not possible to generate a new boosted creature->"); return; } const auto monsterType = g_monsters().getMonsterType(selectedMonster.name); if (!monsterType) { g_logger().warn("[Game::loadBoostedCreature] - " - "It was not possible to generate a new boosted creature-> Monster '{}' not found.", - selectedMonster.name); + "It was not possible to generate a new boosted creature-> Monster '{}' not found.", + selectedMonster.name); return; } @@ -451,7 +491,7 @@ void Game::loadBoostedCreature() { if (!db.executeQuery(query)) { g_logger().warn("[Game::loadBoostedCreature] - " - "Failed to detect boosted creature database. (CODE 02)"); + "Failed to detect boosted creature database. (CODE 02)"); } } @@ -1703,7 +1743,7 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo uint8_t itemStackPos = fromStackPos; if (fromPos.x != 0xFFFF && Position::areInRange<1, 1>(mapFromPos, playerPos) - && !Position::areInRange<1, 1, 0>(mapFromPos, walkPos)) { + && !Position::areInRange<1, 1, 0>(mapFromPos, walkPos)) { // need to pickup the item first std::shared_ptr moveItem = nullptr; @@ -2093,20 +2133,20 @@ ReturnValue Game::internalMoveItem(std::shared_ptr fromCylinder, std:: std::shared_ptr quiver = toCylinder->getItem(); if (quiver && quiver->isQuiver() - && quiver->getHoldingPlayer() - && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { + && quiver->getHoldingPlayer() + && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { quiver->getHoldingPlayer()->sendInventoryItem(CONST_SLOT_RIGHT, quiver); } else { quiver = fromCylinder->getItem(); if (quiver && quiver->isQuiver() - && quiver->getHoldingPlayer() - && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { + && quiver->getHoldingPlayer() + && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { quiver->getHoldingPlayer()->sendInventoryItem(CONST_SLOT_RIGHT, quiver); } } if (SoundEffect_t soundEffect = item->getMovementSound(toCylinder); - toCylinder && soundEffect != SoundEffect_t::SILENCE) { + toCylinder && soundEffect != SoundEffect_t::SILENCE) { if (toCylinder->getContainer() && actor && actor->getPlayer() && (toCylinder->getContainer()->isInsideDepot(true) || toCylinder->getContainer()->getHoldingPlayer())) { actor->getPlayer()->sendSingleSoundEffect(toCylinder->getPosition(), soundEffect, SourceEffect_t::OWN); } else { @@ -2239,8 +2279,8 @@ ReturnValue Game::internalAddItem(std::shared_ptr toCylinder, std::sha } if (addedItem && addedItem->isQuiver() - && addedItem->getHoldingPlayer() - && addedItem->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == addedItem) { + && addedItem->getHoldingPlayer() + && addedItem->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == addedItem) { addedItem->getHoldingPlayer()->sendInventoryItem(CONST_SLOT_RIGHT, addedItem); } @@ -2300,8 +2340,8 @@ ReturnValue Game::internalRemoveItem(std::shared_ptr item, int32_t count / std::shared_ptr quiver = cylinder->getItem(); if (quiver && quiver->isQuiver() - && quiver->getHoldingPlayer() - && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { + && quiver->getHoldingPlayer() + && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { quiver->getHoldingPlayer()->sendInventoryItem(CONST_SLOT_RIGHT, quiver); } @@ -2760,8 +2800,8 @@ std::shared_ptr Game::transformItem(std::shared_ptr item, uint16_t n std::shared_ptr quiver = cylinder->getItem(); if (quiver && quiver->isQuiver() - && quiver->getHoldingPlayer() - && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { + && quiver->getHoldingPlayer() + && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { quiver->getHoldingPlayer()->sendInventoryItem(CONST_SLOT_RIGHT, quiver); } item->startDecaying(); @@ -2772,8 +2812,8 @@ std::shared_ptr Game::transformItem(std::shared_ptr item, uint16_t n std::shared_ptr quiver = cylinder->getItem(); if (quiver && quiver->isQuiver() - && quiver->getHoldingPlayer() - && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { + && quiver->getHoldingPlayer() + && quiver->getHoldingPlayer()->getThing(CONST_SLOT_RIGHT) == quiver) { quiver->getHoldingPlayer()->sendInventoryItem(CONST_SLOT_RIGHT, quiver); } @@ -3699,7 +3739,7 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f mustReloadDepotSearch = true; } else { if (auto targetThing = internalGetThing(player, toPos, toStackPos, toItemId, STACKPOS_FIND_THING); - targetThing && targetThing->getItem() && targetThing->getItem()->isInsideDepot(true)) { + targetThing && targetThing->getItem() && targetThing->getItem()->isInsideDepot(true)) { mustReloadDepotSearch = true; } } @@ -4235,7 +4275,7 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos item->setCustomAttribute("LookFeet", static_cast(outfit.lookFeet)); item->setCustomAttribute("LookAddons", static_cast(outfit.lookAddons)); } else if (auto pastLookType = item->getCustomAttribute("PastLookType"); - pastLookType && pastLookType->getInteger() > 0) { + pastLookType && pastLookType->getInteger() > 0) { item->removeCustomAttribute("LookType"); item->removeCustomAttribute("PastLookType"); } @@ -4247,7 +4287,7 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos item->setCustomAttribute("LookMountLegs", static_cast(outfit.lookMountLegs)); item->setCustomAttribute("LookMountFeet", static_cast(outfit.lookMountFeet)); } else if (auto pastLookMount = item->getCustomAttribute("PastLookMount"); - pastLookMount && pastLookMount->getInteger() > 0) { + pastLookMount && pastLookMount->getInteger() > 0) { item->removeCustomAttribute("LookMount"); item->removeCustomAttribute("PastLookMount"); } @@ -5496,8 +5536,8 @@ void Game::playerLootAllCorpses(std::shared_ptr player, const Position & } if (!tileCorpse->isRewardCorpse() - && tileCorpse->getCorpseOwner() != 0 - && !player->canOpenCorpse(tileCorpse->getCorpseOwner())) { + && tileCorpse->getCorpseOwner() != 0 + && !player->canOpenCorpse(tileCorpse->getCorpseOwner())) { player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE); g_logger().debug("Player {} cannot loot corpse from id {} in position {}", player->getName(), tileItem->getID(), tileItem->getPosition().toString()); continue; @@ -6255,7 +6295,6 @@ void Game::checkCreatureWalk(uint32_t creatureId) { const auto &creature = getCreatureByID(creatureId); if (creature && creature->getHealth() > 0) { creature->onCreatureWalk(); - cleanup(); } } @@ -6318,7 +6357,6 @@ void Game::checkCreatures() { --end; } } - cleanup(); index = (index + 1) % EVENT_CREATURECOUNT; } @@ -7122,9 +7160,9 @@ bool Game::combatChangeHealth(std::shared_ptr attacker, std::shared_pt if (!damage.extension && attackerMonster && targetPlayer) { // Charm rune (target as player) if (charmRune_t activeCharm = g_iobestiary().getCharmFromTarget(targetPlayer, g_monsters().getMonsterTypeByRaceId(attackerMonster->getRaceId())); - activeCharm != CHARM_NONE && activeCharm != CHARM_CLEANSE) { + activeCharm != CHARM_NONE && activeCharm != CHARM_CLEANSE) { if (const auto charm = g_iobestiary().getBestiaryCharm(activeCharm); - charm->type == CHARM_DEFENSIVE && charm->chance > normal_random(0, 100) && g_iobestiary().parseCharmCombat(charm, targetPlayer, attacker, (damage.primary.value + damage.secondary.value))) { + charm->type == CHARM_DEFENSIVE && charm->chance > normal_random(0, 100) && g_iobestiary().parseCharmCombat(charm, targetPlayer, attacker, (damage.primary.value + damage.secondary.value))) { return false; // Dodge charm } } @@ -7510,7 +7548,7 @@ void Game::applyCharmRune( return; } if (charmRune_t activeCharm = g_iobestiary().getCharmFromTarget(attackerPlayer, g_monsters().getMonsterTypeByRaceId(targetMonster->getRaceId())); - activeCharm != CHARM_NONE) { + activeCharm != CHARM_NONE) { const auto charm = g_iobestiary().getBestiaryCharm(activeCharm); int8_t chance = charm->id == CHARM_CRIPPLE ? charm->chance : charm->chance + attackerPlayer->getCharmChanceModifier(); g_logger().debug("charm chance: {}, base: {}, bonus: {}", chance, charm->chance, attackerPlayer->getCharmChanceModifier()); @@ -7536,7 +7574,7 @@ void Game::applyManaLeech( // Void charm rune if (targetMonster) { if (uint16_t playerCharmRaceidVoid = attackerPlayer->parseRacebyCharm(CHARM_VOID, false, 0); - playerCharmRaceidVoid != 0 && playerCharmRaceidVoid == targetMonster->getRace()) { + playerCharmRaceidVoid != 0 && playerCharmRaceidVoid == targetMonster->getRace()) { if (const auto charm = g_iobestiary().getBestiaryCharm(CHARM_VOID)) { manaSkill += charm->percent; } @@ -7567,7 +7605,7 @@ void Game::applyLifeLeech( } if (targetMonster) { if (uint16_t playerCharmRaceidVamp = attackerPlayer->parseRacebyCharm(CHARM_VAMP, false, 0); - playerCharmRaceidVamp != 0 && playerCharmRaceidVamp == targetMonster->getRaceId()) { + playerCharmRaceidVamp != 0 && playerCharmRaceidVamp == targetMonster->getRaceId()) { if (const auto lifec = g_iobestiary().getBestiaryCharm(CHARM_VAMP)) { lifeSkill += lifec->percent; } @@ -7967,8 +8005,6 @@ void Game::shutdown() { map.spawnsNpc.clear(); raids.clear(); - cleanup(); - if (serviceManager) { serviceManager->stop(); } @@ -7980,16 +8016,6 @@ void Game::shutdown() { g_logger().info("Done!"); } -void Game::cleanup() { - for (auto it = browseFields.begin(); it != browseFields.end();) { - if (it->second.expired()) { - it = browseFields.erase(it); - } else { - ++it; - } - } -} - void Game::addBestiaryList(uint16_t raceid, std::string name) { auto it = BestiaryList.find(raceid); if (it != BestiaryList.end()) { @@ -8314,121 +8340,12 @@ void Game::playerCyclopediaCharacterInfo(std::shared_ptr player, uint32_ case CYCLOPEDIA_CHARACTERINFO_COMBATSTATS: player->sendCyclopediaCharacterCombatStats(); break; - case CYCLOPEDIA_CHARACTERINFO_RECENTDEATHS: { - std::ostringstream query; - uint32_t offset = static_cast(page - 1) * entriesPerPage; - query << "SELECT `time`, `level`, `killed_by`, `mostdamage_by`, (select count(*) FROM `player_deaths` WHERE `player_id` = " << playerGUID << ") as `entries` FROM `player_deaths` WHERE `player_id` = " << playerGUID << " ORDER BY `time` DESC LIMIT " << offset << ", " << entriesPerPage; - - uint32_t playerID = player->getID(); - std::function callback = [playerID, page, entriesPerPage](const DBResult_ptr &result, bool) { - std::shared_ptr player = g_game().getPlayerByID(playerID); - if (!player) { - return; - } - - player->resetAsyncOngoingTask(PlayerAsyncTask_RecentDeaths); - if (!result) { - player->sendCyclopediaCharacterRecentDeaths(0, 0, {}); - return; - } - - uint32_t pages = result->getNumber("entries"); - pages += entriesPerPage - 1; - pages /= entriesPerPage; - - std::vector entries; - entries.reserve(result->countResults()); - do { - std::string cause1 = result->getString("killed_by"); - std::string cause2 = result->getString("mostdamage_by"); - - std::ostringstream cause; - cause << "Died at Level " << result->getNumber("level") << " by"; - if (!cause1.empty()) { - const char &character = cause1.front(); - if (character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u') { - cause << " an "; - } else { - cause << " a "; - } - cause << cause1; - } - - if (!cause2.empty()) { - if (!cause1.empty()) { - cause << " and "; - } - - const char &character = cause2.front(); - if (character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u') { - cause << " an "; - } else { - cause << " a "; - } - cause << cause2; - } - cause << '.'; - entries.emplace_back(std::move(cause.str()), result->getNumber("time")); - } while (result->next()); - player->sendCyclopediaCharacterRecentDeaths(page, static_cast(pages), entries); - }; - g_databaseTasks().store(query.str(), callback); - player->addAsyncOngoingTask(PlayerAsyncTask_RecentDeaths); + case CYCLOPEDIA_CHARACTERINFO_RECENTDEATHS: + player->cyclopedia()->loadDeathHistory(page, entriesPerPage); break; - } - case CYCLOPEDIA_CHARACTERINFO_RECENTPVPKILLS: { - // TODO: add guildwar, assists and arena kills - Database &db = Database::getInstance(); - const std::string &escapedName = db.escapeString(player->getName()); - std::ostringstream query; - uint32_t offset = static_cast(page - 1) * entriesPerPage; - query << "SELECT `d`.`time`, `d`.`killed_by`, `d`.`mostdamage_by`, `d`.`unjustified`, `d`.`mostdamage_unjustified`, `p`.`name`, (select count(*) FROM `player_deaths` WHERE ((`killed_by` = " << escapedName << " AND `is_player` = 1) OR (`mostdamage_by` = " << escapedName << " AND `mostdamage_is_player` = 1))) as `entries` FROM `player_deaths` AS `d` INNER JOIN `players` AS `p` ON `d`.`player_id` = `p`.`id` WHERE ((`d`.`killed_by` = " << escapedName << " AND `d`.`is_player` = 1) OR (`d`.`mostdamage_by` = " << escapedName << " AND `d`.`mostdamage_is_player` = 1)) ORDER BY `time` DESC LIMIT " << offset << ", " << entriesPerPage; - - uint32_t playerID = player->getID(); - std::function callback = [playerID, page, entriesPerPage](const DBResult_ptr &result, bool) { - std::shared_ptr player = g_game().getPlayerByID(playerID); - if (!player) { - return; - } - - player->resetAsyncOngoingTask(PlayerAsyncTask_RecentPvPKills); - if (!result) { - player->sendCyclopediaCharacterRecentPvPKills(0, 0, {}); - return; - } - - uint32_t pages = result->getNumber("entries"); - pages += entriesPerPage - 1; - pages /= entriesPerPage; - - std::vector entries; - entries.reserve(result->countResults()); - do { - std::string cause1 = result->getString("killed_by"); - std::string cause2 = result->getString("mostdamage_by"); - std::string name = result->getString("name"); - - uint8_t status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_JUSTIFIED; - if (player->getName() == cause1) { - if (result->getNumber("unjustified") == 1) { - status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED; - } - } else if (player->getName() == cause2) { - if (result->getNumber("mostdamage_unjustified") == 1) { - status = CYCLOPEDIA_CHARACTERINFO_RECENTKILLSTATUS_UNJUSTIFIED; - } - } - - std::ostringstream description; - description << "Killed " << name << '.'; - entries.emplace_back(std::move(description.str()), result->getNumber("time"), status); - } while (result->next()); - player->sendCyclopediaCharacterRecentPvPKills(page, static_cast(pages), entries); - }; - g_databaseTasks().store(query.str(), callback); - player->addAsyncOngoingTask(PlayerAsyncTask_RecentPvPKills); + case CYCLOPEDIA_CHARACTERINFO_RECENTPVPKILLS: + player->cyclopedia()->loadRecentKills(page, entriesPerPage); break; - } case CYCLOPEDIA_CHARACTERINFO_ACHIEVEMENTS: player->achiev()->sendUnlockedSecretAchievements(); break; @@ -9537,7 +9454,7 @@ void Game::playerBosstiarySlot(uint32_t playerId, uint8_t slotId, uint32_t selec uint32_t bossIdSlot = player->getSlotBossId(slotId); if (uint32_t boostedBossId = g_ioBosstiary().getBoostedBossId(); - selectedBossId == 0 && bossIdSlot != boostedBossId) { + selectedBossId == 0 && bossIdSlot != boostedBossId) { uint8_t removeTimes = player->getRemoveTimes(); uint32_t removePrice = g_ioBosstiary().calculteRemoveBoss(removeTimes); g_game().removeMoney(player, removePrice, 0, true); @@ -9573,7 +9490,7 @@ void Game::playerSetMonsterPodium(uint32_t playerId, uint32_t monsterRaceId, con if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { if (stdext::arraylist listDir(128); - player->getPathTo(pos, listDir, 0, 1, true, false)) { + player->getPathTo(pos, listDir, 0, 1, true, false)) { g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos] { playerBrowseField(playerId, pos); }, "Game::playerBrowseField" @@ -9611,7 +9528,7 @@ void Game::playerSetMonsterPodium(uint32_t playerId, uint32_t monsterRaceId, con const auto [podiumVisible, monsterVisible] = podiumAndMonsterVisible; bool changeTentuglyName = false; if (auto monsterOutfit = mType->info.outfit; - (monsterOutfit.lookType != 0 || monsterOutfit.lookTypeEx != 0) && monsterVisible) { + (monsterOutfit.lookType != 0 || monsterOutfit.lookTypeEx != 0) && monsterVisible) { // "Tantugly's Head" boss have to send other looktype to the podium if (monsterOutfit.lookTypeEx == 35105) { monsterOutfit.lookTypeEx = 39003; @@ -9673,7 +9590,7 @@ void Game::playerRotatePodium(uint32_t playerId, const Position &pos, uint8_t st if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { if (stdext::arraylist listDir(128); - player->getPathTo(pos, listDir, 0, 1, true, true)) { + player->getPathTo(pos, listDir, 0, 1, true, true)) { g_dispatcher().addEvent([this, playerId = player->getID(), listDir = listDir.data()] { playerAutoWalk(playerId, listDir); }, "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask( 400, [this, playerId, pos, stackPos, itemId] { @@ -10045,8 +9962,8 @@ void Game::sendUpdateCreature(std::shared_ptr creature) { uint32_t Game::makeInfluencedMonster() { if (auto influencedLimit = g_configManager().getNumber(FORGE_INFLUENCED_CREATURES_LIMIT, __FUNCTION__); - // Condition - forgeableMonsters.empty() || influencedMonsters.size() >= influencedLimit) { + // Condition + forgeableMonsters.empty() || influencedMonsters.size() >= influencedLimit) { return 0; } @@ -10126,8 +10043,8 @@ uint32_t Game::makeFiendishMonster(uint32_t forgeableMonsterId /* = 0*/, bool cr } if (auto fiendishLimit = g_configManager().getNumber(FORGE_FIENDISH_CREATURES_LIMIT, __FUNCTION__); - // Condition - forgeableMonsters.empty() || fiendishMonsters.size() >= fiendishLimit) { + // Condition + forgeableMonsters.empty() || fiendishMonsters.size() >= fiendishLimit) { return 0; } @@ -10231,8 +10148,8 @@ bool Game::removeForgeMonster(uint32_t id, ForgeClassifications_t monsterForgeCl bool Game::removeInfluencedMonster(uint32_t id, bool create /* = false*/) { if (auto find = influencedMonsters.find(id); - // Condition - find != influencedMonsters.end()) { + // Condition + find != influencedMonsters.end()) { influencedMonsters.erase(find); if (create) { @@ -10248,8 +10165,8 @@ bool Game::removeInfluencedMonster(uint32_t id, bool create /* = false*/) { bool Game::removeFiendishMonster(uint32_t id, bool create /* = true*/) { if (auto find = fiendishMonsters.find(id); - // Condition - find != fiendishMonsters.end()) { + // Condition + find != fiendishMonsters.end()) { fiendishMonsters.erase(find); checkForgeEventId(id); @@ -10300,8 +10217,8 @@ void Game::createFiendishMonsters() { } if (auto ret = makeFiendishMonster(); - // Condition - ret == 0) { + // Condition + ret == 0) { return; } @@ -10319,8 +10236,8 @@ void Game::createInfluencedMonsters() { } if (auto ret = makeInfluencedMonster(); - // If condition - ret == 0) { + // If condition + ret == 0) { return; } @@ -10339,8 +10256,8 @@ void Game::checkForgeEventId(uint32_t monsterId) { bool Game::addInfluencedMonster(std::shared_ptr monster) { if (monster && monster->canBeForgeMonster()) { if (auto maxInfluencedMonsters = static_cast(g_configManager().getNumber(FORGE_INFLUENCED_CREATURES_LIMIT, __FUNCTION__)); - // If condition - (influencedMonsters.size() + 1) > maxInfluencedMonsters) { + // If condition + (influencedMonsters.size() + 1) > maxInfluencedMonsters) { return false; } @@ -10749,3 +10666,19 @@ Title Game::getTitleByName(const std::string &name) { } return {}; } + +const std::string &Game::getSummaryKeyByType(uint8_t type) { + return m_summaryCategories[type]; +} + +const std::map &Game::getBlessingNames() { + return m_blessingNames; +} + +const std::unordered_map &Game::getHirelingSkills() { + return m_hirelingSkills; +} + +const std::unordered_map &Game::getHirelingOutfits() { + return m_hirelingOutfits; +} diff --git a/src/game/game.hpp b/src/game/game.hpp index b4be8facd..0537ee030 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -426,7 +426,6 @@ class Game { void updatePlayerHelpers(std::shared_ptr player); - void cleanup(); void shutdown(); void dieSafely(const std::string &errorMsg); void addBestiaryList(uint16_t raceid, std::string name); @@ -733,6 +732,12 @@ class Game { Title getTitleById(uint8_t id); Title getTitleByName(const std::string &name); + const std::string &getSummaryKeyByType(uint8_t type); + + const std::map &getBlessingNames(); + const std::unordered_map &getHirelingSkills(); + const std::unordered_map &getHirelingOutfits(); + private: std::map m_achievements; std::map m_achievementsNameToId; @@ -743,6 +748,12 @@ class Game { std::vector m_highscoreCategories; std::unordered_map m_highscoreCategoriesNames; + std::map m_blessingNames; + + std::unordered_map m_summaryCategories; + std::unordered_map m_hirelingSkills; + std::unordered_map m_hirelingOutfits; + std::map forgeMonsterEventIds; std::unordered_set fiendishMonsters; std::unordered_set influencedMonsters; diff --git a/src/game/game_definitions.hpp b/src/game/game_definitions.hpp index a6ce6e7ea..8b165bc72 100644 --- a/src/game/game_definitions.hpp +++ b/src/game/game_definitions.hpp @@ -102,6 +102,17 @@ enum class HighscoreCategories_t : uint8_t { BOSS_POINTS = 14, }; +enum Blessings_t : uint8_t { + TWIST_OF_FATE = 1, + WISDOM_OF_SOLITUDE = 2, + SPARK_OF_THE_PHOENIX = 3, + FIRE_OF_THE_SUNS = 4, + SPIRITUAL_SHIELDING = 5, + EMBRACE_OF_TIBIA = 6, + BLOOD_OF_THE_MOUNTAIN = 7, + HEARTH_OF_THE_MOUNTAIN = 8, +}; + enum HighscoreType_t : uint8_t { HIGHSCORE_GETENTRIES = 0, HIGHSCORE_OURRANK = 1 diff --git a/src/game/movement/teleport.cpp b/src/game/movement/teleport.cpp index d5a3a73da..44050100e 100644 --- a/src/game/movement/teleport.cpp +++ b/src/game/movement/teleport.cpp @@ -80,8 +80,8 @@ void Teleport::addThing(int32_t, std::shared_ptr thing) { if (checkInfinityLoop(destTile)) { const Position &pos = getPosition(); g_logger().warn("[Teleport:addThing] - " - "Infinity loop teleport at position: {}", - pos.toString()); + "Infinity loop teleport at position: {}", + pos.toString()); return; } diff --git a/src/game/scheduling/dispatcher.cpp b/src/game/scheduling/dispatcher.cpp index 7cff69d66..dbbfc020b 100644 --- a/src/game/scheduling/dispatcher.cpp +++ b/src/game/scheduling/dispatcher.cpp @@ -56,30 +56,51 @@ void Dispatcher::executeSerialEvents(std::vector &tasks) { } void Dispatcher::executeParallelEvents(std::vector &tasks, const uint8_t groupId) { - std::atomic_uint_fast64_t totalTaskSize = tasks.size(); - std::atomic_bool isTasksCompleted = false; + asyncWait(tasks.size(), [groupId, &tasks](size_t i) { + dispacherContext.type = DispatcherType::AsyncEvent; + dispacherContext.group = static_cast(groupId); + tasks[i].execute(); - for (const auto &task : tasks) { - threadPool.detach_task([groupId, &task, &isTasksCompleted, &totalTaskSize] { - dispacherContext.type = DispatcherType::AsyncEvent; - dispacherContext.group = static_cast(groupId); - dispacherContext.taskName = task.getContext(); + dispacherContext.reset(); + }); - task.execute(); + tasks.clear(); +} - dispacherContext.reset(); +void Dispatcher::asyncWait(size_t requestSize, std::function &&f) { + if (requestSize == 0) { + return; + } - totalTaskSize.fetch_sub(1); - if (totalTaskSize.load() == 0) { - isTasksCompleted.store(true); - isTasksCompleted.notify_one(); - } - }); + // This prevents an async call from running inside another async call. + if (asyncWaitDisabled) { + for (uint_fast64_t i = 0; i < requestSize; ++i) { + f(i); + } + return; } - isTasksCompleted.wait(false); + const auto &partitions = generatePartition(requestSize); + const auto pSize = partitions.size(); - tasks.clear(); + BS::multi_future retFuture; + + if (pSize > 1) { + asyncWaitDisabled = true; + const auto min = partitions[1].first; + const auto max = partitions[partitions.size() - 1].second; + retFuture = threadPool.submit_loop(min, max, [&f](const unsigned int i) { f(i); }); + } + + const auto &[min, max] = partitions[0]; + for (uint_fast64_t i = min; i < max; ++i) { + f(i); + } + + if (pSize > 1) { + retFuture.wait(); + asyncWaitDisabled = false; + } } void Dispatcher::executeEvents(const TaskGroup startGroup) { diff --git a/src/game/scheduling/dispatcher.hpp b/src/game/scheduling/dispatcher.hpp index a6cbc8dd6..94b284c93 100644 --- a/src/game/scheduling/dispatcher.hpp +++ b/src/game/scheduling/dispatcher.hpp @@ -108,6 +108,7 @@ class Dispatcher { } void asyncEvent(std::function &&f, TaskGroup group = TaskGroup::GenericParallel); + void asyncWait(size_t size, std::function &&f); uint64_t asyncCycleEvent(uint32_t delay, std::function &&f, TaskGroup group = TaskGroup::GenericParallel) { return scheduleEvent( @@ -173,6 +174,22 @@ class Dispatcher { } } + std::vector> generatePartition(size_t size) const { + if (size == 0) { + return {}; + } + + std::vector> list; + list.reserve(threadPool.get_thread_count()); + + const auto size_per_block = std::ceil(size / static_cast(threadPool.get_thread_count())); + for (uint_fast64_t i = 0; i < size; i += size_per_block) { + list.emplace_back(i, std::min(size, i + size_per_block)); + } + + return list; + } + uint_fast64_t dispatcherCycle = 0; ThreadPool &threadPool; @@ -200,6 +217,8 @@ class Dispatcher { phmap::btree_multiset, Task::Compare> scheduledTasks; phmap::parallel_flat_hash_map_m> scheduledTasksRef; + bool asyncWaitDisabled = false; + friend class CanaryServer; }; diff --git a/src/game/scheduling/task.hpp b/src/game/scheduling/task.hpp index c6591887c..7bdc7db80 100644 --- a/src/game/scheduling/task.hpp +++ b/src/game/scheduling/task.hpp @@ -70,10 +70,10 @@ class Task { bool hasTraceableContext() const { const static auto tasksContext = std::unordered_set({ - "Creature::checkCreatureWalk", "Decay::checkDecay", "Dispatcher::asyncEvent", "Game::checkCreatureAttack", + "Game::checkCreatureWalk", "Game::checkCreatures", "Game::checkImbuements", "Game::checkLight", @@ -94,7 +94,6 @@ class Task { "SpawnNpc::checkSpawnNpc", "Webhook::run", "Protocol::sendRecvMessageCallback", - "sendRecvMessageCallback", }); return tasksContext.contains(context); diff --git a/src/io/functions/iologindata_load_player.cpp b/src/io/functions/iologindata_load_player.cpp index 8f7cf461f..8406cf110 100644 --- a/src/io/functions/iologindata_load_player.cpp +++ b/src/io/functions/iologindata_load_player.cpp @@ -182,6 +182,8 @@ bool IOLoginDataLoad::loadPlayerFirst(std::shared_ptr player, DBResult_p player->setManaShield(result->getNumber("manashield")); player->setMaxManaShield(result->getNumber("max_manashield")); + + player->setMarriageSpouse(result->getNumber("marriage_spouse")); return true; } @@ -215,9 +217,7 @@ void IOLoginDataLoad::loadPlayerBlessings(std::shared_ptr player, DBResu } for (int i = 1; i <= 8; i++) { - std::ostringstream ss; - ss << "blessings" << i; - player->addBlessing(static_cast(i), static_cast(result->getNumber(ss.str()))); + player->addBlessing(static_cast(i), static_cast(result->getNumber(fmt::format("blessings{}", i)))); } } @@ -913,6 +913,7 @@ void IOLoginDataLoad::loadPlayerInitializeSystem(std::shared_ptr player) player->achiev()->loadUnlockedAchievements(); player->badge()->checkAndUpdateNewBadges(); player->title()->checkAndUpdateNewTitles(); + player->cyclopedia()->loadSummaryData(); player->initializePrey(); player->initializeTaskHunting(); diff --git a/src/io/io_bosstiary.cpp b/src/io/io_bosstiary.cpp index 0090c0b3e..2f625cdb7 100644 --- a/src/io/io_bosstiary.cpp +++ b/src/io/io_bosstiary.cpp @@ -89,7 +89,7 @@ void IOBosstiary::loadBoostedBoss() { query << "`date` = '" << today << "',"; query << "`boostname` = " << database.escapeString(bossName) << ","; if (const auto bossType = getMonsterTypeByBossRaceId(bossId); - bossType) { + bossType) { query << "`looktypeEx` = " << static_cast(bossType->info.outfit.lookTypeEx) << ","; query << "`looktype` = " << static_cast(bossType->info.outfit.lookType) << ","; query << "`lookfeet` = " << static_cast(bossType->info.outfit.lookFeet) << ","; @@ -124,7 +124,7 @@ void IOBosstiary::loadBoostedBoss() { void IOBosstiary::addBosstiaryMonster(uint16_t raceId, const std::string &name) { if (auto it = bosstiaryMap.find(raceId); - it != bosstiaryMap.end()) { + it != bosstiaryMap.end()) { return; } @@ -282,7 +282,7 @@ uint8_t IOBosstiary::getBossCurrentLevel(std::shared_ptr player, uint16_ auto bossRace = mType->info.bosstiaryRace; uint8_t level = 0; if (auto it = levelInfos.find(bossRace); - it != levelInfos.end()) { + it != levelInfos.end()) { const std::vector &infoForCurrentRace = it->second; for (const auto &raceInfo : infoForCurrentRace) { if (currentKills >= raceInfo.kills) { diff --git a/src/io/iobestiary.cpp b/src/io/iobestiary.cpp index c54402136..9cd964e7c 100644 --- a/src/io/iobestiary.cpp +++ b/src/io/iobestiary.cpp @@ -225,9 +225,9 @@ void IOBestiary::addBestiaryKill(std::shared_ptr player, const std::shar player->addBestiaryKillCount(raceid, amount); if ((curCount == 0) || // Initial kill stage - (curCount < mtype->info.bestiaryFirstUnlock && (curCount + amount) >= mtype->info.bestiaryFirstUnlock) || // First kill stage reached - (curCount < mtype->info.bestiarySecondUnlock && (curCount + amount) >= mtype->info.bestiarySecondUnlock) || // Second kill stage reached - (curCount < mtype->info.bestiaryToUnlock && (curCount + amount) >= mtype->info.bestiaryToUnlock)) { // Final kill stage reached + (curCount < mtype->info.bestiaryFirstUnlock && (curCount + amount) >= mtype->info.bestiaryFirstUnlock) || // First kill stage reached + (curCount < mtype->info.bestiarySecondUnlock && (curCount + amount) >= mtype->info.bestiarySecondUnlock) || // Second kill stage reached + (curCount < mtype->info.bestiaryToUnlock && (curCount + amount) >= mtype->info.bestiaryToUnlock)) { // Final kill stage reached ss << "You unlocked details for the creature '" << mtype->name << "'"; player->sendTextMessage(MESSAGE_STATUS, ss.str()); player->sendBestiaryEntryChanged(raceid); diff --git a/src/io/iomap.cpp b/src/io/iomap.cpp index d50d9b280..c17978e8d 100644 --- a/src/io/iomap.cpp +++ b/src/io/iomap.cpp @@ -14,27 +14,27 @@ #include "io/filestream.hpp" /* - OTBM_ROOTV1 - | - |--- OTBM_MAP_DATA - | | - | |--- OTBM_TILE_AREA - | | |--- OTBM_TILE - | | |--- OTBM_TILE_SQUARE (not implemented) - | | |--- OTBM_TILE_REF (not implemented) - | | |--- OTBM_HOUSETILE - | | - | |--- OTBM_SPAWNS (not implemented) - | | |--- OTBM_SPAWN_AREA (not implemented) - | | |--- OTBM_MONSTER (not implemented) - | | - | |--- OTBM_TOWNS - | | |--- OTBM_TOWN - | | - | |--- OTBM_WAYPOINTS - | |--- OTBM_WAYPOINT - | - |--- OTBM_ITEM_DEF (not implemented) + OTBM_ROOTV1 + | + |--- OTBM_MAP_DATA + | | + | |--- OTBM_TILE_AREA + | | |--- OTBM_TILE + | | |--- OTBM_TILE_SQUARE (not implemented) + | | |--- OTBM_TILE_REF (not implemented) + | | |--- OTBM_HOUSETILE + | | + | |--- OTBM_SPAWNS (not implemented) + | | |--- OTBM_SPAWN_AREA (not implemented) + | | |--- OTBM_MONSTER (not implemented) + | | + | |--- OTBM_TOWNS + | | |--- OTBM_TOWN + | | + | |--- OTBM_WAYPOINTS + | |--- OTBM_WAYPOINT + | + |--- OTBM_ITEM_DEF (not implemented) */ void IOMap::loadMap(Map* map, const Position &pos) { @@ -170,9 +170,9 @@ void IOMap::parseTileArea(FileStream &stream, Map &map, const Position &pos) { if (tile->isHouse() && iType.movable) { g_logger().warn("[IOMap::loadMap] - " - "Movable item with ID: {}, in house: {}, " - "at position: x {}, y {}, z {}", - id, tile->houseId, x, y, z); + "Movable item with ID: {}, in house: {}, " + "at position: x {}, y {}, z {}", + id, tile->houseId, x, y, z); } else if (iType.isGroundTile()) { tile->ground = map.tryReplaceItemFromCache(item); } else { @@ -200,9 +200,9 @@ void IOMap::parseTileArea(FileStream &stream, Map &map, const Position &pos) { // nothing } else if (tile->isHouse() && iType.movable) { g_logger().warn("[IOMap::loadMap] - " - "Movable item with ID: {}, in house: {}, " - "at position: x {}, y {}, z {}", - id, tile->houseId, x, y, z); + "Movable item with ID: {}, in house: {}, " + "at position: x {}, y {}, z {}", + id, tile->houseId, x, y, z); } else if (iType.isGroundTile()) { tile->ground = map.tryReplaceItemFromCache(item); } else { diff --git a/src/io/ioprey.cpp b/src/io/ioprey.cpp index 642423c2a..6b2816355 100644 --- a/src/io/ioprey.cpp +++ b/src/io/ioprey.cpp @@ -73,7 +73,7 @@ void PreySlot::reloadMonsterGrid(std::vector blackList, uint32_t level uint8_t stageThree; uint8_t stageFour; if (auto levelStage = static_cast(std::floor(level / 100)); - levelStage == 0) { // From level 0 to 99 + levelStage == 0) { // From level 0 to 99 stageOne = 3; stageTwo = 3; stageThree = 2; @@ -154,7 +154,7 @@ void TaskHuntingSlot::reloadMonsterGrid(std::vector blackList, uint32_ uint8_t stageThree; uint8_t stageFour; if (auto levelStage = static_cast(std::floor(level / 100)); - levelStage == 0) { // From level 0 to 99 + levelStage == 0) { // From level 0 to 99 stageOne = 3; stageTwo = 3; stageThree = 2; @@ -253,7 +253,7 @@ void IOPrey::checkPlayerPreys(std::shared_ptr player, uint8_t amount) co for (uint8_t slotId = PreySlot_First; slotId <= PreySlot_Last; slotId++) { if (const auto &slot = player->getPreySlotById(static_cast(slotId)); - slot && slot->isOccupied()) { + slot && slot->isOccupied()) { if (slot->bonusTimeLeft <= amount) { if (slot->option == PreyOption_AutomaticReroll) { if (player->usePreyCards(static_cast(g_configManager().getNumber(PREY_BONUS_REROLL_PRICE, __FUNCTION__)))) { diff --git a/src/items/containers/container.cpp b/src/items/containers/container.cpp index 63ce65774..6c526a850 100644 --- a/src/items/containers/container.cpp +++ b/src/items/containers/container.cpp @@ -63,6 +63,10 @@ std::shared_ptr Container::create(std::shared_ptr tile) { Container::~Container() { if (getID() == ITEM_BROWSEFIELD) { + if (getParent() && getParent()->getTile()) { + g_game().browseFields.erase(getParent()->getTile()); + } + for (std::shared_ptr item : itemlist) { item->setParent(getParent()); } diff --git a/src/items/decay/decay.cpp b/src/items/decay/decay.cpp index 848acffbf..5eaff61a7 100644 --- a/src/items/decay/decay.cpp +++ b/src/items/decay/decay.cpp @@ -156,8 +156,8 @@ void Decay::internalDecayItem(std::shared_ptr item) { auto player = item->getHoldingPlayer(); if (player) { g_logger().error("[{}] - internalDecayItem failed to player {}, item id is same from transform equip/deequip, " - " item id: {}, equip to id: '{}', deequip to id '{}'", - __FUNCTION__, player->getName(), it.id, it.transformEquipTo, it.transformDeEquipTo); + " item id: {}, equip to id: '{}', deequip to id '{}'", + __FUNCTION__, player->getName(), it.id, it.transformEquipTo, it.transformDeEquipTo); } return; } @@ -207,8 +207,8 @@ void Decay::internalDecayItem(std::shared_ptr item) { ReturnValue ret = g_game().internalRemoveItem(item); if (ret != RETURNVALUE_NOERROR) { g_logger().error("[Decay::internalDecayItem] - internalDecayItem failed, " - "error code: {}, item id: {}", - static_cast(ret), item->getID()); + "error code: {}, item id: {}", + static_cast(ret), item->getID()); } } } diff --git a/src/items/functions/item/item_parse.cpp b/src/items/functions/item/item_parse.cpp index 1f247b611..9b63b9aee 100644 --- a/src/items/functions/item/item_parse.cpp +++ b/src/items/functions/item/item_parse.cpp @@ -400,7 +400,7 @@ void ItemParse::parseTransform(const std::string &tmpStrValue, pugi::xml_attribu itemType.decayTo = 0; } if (ItemType &transform = Item::items.getItemType(itemType.transformEquipTo); - transform.type == ITEM_TYPE_NONE) { + transform.type == ITEM_TYPE_NONE) { transform.type = itemType.type; } } else if (stringValue == "transformdeequipto") { @@ -1140,7 +1140,7 @@ void ItemParse::createAndRegisterScript(ItemType &itemType, pugi::xml_node attri token.erase(std::find_if(token.rbegin(), token.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), - token.end()); + token.end()); std::string v1; bool showInDescription = false; diff --git a/src/items/item.cpp b/src/items/item.cpp index 823eb13b3..dd2d5c965 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -132,7 +132,7 @@ bool Item::hasImbuementCategoryId(uint16_t categoryId) const { ImbuementInfo imbuementInfo; if (getImbuementInfo(slotid, &imbuementInfo)) { if (const CategoryImbuement* categoryImbuement = g_imbuements().getCategoryByID(imbuementInfo.imbuement->getCategory()); - categoryImbuement->id == categoryId) { + categoryImbuement->id == categoryId) { return true; } } @@ -142,14 +142,14 @@ bool Item::hasImbuementCategoryId(uint16_t categoryId) const { std::shared_ptr Item::CreateItemAsContainer(const uint16_t type, uint16_t size) { if (const ItemType &it = Item::items[type]; - it.id == 0 - || it.stackable - || it.multiUse - || it.movable - || it.pickupable - || it.isDepot() - || it.isSplash() - || it.isDoor()) { + it.id == 0 + || it.stackable + || it.multiUse + || it.movable + || it.pickupable + || it.isDepot() + || it.isSplash() + || it.isDoor()) { return nullptr; } @@ -883,7 +883,7 @@ void Item::serializeAttr(PropWriteStream &propWriteStream) const { } if (const std::string &text = getString(ItemAttribute_t::TEXT); - !text.empty()) { + !text.empty()) { propWriteStream.write(ATTR_TEXT); propWriteStream.writeString(text); } @@ -911,7 +911,7 @@ void Item::serializeAttr(PropWriteStream &propWriteStream) const { } if (auto decayState = getDecaying(); - decayState == DECAYING_TRUE || decayState == DECAYING_PENDING) { + decayState == DECAYING_TRUE || decayState == DECAYING_PENDING) { propWriteStream.write(ATTR_DECAYING_STATE); propWriteStream.write(decayState); } @@ -1166,7 +1166,7 @@ Item::getDescriptions(const ItemType &it, std::shared_ptr item /*= nullptr separator = true; } if (int32_t hitChance = item->getHitChance(); - hitChance != 0) { + hitChance != 0) { if (separator) { ss << ", "; } @@ -1174,7 +1174,7 @@ Item::getDescriptions(const ItemType &it, std::shared_ptr item /*= nullptr separator = true; } if (int32_t shootRange = item->getShootRange(); - shootRange != 0) { + shootRange != 0) { if (separator) { ss << ", "; } @@ -1579,7 +1579,7 @@ Item::getDescriptions(const ItemType &it, std::shared_ptr item /*= nullptr separator = true; } if (int32_t hitChance = it.hitChance; - hitChance != 0) { + hitChance != 0) { if (separator) { ss << ", "; } @@ -1587,7 +1587,7 @@ Item::getDescriptions(const ItemType &it, std::shared_ptr item /*= nullptr separator = true; } if (int32_t shootRange = it.shootRange; - shootRange != 0) { + shootRange != 0) { if (separator) { ss << ", "; } @@ -1950,7 +1950,7 @@ SoundEffect_t Item::getMovementSound(std::shared_ptr toCylinder) const } if (std::shared_ptr toContainer = toCylinder->getContainer(); - toContainer && toContainer->getHoldingPlayer()) { + toContainer && toContainer->getHoldingPlayer()) { return SoundEffect_t::ITEM_MOVE_BACKPACK; } diff --git a/src/items/items.cpp b/src/items/items.cpp index 7d8ff0cf7..2d4020c54 100644 --- a/src/items/items.cpp +++ b/src/items/items.cpp @@ -260,8 +260,8 @@ bool Items::loadFromXml() { auto toIdAttribute = itemNode.attribute("toid"); if (!toIdAttribute) { g_logger().warn("[Items::loadFromXml] - " - "tag fromid: {} without toid", - fromIdAttribute.value()); + "tag fromid: {} without toid", + fromIdAttribute.value()); continue; } @@ -302,12 +302,12 @@ void Items::parseItemNode(const pugi::xml_node &itemNode, uint16_t id) { } if (std::string xmlName = itemNode.attribute("name").as_string(); - !xmlName.empty() && itemType.name != xmlName) { + !xmlName.empty() && itemType.name != xmlName) { if (!itemType.name.empty()) { if (auto it = std::find_if(nameToItems.begin(), nameToItems.end(), [id](const auto nameMapIt) { return nameMapIt.second == id; }); - it != nameToItems.end()) { + it != nameToItems.end()) { nameToItems.erase(it); } } diff --git a/src/items/tile.cpp b/src/items/tile.cpp index f2006f627..fc16dd579 100644 --- a/src/items/tile.cpp +++ b/src/items/tile.cpp @@ -393,7 +393,7 @@ void Tile::onAddTileItem(std::shared_ptr item) { } if ((!hasFlag(TILESTATE_PROTECTIONZONE) || g_configManager().getBoolean(CLEAN_PROTECTION_ZONES, __FUNCTION__)) - && item->isCleanable()) { + && item->isCleanable()) { if (!this->getHouse()) { g_game().addTileToClean(static_self_cast()); } diff --git a/src/items/weapons/weapons.cpp b/src/items/weapons/weapons.cpp index 6c0d56d88..69d20d43e 100644 --- a/src/items/weapons/weapons.cpp +++ b/src/items/weapons/weapons.cpp @@ -360,8 +360,8 @@ bool Weapon::executeUseWeapon(std::shared_ptr player, const LuaVariant & if (!getScriptInterface()->reserveScriptEnv()) { std::string playerName = player ? player->getName() : "Player nullptr"; g_logger().error("[Weapon::executeUseWeapon - Player {} weaponId {}]" - "Call stack overflow. Too many lua script calls being nested.", - playerName, getID()); + "Call stack overflow. Too many lua script calls being nested.", + playerName, getID()); return false; } diff --git a/src/lua/callbacks/event_callback.cpp b/src/lua/callbacks/event_callback.cpp index d2b88c30f..38e7654d8 100644 --- a/src/lua/callbacks/event_callback.cpp +++ b/src/lua/callbacks/event_callback.cpp @@ -50,8 +50,8 @@ void EventCallback::setType(EventCallback_t type) { bool EventCallback::creatureOnChangeOutfit(std::shared_ptr creature, const Outfit_t &outfit) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::creatureOnChangeOutfit - Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName()); return false; } @@ -72,9 +72,9 @@ bool EventCallback::creatureOnChangeOutfit(std::shared_ptr creature, c ReturnValue EventCallback::creatureOnAreaCombat(std::shared_ptr creature, std::shared_ptr tile, bool aggressive) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::creatureOnAreaCombat - " - "Creature {} on tile position {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), tile->getPosition().toString()); + "Creature {} on tile position {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), tile->getPosition().toString()); return RETURNVALUE_NOTPOSSIBLE; } @@ -112,9 +112,9 @@ ReturnValue EventCallback::creatureOnAreaCombat(std::shared_ptr creatu ReturnValue EventCallback::creatureOnTargetCombat(std::shared_ptr creature, std::shared_ptr target) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::creatureOnTargetCombat - " - "Creature {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), target->getName()); + "Creature {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), target->getName()); return RETURNVALUE_NOTPOSSIBLE; } @@ -150,9 +150,9 @@ ReturnValue EventCallback::creatureOnTargetCombat(std::shared_ptr crea void EventCallback::creatureOnHear(std::shared_ptr creature, std::shared_ptr speaker, const std::string &words, SpeakClasses type) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::creatureOnHear - " - "Creature {} speaker {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), speaker->getName()); + "Creature {} speaker {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), speaker->getName()); return; } @@ -177,9 +177,9 @@ void EventCallback::creatureOnHear(std::shared_ptr creature, std::shar void EventCallback::creatureOnDrainHealth(std::shared_ptr creature, std::shared_ptr attacker, CombatType_t &typePrimary, int32_t &damagePrimary, CombatType_t &typeSecondary, int32_t &damageSecondary, TextColor_t &colorPrimary, TextColor_t &colorSecondary) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::creatureOnDrainHealth - " - "Creature {} attacker {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), attacker->getName()); + "Creature {} attacker {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), attacker->getName()); return; } @@ -229,9 +229,9 @@ void EventCallback::creatureOnDrainHealth(std::shared_ptr creature, st bool EventCallback::partyOnJoin(std::shared_ptr party, std::shared_ptr player) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::partyOnJoin - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -253,9 +253,9 @@ bool EventCallback::partyOnJoin(std::shared_ptr party, std::shared_ptr party, std::shared_ptr player) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::partyOnLeave - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -277,8 +277,8 @@ bool EventCallback::partyOnLeave(std::shared_ptr party, std::shared_ptr

party) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::partyOnDisband - Party leader {}] Call stack " - "overflow. Too many lua script calls being nested.", - party->getLeader() ? party->getLeader()->getName() : "unknown"); + "overflow. Too many lua script calls being nested.", + party->getLeader() ? party->getLeader()->getName() : "unknown"); return false; } @@ -325,9 +325,9 @@ void EventCallback::partyOnShareExperience(std::shared_ptr party, uint64_ bool EventCallback::playerOnBrowseField(std::shared_ptr player, const Position &position) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnBrowseField - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -348,9 +348,9 @@ bool EventCallback::playerOnBrowseField(std::shared_ptr player, const Po void EventCallback::playerOnLook(std::shared_ptr player, const Position &position, std::shared_ptr thing, uint8_t stackpos, int32_t lookDistance) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnLook - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -382,9 +382,9 @@ void EventCallback::playerOnLook(std::shared_ptr player, const Position void EventCallback::playerOnLookInBattleList(std::shared_ptr player, std::shared_ptr creature, int32_t lookDistance) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnLookInBattleList - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -408,9 +408,9 @@ void EventCallback::playerOnLookInBattleList(std::shared_ptr player, std void EventCallback::playerOnLookInTrade(std::shared_ptr player, std::shared_ptr partner, std::shared_ptr item, int32_t lookDistance) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnLookInTrade - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -437,9 +437,9 @@ void EventCallback::playerOnLookInTrade(std::shared_ptr player, std::sha bool EventCallback::playerOnLookInShop(std::shared_ptr player, const ItemType* itemType, uint8_t count) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnLookInShop - " - "Player {} itemType {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), itemType->getPluralName()); + "Player {} itemType {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), itemType->getPluralName()); return false; } @@ -463,9 +463,9 @@ bool EventCallback::playerOnLookInShop(std::shared_ptr player, const Ite void EventCallback::playerOnRemoveCount(std::shared_ptr player, std::shared_ptr item) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnMove - " - "Player {} item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Player {} item {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return; } @@ -492,8 +492,8 @@ bool EventCallback::playerOnMoveItem(std::shared_ptr player, std::shared if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[Action::executeUse - Player {}, on item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return false; } @@ -522,9 +522,9 @@ bool EventCallback::playerOnMoveItem(std::shared_ptr player, std::shared void EventCallback::playerOnItemMoved(std::shared_ptr player, std::shared_ptr item, uint16_t count, const Position &fromPosition, const Position &toPosition, std::shared_ptr fromCylinder, std::shared_ptr toCylinder) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnItemMoved - " - "Player {} item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Player {} item {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return; } @@ -553,9 +553,9 @@ void EventCallback::playerOnItemMoved(std::shared_ptr player, std::share void EventCallback::playerOnChangeZone(std::shared_ptr player, ZoneType_t zone) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnChangeZone - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -575,9 +575,9 @@ void EventCallback::playerOnChangeZone(std::shared_ptr player, ZoneType_ bool EventCallback::playerOnMoveCreature(std::shared_ptr player, std::shared_ptr creature, const Position &fromPosition, const Position &toPosition) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnMoveCreature - " - "Player {} creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), creature->getName()); + "Player {} creature {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), creature->getName()); return false; } @@ -602,9 +602,9 @@ bool EventCallback::playerOnMoveCreature(std::shared_ptr player, std::sh void EventCallback::playerOnReportRuleViolation(std::shared_ptr player, const std::string &targetName, uint8_t reportType, uint8_t reportReason, const std::string &comment, const std::string &translation) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnReportRuleViolation - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -631,9 +631,9 @@ void EventCallback::playerOnReportRuleViolation(std::shared_ptr player, void EventCallback::playerOnReportBug(std::shared_ptr player, const std::string &message, const Position &position, uint8_t category) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnReportBug - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -656,9 +656,9 @@ void EventCallback::playerOnReportBug(std::shared_ptr player, const std: bool EventCallback::playerOnTurn(std::shared_ptr player, Direction direction) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnTurn - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -679,9 +679,9 @@ bool EventCallback::playerOnTurn(std::shared_ptr player, Direction direc bool EventCallback::playerOnTradeRequest(std::shared_ptr player, std::shared_ptr target, std::shared_ptr item) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnTradeRequest - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return false; } @@ -706,9 +706,9 @@ bool EventCallback::playerOnTradeRequest(std::shared_ptr player, std::sh bool EventCallback::playerOnTradeAccept(std::shared_ptr player, std::shared_ptr target, std::shared_ptr item, std::shared_ptr targetItem) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnTradeAccept - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return false; } @@ -736,9 +736,9 @@ bool EventCallback::playerOnTradeAccept(std::shared_ptr player, std::sha void EventCallback::playerOnGainExperience(std::shared_ptr player, std::shared_ptr target, uint64_t &exp, uint64_t rawExp) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnGainExperience - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return; } @@ -774,9 +774,9 @@ void EventCallback::playerOnGainExperience(std::shared_ptr player, std:: void EventCallback::playerOnLoseExperience(std::shared_ptr player, uint64_t &exp) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnLoseExperience - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -804,9 +804,9 @@ void EventCallback::playerOnLoseExperience(std::shared_ptr player, uint6 void EventCallback::playerOnGainSkillTries(std::shared_ptr player, skills_t skill, uint64_t &tries) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnGainSkillTries - " - "Player {} skill {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), fmt::underlying(skill)); + "Player {} skill {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), fmt::underlying(skill)); return; } @@ -835,9 +835,9 @@ void EventCallback::playerOnGainSkillTries(std::shared_ptr player, skill void EventCallback::playerOnCombat(std::shared_ptr player, std::shared_ptr target, std::shared_ptr item, CombatDamage &damage) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnCombat - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return; } @@ -880,7 +880,7 @@ void EventCallback::playerOnCombat(std::shared_ptr player, std::shared_p damage.secondary.value = -damage.secondary.value; } /* - Only EK with dealing physical damage will get elemental damage on skill + Only EK with dealing physical damage will get elemental damage on skill */ if (damage.origin == ORIGIN_SPELL) { if (player->getVocationId() != 4 && player->getVocationId() != 8) { @@ -897,9 +897,9 @@ void EventCallback::playerOnCombat(std::shared_ptr player, std::shared_p void EventCallback::playerOnRequestQuestLog(std::shared_ptr player) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnRequestQuestLog - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -918,9 +918,9 @@ void EventCallback::playerOnRequestQuestLog(std::shared_ptr player) cons void EventCallback::playerOnRequestQuestLine(std::shared_ptr player, uint16_t questId) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::playerOnRequestQuestLine - " - "Player {} questId {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), questId); + "Player {} questId {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), questId); return; } @@ -988,9 +988,9 @@ bool EventCallback::playerOnRotateItem(std::shared_ptr player, std::shar void EventCallback::playerOnWalk(std::shared_ptr player, Direction &dir) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::eventOnWalk - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -1011,9 +1011,9 @@ void EventCallback::playerOnWalk(std::shared_ptr player, Direction &dir) void EventCallback::playerOnStorageUpdate(std::shared_ptr player, const uint32_t key, const int32_t value, int32_t oldValue, uint64_t currentTime) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::eventOnStorageUpdate - " - "Player {} key {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), key); + "Player {} key {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), key); return; } @@ -1038,9 +1038,9 @@ void EventCallback::playerOnStorageUpdate(std::shared_ptr player, const void EventCallback::monsterOnDropLoot(std::shared_ptr monster, std::shared_ptr corpse) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::monsterOnDropLoot - " - "Monster corpse {}] " - "Call stack overflow. Too many lua script calls being nested.", - corpse->getName()); + "Monster corpse {}] " + "Call stack overflow. Too many lua script calls being nested.", + corpse->getName()); return; } @@ -1062,9 +1062,9 @@ void EventCallback::monsterOnDropLoot(std::shared_ptr monster, std::sha void EventCallback::monsterPostDropLoot(std::shared_ptr monster, std::shared_ptr corpse) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::monsterPostDropLoot - " - "Monster corpse {}] " - "Call stack overflow. Too many lua script calls being nested.", - corpse->getName()); + "Monster corpse {}] " + "Call stack overflow. Too many lua script calls being nested.", + corpse->getName()); return; } @@ -1086,9 +1086,9 @@ void EventCallback::monsterPostDropLoot(std::shared_ptr monster, std::s void EventCallback::monsterOnSpawn(std::shared_ptr monster, const Position &position) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("{} - " - "Position {}" - ". Call stack overflow. Too many lua script calls being nested.", - __FUNCTION__, position.toString()); + "Position {}" + ". Call stack overflow. Too many lua script calls being nested.", + __FUNCTION__, position.toString()); return; } @@ -1115,9 +1115,9 @@ void EventCallback::monsterOnSpawn(std::shared_ptr monster, const Posit void EventCallback::npcOnSpawn(std::shared_ptr npc, const Position &position) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("{} - " - "Position {}" - ". Call stack overflow. Too many lua script calls being nested.", - __FUNCTION__, position.toString()); + "Position {}" + ". Call stack overflow. Too many lua script calls being nested.", + __FUNCTION__, position.toString()); return; } @@ -1143,9 +1143,9 @@ void EventCallback::npcOnSpawn(std::shared_ptr npc, const Position &positio bool EventCallback::zoneBeforeCreatureEnter(std::shared_ptr zone, std::shared_ptr creature) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::zoneBeforeCreatureEnter - " - "Zone {} Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - zone->getName(), creature->getName()); + "Zone {} Creature {}] " + "Call stack overflow. Too many lua script calls being nested.", + zone->getName(), creature->getName()); return false; } @@ -1167,9 +1167,9 @@ bool EventCallback::zoneBeforeCreatureEnter(std::shared_ptr zone, std::sha bool EventCallback::zoneBeforeCreatureLeave(std::shared_ptr zone, std::shared_ptr creature) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::zoneBeforeCreatureLeave - " - "Zone {} Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - zone->getName(), creature->getName()); + "Zone {} Creature {}] " + "Call stack overflow. Too many lua script calls being nested.", + zone->getName(), creature->getName()); return false; } @@ -1191,9 +1191,9 @@ bool EventCallback::zoneBeforeCreatureLeave(std::shared_ptr zone, std::sha void EventCallback::zoneAfterCreatureEnter(std::shared_ptr zone, std::shared_ptr creature) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::zoneAfterCreatureEnter - " - "Zone {} Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - zone->getName(), creature->getName()); + "Zone {} Creature {}] " + "Call stack overflow. Too many lua script calls being nested.", + zone->getName(), creature->getName()); return; } @@ -1215,9 +1215,9 @@ void EventCallback::zoneAfterCreatureEnter(std::shared_ptr zone, std::shar void EventCallback::zoneAfterCreatureLeave(std::shared_ptr zone, std::shared_ptr creature) const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[EventCallback::zoneAfterCreatureLeave - " - "Zone {} Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - zone->getName(), creature->getName()); + "Zone {} Creature {}] " + "Call stack overflow. Too many lua script calls being nested.", + zone->getName(), creature->getName()); return; } diff --git a/src/lua/callbacks/events_callbacks.hpp b/src/lua/callbacks/events_callbacks.hpp index 53b119f64..f71103047 100644 --- a/src/lua/callbacks/events_callbacks.hpp +++ b/src/lua/callbacks/events_callbacks.hpp @@ -89,6 +89,32 @@ class EventsCallbacks { } } } + /** + * @brief Checks if all registered callbacks of the specified event type succeed. + * @param eventType The type of event to check. + * @param callbackFunc Function pointer to the callback method. + * @param args Variadic arguments to pass to the callback function. + * @return ReturnValue enum. + */ + template + ReturnValue checkCallbackWithReturnValue(EventCallback_t eventType, CallbackFunc callbackFunc, Args &&... args) { + ReturnValue res = RETURNVALUE_NOERROR; + for (const auto &callback : getCallbacksByType(eventType)) { + auto argsCopy = std::make_tuple(args...); + if (callback && callback->isLoadedCallback()) { + ReturnValue callbackResult = std::apply( + [&callback, &callbackFunc](auto &&... args) { + return ((*callback).*callbackFunc)(std::forward(args)...); + }, + argsCopy + ); + if (callbackResult != RETURNVALUE_NOERROR) { + return callbackResult; + } + } + } + return res; + } /** * @brief Checks if all registered callbacks of the specified event type succeed. diff --git a/src/lua/creature/actions.cpp b/src/lua/creature/actions.cpp index 42f3e12c8..485509cae 100644 --- a/src/lua/creature/actions.cpp +++ b/src/lua/creature/actions.cpp @@ -231,11 +231,11 @@ std::shared_ptr Actions::getAction(std::shared_ptr item) { } if (auto iteratePositions = actionPositionMap.find(item->getPosition()); - iteratePositions != actionPositionMap.end()) { + iteratePositions != actionPositionMap.end()) { if (std::shared_ptr tile = item->getTile(); - tile) { + tile) { if (std::shared_ptr player = item->getHoldingPlayer(); - player && item->getTopParent() == player) { + player && item->getTopParent() == player) { g_logger().debug("[Actions::getAction] - The position only is valid for use item in the map, player name {}", player->getName()); return nullptr; } @@ -515,8 +515,8 @@ bool Action::executeUse(std::shared_ptr player, std::shared_ptr it // onUse(player, item, fromPosition, target, toPosition, isHotkey) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[Action::executeUse - Player {}, on item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return false; } diff --git a/src/lua/creature/actions.hpp b/src/lua/creature/actions.hpp index 80fd2ea54..81a7754a5 100644 --- a/src/lua/creature/actions.hpp +++ b/src/lua/creature/actions.hpp @@ -161,7 +161,7 @@ class Actions final : public Scripts { private: bool hasPosition(Position position) const { if (auto it = actionPositionMap.find(position); - it != actionPositionMap.end()) { + it != actionPositionMap.end()) { return true; } return false; @@ -177,7 +177,7 @@ class Actions final : public Scripts { bool hasItemId(uint16_t itemId) const { if (auto it = useItemMap.find(itemId); - it != useItemMap.end()) { + it != useItemMap.end()) { return true; } return false; @@ -189,7 +189,7 @@ class Actions final : public Scripts { bool hasUniqueId(uint16_t uniqueId) const { if (auto it = uniqueItemMap.find(uniqueId); - it != uniqueItemMap.end()) { + it != uniqueItemMap.end()) { return true; } return false; @@ -201,7 +201,7 @@ class Actions final : public Scripts { bool hasActionId(uint16_t actionId) const { if (auto it = actionItemMap.find(actionId); - it != actionItemMap.end()) { + it != actionItemMap.end()) { return true; } return false; diff --git a/src/lua/creature/creatureevent.cpp b/src/lua/creature/creatureevent.cpp index fe2a782b9..09dbdf086 100644 --- a/src/lua/creature/creatureevent.cpp +++ b/src/lua/creature/creatureevent.cpp @@ -173,8 +173,8 @@ bool CreatureEvent::executeOnLogin(std::shared_ptr player) const { // onLogin(player) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeOnLogin - Player {} event {}]" - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), getName()); return false; } @@ -193,8 +193,8 @@ bool CreatureEvent::executeOnLogout(std::shared_ptr player) const { // onLogout(player) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeOnLogout - Player {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), getName()); return false; } @@ -213,8 +213,8 @@ bool CreatureEvent::executeOnThink(std::shared_ptr creature, uint32_t // onThink(creature, interval) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeOnThink - Creature {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), getName()); return false; } @@ -235,8 +235,8 @@ bool CreatureEvent::executeOnPrepareDeath(std::shared_ptr creature, st // onPrepareDeath(creature, killer) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeOnPrepareDeath - Creature {} killer {}" - " event {}] Call stack overflow. Too many lua script calls being nested.", - creature->getName(), killer->getName(), getName()); + " event {}] Call stack overflow. Too many lua script calls being nested.", + creature->getName(), killer->getName(), getName()); return false; } @@ -264,8 +264,8 @@ bool CreatureEvent::executeOnDeath(std::shared_ptr creature, std::shar // onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeOnDeath - Creature {} killer {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), killer->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), killer->getName(), getName()); return false; } @@ -304,8 +304,8 @@ bool CreatureEvent::executeAdvance(std::shared_ptr player, skills_t skil // onAdvance(player, skill, oldLevel, newLevel) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeAdvance - Player {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), getName()); return false; } @@ -330,12 +330,12 @@ bool CreatureEvent::executeAdvance(std::shared_ptr player, skills_t skil void CreatureEvent::executeOnKill(std::shared_ptr creature, std::shared_ptr target, bool lastHit) const { // onKill(creature, target, lastHit) g_logger().warn("[CreatureEvent::executeOnKill - Creature {} target {} event {}] " - "Deprecated use of onKill event. Use registered onDeath events instead for better performance.", - creature->getName(), target->getName(), getName()); + "Deprecated use of onKill event. Use registered onDeath events instead for better performance.", + creature->getName(), target->getName(), getName()); if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeOnKill - Creature {} target {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), target->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), target->getName(), getName()); return; } @@ -357,9 +357,9 @@ void CreatureEvent::executeModalWindow(std::shared_ptr player, uint32_t // onModalWindow(player, modalWindowId, buttonId, choiceId) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeModalWindow - " - "Player {} modaw window id {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), modalWindowId, getName()); + "Player {} modaw window id {} event {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), modalWindowId, getName()); return; } @@ -383,8 +383,8 @@ bool CreatureEvent::executeTextEdit(std::shared_ptr player, std::shared_ // onTextEdit(player, item, text) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeTextEdit - Player {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), getName()); return false; } @@ -407,9 +407,9 @@ void CreatureEvent::executeHealthChange(std::shared_ptr creature, std: // onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeHealthChange - " - "Creature {} attacker {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), attacker->getName(), getName()); + "Creature {} attacker {} event {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), attacker->getName(), getName()); return; } @@ -452,9 +452,9 @@ void CreatureEvent::executeManaChange(std::shared_ptr creature, std::s // onManaChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeManaChange - " - "Creature {} attacker {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), attacker->getName(), getName()); + "Creature {} attacker {} event {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), attacker->getName(), getName()); return; } @@ -492,9 +492,9 @@ void CreatureEvent::executeExtendedOpcode(std::shared_ptr player, uint8_ // onExtendedOpcode(player, opcode, buffer) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeExtendedOpcode - " - "Player {} event {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), getName()); + "Player {} event {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), getName()); return; } diff --git a/src/lua/creature/events.cpp b/src/lua/creature/events.cpp index 2917d128b..8bdd53465 100644 --- a/src/lua/creature/events.cpp +++ b/src/lua/creature/events.cpp @@ -158,9 +158,9 @@ void Events::eventMonsterOnSpawn(std::shared_ptr monster, const Positio if (!scriptInterface.reserveScriptEnv()) { g_logger().error("{} - " - "Position {}" - ". Call stack overflow. Too many lua script calls being nested.", - __FUNCTION__, position.toString()); + "Position {}" + ". Call stack overflow. Too many lua script calls being nested.", + __FUNCTION__, position.toString()); return; } @@ -192,9 +192,9 @@ void Events::eventNpcOnSpawn(std::shared_ptr npc, const Position &position) if (!scriptInterface.reserveScriptEnv()) { g_logger().error("{} - " - "Position {}" - ". Call stack overflow. Too many lua script calls being nested.", - __FUNCTION__, position.toString()); + "Position {}" + ". Call stack overflow. Too many lua script calls being nested.", + __FUNCTION__, position.toString()); return; } @@ -226,8 +226,8 @@ bool Events::eventCreatureOnChangeOutfit(std::shared_ptr creature, con if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventCreatureOnChangeOutfit - Creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName()); return false; } @@ -253,9 +253,9 @@ ReturnValue Events::eventCreatureOnAreaCombat(std::shared_ptr creature if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventCreatureOnAreaCombat - " - "Creature {} on tile position {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), tile->getPosition().toString()); + "Creature {} on tile position {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), tile->getPosition().toString()); return RETURNVALUE_NOTPOSSIBLE; } @@ -298,9 +298,9 @@ ReturnValue Events::eventCreatureOnTargetCombat(std::shared_ptr creatu if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventCreatureOnTargetCombat - " - "Creature {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), target->getName()); + "Creature {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), target->getName()); return RETURNVALUE_NOTPOSSIBLE; } @@ -341,9 +341,9 @@ void Events::eventCreatureOnHear(std::shared_ptr creature, std::shared if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventCreatureOnHear - " - "Creature {} speaker {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), speaker->getName()); + "Creature {} speaker {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), speaker->getName()); return; } @@ -372,9 +372,9 @@ void Events::eventCreatureOnDrainHealth(std::shared_ptr creature, std: if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventCreatureOnDrainHealth - " - "Creature {} attacker {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), attacker->getName()); + "Creature {} attacker {}] " + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), attacker->getName()); return; } @@ -429,9 +429,9 @@ bool Events::eventPartyOnJoin(std::shared_ptr party, std::shared_ptrgetName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -458,9 +458,9 @@ bool Events::eventPartyOnLeave(std::shared_ptr party, std::shared_ptrgetName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -487,8 +487,8 @@ bool Events::eventPartyOnDisband(std::shared_ptr party) { if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPartyOnDisband - Party leader {}] Call stack " - "overflow. Too many lua script calls being nested.", - party->getLeader() ? party->getLeader()->getName() : "unknown"); + "overflow. Too many lua script calls being nested.", + party->getLeader() ? party->getLeader()->getName() : "unknown"); return false; } @@ -545,9 +545,9 @@ bool Events::eventPlayerOnBrowseField(std::shared_ptr player, const Posi if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnBrowseField - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -573,9 +573,9 @@ void Events::eventPlayerOnLook(std::shared_ptr player, const Position &p if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnLook - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -612,9 +612,9 @@ void Events::eventPlayerOnLookInBattleList(std::shared_ptr player, std:: if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnLookInBattleList - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -643,9 +643,9 @@ void Events::eventPlayerOnLookInTrade(std::shared_ptr player, std::share if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnLookInTrade - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -677,9 +677,9 @@ bool Events::eventPlayerOnLookInShop(std::shared_ptr player, const ItemT if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnLookInShop - " - "Player {} itemType {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), itemType->getPluralName()); + "Player {} itemType {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), itemType->getPluralName()); return false; } @@ -708,9 +708,9 @@ bool Events::eventPlayerOnRemoveCount(std::shared_ptr player, std::share if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnMove - " - "Player {} item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Player {} item {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return false; } @@ -737,9 +737,9 @@ bool Events::eventPlayerOnMoveItem(std::shared_ptr player, std::shared_p if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnMoveItem - " - "Player {} item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Player {} item {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return false; } @@ -773,9 +773,9 @@ void Events::eventPlayerOnItemMoved(std::shared_ptr player, std::shared_ if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnItemMoved - " - "Player {} item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Player {} item {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return; } @@ -809,9 +809,9 @@ void Events::eventPlayerOnChangeZone(std::shared_ptr player, ZoneType_t if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnChangeZone - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -836,9 +836,9 @@ bool Events::eventPlayerOnMoveCreature(std::shared_ptr player, std::shar if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnMoveCreature - " - "Player {} creature {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), creature->getName()); + "Player {} creature {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), creature->getName()); return false; } @@ -868,9 +868,9 @@ void Events::eventPlayerOnReportRuleViolation(std::shared_ptr player, co if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnReportRuleViolation - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -902,9 +902,9 @@ bool Events::eventPlayerOnReportBug(std::shared_ptr player, const std::s if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnReportBug - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -932,9 +932,9 @@ bool Events::eventPlayerOnTurn(std::shared_ptr player, Direction directi if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnTurn - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return false; } @@ -960,9 +960,9 @@ bool Events::eventPlayerOnTradeRequest(std::shared_ptr player, std::shar if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnTradeRequest - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return false; } @@ -992,9 +992,9 @@ bool Events::eventPlayerOnTradeAccept(std::shared_ptr player, std::share if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnTradeAccept - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return false; } @@ -1028,9 +1028,9 @@ void Events::eventPlayerOnGainExperience(std::shared_ptr player, std::sh if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnGainExperience - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return; } @@ -1071,9 +1071,9 @@ void Events::eventPlayerOnLoseExperience(std::shared_ptr player, uint64_ if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnLoseExperience - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -1106,9 +1106,9 @@ void Events::eventPlayerOnGainSkillTries(std::shared_ptr player, skills_ if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnGainSkillTries - " - "Player {} skill {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), fmt::underlying(skill)); + "Player {} skill {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), fmt::underlying(skill)); return; } @@ -1142,9 +1142,9 @@ void Events::eventPlayerOnCombat(std::shared_ptr player, std::shared_ptr if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnCombat - " - "Player {} target {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), target->getName()); + "Player {} target {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), target->getName()); return; } @@ -1199,9 +1199,9 @@ void Events::eventPlayerOnRequestQuestLog(std::shared_ptr player) { if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnRequestQuestLog - " - "Player {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName()); + "Player {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName()); return; } @@ -1225,9 +1225,9 @@ void Events::eventPlayerOnRequestQuestLine(std::shared_ptr player, uint1 if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventPlayerOnRequestQuestLine - " - "Player {} questId {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), questId); + "Player {} questId {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), questId); return; } @@ -1282,9 +1282,9 @@ void Events::eventOnStorageUpdate(std::shared_ptr player, const uint32_t if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventOnStorageUpdate - " - "Player {} key {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), key); + "Player {} key {}] " + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), key); return; } @@ -1314,9 +1314,9 @@ void Events::eventMonsterOnDropLoot(std::shared_ptr monster, std::share if (!scriptInterface.reserveScriptEnv()) { g_logger().error("[Events::eventMonsterOnDropLoot - " - "Monster corpse {}] " - "Call stack overflow. Too many lua script calls being nested.", - corpse->getName()); + "Monster corpse {}] " + "Call stack overflow. Too many lua script calls being nested.", + corpse->getName()); return; } diff --git a/src/lua/creature/movement.cpp b/src/lua/creature/movement.cpp index b302877b3..b75ff31c6 100644 --- a/src/lua/creature/movement.cpp +++ b/src/lua/creature/movement.cpp @@ -133,9 +133,9 @@ bool MoveEvents::registerLuaPositionEvent(const std::shared_ptr moveE bool MoveEvents::registerLuaEvent(const std::shared_ptr moveEvent) { // Check if event is correct if (registerLuaItemEvent(moveEvent) - || registerLuaUniqueEvent(moveEvent) - || registerLuaActionEvent(moveEvent) - || registerLuaPositionEvent(moveEvent)) { + || registerLuaUniqueEvent(moveEvent) + || registerLuaActionEvent(moveEvent) + || registerLuaPositionEvent(moveEvent)) { return true; } else { g_logger().warn( @@ -292,7 +292,7 @@ bool MoveEvents::registerEvent(const std::shared_ptr moveEvent, const std::shared_ptr MoveEvents::getEvent(const std::shared_ptr &tile, MoveEvent_t eventType) { if (auto it = positionsMap.find(tile->getPosition()); - it != positionsMap.end()) { + it != positionsMap.end()) { std::list> &moveEventList = it->second.moveEvent[eventType]; if (!moveEventList.empty()) { return *moveEventList.begin(); @@ -727,12 +727,12 @@ bool MoveEvent::executeStep(const std::shared_ptr &creature, std::shar if (!getScriptInterface()->reserveScriptEnv()) { if (item != nullptr) { g_logger().error("[MoveEvent::executeStep - Creature {} item {}, position {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), item->getName(), pos.toString()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), item->getName(), pos.toString()); } else { g_logger().error("[MoveEvent::executeStep - Creature {}, position {}] " - "Call stack overflow. Too many lua script calls being nested.", - creature->getName(), pos.toString()); + "Call stack overflow. Too many lua script calls being nested.", + creature->getName(), pos.toString()); } return false; } @@ -770,8 +770,8 @@ bool MoveEvent::executeEquip(const std::shared_ptr &player, const std::s // onDeEquip(player, item, slot, isCheck) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[MoveEvent::executeEquip - Player {} item {}] " - "Call stack overflow. Too many lua script calls being nested.", - player->getName(), item->getName()); + "Call stack overflow. Too many lua script calls being nested.", + player->getName(), item->getName()); return false; } @@ -803,9 +803,9 @@ bool MoveEvent::executeAddRemItem(const std::shared_ptr &item, const std:: // onRemoveItem(moveitem, tileitem, pos) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[MoveEvent::executeAddRemItem - " - "Item {} item on tile x: {} y: {} z: {}] " - "Call stack overflow. Too many lua script calls being nested.", - item->getName(), pos.getX(), pos.getY(), pos.getZ()); + "Item {} item on tile x: {} y: {} z: {}] " + "Call stack overflow. Too many lua script calls being nested.", + item->getName(), pos.getX(), pos.getY(), pos.getZ()); return false; } @@ -835,9 +835,9 @@ bool MoveEvent::executeAddRemItem(const std::shared_ptr &item, const Posit // onRemoveItem(moveitem, pos) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[MoveEvent::executeAddRemItem - " - "Item {} item on tile x: {} y: {} z: {}] " - "Call stack overflow. Too many lua script calls being nested.", - item->getName(), pos.getX(), pos.getY(), pos.getZ()); + "Item {} item on tile x: {} y: {} z: {}] " + "Call stack overflow. Too many lua script calls being nested.", + item->getName(), pos.getX(), pos.getY(), pos.getZ()); return false; } diff --git a/src/lua/creature/movement.hpp b/src/lua/creature/movement.hpp index 4ce4297b0..b8168f585 100644 --- a/src/lua/creature/movement.hpp +++ b/src/lua/creature/movement.hpp @@ -47,7 +47,7 @@ class MoveEvents final : public Scripts { bool hasPosition(Position position) const { if (auto it = positionsMap.find(position); - it != positionsMap.end()) { + it != positionsMap.end()) { return true; } return false; @@ -63,7 +63,7 @@ class MoveEvents final : public Scripts { bool hasItemId(int32_t itemId) const { if (auto it = itemIdMap.find(itemId); - it != itemIdMap.end()) { + it != itemIdMap.end()) { return true; } return false; @@ -79,7 +79,7 @@ class MoveEvents final : public Scripts { bool hasUniqueId(int32_t uniqueId) const { if (auto it = uniqueIdMap.find(uniqueId); - it != uniqueIdMap.end()) { + it != uniqueIdMap.end()) { return true; } return false; @@ -95,7 +95,7 @@ class MoveEvents final : public Scripts { bool hasActionId(int32_t actionId) const { if (auto it = actionIdMap.find(actionId); - it != actionIdMap.end()) { + it != actionIdMap.end()) { return true; } return false; diff --git a/src/lua/creature/raids.cpp b/src/lua/creature/raids.cpp index a4500d126..8064bf52b 100644 --- a/src/lua/creature/raids.cpp +++ b/src/lua/creature/raids.cpp @@ -52,16 +52,16 @@ bool Raids::loadFromXml() { ss << "raids/" << name << ".xml"; file = ss.str(); g_logger().warn("{} - " - "'file' tag missing for raid: {} using default: {}", - __FUNCTION__, name, file); + "'file' tag missing for raid: {} using default: {}", + __FUNCTION__, name, file); } interval = pugi::cast(raidNode.attribute("interval2").value()) * 60; if (interval == 0) { g_logger().error("{} - " - "'interval2' tag missing or zero " - "(would divide by 0) for raid: {}", - __FUNCTION__, name); + "'interval2' tag missing or zero " + "(would divide by 0) for raid: {}", + __FUNCTION__, name); continue; } @@ -69,8 +69,8 @@ bool Raids::loadFromXml() { margin = pugi::cast(attr.value()) * 60 * 1000; } else { g_logger().warn("{} - " - "'margin' tag missing for raid: {}", - __FUNCTION__, name); + "'margin' tag missing for raid: {}", + __FUNCTION__, name); margin = 0; } @@ -202,8 +202,8 @@ bool Raid::loadFromXml(const std::string &filename) { raidEvents.push_back(event); } else { g_logger().error("{} - " - "In file: {}, eventNode: {}", - __FUNCTION__, filename, eventNode.name()); + "In file: {}, eventNode: {}", + __FUNCTION__, filename, eventNode.name()); } } @@ -288,8 +288,8 @@ bool AnnounceEvent::configureRaidEvent(const pugi::xml_node &eventNode) { pugi::xml_attribute messageAttribute = eventNode.attribute("message"); if (!messageAttribute) { g_logger().error("{} - " - "'message' tag missing for announce event", - __FUNCTION__); + "'message' tag missing for announce event", + __FUNCTION__); return false; } message = messageAttribute.as_string(); @@ -311,16 +311,16 @@ bool AnnounceEvent::configureRaidEvent(const pugi::xml_node &eventNode) { messageType = MESSAGE_GAMEMASTER_CONSOLE; } else { g_logger().warn("{} - " - "Unknown type tag missing for announce event, " - "using default: {}", - __FUNCTION__, static_cast(messageType)); + "Unknown type tag missing for announce event, " + "using default: {}", + __FUNCTION__, static_cast(messageType)); } } else { messageType = MESSAGE_EVENT_ADVANCE; g_logger().warn("{} - " - "Type tag missing for announce event, " - "using default: {}", - __FUNCTION__, static_cast(messageType)); + "Type tag missing for announce event, " + "using default: {}", + __FUNCTION__, static_cast(messageType)); } return true; } @@ -341,8 +341,8 @@ bool SingleSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { monsterName = attr.as_string(); } else { g_logger().error("{} - " - "'Name' tag missing for singlespawn event", - __FUNCTION__); + "'Name' tag missing for singlespawn event", + __FUNCTION__); return false; } @@ -350,8 +350,8 @@ bool SingleSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { position.x = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'X' tag missing for singlespawn event", - __FUNCTION__); + "'X' tag missing for singlespawn event", + __FUNCTION__); return false; } @@ -359,8 +359,8 @@ bool SingleSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { position.y = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'Y' tag missing for singlespawn event", - __FUNCTION__); + "'Y' tag missing for singlespawn event", + __FUNCTION__); return false; } @@ -368,8 +368,8 @@ bool SingleSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { position.z = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'Z' tag missing for singlespawn event", - __FUNCTION__); + "'Z' tag missing for singlespawn event", + __FUNCTION__); return false; } return true; @@ -405,9 +405,9 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { centerPos.x = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "" - "'centerx' tag missing for areaspawn event", - __FUNCTION__); + "" + "'centerx' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -415,8 +415,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { centerPos.y = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'centery' tag missing for areaspawn event", - __FUNCTION__); + "'centery' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -424,8 +424,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { centerPos.z = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "centerz' tag missing for areaspawn event", - __FUNCTION__); + "centerz' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -441,8 +441,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { fromPos.x = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'fromx' tag missing for areaspawn event", - __FUNCTION__); + "'fromx' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -450,8 +450,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { fromPos.y = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'fromy' tag missing for areaspawn event", - __FUNCTION__); + "'fromy' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -459,8 +459,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { fromPos.z = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'fromz' tag missing for areaspawn event", - __FUNCTION__); + "'fromz' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -468,8 +468,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { toPos.x = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'tox' tag missing for areaspawn event", - __FUNCTION__); + "'tox' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -477,8 +477,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { toPos.y = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'toy' tag missing for areaspawn event", - __FUNCTION__); + "'toy' tag missing for areaspawn event", + __FUNCTION__); return false; } @@ -486,8 +486,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { toPos.z = pugi::cast(attr.value()); } else { g_logger().error("{} - " - "'toz' tag missing for areaspawn event", - __FUNCTION__); + "'toz' tag missing for areaspawn event", + __FUNCTION__); return false; } } @@ -499,8 +499,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { name = attr.value(); } else { g_logger().error("{} - " - "'name' tag missing for monster node", - __FUNCTION__); + "'name' tag missing for monster node", + __FUNCTION__); return false; } @@ -524,8 +524,8 @@ bool AreaSpawnEvent::configureRaidEvent(const pugi::xml_node &eventNode) { maxAmount = minAmount; } else { g_logger().error("{} - " - "'amount' tag missing for monster node", - __FUNCTION__); + "'amount' tag missing for monster node", + __FUNCTION__); return false; } } @@ -570,8 +570,8 @@ bool ScriptEvent::configureRaidEvent(const pugi::xml_node &eventNode) { pugi::xml_attribute scriptAttribute = eventNode.attribute("script"); if (!scriptAttribute) { g_logger().error("{} - " - "No script file found for raid", - __FUNCTION__); + "No script file found for raid", + __FUNCTION__); return false; } @@ -595,8 +595,8 @@ bool ScriptEvent::executeEvent() { // onRaid() if (!scriptInterface->reserveScriptEnv()) { g_logger().error("{} - Script with name {} " - "Call stack overflow. Too many lua script calls being nested.", - __FUNCTION__, getScriptName()); + "Call stack overflow. Too many lua script calls being nested.", + __FUNCTION__, getScriptName()); return false; } diff --git a/src/lua/creature/talkaction.cpp b/src/lua/creature/talkaction.cpp index 3586bdbce..c1b8c028d 100644 --- a/src/lua/creature/talkaction.cpp +++ b/src/lua/creature/talkaction.cpp @@ -83,8 +83,8 @@ bool TalkAction::executeSay(std::shared_ptr player, const std::string &w // onSay(player, words, param, type) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[TalkAction::executeSay - Player {} words {}] " - "Call stack overflow. Too many lua script calls being nested. Script name {}", - player->getName(), getWords(), getScriptInterface()->getLoadingScriptName()); + "Call stack overflow. Too many lua script calls being nested. Script name {}", + player->getName(), getWords(), getScriptInterface()->getLoadingScriptName()); return false; } diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index 4858b3ab2..83ecd0918 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -28,6 +28,7 @@ #include "lua/callbacks/events_callbacks.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" +#include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" #include "map/spectators.hpp" @@ -728,8 +729,8 @@ int GameFunctions::luaGameGetDummies(lua_State* L) { * @details This function provides a table containing two sub-tables: one for free dummies and one for house (or premium) dummies. * @note usage on lua: - local dummies = Game.getDummies() - local rate = dummies[1] -- Retrieve dummy rate + local dummies = Game.getDummies() + local rate = dummies[1] -- Retrieve dummy rate */ const auto &dummies = Item::items.getDummys(); diff --git a/src/lua/functions/creatures/combat/spell_functions.cpp b/src/lua/functions/creatures/combat/spell_functions.cpp index 0bcf7c9c1..a24407c16 100644 --- a/src/lua/functions/creatures/combat/spell_functions.cpp +++ b/src/lua/functions/creatures/combat/spell_functions.cpp @@ -18,7 +18,7 @@ int SpellFunctions::luaSpellCreate(lua_State* L) { // Spell(type) ex: Spell(SPELL_INSTANT) or Spell(SPELL_RUNE) to create a new spell if (lua_gettop(L) == 1) { g_logger().error("[SpellFunctions::luaSpellCreate] - " - "There is no parameter set!"); + "There is no parameter set!"); lua_pushnil(L); return 1; } @@ -209,16 +209,16 @@ int SpellFunctions::luaSpellGroup(lua_State* L) { spell->setGroup(group); } else { g_logger().warn("[SpellFunctions::luaSpellGroup] - " - "Unknown group: {}", - getString(L, 2)); + "Unknown group: {}", + getString(L, 2)); pushBoolean(L, false); return 1; } pushBoolean(L, true); } else { g_logger().warn("[SpellFunctions::luaSpellGroup] - " - "Unknown group: {}", - getString(L, 2)); + "Unknown group: {}", + getString(L, 2)); pushBoolean(L, false); return 1; } @@ -235,8 +235,8 @@ int SpellFunctions::luaSpellGroup(lua_State* L) { spell->setGroup(primaryGroup); } else { g_logger().warn("[SpellFunctions::luaSpellGroup] - " - "Unknown primaryGroup: {}", - getString(L, 2)); + "Unknown primaryGroup: {}", + getString(L, 2)); pushBoolean(L, false); return 1; } @@ -245,16 +245,16 @@ int SpellFunctions::luaSpellGroup(lua_State* L) { spell->setSecondaryGroup(secondaryGroup); } else { g_logger().warn("[SpellFunctions::luaSpellGroup] - " - "Unknown secondaryGroup: {}", - getString(L, 3)); + "Unknown secondaryGroup: {}", + getString(L, 3)); pushBoolean(L, false); return 1; } pushBoolean(L, true); } else { g_logger().warn("[SpellFunctions::luaSpellGroup] - " - "Unknown primaryGroup: {} or secondaryGroup: {}", - getString(L, 2), getString(L, 3)); + "Unknown primaryGroup: {} or secondaryGroup: {}", + getString(L, 2), getString(L, 3)); pushBoolean(L, false); return 1; } diff --git a/src/lua/functions/creatures/creature_functions.cpp b/src/lua/functions/creatures/creature_functions.cpp index 7a40cc426..4ae5da0e1 100644 --- a/src/lua/functions/creatures/creature_functions.cpp +++ b/src/lua/functions/creatures/creature_functions.cpp @@ -793,7 +793,7 @@ int CreatureFunctions::luaCreatureTeleportTo(lua_State* L) { const Position oldPosition = creature->getPosition(); if (auto ret = g_game().internalTeleport(creature, position, pushMovement); - ret != RETURNVALUE_NOERROR) { + ret != RETURNVALUE_NOERROR) { g_logger().debug("[{}] Failed to teleport creature {}, on position {}, error code: {}", __FUNCTION__, creature->getName(), oldPosition.toString(), getReturnMessage(ret)); pushBoolean(L, false); return 1; diff --git a/src/lua/functions/creatures/monster/loot_functions.cpp b/src/lua/functions/creatures/monster/loot_functions.cpp index 3fe3a1883..47e0d8778 100644 --- a/src/lua/functions/creatures/monster/loot_functions.cpp +++ b/src/lua/functions/creatures/monster/loot_functions.cpp @@ -29,7 +29,7 @@ int LootFunctions::luaLootSetId(lua_State* L) { pushBoolean(L, true); } else { g_logger().warn("[LootFunctions::luaLootSetId] - " - "Unknown loot item loot, int value expected"); + "Unknown loot item loot, int value expected"); lua_pushnil(L); } } else { @@ -47,16 +47,16 @@ int LootFunctions::luaLootSetIdFromName(lua_State* L) { if (ids.first == Item::items.nameToItems.cend()) { g_logger().warn("[LootFunctions::luaLootSetIdFromName] - " - "Unknown loot item {}", - name); + "Unknown loot item {}", + name); lua_pushnil(L); return 1; } if (std::next(ids.first) != ids.second) { g_logger().warn("[LootFunctions::luaLootSetIdFromName] - " - "Non-unique loot item {}", - name); + "Non-unique loot item {}", + name); lua_pushnil(L); return 1; } @@ -65,7 +65,7 @@ int LootFunctions::luaLootSetIdFromName(lua_State* L) { pushBoolean(L, true); } else { g_logger().warn("[LootFunctions::luaLootSetIdFromName] - " - "Unknown loot item loot, string value expected"); + "Unknown loot item loot, string value expected"); lua_pushnil(L); } return 1; diff --git a/src/lua/functions/creatures/monster/monster_type_functions.cpp b/src/lua/functions/creatures/monster/monster_type_functions.cpp index b937083fd..ded7c2054 100644 --- a/src/lua/functions/creatures/monster/monster_type_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_type_functions.cpp @@ -681,8 +681,8 @@ int MonsterTypeFunctions::luaMonsterTypeCombatImmunities(lua_State* L) { combatType = COMBAT_NEUTRALDAMAGE; } else { g_logger().warn("[MonsterTypeFunctions::luaMonsterTypeCombatImmunities] - " - "Unknown immunity name {} for monster: {}", - immunity, monsterType->name); + "Unknown immunity name {} for monster: {}", + immunity, monsterType->name); lua_pushnil(L); } @@ -739,8 +739,8 @@ int MonsterTypeFunctions::luaMonsterTypeConditionImmunities(lua_State* L) { conditionType = CONDITION_BLEEDING; } else { g_logger().warn("[MonsterTypeFunctions::luaMonsterTypeConditionImmunities] - " - "Unknown immunity name: {} for monster: {}", - immunity, monsterType->name); + "Unknown immunity name: {} for monster: {}", + immunity, monsterType->name); lua_pushnil(L); } @@ -1195,8 +1195,8 @@ int MonsterTypeFunctions::luaMonsterTypeRace(lua_State* L) { monsterType->info.race = RACE_INK; } else { g_logger().warn("[MonsterTypeFunctions::luaMonsterTypeRace] - " - "Unknown race type {}", - race); + "Unknown race type {}", + race); lua_pushnil(L); return 1; } diff --git a/src/lua/functions/creatures/npc/npc_functions.cpp b/src/lua/functions/creatures/npc/npc_functions.cpp index 8c19a4ede..13e9b499a 100644 --- a/src/lua/functions/creatures/npc/npc_functions.cpp +++ b/src/lua/functions/creatures/npc/npc_functions.cpp @@ -354,7 +354,6 @@ int NpcFunctions::luaNpcOpenShopWindow(lua_State* L) { return 1; } - npc->addShopPlayer(player); pushBoolean(L, player->openShopWindow(npc)); return 1; } @@ -405,10 +404,7 @@ int NpcFunctions::luaNpcOpenShopWindowTable(lua_State* L) { } lua_pop(L, 3); - // Close any eventual other shop window currently open. - player->closeShopWindow(true); - npc->addShopPlayer(player, items); - pushBoolean(L, player->openShopWindow(npc)); + pushBoolean(L, player->openShopWindow(npc, items)); return 1; } @@ -429,7 +425,7 @@ int NpcFunctions::luaNpcCloseShopWindow(lua_State* L) { } if (player->getShopOwner() == npc) { - player->closeShopWindow(true); + player->closeShopWindow(); } pushBoolean(L, true); @@ -577,7 +573,7 @@ int NpcFunctions::luaNpcSellItem(lua_State* L) { } uint64_t pricePerUnit = 0; - const std::vector &shopVector = npc->getShopItemVector(player->getGUID()); + const auto &shopVector = npc->getShopItemVector(player->getGUID()); for (ShopBlock shopBlock : shopVector) { if (itemId == shopBlock.itemId && shopBlock.itemBuyPrice != 0) { pricePerUnit = shopBlock.itemBuyPrice; diff --git a/src/lua/functions/creatures/npc/shop_functions.cpp b/src/lua/functions/creatures/npc/shop_functions.cpp index ee848e0bf..122e249a8 100644 --- a/src/lua/functions/creatures/npc/shop_functions.cpp +++ b/src/lua/functions/creatures/npc/shop_functions.cpp @@ -28,7 +28,7 @@ int ShopFunctions::luaShopSetId(lua_State* L) { pushBoolean(L, true); } else { g_logger().warn("[ShopFunctions::luaShopSetId] - " - "Unknown shop item shop, int value expected"); + "Unknown shop item shop, int value expected"); lua_pushnil(L); } } else { @@ -46,16 +46,16 @@ int ShopFunctions::luaShopSetIdFromName(lua_State* L) { if (ids.first == Item::items.nameToItems.cend()) { g_logger().warn("[ShopFunctions::luaShopSetIdFromName] - " - "Unknown shop item {}", - name); + "Unknown shop item {}", + name); lua_pushnil(L); return 1; } if (std::next(ids.first) != ids.second) { g_logger().warn("[ShopFunctions::luaShopSetIdFromName] - " - "Non-unique shop item {}", - name); + "Non-unique shop item {}", + name); lua_pushnil(L); return 1; } @@ -64,7 +64,7 @@ int ShopFunctions::luaShopSetIdFromName(lua_State* L) { pushBoolean(L, true); } else { g_logger().warn("[ShopFunctions::luaShopSetIdFromName] - " - "Unknown shop item shop, string value expected"); + "Unknown shop item shop, string value expected"); lua_pushnil(L); } return 1; diff --git a/src/lua/functions/creatures/player/player_functions.cpp b/src/lua/functions/creatures/player/player_functions.cpp index 5f14db6ea..52fd4517f 100644 --- a/src/lua/functions/creatures/player/player_functions.cpp +++ b/src/lua/functions/creatures/player/player_functions.cpp @@ -16,6 +16,7 @@ #include "creatures/players/wheel/player_wheel.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" +#include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" #include "game/game.hpp" #include "io/iologindata.hpp" @@ -407,7 +408,7 @@ int PlayerFunctions::luaPlayerGetPreyExperiencePercentage(lua_State* L) { // player:getPreyExperiencePercentage(raceId) if (std::shared_ptr player = getUserdataShared(L, 1)) { if (const std::unique_ptr &slot = player->getPreyWithMonster(getNumber(L, 2, 0)); - slot && slot->isOccupied() && slot->bonus == PreyBonus_Experience && slot->bonusTimeLeft > 0) { + slot && slot->isOccupied() && slot->bonus == PreyBonus_Experience && slot->bonusTimeLeft > 0) { lua_pushnumber(L, static_cast(100 + slot->bonusPercentage)); } else { lua_pushnumber(L, 100); @@ -457,7 +458,7 @@ int PlayerFunctions::luaPlayerGetPreyLootPercentage(lua_State* L) { // player:getPreyLootPercentage(raceid) if (std::shared_ptr player = getUserdataShared(L, 1)) { if (const std::unique_ptr &slot = player->getPreyWithMonster(getNumber(L, 2, 0)); - slot && slot->isOccupied() && slot->bonus == PreyBonus_Loot) { + slot && slot->isOccupied() && slot->bonus == PreyBonus_Loot) { lua_pushnumber(L, slot->bonusPercentage); } else { lua_pushnumber(L, 0); @@ -472,7 +473,7 @@ int PlayerFunctions::luaPlayerisMonsterPrey(lua_State* L) { // player:isMonsterPrey(raceid) if (std::shared_ptr player = getUserdataShared(L, 1)) { if (const std::unique_ptr &slot = player->getPreyWithMonster(getNumber(L, 2, 0)); - slot && slot->isOccupied()) { + slot && slot->isOccupied()) { pushBoolean(L, true); } else { pushBoolean(L, false); @@ -486,7 +487,7 @@ int PlayerFunctions::luaPlayerisMonsterPrey(lua_State* L) { int PlayerFunctions::luaPlayerPreyThirdSlot(lua_State* L) { // get: player:preyThirdSlot() set: player:preyThirdSlot(bool) if (std::shared_ptr player = getUserdataShared(L, 1); - const auto &slot = player->getPreySlotById(PreySlot_Three)) { + const auto &slot = player->getPreySlotById(PreySlot_Three)) { if (!slot) { lua_pushnil(L); } else if (lua_gettop(L) == 1) { @@ -513,7 +514,7 @@ int PlayerFunctions::luaPlayerPreyThirdSlot(lua_State* L) { int PlayerFunctions::luaPlayerTaskThirdSlot(lua_State* L) { // get: player:taskHuntingThirdSlot() set: player:taskHuntingThirdSlot(bool) if (std::shared_ptr player = getUserdataShared(L, 1); - const auto &slot = player->getTaskHuntingSlotById(PreySlot_Three)) { + const auto &slot = player->getTaskHuntingSlotById(PreySlot_Three)) { if (lua_gettop(L) == 1) { pushBoolean(L, slot->state != PreyTaskDataState_Locked); } else { @@ -2732,7 +2733,7 @@ int PlayerFunctions::luaPlayerRemoveBlessing(lua_State* L) { } int PlayerFunctions::luaPlayerGetBlessingCount(lua_State* L) { - // player:getBlessingCount(index) + // player:getBlessingCount(index[, storeCount = false]) std::shared_ptr player = getUserdataShared(L, 1); uint8_t index = getNumber(L, 2); if (index == 0) { @@ -2740,7 +2741,7 @@ int PlayerFunctions::luaPlayerGetBlessingCount(lua_State* L) { } if (player) { - lua_pushnumber(L, player->getBlessingCount(index)); + lua_pushnumber(L, player->getBlessingCount(index, getBoolean(L, 3, false))); } else { lua_pushnil(L); } @@ -3574,7 +3575,7 @@ int PlayerFunctions::luaPlayerBosstiaryCooldownTimer(lua_State* L) { int PlayerFunctions::luaPlayerGetBosstiaryLevel(lua_State* L) { // player:getBosstiaryLevel(name) if (std::shared_ptr player = getUserdataShared(L, 1); - player) { + player) { const auto mtype = g_monsters().getMonsterType(getString(L, 2)); if (mtype) { uint32_t bossId = mtype->info.raceid; @@ -3596,7 +3597,7 @@ int PlayerFunctions::luaPlayerGetBosstiaryLevel(lua_State* L) { int PlayerFunctions::luaPlayerGetBosstiaryKills(lua_State* L) { // player:getBosstiaryKills(name) if (std::shared_ptr player = getUserdataShared(L, 1); - player) { + player) { const auto mtype = g_monsters().getMonsterType(getString(L, 2)); if (mtype) { uint32_t bossId = mtype->info.raceid; @@ -3618,7 +3619,7 @@ int PlayerFunctions::luaPlayerGetBosstiaryKills(lua_State* L) { int PlayerFunctions::luaPlayerAddBosstiaryKill(lua_State* L) { // player:addBosstiaryKill(name[, amount = 1]) if (std::shared_ptr player = getUserdataShared(L, 1); - player) { + player) { const auto mtype = g_monsters().getMonsterType(getString(L, 2)); if (mtype) { g_ioBosstiary().addBosstiaryKill(player, mtype, getNumber(L, 3, 1)); @@ -4355,3 +4356,25 @@ int PlayerFunctions::luaPlayerSetCurrentTitle(lua_State* L) { pushBoolean(L, true); return 1; } + +int PlayerFunctions::luaPlayerCreateTransactionSummary(lua_State* L) { + // player:createTransactionSummary(type, amount[, id = 0]) + const auto &player = getUserdataShared(L, 1); + if (!player) { + reportErrorFunc(getErrorDesc(LUA_ERROR_PLAYER_NOT_FOUND)); + return 1; + } + + auto type = getNumber(L, 2, 0); + if (type == 0) { + reportErrorFunc(getErrorDesc(LUA_ERROR_VARIANT_NOT_FOUND)); + return 1; + } + + auto amount = getNumber(L, 3, 1); + auto id = getString(L, 4, ""); + + player->cyclopedia()->updateStoreSummary(type, amount, id); + 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 4d89a86d2..281e51ae8 100644 --- a/src/lua/functions/creatures/player/player_functions.hpp +++ b/src/lua/functions/creatures/player/player_functions.hpp @@ -372,6 +372,9 @@ class PlayerFunctions final : LuaScriptInterface { registerMethod(L, "Player", "getTitles", PlayerFunctions::luaPlayerGetTitles); registerMethod(L, "Player", "setCurrentTitle", PlayerFunctions::luaPlayerSetCurrentTitle); + // Store Summary + registerMethod(L, "Player", "createTransactionSummary", PlayerFunctions::luaPlayerCreateTransactionSummary); + GroupFunctions::init(L); GuildFunctions::init(L); MountFunctions::init(L); @@ -732,5 +735,7 @@ class PlayerFunctions final : LuaScriptInterface { static int luaPlayerGetTitles(lua_State* L); static int luaPlayerSetCurrentTitle(lua_State* L); + static int luaPlayerCreateTransactionSummary(lua_State* L); + friend class CreatureFunctions; }; diff --git a/src/lua/functions/events/action_functions.cpp b/src/lua/functions/events/action_functions.cpp index c1fd581f8..31b202465 100644 --- a/src/lua/functions/events/action_functions.cpp +++ b/src/lua/functions/events/action_functions.cpp @@ -133,7 +133,7 @@ int ActionFunctions::luaActionPosition(lua_State* L) { // The parameter "- 1" because self is a parameter aswell, which we want to skip L 1 (UserData) // isNumber(L, 2) is for skip the itemId if (int parameters = lua_gettop(L) - 1; - parameters > 1 && isNumber(L, 2)) { + parameters > 1 && isNumber(L, 2)) { for (int i = 0; i < parameters; ++i) { action->setPositionsVector(getPosition(L, 2 + i)); } diff --git a/src/lua/functions/events/creature_event_functions.cpp b/src/lua/functions/events/creature_event_functions.cpp index 7b5e25a12..7edbabad1 100644 --- a/src/lua/functions/events/creature_event_functions.cpp +++ b/src/lua/functions/events/creature_event_functions.cpp @@ -54,8 +54,8 @@ int CreatureEventFunctions::luaCreatureEventType(lua_State* L) { creatureEvent->setEventType(CREATURE_EVENT_EXTENDED_OPCODE); } else { g_logger().error("[CreatureEventFunctions::luaCreatureEventType] - " - "Invalid type for creature event: {}", - typeName); + "Invalid type for creature event: {}", + typeName); pushBoolean(L, false); } creatureEvent->setLoaded(true); diff --git a/src/lua/functions/events/global_event_functions.cpp b/src/lua/functions/events/global_event_functions.cpp index 8f54e5b03..ea6a5f7df 100644 --- a/src/lua/functions/events/global_event_functions.cpp +++ b/src/lua/functions/events/global_event_functions.cpp @@ -42,7 +42,7 @@ int GlobalEventFunctions::luaGlobalEventType(lua_State* L) { global->setEventType(GLOBALEVENT_ON_THINK); } else { g_logger().error("[GlobalEventFunctions::luaGlobalEventType] - " - "Invalid type for global event: {}"); + "Invalid type for global event: {}"); pushBoolean(L, false); } pushBoolean(L, true); @@ -97,8 +97,8 @@ int GlobalEventFunctions::luaGlobalEventTime(lua_State* L) { int32_t hour = params.front(); if (hour < 0 || hour > 23) { g_logger().error("[GlobalEventFunctions::luaGlobalEventTime] - " - "Invalid hour {} for globalevent with name: {}", - timer, globalevent->getName()); + "Invalid hour {} for globalevent with name: {}", + timer, globalevent->getName()); pushBoolean(L, false); return 1; } @@ -111,8 +111,8 @@ int GlobalEventFunctions::luaGlobalEventTime(lua_State* L) { min = params[1]; if (min < 0 || min > 59) { g_logger().error("[GlobalEventFunctions::luaGlobalEventTime] - " - "Invalid minute: {} for globalevent with name: {}", - timer, globalevent->getName()); + "Invalid minute: {} for globalevent with name: {}", + timer, globalevent->getName()); pushBoolean(L, false); return 1; } @@ -121,8 +121,8 @@ int GlobalEventFunctions::luaGlobalEventTime(lua_State* L) { sec = params[2]; if (sec < 0 || sec > 59) { g_logger().error("[GlobalEventFunctions::luaGlobalEventTime] - " - "Invalid minute: {} for globalevent with name: {}", - timer, globalevent->getName()); + "Invalid minute: {} for globalevent with name: {}", + timer, globalevent->getName()); pushBoolean(L, false); return 1; } diff --git a/src/lua/functions/events/move_event_functions.cpp b/src/lua/functions/events/move_event_functions.cpp index 5de49c26f..8340dded9 100644 --- a/src/lua/functions/events/move_event_functions.cpp +++ b/src/lua/functions/events/move_event_functions.cpp @@ -47,8 +47,8 @@ int MoveEventFunctions::luaMoveEventType(lua_State* L) { moveevent->moveFunction = moveevent->RemoveItemField; } else { g_logger().error("[MoveEventFunctions::luaMoveEventType] - " - "No valid event name: {}", - typeName); + "No valid event name: {}", + typeName); pushBoolean(L, false); } pushBoolean(L, true); @@ -126,8 +126,8 @@ int MoveEventFunctions::luaMoveEventSlot(lua_State* L) { moveevent->setSlot(SLOTP_AMMO); } else { g_logger().warn("[MoveEventFunctions::luaMoveEventSlot] - " - "Unknown slot type: {}", - slotName); + "Unknown slot type: {}", + slotName); pushBoolean(L, false); return 1; } diff --git a/src/lua/functions/items/item_functions.cpp b/src/lua/functions/items/item_functions.cpp index 71ab040f4..361a469da 100644 --- a/src/lua/functions/items/item_functions.cpp +++ b/src/lua/functions/items/item_functions.cpp @@ -398,7 +398,7 @@ int ItemFunctions::luaItemSetAttribute(lua_State* L) { switch (attribute) { case ItemAttribute_t::DECAYSTATE: { if (ItemDecayState_t decayState = getNumber(L, 3); - decayState == DECAYING_FALSE || decayState == DECAYING_STOPPING) { + decayState == DECAYING_FALSE || decayState == DECAYING_STOPPING) { g_decay().stopDecay(item); } else { g_decay().startDecay(item); diff --git a/src/lua/functions/items/weapon_functions.cpp b/src/lua/functions/items/weapon_functions.cpp index 962c1181f..61eff2dfb 100644 --- a/src/lua/functions/items/weapon_functions.cpp +++ b/src/lua/functions/items/weapon_functions.cpp @@ -77,8 +77,8 @@ int WeaponFunctions::luaWeaponAction(lua_State* L) { weapon->action = WEAPONACTION_MOVE; } else { g_logger().error("[WeaponFunctions::luaWeaponAction] - " - "No valid action {}", - typeName); + "No valid action {}", + typeName); pushBoolean(L, false); } pushBoolean(L, true); @@ -285,8 +285,8 @@ int WeaponFunctions::luaWeaponElement(lua_State* L) { weapon->params.combatType = COMBAT_HOLYDAMAGE; } else { g_logger().warn("[WeaponFunctions:luaWeaponElement] - " - "Type {} does not exist", - element); + "Type {} does not exist", + element); } } else { weapon->params.combatType = getNumber(L, 2); @@ -539,8 +539,8 @@ int WeaponFunctions::luaWeaponAmmoType(lua_State* L) { it.ammoType = AMMO_BOLT; } else { g_logger().warn("[WeaponFunctions:luaWeaponAmmoType] - " - "Type {} does not exist", - type); + "Type {} does not exist", + type); lua_pushnil(L); return 1; } @@ -604,8 +604,8 @@ int WeaponFunctions::luaWeaponExtraElement(lua_State* L) { it.abilities->elementType = COMBAT_HOLYDAMAGE; } else { g_logger().warn("[WeaponFunctions:luaWeaponExtraElement] - " - "Type {} does not exist", - element); + "Type {} does not exist", + element); } } else { it.abilities->elementType = getNumber(L, 3); diff --git a/src/lua/functions/lua_functions_loader.cpp b/src/lua/functions/lua_functions_loader.cpp index 69ee85dd8..c2dedfb57 100644 --- a/src/lua/functions/lua_functions_loader.cpp +++ b/src/lua/functions/lua_functions_loader.cpp @@ -289,13 +289,13 @@ void LuaFunctionsLoader::setWeakMetatable(lua_State* L, int32_t index, const std int metatable = lua_gettop(L); for (static const std::vector methodKeys = { "__index", "__metatable", "__eq" }; - const std::string &metaKey : methodKeys) { + const std::string &metaKey : methodKeys) { lua_getfield(L, childMetatable, metaKey.c_str()); lua_setfield(L, metatable, metaKey.c_str()); } for (static const std::vector methodIndexes = { 'h', 'p', 't' }; - int metaIndex : methodIndexes) { + int metaIndex : methodIndexes) { lua_rawgeti(L, childMetatable, metaIndex); lua_rawseti(L, metatable, metaIndex); } diff --git a/src/lua/global/baseevents.cpp b/src/lua/global/baseevents.cpp index 9728342f7..3b312100d 100644 --- a/src/lua/global/baseevents.cpp +++ b/src/lua/global/baseevents.cpp @@ -25,7 +25,7 @@ bool BaseEvents::loadFromXml() { basePath + "lib/" + scriptsName + ".lua", scriptsName + ".lua" ) - == -1) { + == -1) { g_logger().warn(__FUNCTION__, scriptsName, scriptsName); } @@ -107,8 +107,8 @@ bool Event::checkScript(const std::string &basePath, const std::string &scriptsN int32_t id = testInterface->getEvent(getScriptEventName()); if (id == -1) { g_logger().warn("[Event::checkScript] - Event " - "{} not found {}", - getScriptEventName(), scriptFile); + "{} not found {}", + getScriptEventName(), scriptFile); return false; } return true; diff --git a/src/lua/global/globalevent.cpp b/src/lua/global/globalevent.cpp index 9626173dc..04420431d 100644 --- a/src/lua/global/globalevent.cpp +++ b/src/lua/global/globalevent.cpp @@ -126,8 +126,8 @@ void GlobalEvents::think() { if (!globalEvent->executeEvent()) { g_logger().error("[GlobalEvents::think] - " - "Failed to execute event: {}", - globalEvent->getName()); + "Failed to execute event: {}", + globalEvent->getName()); } nextExecutionTime = globalEvent->getInterval(); @@ -206,8 +206,8 @@ bool GlobalEvent::executePeriodChange(LightState_t lightState, LightInfo lightIn // onPeriodChange(lightState, lightTime) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[GlobalEvent::executePeriodChange - {}] " - "Call stack overflow. Too many lua script calls being nested.", - getName()); + "Call stack overflow. Too many lua script calls being nested.", + getName()); return false; } @@ -226,8 +226,8 @@ bool GlobalEvent::executeRecord(uint32_t current, uint32_t old) { // onRecord(current, old) if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[GlobalEvent::executeRecord - {}] " - "Call stack overflow. Too many lua script calls being nested.", - getName()); + "Call stack overflow. Too many lua script calls being nested.", + getName()); return false; } @@ -245,8 +245,8 @@ bool GlobalEvent::executeRecord(uint32_t current, uint32_t old) { bool GlobalEvent::executeEvent() const { if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[GlobalEvent::executeEvent - {}] " - "Call stack overflow. Too many lua script calls being nested.", - getName()); + "Call stack overflow. Too many lua script calls being nested.", + getName()); return false; } diff --git a/src/lua/scripts/lua_environment.cpp b/src/lua/scripts/lua_environment.cpp index f3d2273df..cd5023a8d 100644 --- a/src/lua/scripts/lua_environment.cpp +++ b/src/lua/scripts/lua_environment.cpp @@ -174,8 +174,8 @@ void LuaEnvironment::executeTimerEvent(uint32_t eventIndex) { callFunction(timerEventDesc.parameters.size()); } else { g_logger().error("[LuaEnvironment::executeTimerEvent - Lua file {}] " - "Call stack overflow. Too many lua script calls being nested", - getLoadingFile()); + "Call stack overflow. Too many lua script calls being nested", + getLoadingFile()); } // free resources diff --git a/src/lua/scripts/scripts.cpp b/src/lua/scripts/scripts.cpp index 1d395cdd0..cb92c1cc2 100644 --- a/src/lua/scripts/scripts.cpp +++ b/src/lua/scripts/scripts.cpp @@ -88,7 +88,7 @@ bool Scripts::loadScripts(std::string loadPath, bool isLib, bool reload) { // Check if file start with "#" if (std::string disable("#"); - file.front() == disable.front()) { + file.front() == disable.front()) { // Send log of disabled script if (g_configManager().getBoolean(SCRIPTS_CONSOLE_LOGS, __FUNCTION__)) { g_logger().info("[script]: {} [disabled]", realPath.filename().string()); diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index 842622b2a..261147fff 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -753,8 +753,8 @@ bool Houses::loadHousesXML(const std::string &filename) { ); if (entryPos.x == 0 && entryPos.y == 0 && entryPos.z == 0) { g_logger().warn("[Houses::loadHousesXML] - Entry not set for house " - "name: {} with id: {}", - house->getName(), houseId); + "name: {} with id: {}", + house->getName(), houseId); } house->setEntryPos(entryPos); diff --git a/src/map/house/housetile.cpp b/src/map/house/housetile.cpp index 6b301f0e8..5e728a14e 100644 --- a/src/map/house/housetile.cpp +++ b/src/map/house/housetile.cpp @@ -95,9 +95,9 @@ std::shared_ptr HouseTile::queryDestination(int32_t &index, const std: std::shared_ptr destTile = g_game().map.getTile(entryPos); if (!destTile) { g_logger().error("[HouseTile::queryDestination] - " - "Entry not correct for house name: {} " - "with id: {} not found tile: {}", - house->getName(), house->getId(), entryPos.toString()); + "Entry not correct for house name: {} " + "with id: {} not found tile: {}", + house->getName(), house->getId(), entryPos.toString()); destTile = g_game().map.getTile(player->getTemplePosition()); if (!destTile) { destTile = Tile::nullptr_tile; diff --git a/src/map/map.cpp b/src/map/map.cpp index 8b8cebeb5..82629aeae 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -342,13 +342,35 @@ void Map::moveCreature(const std::shared_ptr &creature, const std::sha bool teleport = forceTeleport || !newTile->getGround() || !Position::areInRange<1, 1, 0>(oldPos, newPos); - auto spectators = Spectators() - .find(oldPos, true) - .find(newPos, true); + Spectators spectators; + if (!teleport && oldPos.z == newPos.z) { + int32_t minRangeX = MAP_MAX_VIEW_PORT_X; + int32_t maxRangeX = MAP_MAX_VIEW_PORT_X; + int32_t minRangeY = MAP_MAX_VIEW_PORT_Y; + int32_t maxRangeY = MAP_MAX_VIEW_PORT_Y; + + if (oldPos.y > newPos.y) { + ++minRangeY; + } else if (oldPos.y < newPos.y) { + ++maxRangeY; + } + + if (oldPos.x < newPos.x) { + ++maxRangeX; + } else if (oldPos.x > newPos.x) { + ++minRangeX; + } + + spectators.find(oldPos, true, minRangeX, maxRangeX, minRangeY, maxRangeY); + } else { + spectators.find(oldPos, true); + spectators.find(newPos, true); + } auto playersSpectators = spectators.filter(); std::vector oldStackPosVector; + oldStackPosVector.reserve(playersSpectators.size()); for (const auto &spec : playersSpectators) { if (spec->canSeeCreature(creature)) { oldStackPosVector.push_back(oldTile->getClientIndexOfCreature(spec->getPlayer(), creature)); diff --git a/src/map/mapcache.cpp b/src/map/mapcache.cpp index 0448615ee..cb3e95eb3 100644 --- a/src/map/mapcache.cpp +++ b/src/map/mapcache.cpp @@ -70,7 +70,7 @@ void MapCache::parseItemAttr(const std::shared_ptr &BasicItem, std::s } /* if (BasicItem.description != 0) - item->setAttribute(ItemAttribute_t::DESCRIPTION, STRING_CACHE[BasicItem.description]);*/ + item->setAttribute(ItemAttribute_t::DESCRIPTION, STRING_CACHE[BasicItem.description]);*/ } std::shared_ptr MapCache::createItem(const std::shared_ptr &BasicItem, Position position) { diff --git a/src/map/spectators.cpp b/src/map/spectators.cpp index 36cce6d53..405119b83 100644 --- a/src/map/spectators.cpp +++ b/src/map/spectators.cpp @@ -18,50 +18,27 @@ void Spectators::clearCache() { spectatorsCache.clear(); } -bool Spectators::contains(const std::shared_ptr &creature) { - return creatures.contains(creature); -} - -bool Spectators::erase(const std::shared_ptr &creature) { - return creatures.erase(creature); -} - Spectators Spectators::insert(const std::shared_ptr &creature) { if (creature) { - creatures.emplace(creature); + creatures.emplace_back(creature); } return *this; } -Spectators Spectators::insertAll(const SpectatorList &list) { +Spectators Spectators::insertAll(const CreatureVector &list) { if (!list.empty()) { - creatures.insertAll(list); - } - return *this; -} + const bool hasValue = !creatures.empty(); -Spectators Spectators::join(Spectators &anotherSpectators) { - return insertAll(anotherSpectators.creatures.data()); -} - -bool Spectators::empty() const noexcept { - return creatures.empty(); -} + creatures.insert(creatures.end(), list.begin(), list.end()); -size_t Spectators::size() noexcept { - return creatures.size(); -} - -CreatureVector::iterator Spectators::begin() noexcept { - return creatures.begin(); -} - -CreatureVector::iterator Spectators::end() noexcept { - return creatures.end(); -} - -const CreatureVector &Spectators::data() noexcept { - return creatures.data(); + // Remove duplicate + if (hasValue) { + std::unordered_set uset(creatures.begin(), creatures.end()); + creatures.clear(); + creatures.insert(creatures.end(), uset.begin(), uset.end()); + } + } + return *this; } bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onlyPlayers, const Position ¢erPos, bool checkDistance, bool multifloor, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY) { @@ -77,16 +54,16 @@ bool Spectators::checkCache(const SpectatorsCache::FloorData &specData, bool onl } if (checkDistance) { - SpectatorList spectators; + CreatureVector spectators; spectators.reserve(creatures.size()); for (const auto &creature : *list) { const auto &specPos = creature->getPosition(); if (centerPos.x - specPos.x >= minRangeX - && centerPos.y - specPos.y >= minRangeY - && centerPos.x - specPos.x <= maxRangeX - && centerPos.y - specPos.y <= maxRangeY - && (multifloor || specPos.z == centerPos.z) - && (!onlyPlayers || creature->getPlayer())) { + && centerPos.y - specPos.y >= minRangeY + && centerPos.x - specPos.x <= maxRangeX + && centerPos.y - specPos.y <= maxRangeY + && (multifloor || specPos.z == centerPos.z) + && (!onlyPlayers || creature->getPlayer())) { spectators.emplace_back(creature); } } @@ -176,7 +153,7 @@ Spectators Spectators::find(const Position ¢erPos, bool multifloor, bool onl const int32_t endx2 = x2 - (x2 & SECTOR_MASK); const int32_t endy2 = y2 - (y2 & SECTOR_MASK); - SpectatorList spectators; + CreatureVector spectators; spectators.reserve(std::max(MAP_MAX_VIEW_PORT_X, MAP_MAX_VIEW_PORT_Y) * 2); const MapSector* startSector = g_game().map.getMapSector(startx1, starty1); diff --git a/src/map/spectators.hpp b/src/map/spectators.hpp index 93526e05c..9e998da2b 100644 --- a/src/map/spectators.hpp +++ b/src/map/spectators.hpp @@ -16,12 +16,10 @@ class Monster; class Npc; struct Position; -using SpectatorList = std::vector>; - struct SpectatorsCache { struct FloorData { - std::optional floor; - std::optional multiFloor; + std::optional floor; + std::optional multiFloor; }; int32_t minRangeX { 0 }; @@ -48,16 +46,39 @@ class Spectators { requires std::is_base_of_v Spectators filter(); - bool contains(const std::shared_ptr &creature); - bool erase(const std::shared_ptr &creature); Spectators insert(const std::shared_ptr &creature); - Spectators insertAll(const SpectatorList &list); - Spectators join(Spectators &anotherSpectators); - bool empty() const noexcept; - size_t size() noexcept; - CreatureVector::iterator begin() noexcept; - CreatureVector::iterator end() noexcept; - const CreatureVector &data() noexcept; + Spectators insertAll(const CreatureVector &list); + Spectators join(const Spectators &anotherSpectators) { + return insertAll(anotherSpectators.creatures); + } + + bool contains(const std::shared_ptr &creature) const { + return std::ranges::find(creatures, creature) != creatures.end(); + } + + bool erase(const std::shared_ptr &creature) { + return std::erase(creatures, creature) > 0; + } + + bool empty() const noexcept { + return creatures.empty(); + } + + size_t size() const noexcept { + return creatures.size(); + } + + auto begin() const noexcept { + return creatures.begin(); + } + + auto end() const noexcept { + return creatures.end(); + } + + const auto &data() const noexcept { + return creatures; + } private: static phmap::flat_hash_map spectatorsCache; @@ -65,7 +86,7 @@ class Spectators { Spectators find(const Position ¢erPos, bool multifloor = false, bool onlyPlayers = false, int32_t minRangeX = 0, int32_t maxRangeX = 0, int32_t minRangeY = 0, int32_t maxRangeY = 0); bool checkCache(const SpectatorsCache::FloorData &specData, bool onlyPlayers, const Position ¢erPos, bool checkDistance, bool multifloor, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY); - stdext::vector_set> creatures; + CreatureVector creatures; }; template diff --git a/src/server/network/connection/connection.cpp b/src/server/network/connection/connection.cpp index 3effd52f8..307238442 100644 --- a/src/server/network/connection/connection.cpp +++ b/src/server/network/connection/connection.cpp @@ -241,7 +241,7 @@ void Connection::parsePacket(const std::error_code &error) { // Check packet checksum uint32_t checksum; if (int32_t len = msg.getLength() - msg.getBufferPosition() - CHECKSUM_LENGTH; - len > 0) { + len > 0) { checksum = adlerChecksum(msg.getBuffer() + msg.getBufferPosition() + CHECKSUM_LENGTH, len); } else { checksum = 0; diff --git a/src/server/network/message/networkmessage.cpp b/src/server/network/message/networkmessage.cpp index 159631355..38acc0b48 100644 --- a/src/server/network/message/networkmessage.cpp +++ b/src/server/network/message/networkmessage.cpp @@ -40,9 +40,9 @@ Position NetworkMessage::getPosition() { return pos; } -void NetworkMessage::addString(const std::string &value, const std::string &function) { +void NetworkMessage::addString(const std::string &value, const std::string &function /* = ""*/) { size_t stringLen = value.length(); - if (value.empty()) { + if (value.empty() && !function.empty()) { g_logger().debug("[NetworkMessage::addString] - Value string is empty, function '{}'", function); } if (!canAdd(stringLen + 2)) { diff --git a/src/server/network/message/networkmessage.hpp b/src/server/network/message/networkmessage.hpp index 72f0e69c3..02e192531 100644 --- a/src/server/network/message/networkmessage.hpp +++ b/src/server/network/message/networkmessage.hpp @@ -90,7 +90,20 @@ class NetworkMessage { void addBytes(const char* bytes, size_t size); void addPaddingBytes(size_t n); - void addString(const std::string &value, const std::string &function); + /** + * Adds a string to the network message buffer. + * + * @param value The string value to be added to the message buffer. + * @param function * @param function An optional parameter that specifies the function name from which `addString` is invoked. + * Including this enhances logging by adding the function name to the debug and error log messages. + * This helps in debugging by indicating the context when issues occur, such as attempting to add an + * empty string or when there are message size errors. + * + * When the function parameter is used, it aids in identifying the context in log messages, + * making it easier to diagnose issues related to network message construction, + * especially in complex systems where the same method might be called from multiple places. + */ + void addString(const std::string &value, const std::string &function = ""); void addDouble(double value, uint8_t precision = 2); diff --git a/src/server/network/protocol/protocol.cpp b/src/server/network/protocol/protocol.cpp index 6f6a1c822..255899f2f 100644 --- a/src/server/network/protocol/protocol.cpp +++ b/src/server/network/protocol/protocol.cpp @@ -50,7 +50,7 @@ bool Protocol::sendRecvMessageCallback(NetworkMessage &msg) { protocol->parsePacket(msg); protocolConnection->resumeWork(); } - } }, __FUNCTION__); + } }, "Protocol::sendRecvMessageCallback"); return true; } @@ -78,7 +78,7 @@ bool Protocol::onRecvMessage(NetworkMessage &msg) { } else { uint32_t checksum; if (int32_t len = msg.getLength() - msg.getBufferPosition(); - len > 0) { + len > 0) { checksum = adlerChecksum(msg.getBuffer() + msg.getBufferPosition(), len); } else { checksum = 0; diff --git a/src/server/network/protocol/protocol.hpp b/src/server/network/protocol/protocol.hpp index c264f49bf..54e3dcfd4 100644 --- a/src/server/network/protocol/protocol.hpp +++ b/src/server/network/protocol/protocol.hpp @@ -50,7 +50,7 @@ class Protocol : public std::enable_shared_from_this { void send(OutputMessage_ptr msg) const { if (auto connection = getConnection(); - connection != nullptr) { + connection != nullptr) { connection->send(msg); } } diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 8cf0660a2..18c23fbb1 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -28,6 +28,7 @@ #include "creatures/players/wheel/player_wheel.hpp" #include "creatures/players/achievement/player_achievement.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" +#include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" #include "creatures/players/grouping/familiars.hpp" #include "server/network/protocol/protocolgame.hpp" @@ -1485,7 +1486,7 @@ void ProtocolGame::GetFloorDescription(NetworkMessage &msg, int32_t x, int32_t y void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool &known, uint32_t &removedKnown) { if (auto [creatureKnown, creatureInserted] = knownCreatureSet.insert(id); - !creatureInserted) { + !creatureInserted) { known = true; return; } @@ -1499,7 +1500,7 @@ void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool &known, uint32_t &remo // We need to protect party players from removing std::shared_ptr creature = g_game().getCreatureByID(*it); if (std::shared_ptr checkPlayer; - creature && (checkPlayer = creature->getPlayer()) != nullptr) { + creature && (checkPlayer = creature->getPlayer()) != nullptr) { if (player->getParty() != checkPlayer->getParty() && !canSee(creature)) { removedKnown = *it; knownCreatureSet.erase(it); @@ -2334,7 +2335,7 @@ void ProtocolGame::parseBestiarysendMonsterData(NetworkMessage &msg) { if (!mtype) { g_logger().warn("[ProtocolGame::parseBestiarysendMonsterData] - " - "MonsterType was not found"); + "MonsterType was not found"); return; } @@ -2944,8 +2945,8 @@ void ProtocolGame::parseBestiarysendCreatures(NetworkMessage &msg) { if (race.empty()) { g_logger().warn("[ProtocolGame::parseBestiarysendCreature] - " - "Race was not found: {}, search: {}", - raceName, search); + "Race was not found: {}, search: {}", + raceName, search); return; } text = raceName; @@ -3381,7 +3382,7 @@ void ProtocolGame::sendAddMarker(const Position &pos, uint8_t markType, const st msg.addByte(0xDD); if (!oldProtocol) { - msg.addByte(0x00); // unknow + msg.addByte(enumToValue(CyclopediaMapData_t::MinimapMarker)); } msg.addPosition(pos); @@ -3456,7 +3457,7 @@ void ProtocolGame::sendCyclopediaCharacterGeneralStats() { msg.add(player->getOfflineTrainingTime() / 60 / 1000); msg.add(player->getSpeed()); msg.add(player->getBaseSpeed()); - msg.add(player->getBonusCapacity()); + msg.add(player->getCapacity()); msg.add(player->getBaseCapacity()); msg.add(player->hasFlag(PlayerFlags_t::HasInfiniteCapacity) ? 1000000 : player->getFreeCapacity()); msg.addByte(8); @@ -3660,21 +3661,15 @@ void ProtocolGame::sendCyclopediaCharacterRecentDeaths(uint16_t page, uint16_t p NetworkMessage msg; msg.addByte(0xDA); msg.addByte(CYCLOPEDIA_CHARACTERINFO_RECENTDEATHS); - msg.addByte(0x00); - - uint16_t totalPages = static_cast(std::ceil(static_cast(entries.size()) / pages)); - uint16_t currentPage = std::min(page, totalPages); - uint16_t firstObject = (currentPage - 1) * pages; - uint16_t finalObject = firstObject + pages; - - msg.add(currentPage); - msg.add(totalPages); + msg.addByte(0x00); // 0x00 Here means 'no error' + msg.add(page); msg.add(pages); - for (uint16_t i = firstObject; i < finalObject; i++) { - RecentDeathEntry entry = entries[i]; + msg.add(entries.size()); + for (const RecentDeathEntry &entry : entries) { msg.add(entry.timestamp); msg.addString(entry.cause, "ProtocolGame::sendCyclopediaCharacterRecentDeaths - entry.cause"); } + writeToOutputBuffer(msg); } @@ -3686,22 +3681,16 @@ void ProtocolGame::sendCyclopediaCharacterRecentPvPKills(uint16_t page, uint16_t NetworkMessage msg; msg.addByte(0xDA); msg.addByte(CYCLOPEDIA_CHARACTERINFO_RECENTPVPKILLS); - msg.addByte(0x00); - - uint16_t totalPages = static_cast(std::ceil(static_cast(entries.size()) / pages)); - uint16_t currentPage = std::min(page, totalPages); - uint16_t firstObject = (currentPage - 1) * pages; - uint16_t finalObject = firstObject + pages; - - msg.add(currentPage); - msg.add(totalPages); + msg.addByte(0x00); // 0x00 Here means 'no error' + msg.add(page); msg.add(pages); - for (uint16_t i = firstObject; i < finalObject; i++) { - RecentPvPKillEntry entry = entries[i]; + msg.add(entries.size()); + for (const RecentPvPKillEntry &entry : entries) { msg.add(entry.timestamp); msg.addString(entry.description, "ProtocolGame::sendCyclopediaCharacterRecentPvPKills - entry.description"); msg.addByte(entry.status); } + writeToOutputBuffer(msg); } @@ -3959,17 +3948,72 @@ void ProtocolGame::sendCyclopediaCharacterStoreSummary() { msg.addByte(CYCLOPEDIA_CHARACTERINFO_STORESUMMARY); msg.addByte(0x00); // 0x00 Here means 'no error' msg.add(player->getXpBoostTime()); // Remaining Store Xp Boost Time - msg.add(0); // RemainingDailyRewardXpBoostTime + auto remaining = player->kv()->get("daily-reward-xp-boost"); + msg.add(remaining ? static_cast(remaining->getNumber()) : 0); // Remaining Daily Reward Xp Boost Time + + auto cyclopediaSummary = player->cyclopedia()->getSummary(); + + // getBlessingsObtained + auto blessingNames = g_game().getBlessingNames(); + msg.addByte(static_cast(blessingNames.size())); + for (const auto &bless : blessingNames) { + msg.addString(bless.second, "ProtocolGame::sendCyclopediaCharacterStoreSummary - blessing.name"); + uint8_t blessingIndex = bless.first - 1; + msg.addByte((blessingIndex < player->blessings.size()) ? static_cast(player->blessings[blessingIndex]) : 0); + } + + uint8_t preySlotsUnlocked = 0; + // Prey third slot unlocked + if (const auto &slotP = player->getPreySlotById(PreySlot_Three); + slotP && slotP->state != PreyDataState_Locked) { + preySlotsUnlocked++; + } + // Task hunting third slot unlocked + if (const auto &slotH = player->getTaskHuntingSlotById(PreySlot_Three); + slotH && slotH->state != PreyTaskDataState_Locked) { + preySlotsUnlocked++; + } + msg.addByte(preySlotsUnlocked); // getPreySlotById + getTaskHuntingSlotById + + msg.addByte(cyclopediaSummary.m_preyWildcards); // getPreyCardsObtained + msg.addByte(cyclopediaSummary.m_instantRewards); // getRewardCollectionObtained + msg.addByte(player->hasCharmExpansion() ? 0x01 : 0x00); + msg.addByte(cyclopediaSummary.m_hirelings); // getHirelingsObtained + + std::vector m_hSkills; + for (const auto &it : g_game().getHirelingSkills()) { + if (player->kv()->scoped("hireling-skills")->get(it.second)) { + m_hSkills.emplace_back(it.first); + g_logger().debug("skill id: {}, name: {}", it.first, it.second); + } + } + msg.addByte(m_hSkills.size()); + for (const auto &id : m_hSkills) { + msg.addByte(id - 1000); + } + + /*std::vector m_hOutfits; + for (const auto &it : g_game().getHirelingOutfits()) { + if (player->kv()->scoped("hireling-outfits")->get(it.second)) { + m_hOutfits.emplace_back(it.first); + g_logger().debug("outfit id: {}, name: {}", it.first, it.second); + } + } + msg.addByte(m_hOutfits.size()); + for (const auto &id : m_hOutfits) { + msg.addByte(0x01); // TODO need to get the correct id from hireling outfit + }*/ + msg.addByte(0x00); // hireling outfit size + + auto houseItems = player->cyclopedia()->getResult(static_cast(Summary_t::HOUSE_ITEMS)); + msg.add(houseItems.size()); + for (const auto &hItem_it : houseItems) { + const ItemType &it = Item::items[hItem_it.first]; + msg.add(it.id); // Item ID + msg.addString(it.name, "ProtocolGame::sendCyclopediaCharacterStoreSummary - houseItem.name"); + msg.addByte(hItem_it.second); + } - msg.addByte(0x00); // getBlessingsObtained - msg.addByte(0x00); // getTaskHuntingSlotById - msg.addByte(0x00); // getPreyCardsObtained - msg.addByte(0x00); // getRewardCollectionObtained - msg.addByte(0x00); // player->hasCharmExpansion() ? 0x01 : 0x00 - msg.addByte(0x00); // getHirelingsObtained - msg.addByte(0x00); // getHirelinsJobsObtained - msg.addByte(0x00); // getHirelinsOutfitsObtained - msg.add(0); // getHouseItemsObtained writeToOutputBuffer(msg); } @@ -4028,23 +4072,23 @@ void ProtocolGame::sendCyclopediaCharacterInspection() { auto playerDescriptionPosition = msg.getBufferPosition(); msg.skipBytes(1); + // Player title + if (player->title()->getCurrentTitle() != 0) { + playerDescriptionSize++; + msg.addString("Character Title", "ProtocolGame::sendCyclopediaCharacterInspection - Title"); + msg.addString(player->title()->getCurrentTitleName(), "ProtocolGame::sendCyclopediaCharacterInspection - player->title()->getCurrentTitleName()"); + } + // Level description playerDescriptionSize++; msg.addString("Level", "ProtocolGame::sendCyclopediaCharacterInspection - Level"); + msg.addString(std::to_string(player->getLevel()), "ProtocolGame::sendCyclopediaCharacterInspection - std::to_string(player->getLevel())"); // Vocation description playerDescriptionSize++; - msg.addString(std::to_string(player->getLevel()), "ProtocolGame::sendCyclopediaCharacterInspection - std::to_string(player->getLevel())"); msg.addString("Vocation", "ProtocolGame::sendCyclopediaCharacterInspection - Vocation"); msg.addString(player->getVocation()->getVocName(), "ProtocolGame::sendCyclopediaCharacterInspection - player->getVocation()->getVocName()"); - // Player title - if (player->title()->getCurrentTitle() != 0) { - playerDescriptionSize++; - msg.addString("Title", "ProtocolGame::sendCyclopediaCharacterInspection - Title"); - msg.addString(player->title()->getCurrentTitleName(), "ProtocolGame::sendCyclopediaCharacterInspection - player->title()->getCurrentTitleName()"); - } - // Loyalty title if (!player->getLoyaltyTitle().empty()) { playerDescriptionSize++; @@ -4052,6 +4096,47 @@ void ProtocolGame::sendCyclopediaCharacterInspection() { msg.addString(player->getLoyaltyTitle(), "ProtocolGame::sendCyclopediaCharacterInspection - player->getLoyaltyTitle()"); } + // Marriage description + if (const auto spouseId = player->getMarriageSpouse(); spouseId > 0) { + if (const auto &spouse = g_game().getPlayerByID(spouseId, true); spouse) { + playerDescriptionSize++; + msg.addString("Married to", "ProtocolGame::sendCyclopediaCharacterInspection - Married to"); + msg.addString(spouse->getName(), "ProtocolGame::sendCyclopediaCharacterInspection - spouse->getName()"); + } + } + + // Prey description + for (uint8_t slotId = PreySlot_First; slotId <= PreySlot_Last; slotId++) { + if (const auto &slot = player->getPreySlotById(static_cast(slotId)); + slot && slot->isOccupied()) { + playerDescriptionSize++; + std::string activePrey = fmt::format("Active Prey {}", slotId + 1); + msg.addString(activePrey, "ProtocolGame::sendCyclopediaCharacterInspection - active prey"); + + std::string desc; + if (auto mtype = g_monsters().getMonsterTypeByRaceId(slot->selectedRaceId)) { + desc.append(mtype->name); + } else { + desc.append("Unknown creature"); + } + + if (slot->bonus == PreyBonus_Damage) { + desc.append(" (Improved Damage +"); + } else if (slot->bonus == PreyBonus_Defense) { + desc.append(" (Improved Defense +"); + } else if (slot->bonus == PreyBonus_Experience) { + desc.append(" (Improved Experience +"); + } else if (slot->bonus == PreyBonus_Loot) { + desc.append(" (Improved Loot +"); + } + desc.append(fmt::format("{}%, remaining", slot->bonusPercentage)); + uint8_t hours = slot->bonusTimeLeft / 3600; + uint8_t minutes = (slot->bonusTimeLeft - (hours * 3600)) / 60; + desc.append(fmt::format("{}:{}{}h", hours, (minutes < 10 ? "0" : ""), minutes)); + msg.addString(desc, "ProtocolGame::sendCyclopediaCharacterInspection - prey description"); + } + } + // Outfit description playerDescriptionSize++; msg.addString("Outfit", "ProtocolGame::sendCyclopediaCharacterInspection - Outfit"); @@ -4637,29 +4722,45 @@ void ProtocolGame::sendLootStats(std::shared_ptr item, uint8_t count) { } void ProtocolGame::sendShop(std::shared_ptr npc) { + Benchmark brenchmark; NetworkMessage msg; msg.addByte(0x7A); msg.addString(npc->getName(), "ProtocolGame::sendShop - npc->getName()"); if (!oldProtocol) { msg.add(npc->getCurrency()); - msg.addString(std::string(), "ProtocolGame::sendShop - std::string()"); // Currency name + msg.addString(std::string()); // Currency name } - std::vector shoplist = npc->getShopItemVector(player->getGUID()); + const auto &shoplist = npc->getShopItemVector(player->getGUID()); uint16_t itemsToSend = std::min(shoplist.size(), std::numeric_limits::max()); msg.add(itemsToSend); + // Initialize before the loop to avoid database overload on each iteration + auto talkactionHidden = player->kv()->get("npc-shop-hidden-sell-item"); + // Initialize the inventoryMap outside the loop to avoid creation on each iteration + std::map inventoryMap; + player->getAllSaleItemIdAndCount(inventoryMap); uint16_t i = 0; for (const ShopBlock &shopBlock : shoplist) { if (++i > itemsToSend) { break; } + // Hidden sell items from the shop if they are not in the player's inventory + if (talkactionHidden && talkactionHidden->get()) { + const auto &foundItem = inventoryMap.find(shopBlock.itemId); + if (foundItem == inventoryMap.end() && shopBlock.itemSellPrice > 0 && shopBlock.itemBuyPrice == 0) { + AddHiddenShopItem(msg); + continue; + } + } + AddShopItem(msg, shopBlock); } writeToOutputBuffer(msg); + g_logger().debug("ProtocolGame::sendShop - Time: {} ms, shop items: {}", brenchmark.duration(), shoplist.size()); } void ProtocolGame::sendCloseShop() { @@ -4871,7 +4972,7 @@ void ProtocolGame::updateCoinBalance() { threadPlayer->sendCoinBalance(); } }, - "ProtocolGame::updateCoinBalance"); + "ProtocolGame::updateCoinBalance"); } void ProtocolGame::sendMarketLeave() { @@ -5266,9 +5367,9 @@ void ProtocolGame::sendOpenForge() { for each convergence fusion (1 per item slot, only class 4): 1 byte: count fusable items for each fusable item: - 2 bytes: item id - 1 byte: tier - 2 bytes: count + 2 bytes: item id + 1 byte: tier + 2 bytes: count */ for (const auto &[slot, itemMap] : convergenceItemsMap) { uint8_t totalItemsCount = 0; @@ -5348,15 +5449,15 @@ void ProtocolGame::sendOpenForge() { /* for each convergence transfer: - 2 bytes: count donors - for each donor: - 2 bytes: item id - 1 byte: tier - 2 bytes: count - 2 bytes: count receivers - for each receiver: - 2 bytes: item id - 2 bytes: count + 2 bytes: count donors + for each donor: + 2 bytes: item id + 1 byte: tier + 2 bytes: count + 2 bytes: count receivers + for each receiver: + 2 bytes: item id + 2 bytes: count */ for (const auto &[slot, itemMap] : convergenceItemsMap) { uint16_t donorCount = 0; @@ -5857,6 +5958,8 @@ void ProtocolGame::sendMarketDetail(uint16_t itemId, uint8_t tier) { msg.add(purchaseStatistics.highestPrice); msg.add(purchaseStatistics.lowestPrice); } + } else { + msg.addByte(0x00); } } else { msg.addByte(0x00); // send to old protocol ? @@ -5880,6 +5983,8 @@ void ProtocolGame::sendMarketDetail(uint16_t itemId, uint8_t tier) { msg.add(saleStatistics.highestPrice); msg.add(saleStatistics.lowestPrice); } + } else { + msg.addByte(0x00); } } else { msg.addByte(0x00); // send to old protocol ? @@ -6564,6 +6669,7 @@ void ProtocolGame::sendAddCreature(std::shared_ptr creature, const Pos if (isLogin) { sendMagicEffect(pos, CONST_ME_TELEPORT); + sendHotkeyPreset(); sendDisableLoginMusic(); } @@ -7451,7 +7557,7 @@ void ProtocolGame::AddCreature(NetworkMessage &msg, std::shared_ptr cr } if (!oldProtocol && creature->isHealthHidden()) { - msg.addString("", "ProtocolGame::AddCreature - empty"); + msg.addString(std::string()); } else { msg.addString(creature->getName(), "ProtocolGame::AddCreature - creature->getName()"); } @@ -7673,7 +7779,7 @@ void ProtocolGame::addImbuementInfo(NetworkMessage &msg, uint16_t imbuementId) c msg.add(imbuementId); msg.addString(baseImbuement->name + " " + imbuement->getName(), "ProtocolGame::addImbuementInfo - baseImbuement->name + " - " + imbuement->getName()"); + " + imbuement->getName()"); msg.addString(imbuement->getDescription(), "ProtocolGame::addImbuementInfo - imbuement->getDescription()"); msg.addString(categoryImbuement->name + imbuement->getSubGroup(), "ProtocolGame::addImbuementInfo - categoryImbuement->name + imbuement->getSubGroup()"); @@ -7811,7 +7917,7 @@ void ProtocolGame::updatePartyTrackerAnalyzer(const std::shared_ptr party for (const std::shared_ptr &analyzer : party->membersData) { msg.add(analyzer->id); if (std::shared_ptr member = g_game().getPlayerByID(analyzer->id); - !member || !member->getParty() || member->getParty() != party) { + !member || !member->getParty() || member->getParty() != party) { msg.addByte(0); } else { msg.addByte(1); @@ -8097,7 +8203,7 @@ void ProtocolGame::AddHiddenShopItem(NetworkMessage &msg) { // Empty bytes from AddShopItem msg.add(0); msg.addByte(0); - msg.addString(std::string(), "ProtocolGame::AddHiddenShopItem - std::string()"); + msg.addString(std::string()); msg.add(0); msg.add(0); msg.add(0); @@ -8110,18 +8216,6 @@ void ProtocolGame::AddShopItem(NetworkMessage &msg, const ShopBlock &shopBlock) return; } - // Hidden sell items from the shop if they are not in the player's inventory - auto talkactionHidden = player->kv()->get("npc-shop-hidden-sell-item"); - if (talkactionHidden && talkactionHidden->get() == true) { - std::map inventoryMap; - player->getAllSaleItemIdAndCount(inventoryMap); - auto inventoryItems = inventoryMap.find(shopBlock.itemId); - if (inventoryItems == inventoryMap.end() && shopBlock.itemSellPrice > 0 && shopBlock.itemBuyPrice == 0) { - AddHiddenShopItem(msg); - return; - } - } - const ItemType &it = Item::items[shopBlock.itemId]; msg.add(shopBlock.itemId); if (it.isSplash() || it.isFluidContainer()) { @@ -8217,7 +8311,7 @@ void ProtocolGame::sendInventoryImbuements(const std::mapgetBaseID()); msg.addByte(0x01); msg.addString(baseImbuement->name + " " + imbuement->getName(), "ProtocolGame::sendInventoryImbuements - baseImbuement->name + " - " + imbuement->getName()"); + " + imbuement->getName()"); msg.add(imbuement->getIconID()); msg.add(imbuementInfo.duration); @@ -8705,7 +8799,7 @@ void ProtocolGame::parseSendBosstiarySlots() { auto bossesUnlockedList = g_ioBosstiary().getBosstiaryFinished(player); if (auto it = std::ranges::find(bossesUnlockedList.begin(), bossesUnlockedList.end(), boostedBossId); - it != bossesUnlockedList.end()) { + it != bossesUnlockedList.end()) { bossesUnlockedList.erase(it); } auto bossesUnlockedSize = static_cast(bossesUnlockedList.size()); @@ -8921,7 +9015,7 @@ void ProtocolGame::sendBosstiaryCooldownTimer() { msg.skipBytes(2); // Boss count uint16_t bossesCount = 0; for (std::map bossesMap = g_ioBosstiary().getBosstiaryMap(); - const auto &[bossRaceId, _] : bossesMap) { + const auto &[bossRaceId, _] : bossesMap) { const auto mType = g_ioBosstiary().getMonsterTypeByBossRaceId(bossRaceId); if (!mType) { continue; @@ -9048,3 +9142,17 @@ void ProtocolGame::sendDisableLoginMusic() { msg.addByte(0x00); writeToOutputBuffer(msg); } + +void ProtocolGame::sendHotkeyPreset() { + if (!player || oldProtocol) { + return; + } + + auto vocation = g_vocations().getVocation(player->getVocation()->getBaseId()); + if (vocation) { + NetworkMessage msg; + msg.addByte(0x9D); + msg.add(vocation->getClientId()); + writeToOutputBuffer(msg); + } +} diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 100ca199b..55e9cbfba 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -14,6 +14,7 @@ #include "creatures/creature.hpp" #include "enums/forge_conversion.hpp" #include "creatures/players/cyclopedia/player_badge.hpp" +#include "creatures/players/cyclopedia/player_cyclopedia.hpp" #include "creatures/players/cyclopedia/player_title.hpp" class NetworkMessage; @@ -514,6 +515,7 @@ class ProtocolGame final : public Protocol { void sendSingleSoundEffect(const Position &pos, SoundEffect_t id, SourceEffect_t source); void sendDoubleSoundEffect(const Position &pos, SoundEffect_t mainSoundId, SourceEffect_t mainSource, SoundEffect_t secondarySoundId, SourceEffect_t secondarySource); + void sendHotkeyPreset(); void sendDisableLoginMusic(); uint8_t m_playerDeathTime = 0; diff --git a/src/server/network/protocol/protocollogin.cpp b/src/server/network/protocol/protocollogin.cpp index b59a37044..d6e9e3cb9 100644 --- a/src/server/network/protocol/protocollogin.cpp +++ b/src/server/network/protocol/protocollogin.cpp @@ -177,5 +177,5 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage &msg) { g_dispatcher().addEvent([self = std::static_pointer_cast(shared_from_this()), accountDescriptor, password] { self->getCharacterList(accountDescriptor, password); }, - "ProtocolLogin::getCharacterList"); + "ProtocolLogin::getCharacterList"); } diff --git a/src/server/network/protocol/protocolstatus.cpp b/src/server/network/protocol/protocolstatus.cpp index 93f2e458a..ca40a8c00 100644 --- a/src/server/network/protocol/protocolstatus.cpp +++ b/src/server/network/protocol/protocolstatus.cpp @@ -47,7 +47,7 @@ void ProtocolStatus::onRecvFirstMessage(NetworkMessage &msg) { g_dispatcher().addEvent([self = std::static_pointer_cast(shared_from_this())] { self->sendStatusString(); }, - "ProtocolStatus::sendStatusString"); + "ProtocolStatus::sendStatusString"); return; } break; @@ -63,7 +63,7 @@ void ProtocolStatus::onRecvFirstMessage(NetworkMessage &msg) { g_dispatcher().addEvent([self = std::static_pointer_cast(shared_from_this()), requestedInfo, characterName] { self->sendInfo(requestedInfo, characterName); }, - "ProtocolStatus::sendInfo"); + "ProtocolStatus::sendInfo"); return; } diff --git a/src/server/server.hpp b/src/server/server.hpp index 054ec2607..42134f765 100644 --- a/src/server/server.hpp +++ b/src/server/server.hpp @@ -114,8 +114,8 @@ template bool ServiceManager::add(uint16_t port) { if (port == 0) { g_logger().error("[ServiceManager::add] - " - "No port provided for service {}, service disabled", - ProtocolType::protocol_name()); + "No port provided for service {}, service disabled", + ProtocolType::protocol_name()); return false; } @@ -132,8 +132,8 @@ bool ServiceManager::add(uint16_t port) { if (service_port->is_single_socket() || ProtocolType::SERVER_SENDS_FIRST) { g_logger().error("[ServiceManager::add] - " - "{} and {} cannot use the same port {}", - ProtocolType::protocol_name(), service_port->get_protocol_names(), port); + "{} and {} cannot use the same port {}", + ProtocolType::protocol_name(), service_port->get_protocol_names(), port); return false; } } diff --git a/src/server/signals.cpp b/src/server/signals.cpp index 978b589eb..c85b21312 100644 --- a/src/server/signals.cpp +++ b/src/server/signals.cpp @@ -38,8 +38,8 @@ void Signals::asyncWait() { set.async_wait([this](std::error_code err, int signal) { if (err) { g_logger().error("[Signals::asyncWait] - " - "Signal handling error: {}", - err.message()); + "Signal handling error: {}", + err.message()); return; } dispatchSignalHandler(signal); diff --git a/src/utils/simd.hpp b/src/utils/simd.hpp index 3961d51e7..7e57e75bf 100644 --- a/src/utils/simd.hpp +++ b/src/utils/simd.hpp @@ -13,7 +13,7 @@ #if defined(__DISABLE_VECTORIZATION__) // You might want to disable vectorization on some compilers - // it can just get buggy and the engine will crashes + // it can just get buggy and the engine will crashes #undef __NEON__ #undef __ARM_NEON__ #undef __ARM_FEATURE_SIMD32 diff --git a/src/utils/tools.cpp b/src/utils/tools.cpp index 584d4a6b5..6504fda85 100644 --- a/src/utils/tools.cpp +++ b/src/utils/tools.cpp @@ -1834,6 +1834,31 @@ std::string getVerbForPronoun(PlayerPronoun_t pronoun, bool pastTense) { return pastTense ? "was" : "is"; } +std::string formatWithArticle(const std::string &value, bool withSpace) { + if (value.empty()) { + return ""; + } + + auto removeArticle = [](const std::string &str) -> std::string { + const std::string articles[] = { "a ", "an " }; + for (const auto &article : articles) { + if (str.size() > article.size() && std::equal(article.begin(), article.end(), str.begin(), [](char a, char b) { return std::tolower(a) == std::tolower(b); })) { + return str.substr(article.size()); + } + } + return str; + }; + + std::string modifiedValue = removeArticle(value); + if (modifiedValue.empty()) { + return ""; + } + + const char &character = std::tolower(modifiedValue.front()); + auto article = character == 'a' || character == 'e' || character == 'i' || character == 'o' || character == 'u' ? "an" : "a"; + return fmt::format("{}{} {}.", withSpace ? " " : "", article, modifiedValue); +} + std::vector split(const std::string &str, char delimiter /* = ','*/) { std::vector tokens; std::string token; diff --git a/src/utils/tools.hpp b/src/utils/tools.hpp index 25683bf22..1f8ed3822 100644 --- a/src/utils/tools.hpp +++ b/src/utils/tools.hpp @@ -201,6 +201,8 @@ std::string getPlayerPossessivePronoun(PlayerPronoun_t pronoun, PlayerSex_t sex, std::string getPlayerReflexivePronoun(PlayerPronoun_t pronoun, PlayerSex_t sex, const std::string &name); std::string getVerbForPronoun(PlayerPronoun_t pronoun, bool pastTense = false); +std::string formatWithArticle(const std::string &value, bool withSpace = true); + std::string toKey(const std::string &str); static inline double quadraticPoly(double a, double b, double c, double x) { diff --git a/src/utils/utils_definitions.hpp b/src/utils/utils_definitions.hpp index af2c40ba5..7466c83a8 100644 --- a/src/utils/utils_definitions.hpp +++ b/src/utils/utils_definitions.hpp @@ -709,17 +709,6 @@ enum class PlayerFlags_t : uint8_t { FlagLast }; -enum Blessings_t : uint8_t { - TWIST_OF_FATE = 1, - WISDOM_OF_SOLITUDE = 2, - SPARK_OF_THE_PHOENIX = 3, - FIRE_OF_THE_SUNS = 4, - SPIRITUAL_SHIELDING = 5, - EMBRACE_OF_TIBIA = 6, - BLOOD_OF_THE_MOUNTAIN = 7, - HEARTH_OF_THE_MOUNTAIN = 8, -}; - enum BedItemPart_t : uint8_t { BED_NONE_PART, BED_PILLOW_PART, diff --git a/start.sh b/start.sh index 12d48ac31..95cac51e1 100644 --- a/start.sh +++ b/start.sh @@ -21,8 +21,8 @@ while true; do "$BIN_PATH" 2>&1 | awk '{ print strftime("%F %T - "), $0; fflush(); }' | tee "logs/$(date +"%F %H-%M-%S.log")" # Verificar se a tecla 'q' foi pressionada - read -t 1 -N 1 -r input - if [[ "$input" == "q" ]]; then - break - fi + read -t 1 -N 1 -r input + if [[ "$input" == "q" ]]; then + break + fi done diff --git a/vcproj/otxserver.vcxproj b/vcproj/otxserver.vcxproj index 5222db9ad..eba7e9510 100644 --- a/vcproj/otxserver.vcxproj +++ b/vcproj/otxserver.vcxproj @@ -46,6 +46,7 @@ + @@ -261,6 +262,7 @@ +