diff --git a/config.lua.dist b/config.lua.dist index ea65eef4e..536c78c3b 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -511,6 +511,7 @@ bossDefaultTimeToFightAgain = 20 * 60 * 60 -- 20 hours bossDefaultTimeToDefeat = 20 * 60 -- 20 minutes -- Monsters +defaultRespawnTime = 60 deSpawnRange = 2 deSpawnRadius = 50 diff --git a/data-otxserver/lib/others/load.lua b/data-otxserver/lib/others/load.lua index 1052efb7b..031c8fb20 100644 --- a/data-otxserver/lib/others/load.lua +++ b/data-otxserver/lib/others/load.lua @@ -1,2 +1 @@ dofile(DATA_DIRECTORY .. "/lib/others/dawnport.lua") -dofile(DATA_DIRECTORY .. "/lib/others/vip_system.lua") diff --git a/data-otxserver/scripts/creaturescripts/customs/vip.lua b/data-otxserver/scripts/creaturescripts/customs/vip.lua deleted file mode 100644 index 0ae99c00f..000000000 --- a/data-otxserver/scripts/creaturescripts/customs/vip.lua +++ /dev/null @@ -1,20 +0,0 @@ -local playerLogin = CreatureEvent("VipLogin") - -function playerLogin.onLogin(player) - if configManager.getBoolean(configKeys.VIP_SYSTEM_ENABLED) then - local wasVip = player:kv():scoped("account"):get("vip-system") or false - if wasVip and not player:isVip() then - player:onRemoveVip() - end - if not wasVip and player:isVip() then - player:onAddVip(player:getVipDays()) - end - - if player:isVip() then - CheckPremiumAndPrint(player, MESSAGE_LOGIN) - end - end - return true -end - -playerLogin:register() diff --git a/data-otxserver/scripts/game_migrations/20241715984279_move_wheel_scrolls_from_storagename_to_kv.lua b/data-otxserver/scripts/game_migrations/20241715984279_move_wheel_scrolls_from_storagename_to_kv.lua new file mode 100644 index 000000000..a5cc9a123 --- /dev/null +++ b/data-otxserver/scripts/game_migrations/20241715984279_move_wheel_scrolls_from_storagename_to_kv.lua @@ -0,0 +1,24 @@ +local promotionScrolls = { + { oldScroll = "wheel.scroll.abridged", newScroll = "abridged" }, + { oldScroll = "wheel.scroll.basic", newScroll = "basic" }, + { oldScroll = "wheel.scroll.revised", newScroll = "revised" }, + { oldScroll = "wheel.scroll.extended", newScroll = "extended" }, + { oldScroll = "wheel.scroll.advanced", newScroll = "advanced" }, +} + +local function migrate(player) + for _, scrollTable in ipairs(promotionScrolls) do + local oldStorage = player:getStorageValueByName(scrollTable.oldScroll) + if oldStorage > 0 then + player:kv():scoped("wheel-of-destiny"):scoped("scrolls"):set(scrollTable.newScroll, true) + end + end +end + +local migration = Migration("20241715984279_move_wheel_scrolls_from_storagename_to_kv") + +function migration:onExecute() + self:forEachPlayer(migrate) +end + +migration:register() diff --git a/data/items/items.xml b/data/items/items.xml index e7e73d975..9fdc89bbd 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -75820,5 +75820,295 @@ Granted by TibiaGoals.com"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/libs/functions/bosslever.lua b/data/libs/functions/boss_lever.lua similarity index 100% rename from data/libs/functions/bosslever.lua rename to data/libs/functions/boss_lever.lua diff --git a/data/libs/functions/load.lua b/data/libs/functions/load.lua index c63276d94..0fab2c3cb 100644 --- a/data/libs/functions/load.lua +++ b/data/libs/functions/load.lua @@ -1,14 +1,15 @@ -- Load core functions dofile(CORE_DIRECTORY .. "/libs/functions/bit.lua") dofile(CORE_DIRECTORY .. "/libs/functions/bitwise_flags.lua") +dofile(CORE_DIRECTORY .. "/libs/functions/boss_lever.lua") dofile(CORE_DIRECTORY .. "/libs/functions/combat.lua") dofile(CORE_DIRECTORY .. "/libs/functions/constants.lua") dofile(CORE_DIRECTORY .. "/libs/functions/container.lua") dofile(CORE_DIRECTORY .. "/libs/functions/creature.lua") -dofile(CORE_DIRECTORY .. "/libs/functions/functions.lua") -dofile(CORE_DIRECTORY .. "/libs/functions/gematelier.lua") dofile(CORE_DIRECTORY .. "/libs/functions/fs.lua") +dofile(CORE_DIRECTORY .. "/libs/functions/functions.lua") dofile(CORE_DIRECTORY .. "/libs/functions/game.lua") +dofile(CORE_DIRECTORY .. "/libs/functions/gematelier.lua") dofile(CORE_DIRECTORY .. "/libs/functions/item.lua") dofile(CORE_DIRECTORY .. "/libs/functions/itemtype.lua") dofile(CORE_DIRECTORY .. "/libs/functions/lever.lua") @@ -20,14 +21,13 @@ dofile(CORE_DIRECTORY .. "/libs/functions/player.lua") dofile(CORE_DIRECTORY .. "/libs/functions/position.lua") dofile(CORE_DIRECTORY .. "/libs/functions/pronouns.lua") dofile(CORE_DIRECTORY .. "/libs/functions/quests.lua") +dofile(CORE_DIRECTORY .. "/libs/functions/queue.lua") dofile(CORE_DIRECTORY .. "/libs/functions/revscriptsys.lua") +dofile(CORE_DIRECTORY .. "/libs/functions/set.lua") dofile(CORE_DIRECTORY .. "/libs/functions/spawn.lua") dofile(CORE_DIRECTORY .. "/libs/functions/spectators.lua") -dofile(CORE_DIRECTORY .. "/libs/functions/bosslever.lua") dofile(CORE_DIRECTORY .. "/libs/functions/string.lua") dofile(CORE_DIRECTORY .. "/libs/functions/tables.lua") dofile(CORE_DIRECTORY .. "/libs/functions/teleport.lua") dofile(CORE_DIRECTORY .. "/libs/functions/tile.lua") dofile(CORE_DIRECTORY .. "/libs/functions/vocation.lua") -dofile(CORE_DIRECTORY .. "/libs/functions/set.lua") -dofile(CORE_DIRECTORY .. "/libs/functions/queue.lua") diff --git a/data/libs/systems/load.lua b/data/libs/systems/load.lua index 5c7073ad6..281b8b1d4 100644 --- a/data/libs/systems/load.lua +++ b/data/libs/systems/load.lua @@ -9,4 +9,5 @@ dofile(CORE_DIRECTORY .. "/libs/systems/hazard.lua") dofile(CORE_DIRECTORY .. "/libs/systems/hireling.lua") dofile(CORE_DIRECTORY .. "/libs/systems/raids.lua") dofile(CORE_DIRECTORY .. "/libs/systems/reward_boss.lua") +dofile(CORE_DIRECTORY .. "/libs/systems/vip.lua") dofile(CORE_DIRECTORY .. "/libs/systems/zones.lua") diff --git a/data-otxserver/lib/others/vip_system.lua b/data/libs/systems/vip.lua similarity index 61% rename from data-otxserver/lib/others/vip_system.lua rename to data/libs/systems/vip.lua index 5a393157c..9e76fd8ad 100644 --- a/data-otxserver/lib/others/vip_system.lua +++ b/data/libs/systems/vip.lua @@ -1,16 +1,10 @@ local config = { - activationMessage = "You have received %s VIP days.", - activationMessageType = MESSAGE_EVENT_ADVANCE, - - expirationMessage = "Your VIP days ran out.", - expirationMessageType = MESSAGE_ADMINISTRATOR, - outfits = {}, mounts = {}, } function Player.onRemoveVip(self) - self:sendTextMessage(config.expirationMessageType, config.expirationMessage) + self:sendTextMessage(MESSAGE_ADMINISTRATOR, "Your VIP status has expired. All VIP benefits have been removed.") for _, outfit in ipairs(config.outfits) do self:removeOutfit(outfit) @@ -21,13 +15,14 @@ function Player.onRemoveVip(self) end local playerOutfit = self:getOutfit() - if table.contains(config.outfits, self:getOutfit().lookType) then + if table.contains(config.outfits, playerOutfit.lookType) then if self:getSex() == PLAYERSEX_FEMALE then playerOutfit.lookType = 136 else playerOutfit.lookType = 128 end playerOutfit.lookAddons = 0 + self:setOutfit(playerOutfit) end @@ -36,7 +31,7 @@ end function Player.onAddVip(self, days, silent) if not silent then - self:sendTextMessage(config.activationMessageType, string.format(config.activationMessage, days)) + self:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("You have been granted %s days of VIP status.", days)) end for _, outfit in ipairs(config.outfits) do @@ -52,16 +47,15 @@ end function CheckPremiumAndPrint(player, msgType) if player:getVipDays() == 0xFFFF then - player:sendTextMessage(msgType, "You have infinite amount of VIP days left.") + player:sendTextMessage(msgType, "You have an unlimited VIP status.") return true end local playerVipTime = player:getVipTime() if playerVipTime < os.time() then - local msg = "You do not have VIP on your account." - player:sendTextMessage(msgType, msg) + player:sendTextMessage(msgType, "Your VIP status is currently inactive.") return true end - player:sendTextMessage(msgType, string.format("You have %s of VIP time left.", getFormattedTimeRemaining(playerVipTime))) + player:sendTextMessage(msgType, string.format("You have %s of VIP time remaining.", getFormattedTimeRemaining(playerVipTime))) end diff --git a/data-otxserver/scripts/actions/other/hirelinglamp.lua b/data/scripts/actions/items/hireling_lamp.lua similarity index 93% rename from data-otxserver/scripts/actions/other/hirelinglamp.lua rename to data/scripts/actions/items/hireling_lamp.lua index 8117b5366..0ffed1fa7 100644 --- a/data-otxserver/scripts/actions/other/hirelinglamp.lua +++ b/data/scripts/actions/items/hireling_lamp.lua @@ -2,8 +2,9 @@ local hirelingLamp = Action() function hirelingLamp.onUse(player, item, fromPosition, target, toPosition, isHotkey) local spawnPosition = player:getPosition() - local hireling_id = item:getCustomAttribute("Hireling") + local hirelingId = item:getCustomAttribute("Hireling") local house = spawnPosition and spawnPosition:getTile() and spawnPosition:getTile():getHouse() or nil + if not house then player:getPosition():sendMagicEffect(CONST_ME_POFF) player:sendTextMessage(MESSAGE_FAILURE, "You may use this only inside a house.") @@ -22,10 +23,10 @@ function hirelingLamp.onUse(player, item, fromPosition, target, toPosition, isHo return false end - local hireling = getHirelingById(hireling_id) + local hireling = getHirelingById(hirelingId) if not hireling then player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "There was an error creating the hireling and it has been deleted, please, contact server admin.") - logger.warn("[hirelingLamp.onUse] Player {} is using hireling with id {} not exist in the database", player:getName(), hireling_id) + logger.warn("[hirelingLamp.onUse] Player {} is using hireling with id {} not exist in the database", player:getName(), hirelingId) logger.error("Deleted the lamp") item:remove(1) return true diff --git a/data/scripts/actions/objects/large_seashell.lua b/data/scripts/actions/objects/large_seashell.lua new file mode 100644 index 000000000..c6d767146 --- /dev/null +++ b/data/scripts/actions/objects/large_seashell.lua @@ -0,0 +1,30 @@ +local largeSeashell = Action() + +function largeSeashell.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if player:hasExhaustion("delay-large-seashell") then + player:say("You have already opened a shell today.", TALKTYPE_MONSTER_SAY, false, player, item:getPosition()) + return true + end + + local chance = math.random(100) + local message = "Nothing is inside." + + if chance <= 16 then + doTargetCombatHealth(0, player, COMBAT_PHYSICALDAMAGE, -200, -200, CONST_ME_NONE) + message = "Ouch! You squeezed your fingers." + elseif chance > 16 and chance <= 64 then + Game.createItem(math.random(281, 282), 1, player:getPosition()) + message = "You found a beautiful pearl." + player:addAchievementProgress("Shell Seeker", 100) + end + + player:setExhaustion("delay-large-seashell", 20 * 60 * 60) + player:say(message, TALKTYPE_MONSTER_SAY, false, player, item:getPosition()) + item:transform(198) + item:decay() + item:getPosition():sendMagicEffect(CONST_ME_BUBBLES) + return true +end + +largeSeashell:id(197) +largeSeashell:register() diff --git a/data-otxserver/scripts/globalevents/others/bosslever_death.lua b/data/scripts/creaturescripts/monster/boss_lever_death.lua similarity index 99% rename from data-otxserver/scripts/globalevents/others/bosslever_death.lua rename to data/scripts/creaturescripts/monster/boss_lever_death.lua index 9538fe15e..a2c58d1e4 100644 --- a/data-otxserver/scripts/globalevents/others/bosslever_death.lua +++ b/data/scripts/creaturescripts/monster/boss_lever_death.lua @@ -1,22 +1,28 @@ local onBossDeath = CreatureEvent("BossLeverOnDeath") + function onBossDeath.onDeath(creature) if not creature then return true end + local name = creature:getName() local key = "boss." .. toKey(name) local zone = Zone(key) + if not zone then return true end + local bossLever = BossLever[name] if not bossLever then return true end + if bossLever.timeoutEvent then stopEvent(bossLever.timeoutEvent) bossLever.timeoutEvent = nil end + if bossLever.timeAfterKill > 0 then zone:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The " .. name .. " has been defeated. You have " .. bossLever.timeAfterKill .. " seconds to leave the room.") bossLever.timeoutEvent = addEvent(function(zn) @@ -26,4 +32,5 @@ function onBossDeath.onDeath(creature) end return true end + onBossDeath:register() diff --git a/data-otxserver/scripts/creaturescripts/others/forge_kill.lua b/data/scripts/creaturescripts/monster/forge_kill.lua similarity index 100% rename from data-otxserver/scripts/creaturescripts/others/forge_kill.lua rename to data/scripts/creaturescripts/monster/forge_kill.lua diff --git a/data-otxserver/scripts/creaturescripts/others/adventure_blessing_login.lua b/data/scripts/creaturescripts/player/adventure_blessing_login.lua similarity index 99% rename from data-otxserver/scripts/creaturescripts/others/adventure_blessing_login.lua rename to data/scripts/creaturescripts/player/adventure_blessing_login.lua index df0405271..8ebf88a72 100644 --- a/data-otxserver/scripts/creaturescripts/others/adventure_blessing_login.lua +++ b/data/scripts/creaturescripts/player/adventure_blessing_login.lua @@ -1,6 +1,7 @@ dofile(CORE_DIRECTORY .. "/modules/scripts/blessings/blessings.lua") local adventurerBlessingLogin = CreatureEvent("AdventurerBlessingLogin") + function adventurerBlessingLogin.onLogin(player) return Blessings.doAdventurerBlessing(player) end diff --git a/data/scripts/creaturescripts/player/login.lua b/data/scripts/creaturescripts/player/login.lua index 34d139a04..fbe4f9e63 100644 --- a/data/scripts/creaturescripts/player/login.lua +++ b/data/scripts/creaturescripts/player/login.lua @@ -49,10 +49,8 @@ function playerLoginGlobal.onLogin(player) end -- Boosted - player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Today's boosted creature: " .. Game.getBoostedCreature() .. " \ - Boosted creatures yield more experience points, carry more loot than usual and respawn at a faster rate.") - player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, "Today's boosted boss: " .. Game.getBoostedBoss() .. " \ - Boosted bosses contain more loot and count more kills for your Bosstiary.") + player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, string.format("Today's boosted creature: %s.\nBoosted creatures yield more experience points, carry more loot than usual, and respawn at a faster rate.", Game.getBoostedCreature())) + player:sendTextMessage(MESSAGE_BOOSTED_CREATURE, string.format("Today's boosted boss: %s.\nBoosted bosses contain more loot and count more kills for your Bosstiary.", Game.getBoostedBoss())) -- Rewards local rewards = #player:getRewardList() @@ -118,6 +116,24 @@ function playerLoginGlobal.onLogin(player) player:setStaminaXpBoost(player:getFinalBonusStamina() * 100) player:getFinalLowLevelBonus() + -- Updates the player's VIP status and executes corresponding actions if applicable. + if configManager.getBoolean(configKeys.VIP_SYSTEM_ENABLED) then + local isVipNow = player:isVip() + local wasVip = player:kv():scoped("account"):get("vip-system") or false + + if wasVip ~= isVipNow then + if wasVip then + player:onRemoveVip() + else + player:onAddVip(player:getVipDays()) + end + end + + if isVipNow then + CheckPremiumAndPrint(player, MESSAGE_LOGIN) + end + end + -- Set Ghost Mode if player:getGroup():getId() >= GROUP_TYPE_GAMEMASTER then player:setGhostMode(true) diff --git a/data/scripts/talkactions/god/add_skill.lua b/data/scripts/talkactions/god/add_skill.lua index 206445823..09d240ece 100644 --- a/data/scripts/talkactions/god/add_skill.lua +++ b/data/scripts/talkactions/god/add_skill.lua @@ -16,11 +16,6 @@ local function getSkillId(skillName) end end -local function getExpForLevel(level) - level = level - 1 - return ((50 * level * level * level) - (150 * level * level) + (400 * level)) / 3 -end - local addSkill = TalkAction("/addskill") function addSkill.onSay(player, words, param) @@ -54,7 +49,7 @@ function addSkill.onSay(player, words, param) local ch = split[2]:sub(1, 1) if ch == "l" or ch == "e" then targetLevel = target:getLevel() + count - targetExp = getExpForLevel(targetLevel) + targetExp = Game.getExperienceForLevel(targetLevel) addExp = targetExp - target:getExperience() target:addExperience(addExp, false) elseif ch == "m" then diff --git a/data-otxserver/scripts/weapons/dawnport_weapon.lua b/data/scripts/weapons/dawnport_weapons.lua similarity index 100% rename from data-otxserver/scripts/weapons/dawnport_weapon.lua rename to data/scripts/weapons/dawnport_weapons.lua diff --git a/data-otxserver/scripts/weapons/scripts/burst_arrow.lua b/data/scripts/weapons/scripts/burst_arrow.lua similarity index 100% rename from data-otxserver/scripts/weapons/scripts/burst_arrow.lua rename to data/scripts/weapons/scripts/burst_arrow.lua diff --git a/data-otxserver/scripts/weapons/scripts/diamond_arrow.lua b/data/scripts/weapons/scripts/diamond_arrow.lua similarity index 100% rename from data-otxserver/scripts/weapons/scripts/diamond_arrow.lua rename to data/scripts/weapons/scripts/diamond_arrow.lua diff --git a/data-otxserver/scripts/weapons/scripts/poison_arrow.lua b/data/scripts/weapons/scripts/poison_arrow.lua similarity index 100% rename from data-otxserver/scripts/weapons/scripts/poison_arrow.lua rename to data/scripts/weapons/scripts/poison_arrow.lua diff --git a/data-otxserver/scripts/weapons/scripts/viper_star.lua b/data/scripts/weapons/scripts/viper_star.lua similarity index 100% rename from data-otxserver/scripts/weapons/scripts/viper_star.lua rename to data/scripts/weapons/scripts/viper_star.lua diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index 22043f425..0e53c9754 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -50,6 +50,7 @@ enum ConfigKey_t : uint16_t { DATA_DIRECTORY, DAY_KILLS_TO_RED, DEATH_LOSE_PERCENT, + DEFAULT_RESPAWN_TIME, DEFAULT_DESPAWNRADIUS, DEFAULT_DESPAWNRANGE, DEFAULT_PRIORITY, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index e1345bbac..35d2cf3b1 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -225,6 +225,7 @@ bool ConfigManager::load() { loadIntConfig(L, CRITICALCHANCE, "criticalChance", 10); loadIntConfig(L, DAY_KILLS_TO_RED, "dayKillsToRedSkull", 3); loadIntConfig(L, DEATH_LOSE_PERCENT, "deathLosePercent", -1); + loadIntConfig(L, DEFAULT_RESPAWN_TIME, "defaultRespawnTime", 60); loadIntConfig(L, DEFAULT_DESPAWNRADIUS, "deSpawnRadius", 50); loadIntConfig(L, DEFAULT_DESPAWNRANGE, "deSpawnRange", 2); loadIntConfig(L, DEPOTCHEST, "depotChest", 4); diff --git a/src/creatures/monsters/spawns/spawn_monster.cpp b/src/creatures/monsters/spawns/spawn_monster.cpp index ef5912c80..968b90d8c 100644 --- a/src/creatures/monsters/spawns/spawn_monster.cpp +++ b/src/creatures/monsters/spawns/spawn_monster.cpp @@ -94,7 +94,15 @@ bool SpawnsMonster::loadFromXML(const std::string &filemonstername) { weight = pugi::cast(weightAttribute.value()); } - spawnMonster.addMonster(nameAttribute.as_string(), pos, dir, pugi::cast(childMonsterNode.attribute("spawntime").value()) * 1000, weight); + uint32_t scheduleInterval = g_configManager().getNumber(DEFAULT_RESPAWN_TIME, __FUNCTION__); + + try { + scheduleInterval = pugi::cast(childMonsterNode.attribute("spawntime").value()); + } catch (...) { + g_logger().warn("Failed to add schedule interval to monster: {}, interval: {}. Setting to default respawn time: {}", nameAttribute.value(), childMonsterNode.attribute("spawntime").value(), scheduleInterval); + } + + spawnMonster.addMonster(nameAttribute.as_string(), pos, dir, scheduleInterval * 1000, weight); } } } diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 58bebfb9f..c0761704d 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -230,9 +230,8 @@ class Player final : public Creature, public Cylinder, public Bankable { void addList() override; void removePlayer(bool displayEffect, bool forced = true); - static uint64_t getExpForLevel(int32_t lv) { - lv--; - return ((50ULL * lv * lv * lv) - (150ULL * lv * lv) + (400ULL * lv)) / 3ULL; + static uint64_t getExpForLevel(const uint32_t level) { + return (((level - 6ULL) * level + 17ULL) * level - 12ULL) / 6ULL * 100ULL; } uint16_t getStaminaMinutes() const { diff --git a/src/game/game.cpp b/src/game/game.cpp index 621e35938..899a89549 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -5165,7 +5165,7 @@ void Game::playerBuyItem(uint32_t playerId, uint16_t itemId, uint8_t count, uint return; } - if (inBackpacks) { + if (inBackpacks || it.isContainer()) { uint32_t maxContainer = static_cast(g_configManager().getNumber(MAX_CONTAINER, __FUNCTION__)); auto backpack = player->getInventoryItem(CONST_SLOT_BACKPACK); auto mainBackpack = backpack ? backpack->getContainer() : nullptr; diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index 0fdbc96f4..4858b3ab2 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -191,6 +191,17 @@ int GameFunctions::luaGameloadMapChunk(lua_State* L) { return 0; } +int GameFunctions::luaGameGetExperienceForLevel(lua_State* L) { + // Game.getExperienceForLevel(level) + const uint32_t level = getNumber(L, 1); + if (level == 0) { + reportErrorFunc("Level must be greater than 0."); + } else { + lua_pushnumber(L, Player::getExpForLevel(level)); + } + return 1; +} + int GameFunctions::luaGameGetMonsterCount(lua_State* L) { // Game.getMonsterCount() lua_pushnumber(L, g_game().getMonstersOnline()); diff --git a/src/lua/functions/core/game/game_functions.hpp b/src/lua/functions/core/game/game_functions.hpp index 7f3b642e9..70e81061c 100644 --- a/src/lua/functions/core/game/game_functions.hpp +++ b/src/lua/functions/core/game/game_functions.hpp @@ -28,6 +28,7 @@ class GameFunctions final : LuaScriptInterface { registerMethod(L, "Game", "loadMap", GameFunctions::luaGameLoadMap); registerMethod(L, "Game", "loadMapChunk", GameFunctions::luaGameloadMapChunk); + registerMethod(L, "Game", "getExperienceForLevel", GameFunctions::luaGameGetExperienceForLevel); registerMethod(L, "Game", "getMonsterCount", GameFunctions::luaGameGetMonsterCount); registerMethod(L, "Game", "getPlayerCount", GameFunctions::luaGameGetPlayerCount); registerMethod(L, "Game", "getNpcCount", GameFunctions::luaGameGetNpcCount); @@ -103,6 +104,7 @@ class GameFunctions final : LuaScriptInterface { static int luaGameLoadMap(lua_State* L); static int luaGameloadMapChunk(lua_State* L); + static int luaGameGetExperienceForLevel(lua_State* L); static int luaGameGetMonsterCount(lua_State* L); static int luaGameGetPlayerCount(lua_State* L); static int luaGameGetNpcCount(lua_State* L); diff --git a/src/server/network/connection/connection.cpp b/src/server/network/connection/connection.cpp index 1c575ff00..3effd52f8 100644 --- a/src/server/network/connection/connection.cpp +++ b/src/server/network/connection/connection.cpp @@ -105,7 +105,7 @@ void Connection::accept(Protocol_ptr protocolPtr) { void Connection::acceptInternal(bool toggleParseHeader) { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); + readTimer.async_wait([self = std::weak_ptr(shared_from_this())](const std::error_code &error) { Connection::handleTimeout(self, error); }); try { asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), [self = shared_from_this(), toggleParseHeader](const std::error_code &error, std::size_t N) { @@ -147,7 +147,7 @@ void Connection::parseProxyIdentification(const std::error_code &error) { connectionState = CONNECTION_STATE_READINGS; try { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); + readTimer.async_wait([self = std::weak_ptr(shared_from_this())](const std::error_code &error) { Connection::handleTimeout(self, error); }); // Read the remainder of proxy identification asio::async_read(socket, asio::buffer(msg.getBuffer(), remainder), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->parseProxyIdentification(error); }); @@ -208,7 +208,7 @@ void Connection::parseHeader(const std::error_code &error) { try { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); + readTimer.async_wait([self = std::weak_ptr(shared_from_this())](const std::error_code &error) { Connection::handleTimeout(self, error); }); // Read packet content msg.setLength(size + HEADER_LENGTH); @@ -275,7 +275,7 @@ void Connection::parsePacket(const std::error_code &error) { try { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); + readTimer.async_wait([self = std::weak_ptr(shared_from_this())](const std::error_code &error) { Connection::handleTimeout(self, error); }); if (!skipReadingNextPacket) { // Wait to the next packet @@ -289,7 +289,7 @@ void Connection::parsePacket(const std::error_code &error) { void Connection::resumeWork() { readTimer.expires_from_now(std::chrono::seconds(CONNECTION_READ_TIMEOUT)); - readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); + readTimer.async_wait([self = std::weak_ptr(shared_from_this())](const std::error_code &error) { Connection::handleTimeout(self, error); }); try { asio::async_read(socket, asio::buffer(msg.getBuffer(), HEADER_LENGTH), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->parseHeader(error); }); @@ -358,7 +358,7 @@ uint32_t Connection::getIP() { void Connection::internalSend(const OutputMessage_ptr &outputMessage) { writeTimer.expires_from_now(std::chrono::seconds(CONNECTION_WRITE_TIMEOUT)); - readTimer.async_wait([self = shared_from_this()](const std::error_code &error) { Connection::handleTimeout(std::weak_ptr(self), error); }); + writeTimer.async_wait([self = std::weak_ptr(shared_from_this())](const std::error_code &error) { Connection::handleTimeout(self, error); }); try { asio::async_write(socket, asio::buffer(outputMessage->getOutputBuffer(), outputMessage->getLength()), [self = shared_from_this()](const std::error_code &error, std::size_t N) { self->onWriteOperation(error); }); diff --git a/vcpkg.json b/vcpkg.json index 1f821379b..eed7e776e 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -18,6 +18,11 @@ "spdlog", "zlib", "bshoshany-thread-pool", + { + "name": "opentelemetry-cpp", + "default-features": true, + "features": ["otlp-http", "prometheus"] + }, { "name": "libmariadb", "features": [