From e100a838378e1cf90d5b287f01c4d950d40723af Mon Sep 17 00:00:00 2001 From: Matt Gomez Date: Wed, 22 Nov 2023 18:32:55 -0600 Subject: [PATCH] update : https://github.com/opentibiabr/canary/commit/fc0b9a3823ccf77303419c38d1ac4ebe536805ad --- config.lua.dist | 2 ++ src/config/config_definitions.hpp | 2 ++ src/config/configmanager.cpp | 2 ++ src/creatures/combat/combat.cpp | 5 ++-- src/creatures/creature.cpp | 2 +- src/creatures/creature.hpp | 12 +++++++++ src/creatures/monsters/monster.hpp | 3 +++ src/creatures/npcs/npc.hpp | 3 +++ src/creatures/players/player.cpp | 25 ++++++++++++++++++ src/creatures/players/player.hpp | 9 +++++++ src/game/game.cpp | 6 ++--- src/io/iomarket.cpp | 7 ++--- src/items/containers/container.hpp | 4 +++ src/items/item.hpp | 3 +++ src/items/thing.hpp | 6 ++--- .../functions/core/game/config_functions.cpp | 1 + src/lua/global/shared_object.hpp | 5 ++++ src/map/house/house.cpp | 26 +++++++++++++++---- src/server/network/protocol/protocolgame.cpp | 12 ++++++++- .../network/protocol/protocolstatus.cpp | 2 +- 20 files changed, 116 insertions(+), 21 deletions(-) diff --git a/config.lua.dist b/config.lua.dist index 85bfc4691..aaabedcb2 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -285,6 +285,7 @@ houseRentRate = 1.0 houseOwnedByAccount = false houseBuyLevel = 100 housePurchasedShowPrice = false +houseLoseAfterInactivity = 30 -- days; 0 = never onlyInvitedCanMoveHouseItems = true togglehouseTransferOnRestart = true @@ -479,6 +480,7 @@ vipBonusSkill = 0 vipAutoLootVipOnly = false vipStayOnline = false vipFamiliarTimeCooldownReduction = 0 +vipKeepHouse = false -- NOTE: set rewardChestCollectEnabled to true to enable the reward collect system -- NOTE set rewardChestMaxCollectItems max items per collect action diff --git a/src/config/config_definitions.hpp b/src/config/config_definitions.hpp index 417a5348a..bf86266f3 100644 --- a/src/config/config_definitions.hpp +++ b/src/config/config_definitions.hpp @@ -84,6 +84,7 @@ enum booleanConfig_t { TOGGLE_ATTACK_SPEED_ONFIST, VIP_SYSTEM_ENABLED, VIP_AUTOLOOT_VIP_ONLY, + VIP_KEEP_HOUSE, VIP_STAY_ONLINE, REWARD_CHEST_COLLECT_ENABLED, TOGGLE_MOUNT_IN_PZ, @@ -145,6 +146,7 @@ enum integerConfig_t { RATE_KILLING_IN_THE_NAME_OF_POINTS, HOUSE_PRICE_PER_SQM, HOUSE_BUY_LEVEL, + HOUSE_LOSE_AFTER_INACTIVITY, MAX_MESSAGEBUFFER, ACTIONS_DELAY_INTERVAL, EX_ACTIONS_DELAY_INTERVAL, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index 8f46b9b3f..5d52ca11b 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -223,6 +223,7 @@ bool ConfigManager::load() { integer[HOUSE_PRICE_PER_SQM] = getGlobalNumber(L, "housePriceEachSQM", 1000); integer[HOUSE_BUY_LEVEL] = getGlobalNumber(L, "houseBuyLevel", 0); + integer[HOUSE_LOSE_AFTER_INACTIVITY] = getGlobalNumber(L, "houseLoseAfterInactivity", 0); boolean[HOUSE_PURSHASED_SHOW_PRICE] = getGlobalBoolean(L, "housePurchasedShowPrice", false); boolean[ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS] = getGlobalBoolean(L, "onlyInvitedCanMoveHouseItems", true); @@ -384,6 +385,7 @@ bool ConfigManager::load() { integer[VIP_BONUS_LOOT] = getGlobalNumber(L, "vipBonusLoot", 0); integer[VIP_BONUS_SKILL] = getGlobalNumber(L, "vipBonusSkill", 0); boolean[VIP_AUTOLOOT_VIP_ONLY] = getGlobalBoolean(L, "vipAutoLootVipOnly", false); + boolean[VIP_KEEP_HOUSE] = getGlobalBoolean(L, "vipKeepHouse", false); boolean[VIP_STAY_ONLINE] = getGlobalBoolean(L, "vipStayOnline", false); integer[VIP_FAMILIAR_TIME_COOLDOWN_REDUCTION] = getGlobalNumber(L, "vipFamiliarTimeCooldownReduction", 0); diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 9a80ad55c..2a646be07 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -297,19 +297,20 @@ ReturnValue Combat::canDoCombat(std::shared_ptr attacker, std::shared_ return RETURNVALUE_NOERROR; } + auto targetPlayer = target ? target->getPlayer() : nullptr; if (target) { std::shared_ptr tile = target->getTile(); if (tile->hasProperty(CONST_PROP_BLOCKPROJECTILE)) { return RETURNVALUE_NOTENOUGHROOM; } if (tile->hasFlag(TILESTATE_PROTECTIONZONE)) { - return RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE; + auto permittedOnPz = targetPlayer ? targetPlayer->hasPermittedConditionInPZ() : false; + return permittedOnPz ? RETURNVALUE_NOERROR : RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE; } } if (attacker) { const std::shared_ptr attackerMaster = attacker->getMaster(); - auto targetPlayer = target ? target->getPlayer() : nullptr; if (targetPlayer) { if (targetPlayer->hasFlag(PlayerFlags_t::CannotBeAttacked)) { return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER; diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 46804d6b5..4d9894772 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -754,7 +754,7 @@ bool Creature::dropCorpse(std::shared_ptr lastHitCreature, std::shared auto monster = getMonster(); if (monster && !monster->isRewardBoss()) { std::ostringstream lootMessage; - lootMessage << "Loot of " << getNameDescription() << ": " << corpse->getContainer()->getContentDescription(player->getProtocolVersion() < 1200); + lootMessage << "Loot of " << getNameDescription() << ": " << corpse->getContainer()->getContentDescription(player->getProtocolVersion() < 1200) << "."; auto suffix = corpse->getContainer()->getAttribute(ItemAttribute_t::LOOTMESSAGE_SUFFIX); if (!suffix.empty()) { lootMessage << suffix; diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index 45e2dbe6a..2052e7a28 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -76,15 +76,27 @@ class Creature : virtual public Thing, public SharedObject { std::shared_ptr getCreature() override final { return static_self_cast(); } + std::shared_ptr getCreature() const override final { + return static_self_cast(); + } virtual std::shared_ptr getPlayer() { return nullptr; } + virtual std::shared_ptr getPlayer() const { + return nullptr; + } virtual std::shared_ptr getNpc() { return nullptr; } + virtual std::shared_ptr getNpc() const { + return nullptr; + } virtual std::shared_ptr getMonster() { return nullptr; } + virtual std::shared_ptr getMonster() const { + return nullptr; + } virtual const std::string &getName() const = 0; // Real creature name, set on creature creation "createNpcType(typeName) and createMonsterType(typeName)" diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp index 2422ae767..b61945430 100644 --- a/src/creatures/monsters/monster.hpp +++ b/src/creatures/monsters/monster.hpp @@ -32,6 +32,9 @@ class Monster final : public Creature { std::shared_ptr getMonster() override { return static_self_cast(); } + std::shared_ptr getMonster() const override { + return static_self_cast(); + } void setID() override { if (id == 0) { diff --git a/src/creatures/npcs/npc.hpp b/src/creatures/npcs/npc.hpp index 993934374..5f1183605 100644 --- a/src/creatures/npcs/npc.hpp +++ b/src/creatures/npcs/npc.hpp @@ -40,6 +40,9 @@ class Npc final : public Creature { std::shared_ptr getNpc() override { return static_self_cast(); } + std::shared_ptr getNpc() const override { + return static_self_cast(); + } void setID() override { if (id == 0) { diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 9002feea8..f63d37999 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -6722,6 +6722,10 @@ std::pair>, std::mapisStoreItem()) { + continue; + } + const ItemType &itemType = Item::items[item->getID()]; if (itemType.wareId == 0) { continue; @@ -7712,3 +7716,24 @@ std::shared_ptr Player::getLootPouch() { return container; } + +bool Player::hasPermittedConditionInPZ() const { + static const std::unordered_set allowedConditions = { + CONDITION_ENERGY, + CONDITION_FIRE, + CONDITION_POISON, + CONDITION_BLEEDING, + CONDITION_CURSED, + CONDITION_DAZZLED + }; + + bool hasPermittedCondition = false; + for (auto condition : allowedConditions) { + if (getCondition(condition)) { + hasPermittedCondition = true; + break; + } + } + + return hasPermittedCondition; +} diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 45611aaf9..9757717e6 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -121,6 +121,9 @@ class Player final : public Creature, public Cylinder, public Bankable { std::shared_ptr getPlayer() override { return static_self_cast(); } + std::shared_ptr getPlayer() const override { + return static_self_cast(); + } static std::shared_ptr createPlayerTask(uint32_t delay, std::function f, std::string context); @@ -341,6 +344,10 @@ class Player final : public Creature, public Cylinder, public Bankable { operatingSystem = clientos; } + bool isOldProtocol() { + return client && client->oldProtocol; + } + uint32_t getProtocolVersion() const { if (!client) { return 0; @@ -2541,6 +2548,8 @@ class Player final : public Creature, public Cylinder, public Bankable { std::shared_ptr getLootPouch(); + bool hasPermittedConditionInPZ() const; + private: friend class PlayerLock; std::mutex mutex; diff --git a/src/game/game.cpp b/src/game/game.cpp index 8d16fd624..5aa0e6eec 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1654,11 +1654,9 @@ ReturnValue Game::checkMoveItemToCylinder(std::shared_ptr player, std::s } } - if (item->isStoreItem() && !toHouseTile) { + if (item->isStoreItem() && !house) { return RETURNVALUE_NOTPOSSIBLE; } - - return RETURNVALUE_NOERROR; } } @@ -4216,6 +4214,8 @@ void Game::playerStashWithdraw(uint32_t playerId, uint16_t itemId, uint32_t coun if (player->isDepotSearchOpenOnItem(itemId)) { player->requestDepotSearchItem(itemId, 0); } + + player->sendOpenStash(true); } void Game::playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index, uint8_t containerCategory) { diff --git a/src/io/iomarket.cpp b/src/io/iomarket.cpp index d6b610930..6aa25e65f 100644 --- a/src/io/iomarket.cpp +++ b/src/io/iomarket.cpp @@ -132,12 +132,9 @@ void IOMarket::processExpiredOffers(DBResult_ptr result, bool) { continue; } - std::shared_ptr player = g_game().getPlayerByGUID(playerId); + std::shared_ptr player = g_game().getPlayerByGUID(playerId, true); if (!player) { - player = std::make_shared(nullptr); - if (!IOLoginData::loadPlayerById(player, playerId)) { - continue; - } + continue; } if (itemType.stackable) { diff --git a/src/items/containers/container.hpp b/src/items/containers/container.hpp index 56d048f3b..70d4571ba 100644 --- a/src/items/containers/container.hpp +++ b/src/items/containers/container.hpp @@ -55,6 +55,10 @@ class Container : public Item, public Cylinder { return static_self_cast(); } + std::shared_ptr getContainer() const override final { + return static_self_cast(); + } + std::shared_ptr getRootContainer(); virtual std::shared_ptr getDepotLocker() { diff --git a/src/items/item.hpp b/src/items/item.hpp index b8db280de..b1847b47d 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -235,6 +235,9 @@ class Item : virtual public Thing, public ItemProperties, public SharedObject { std::shared_ptr getItem() override final { return static_self_cast(); } + std::shared_ptr getItem() const override final { + return static_self_cast(); + } virtual std::shared_ptr getTeleport() { return nullptr; } diff --git a/src/items/thing.hpp b/src/items/thing.hpp index 5b75e716c..05f961ec9 100644 --- a/src/items/thing.hpp +++ b/src/items/thing.hpp @@ -54,19 +54,19 @@ class Thing { virtual std::shared_ptr getContainer() { return nullptr; } - virtual std::shared_ptr getContainer() const { + virtual std::shared_ptr getContainer() const { return nullptr; } virtual std::shared_ptr getItem() { return nullptr; } - virtual std::shared_ptr getItem() const { + virtual std::shared_ptr getItem() const { return nullptr; } virtual std::shared_ptr getCreature() { return nullptr; } - virtual std::shared_ptr getCreature() const { + virtual std::shared_ptr getCreature() const { return nullptr; } diff --git a/src/lua/functions/core/game/config_functions.cpp b/src/lua/functions/core/game/config_functions.cpp index bdeaa226f..96ce09cdc 100644 --- a/src/lua/functions/core/game/config_functions.cpp +++ b/src/lua/functions/core/game/config_functions.cpp @@ -103,6 +103,7 @@ void ConfigFunctions::init(lua_State* L) { registerEnumIn(L, "configKeys", RATE_KILLING_IN_THE_NAME_OF_POINTS); registerEnumIn(L, "configKeys", HOUSE_PRICE_PER_SQM); registerEnumIn(L, "configKeys", HOUSE_BUY_LEVEL); + registerEnumIn(L, "configKeys", HOUSE_LOSE_AFTER_INACTIVITY); registerEnumIn(L, "configKeys", MAX_MESSAGEBUFFER); registerEnumIn(L, "configKeys", ACTIONS_DELAY_INTERVAL); registerEnumIn(L, "configKeys", EX_ACTIONS_DELAY_INTERVAL); diff --git a/src/lua/global/shared_object.hpp b/src/lua/global/shared_object.hpp index 62cc26b33..3370bb022 100644 --- a/src/lua/global/shared_object.hpp +++ b/src/lua/global/shared_object.hpp @@ -29,6 +29,11 @@ class SharedObject : public std::enable_shared_from_this { return std::static_pointer_cast(shared_from_this()); } + template + std::shared_ptr static_self_cast() const { + return std::static_pointer_cast(shared_from_this()); + } + template std::shared_ptr dynamic_self_cast() { return std::dynamic_pointer_cast(shared_from_this()); diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index 20af6ee40..828753b8c 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -752,11 +752,6 @@ void Houses::payHouses(RentPeriod_t rentPeriod) const { continue; } - const uint32_t rent = house->getRent(); - if (rent == 0 || house->getPaidUntil() > currentTime) { - continue; - } - const uint32_t ownerId = house->getOwner(); const auto &town = g_game().map.towns.getTown(house->getTownId()); if (!town) { @@ -770,6 +765,27 @@ void Houses::payHouses(RentPeriod_t rentPeriod) const { continue; } + // Player hasn't logged in for a while, reset house owner + auto daysToReset = g_configManager().getNumber(HOUSE_LOSE_AFTER_INACTIVITY); + if (daysToReset > 0) { + auto daysSinceLastLogin = (currentTime - player->getLastLoginSaved()) / (60 * 60 * 24); + bool vipKeep = g_configManager().getBoolean(VIP_KEEP_HOUSE) && player->isVip(); + bool activityKeep = daysSinceLastLogin < daysToReset; + if (vipKeep && !activityKeep) { + g_logger().info("Player {} has not logged in for {} days, but is a VIP, so the house will not be reset.", player->getName(), daysToReset); + } else if (!vipKeep && !activityKeep) { + g_logger().info("Player {} has not logged in for {} days, so the house will be reset.", player->getName(), daysToReset); + house->setOwner(0, true, player); + g_saveManager().savePlayer(player); + continue; + } + } + + const uint32_t rent = house->getRent(); + if (rent == 0 || house->getPaidUntil() > currentTime) { + continue; + } + if (player->getBankBalance() >= rent) { g_game().removeMoney(player, rent, 0, true); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index dc6cea87b..b9e6e673c 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -469,6 +469,8 @@ void ProtocolGame::login(const std::string &name, uint32_t accountId, OperatingS writeToOutputBuffer(opcodeMessage); } + g_logger().debug("Player logging in in version '{}' and oldProtocol '{}'", getVersion(), oldProtocol); + // dispatcher thread std::shared_ptr foundPlayer = g_game().getPlayerUniqueLogin(name); if (!foundPlayer) { @@ -734,6 +736,11 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage &msg) { std::shared_ptr foundPlayer = g_game().getPlayerUniqueLogin(characterName); if (foundPlayer && foundPlayer->client) { + if (foundPlayer->getProtocolVersion() != getVersion() && foundPlayer->isOldProtocol() != oldProtocol) { + disconnectClient(fmt::format("You are already logged in using protocol '{}'. Please log out from the other session to connect here.", foundPlayer->getProtocolVersion())); + return; + } + foundPlayer->client->disconnectClient("You are already connected through another client. Please use only one client at a time!"); } @@ -6899,7 +6906,10 @@ void ProtocolGame::sendPreyData(const std::unique_ptr &slot) { } if (oldProtocol) { - msg.add(static_cast(std::max(std::max(static_cast(((slot->freeRerollTimeStamp - OTSYS_TIME()) / 1000)), 0), 0))); + auto currentTime = OTSYS_TIME(); + auto timeDiffMs = (slot->freeRerollTimeStamp > currentTime) ? (slot->freeRerollTimeStamp - currentTime) : 0; + auto timeDiffMinutes = timeDiffMs / 60000; + msg.add(timeDiffMinutes ? timeDiffMinutes : 0); } else { msg.add(std::max(static_cast(((slot->freeRerollTimeStamp - OTSYS_TIME()) / 1000)), 0)); msg.addByte(static_cast(slot->option)); diff --git a/src/server/network/protocol/protocolstatus.cpp b/src/server/network/protocol/protocolstatus.cpp index 7765a78c4..fbea86e1a 100644 --- a/src/server/network/protocol/protocolstatus.cpp +++ b/src/server/network/protocol/protocolstatus.cpp @@ -18,7 +18,7 @@ std::string ProtocolStatus::SERVER_NAME = "OTX Server"; std::string ProtocolStatus::SERVER_VERSION = "6.2"; -std::string ProtocolStatus::SERVER_DEVELOPERS = "OpenTibiaBR Organization under. Base: Canary (3.1.1). And data edited by: Mattyx14"; +std::string ProtocolStatus::SERVER_DEVELOPERS = "OpenTibiaBR Organization. Based on: Canary (3.1.1). And data edited by: Mattyx14"; std::map ProtocolStatus::ipConnectMap; const uint64_t ProtocolStatus::start = OTSYS_TIME();