From fef55792f5aa1ecab4dfdedacf2801a9884fe00c Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Sun, 27 Oct 2024 00:26:27 -0300 Subject: [PATCH 01/28] init Delete testByte.lua --- config.lua.dist | 3 +- data-otservbr-global/migrations/46.lua | 27 +- data-otservbr-global/migrations/47.lua | 3 + data-otservbr-global/world/otservbr-house.xml | 1970 ++++++++--------- .../globalevents/server_initialization.lua | 24 - data/scripts/talkactions/player/buy_house.lua | 8 +- .../talkactions/player/leave_house.lua | 8 +- .../scripts/talkactions/player/sell_house.lua | 8 +- schema.sql | 13 +- src/account/account.cpp | 7 + src/account/account.hpp | 3 + src/account/account_info.hpp | 1 + src/account/account_repository_db.cpp | 5 +- src/config/config_enums.hpp | 1 + src/config/configmanager.cpp | 1 + src/creatures/players/player.cpp | 35 + src/creatures/players/player.hpp | 17 + src/enums/player_cyclopedia.hpp | 21 + src/game/game.cpp | 177 +- src/game/game.hpp | 6 + src/io/iologindata.cpp | 8 - src/io/iologindata.hpp | 1 - src/io/iomapserialize.cpp | 55 +- src/lua/functions/map/house_functions.cpp | 2 +- src/map/house/house.cpp | 105 +- src/map/house/house.hpp | 104 + src/server/network/protocol/protocolgame.cpp | 127 ++ src/server/network/protocol/protocolgame.hpp | 5 + 28 files changed, 1682 insertions(+), 1063 deletions(-) create mode 100644 data-otservbr-global/migrations/47.lua diff --git a/config.lua.dist b/config.lua.dist index 4d28a2033cd..5f5c128a4e4 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -344,9 +344,10 @@ Setting this to false may pose risks; if a house is abandoned and contains a lar ]] -- Periods: daily/weekly/monthly/yearly/never -- Base: sqm,rent,sqm+rent +toggleCyclopediaHouseAuction = true housePriceRentMultiplier = 0.0 housePriceEachSQM = 1000 -houseRentPeriod = "never" +houseRentPeriod = "monthly" houseRentRate = 1.0 houseOwnedByAccount = false houseBuyLevel = 100 diff --git a/data-otservbr-global/migrations/46.lua b/data-otservbr-global/migrations/46.lua index 86a6d8ffec1..600bb3785ad 100644 --- a/data-otservbr-global/migrations/46.lua +++ b/data-otservbr-global/migrations/46.lua @@ -1,3 +1,28 @@ function onUpdateDatabase() - return false -- true = There are others migrations file | false = this is the last migration file + logger.info("Updating database to version 44 (House Auction)") + + db.query([[ + ALTER TABLE `houses` + DROP `bid`, + DROP `bid_end`, + DROP `last_bid`, + DROP `highest_bidder` + ]]) + + db.query([[ + ALTER TABLE `houses` + ADD `bidder` int(11) NOT NULL DEFAULT '0', + ADD `bidder_name` varchar(255) NOT NULL DEFAULT '', + ADD `highest_bid` int(11) NOT NULL DEFAULT '0', + ADD `internal_bid` int(11) NOT NULL DEFAULT '0', + ADD `bid_end_date` int(11) NOT NULL DEFAULT '0', + ADD `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0' + ]]) + + db.query([[ + ALTER TABLE `accounts` + ADD `house_bid_id` int(11) NOT NULL DEFAULT '0' + ]]) + + return true end diff --git a/data-otservbr-global/migrations/47.lua b/data-otservbr-global/migrations/47.lua new file mode 100644 index 00000000000..86a6d8ffec1 --- /dev/null +++ b/data-otservbr-global/migrations/47.lua @@ -0,0 +1,3 @@ +function onUpdateDatabase() + return false -- true = There are others migrations file | false = this is the last migration file +end diff --git a/data-otservbr-global/world/otservbr-house.xml b/data-otservbr-global/world/otservbr-house.xml index 7eff23b4606..bedef70ff1f 100644 --- a/data-otservbr-global/world/otservbr-house.xml +++ b/data-otservbr-global/world/otservbr-house.xml @@ -1,987 +1,987 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/data/scripts/globalevents/server_initialization.lua b/data/scripts/globalevents/server_initialization.lua index df29660d373..a58cf01d3a2 100644 --- a/data/scripts/globalevents/server_initialization.lua +++ b/data/scripts/globalevents/server_initialization.lua @@ -27,29 +27,6 @@ local function moveExpiredBansToHistory() end end --- Function to check and process house auctions -local function processHouseAuctions() - local resultId = db.storeQuery("SELECT `id`, `highest_bidder`, `last_bid`, " .. "(SELECT `balance` FROM `players` WHERE `players`.`id` = `highest_bidder`) AS `balance` " .. "FROM `houses` WHERE `owner` = 0 AND `bid_end` != 0 AND `bid_end` < " .. os.time()) - if resultId then - repeat - local house = House(Result.getNumber(resultId, "id")) - if house then - local highestBidder = Result.getNumber(resultId, "highest_bidder") - local balance = Result.getNumber(resultId, "balance") - local lastBid = Result.getNumber(resultId, "last_bid") - if balance >= lastBid then - db.query("UPDATE `players` SET `balance` = " .. (balance - lastBid) .. " WHERE `id` = " .. highestBidder) - house:setHouseOwner(highestBidder) - end - - db.asyncQuery("UPDATE `houses` SET `last_bid` = 0, `bid_end` = 0, `highest_bidder` = 0, `bid` = 0 " .. "WHERE `id` = " .. house:getId()) - end - until not Result.next(resultId) - - Result.free(resultId) - end -end - -- Function to store towns in the database local function storeTownsInDatabase() db.query("TRUNCATE TABLE `towns`") @@ -150,7 +127,6 @@ function serverInitialization.onStartup() cleanupDatabase() moveExpiredBansToHistory() - processHouseAuctions() storeTownsInDatabase() checkAndLogDuplicateValues({ "Global", "GlobalStorage", "Storage" }) updateEventRates() diff --git a/data/scripts/talkactions/player/buy_house.lua b/data/scripts/talkactions/player/buy_house.lua index c3784d81a6b..84d3a34aad0 100644 --- a/data/scripts/talkactions/player/buy_house.lua +++ b/data/scripts/talkactions/player/buy_house.lua @@ -60,6 +60,8 @@ function buyHouse.onSay(player, words, param) return true end -buyHouse:separator(" ") -buyHouse:groupType("normal") -buyHouse:register() +if not configManager.getBoolean(configKeys.CYCLOPEDIA_HOUSE_AUCTION) then + buyHouse:separator(" ") + buyHouse:groupType("normal") + buyHouse:register() +end diff --git a/data/scripts/talkactions/player/leave_house.lua b/data/scripts/talkactions/player/leave_house.lua index 20ad186f2d2..d954eb1dcf0 100644 --- a/data/scripts/talkactions/player/leave_house.lua +++ b/data/scripts/talkactions/player/leave_house.lua @@ -42,6 +42,8 @@ function leaveHouse.onSay(player, words, param) return true end -leaveHouse:separator(" ") -leaveHouse:groupType("normal") -leaveHouse:register() +if not configManager.getBoolean(configKeys.CYCLOPEDIA_HOUSE_AUCTION) then + leaveHouse:separator(" ") + leaveHouse:groupType("normal") + leaveHouse:register() +end diff --git a/data/scripts/talkactions/player/sell_house.lua b/data/scripts/talkactions/player/sell_house.lua index c96cb5f71c3..dadadd066d1 100644 --- a/data/scripts/talkactions/player/sell_house.lua +++ b/data/scripts/talkactions/player/sell_house.lua @@ -20,6 +20,8 @@ function sellHouse.onSay(player, words, param) return true end -sellHouse:separator(" ") -sellHouse:groupType("normal") -sellHouse:register() +if not configManager.getBoolean(configKeys.CYCLOPEDIA_HOUSE_AUCTION) then + sellHouse:separator(" ") + sellHouse:groupType("normal") + sellHouse:register() +end diff --git a/schema.sql b/schema.sql index af245067057..821b3bcff41 100644 --- a/schema.sql +++ b/schema.sql @@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS `server_config` ( CONSTRAINT `server_config_pk` PRIMARY KEY (`config`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '46'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); +INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '47'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); -- Table structure `accounts` CREATE TABLE IF NOT EXISTS `accounts` ( @@ -24,6 +24,7 @@ CREATE TABLE IF NOT EXISTS `accounts` ( `tournament_coins` int(12) UNSIGNED NOT NULL DEFAULT '0', `creation` int(11) UNSIGNED NOT NULL DEFAULT '0', `recruiter` INT(6) DEFAULT 0, + `house_bid_id` int(11) NOT NULL DEFAULT '0', CONSTRAINT `accounts_pk` PRIMARY KEY (`id`), CONSTRAINT `accounts_unique` UNIQUE (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; @@ -451,13 +452,15 @@ CREATE TABLE IF NOT EXISTS `houses` ( `name` varchar(255) NOT NULL, `rent` int(11) NOT NULL DEFAULT '0', `town_id` int(11) NOT NULL DEFAULT '0', - `bid` int(11) NOT NULL DEFAULT '0', - `bid_end` int(11) NOT NULL DEFAULT '0', - `last_bid` int(11) NOT NULL DEFAULT '0', - `highest_bidder` int(11) NOT NULL DEFAULT '0', `size` int(11) NOT NULL DEFAULT '0', `guildid` int(11), `beds` int(11) NOT NULL DEFAULT '0', + `bidder` int(11) NOT NULL DEFAULT '0', + `bidder_name` varchar(255) NOT NULL DEFAULT '', + `highest_bid` int(11) NOT NULL DEFAULT '0', + `internal_bid` int(11) NOT NULL DEFAULT '0', + `bid_end_date` int(11) NOT NULL DEFAULT '0', + `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0', INDEX `owner` (`owner`), INDEX `town_id` (`town_id`), CONSTRAINT `houses_pk` PRIMARY KEY (`id`) diff --git a/src/account/account.cpp b/src/account/account.cpp index 2cd411ef3e7..60b78c0f0ac 100644 --- a/src/account/account.cpp +++ b/src/account/account.cpp @@ -296,3 +296,10 @@ uint32_t Account::getAccountAgeInDays() const { [[nodiscard]] time_t Account::getPremiumLastDay() const { return m_account.premiumLastDay; } + +uint32_t Account::getHouseBidId() const { + return m_account.houseBidId; +} +void Account::setHouseBidId(uint32_t houseId) { + m_account.houseBidId = houseId; +} diff --git a/src/account/account.hpp b/src/account/account.hpp index d968ba8ddfb..2820050ded5 100644 --- a/src/account/account.hpp +++ b/src/account/account.hpp @@ -112,6 +112,9 @@ class Account { std::tuple, uint8_t> getAccountPlayers() const; + void setHouseBidId(uint32_t houseId); + uint32_t getHouseBidId() const; + // Old protocol compat void setProtocolCompat(bool toggle); diff --git a/src/account/account_info.hpp b/src/account/account_info.hpp index 698c3b96c1c..ea4198b98a4 100644 --- a/src/account/account_info.hpp +++ b/src/account/account_info.hpp @@ -24,4 +24,5 @@ struct AccountInfo { time_t sessionExpires = 0; uint32_t premiumDaysPurchased = 0; uint32_t creationTime = 0; + uint32_t houseBidId = 0; }; diff --git a/src/account/account_repository_db.cpp b/src/account/account_repository_db.cpp index 10f3d6f3a41..64e90619304 100644 --- a/src/account/account_repository_db.cpp +++ b/src/account/account_repository_db.cpp @@ -44,13 +44,14 @@ bool AccountRepositoryDB::loadBySession(const std::string &sessionKey, AccountIn bool AccountRepositoryDB::save(const AccountInfo &accInfo) { bool successful = g_database().executeQuery( fmt::format( - "UPDATE `accounts` SET `type` = {}, `premdays` = {}, `lastday` = {}, `creation` = {}, `premdays_purchased` = {} WHERE `id` = {}", + "UPDATE `accounts` SET `type` = {}, `premdays` = {}, `lastday` = {}, `creation` = {}, `premdays_purchased` = {}, `house_bid_id` = {} WHERE `id` = {}", accInfo.accountType, accInfo.premiumRemainingDays, accInfo.premiumLastDay, accInfo.creationTime, accInfo.premiumDaysPurchased, - accInfo.id + accInfo.id, + accInfo.houseBidId ) ); diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index 559045fdb9b..a3294d692dc 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -46,6 +46,7 @@ enum ConfigKey_t : uint16_t { CONVERT_UNSAFE_SCRIPTS, CORE_DIRECTORY, CRITICALCHANCE, + CYCLOPEDIA_HOUSE_AUCTION, DATA_DIRECTORY, DAY_KILLS_TO_RED, DEATH_LOSE_PERCENT, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index aa028b52284..f5bafa4fbc3 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -155,6 +155,7 @@ bool ConfigManager::load() { loadBoolConfig(L, VIP_SYSTEM_ENABLED, "vipSystemEnabled", false); loadBoolConfig(L, WARN_UNSAFE_SCRIPTS, "warnUnsafeScripts", true); loadBoolConfig(L, XP_DISPLAY_MODE, "experienceDisplayRates", true); + loadBoolConfig(L, CYCLOPEDIA_HOUSE_AUCTION, "toggleCyclopediaHouseAuction", true); loadFloatConfig(L, BESTIARY_RATE_CHARM_SHOP_PRICE, "bestiaryRateCharmShopPrice", 1.0); loadFloatConfig(L, COMBAT_CHAIN_SKILL_FORMULA_AXE, "combatChainSkillFormulaAxe", 0.9); diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 59d1d6a718a..4487523f395 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -8232,3 +8232,38 @@ uint16_t Player::getPlayerVocationEnum() const { return Vocation_t::VOCATION_NONE; } + +BidErrorMessage Player::canBidHouse(uint32_t houseId) { + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house) { + return BidErrorMessage::Internal; + } + + if (getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) { + return BidErrorMessage::Rookgaard; + } + + if (!isPremium()) { + return BidErrorMessage::Premium; + } + + if (getAccount()->getHouseBidId() != 0) { + return BidErrorMessage::OnlyOneBid; + } + + if (getBankBalance() < (house->getRent() + house->getHighestBid())) { + return BidErrorMessage::NotEnoughMoney; + } + + if (house->isGuildhall()) { + if (getGuildRank() && getGuildRank()->level != 3) { + return BidErrorMessage::Guildhall; + } + + if (getGuild() && getGuild()->getBankBalance() < (house->getRent() + house->getHighestBid())) { + return BidErrorMessage::NotEnoughGuildMoney; + } + } + + return BidErrorMessage::NoError; +} \ No newline at end of file diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index cd69cec99a0..dedf6b9d119 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -1582,6 +1582,23 @@ class Player final : public Creature, public Cylinder, public Bankable { client->sendOutfitWindow(); } } + + BidErrorMessage canBidHouse(uint32_t houseId); + void sendCyclopediaHouseList(HouseMap houses) { + if (client) { + client->sendCyclopediaHouseList(houses); + } + } + void sendResourceBalance(Resource_t resourceType, uint64_t value) { + if (client) { + client->sendResourceBalance(resourceType, value); + } + } + void sendHouseAuctionMessage(uint32_t houseId, HouseAuctionType type, uint8_t index, bool bidSuccess = false) { + if (client) { + client->sendHouseAuctionMessage(houseId, type, index, bidSuccess); + } + } // Imbuements void onApplyImbuement(Imbuement* imbuement, std::shared_ptr item, uint8_t slot, bool protectionCharm); void onClearImbuement(std::shared_ptr item, uint8_t slot); diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index 295e573984f..fb2a97dac13 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -60,3 +60,24 @@ enum class CyclopediaMapData_t : uint8_t { Donations = 9, SetCurrentArea = 10, }; + +enum class HouseAuctionType : uint8_t { + Bid = 1, + MoveOut = 2, +}; + +enum class BidSuccessMessage : uint8_t { + BidSuccess = 0, + LowerBid = 1, +}; + +enum class BidErrorMessage : uint8_t { + NoError = 0, + Rookgaard = 3, + Premium = 5, + Guildhall = 6, + OnlyOneBid = 7, + NotEnoughMoney = 17, + NotEnoughGuildMoney = 21, + Internal = 24, +}; \ No newline at end of file diff --git a/src/game/game.cpp b/src/game/game.cpp index 00a81c63e78..18281b3bc51 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10241,15 +10241,18 @@ bool Game::removeFiendishMonster(uint32_t id, bool create /* = true*/) { } void Game::updateForgeableMonsters() { - forgeableMonsters.clear(); - for (const auto &[monsterId, monster] : monsters) { - auto monsterTile = monster->getTile(); - if (!monsterTile) { - continue; - } + if (auto influencedLimit = g_configManager().getNumber(FORGE_INFLUENCED_CREATURES_LIMIT, __FUNCTION__); + forgeableMonsters.size() < influencedLimit * 2) { + forgeableMonsters.clear(); + for (const auto &[monsterId, monster] : monsters) { + auto monsterTile = monster->getTile(); + if (!monsterTile) { + continue; + } - if (monster->canBeForgeMonster() && !monsterTile->hasFlag(TILESTATE_NOLOGOUT)) { - forgeableMonsters.push_back(monster->getID()); + if (monster->canBeForgeMonster() && !monsterTile->hasFlag(TILESTATE_NOLOGOUT)) { + forgeableMonsters.push_back(monster->getID()); + } } } @@ -10736,3 +10739,161 @@ const std::unordered_map &Game::getHirelingSkills() { const std::unordered_map &Game::getHirelingOutfits() { return m_hirelingOutfits; } + +void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string townName) { + std::shared_ptr player = getPlayerByID(playerId); + if (!player) { + return; + } + + HouseMap houses; + if (!townName.empty()) { + const auto& housesList = g_game().map.houses.getHouses(); + for (const auto& it : housesList) { + const auto& house = it.second; + const auto& town = g_game().map.towns.getTown(house->getTownId()); + if (!town) { + return; + } + + const std::string houseTown = town->getName(); + if (houseTown == townName) { + houses.emplace(house->getClientId(), house); + } + } + } else { + auto playerHouses = g_game().map.houses.getAllHousesByPlayerId(player->getGUID()); + if (playerHouses.size()) { + for (const auto playerHouse : playerHouses) { + if (!playerHouse) { + continue; + } + houses.emplace(playerHouse->getClientId(), playerHouse); + } + } else { + const auto house = g_game().map.houses.getHouseByBidderName(player->getName()); + if (house) { + houses.emplace(house->getClientId(), house); + } + } + } + player->sendCyclopediaHouseList(houses); +} + +void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_t bidValue) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION, __FUNCTION__)) { + return; + } + + std::shared_ptr player = getPlayerByID(playerId); + if (!player) { + return; + } + + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house) { + return; + } + + auto ret = player->canBidHouse(houseId); + if (ret != BidErrorMessage::NoError) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(ret)); + } + ret = BidErrorMessage::NotEnoughMoney; + auto retSuccess = BidSuccessMessage::BidSuccess; + + if(house->getBidderName().empty()) { + if (!processBankAuction(player, house, bidValue)) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(ret)); + return; + } + house->setHighestBid(0); + house->setInternalBid(bidValue); + house->setBidHolderLimit(bidValue); + house->setBidderName(player->getName()); + house->setBidder(player->getGUID()); + house->calculateBidEndDate(1); + } else if (house->getBidderName() == player->getName()) { + if (!processBankAuction(player, house, bidValue, true)) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(ret)); + return; + } + house->setInternalBid(bidValue); + house->setBidHolderLimit(bidValue); + } else if (bidValue <= house->getInternalBid()) { + house->setHighestBid(bidValue); + retSuccess = BidSuccessMessage::LowerBid; + } else { + if (!processBankAuction(player, house, bidValue)) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(ret)); + return; + } + house->setHighestBid(house->getInternalBid() + 1); + house->setInternalBid(bidValue); + house->setBidHolderLimit(bidValue); + house->setBidderName(player->getName()); + house->setBidder(player->getGUID()); + } + + const auto& town = g_game().map.towns.getTown(house->getTownId()); + if (!town) { + return; + } + + const std::string houseTown = town->getName(); + player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(retSuccess), true); + playerCyclopediaHousesByTown(playerId, houseTown); +} + +void Game::playerCyclopediaHouseLeave(uint32_t playerId, uint32_t houseId, uint32_t timestamp) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION, __FUNCTION__)) { + return; + } + + std::shared_ptr player = getPlayerByID(playerId); + if (!player) { + return; + } + + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house || house->getOwner() != player->getGUID()) { + return; + } + + house->setBidEndDate(timestamp); + house->setBidder(-1); + + playerCyclopediaHousesByTown(playerId, ""); +} + +bool Game::processBankAuction(std::shared_ptr player, std::shared_ptr house, uint64_t bid, bool replace /* = false*/) { + if (!replace && player->getBankBalance() < (house->getRent() + bid)) { + return false; + } + + if (player->getBankBalance() < bid) { + return false; + } + + uint64_t balance = player->getBankBalance(); + if (replace) { + player->setBankBalance(balance - (bid - house->getInternalBid())); + } else { + player->setBankBalance(balance - (house->getRent() + bid)); + } + + player->sendResourceBalance(RESOURCE_BANK, player->getBankBalance()); + + if (house->getBidderName() != player->getName()) { + const auto otherPlayer = g_game().getPlayerByName(house->getBidderName()); + if (!otherPlayer) { + uint32_t bidderGuid = IOLoginData::getGuidByName(house->getBidderName()); + IOLoginData::increaseBankBalance(bidderGuid, (house->getBidHolderLimit() + house->getRent())); + } else { + otherPlayer->setBankBalance(otherPlayer->getBankBalance() + (house->getBidHolderLimit() + house->getRent())); + otherPlayer->sendResourceBalance(RESOURCE_BANK, otherPlayer->getBankBalance()); + } + } + + return true; +} diff --git a/src/game/game.hpp b/src/game/game.hpp index e04dbb26cff..1b0b9b369d3 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -315,6 +315,12 @@ class Game { void playerHighscores(std::shared_ptr player, HighscoreType_t type, uint8_t category, uint32_t vocation, const std::string &worldName, uint16_t page, uint8_t entriesPerPage); static std::string getSkillNameById(uint8_t &skill); + // House Auction + void playerCyclopediaHousesByTown(uint32_t playerId, const std::string townName); + void playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_t bidValue); + void playerCyclopediaHouseLeave(uint32_t playerId, uint32_t houseId, uint32_t timestamp); + bool processBankAuction(std::shared_ptr player, std::shared_ptr house, uint64_t bid, bool replace = false); + void updatePlayerSaleItems(uint32_t playerId); bool internalStartTrade(std::shared_ptr player, std::shared_ptr partner, std::shared_ptr tradeItem); diff --git a/src/io/iologindata.cpp b/src/io/iologindata.cpp index 17816f969de..4548a1c91fa 100644 --- a/src/io/iologindata.cpp +++ b/src/io/iologindata.cpp @@ -350,14 +350,6 @@ void IOLoginData::increaseBankBalance(uint32_t guid, uint64_t bankBalance) { Database::getInstance().executeQuery(query.str()); } -bool IOLoginData::hasBiddedOnHouse(uint32_t guid) { - Database &db = Database::getInstance(); - - std::ostringstream query; - query << "SELECT `id` FROM `houses` WHERE `highest_bidder` = " << guid << " LIMIT 1"; - return db.storeQuery(query.str()).get() != nullptr; -} - std::vector IOLoginData::getVIPEntries(uint32_t accountId) { std::string query = fmt::format("SELECT `player_id`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `name`, `description`, `icon`, `notify` FROM `account_viplist` WHERE `account_id` = {}", accountId); std::vector entries; diff --git a/src/io/iologindata.hpp b/src/io/iologindata.hpp index 79fa3b59ad7..058fd8c4a98 100644 --- a/src/io/iologindata.hpp +++ b/src/io/iologindata.hpp @@ -29,7 +29,6 @@ class IOLoginData { static std::string getNameByGuid(uint32_t guid); static bool formatPlayerName(std::string &name); static void increaseBankBalance(uint32_t guid, uint64_t bankBalance); - static bool hasBiddedOnHouse(uint32_t guid); static std::vector getVIPEntries(uint32_t accountId); static void addVIPEntry(uint32_t accountId, uint32_t guid, const std::string &description, uint32_t icon, bool notify); diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index 220b50a85e6..41087ed202a 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -273,7 +273,7 @@ void IOMapSerialize::saveTile(PropWriteStream &stream, std::shared_ptr til bool IOMapSerialize::loadHouseInfo() { Database &db = Database::getInstance(); - DBResult_ptr result = db.storeQuery("SELECT `id`, `owner`, `new_owner`, `paid`, `warnings` FROM `houses`"); + DBResult_ptr result = db.storeQuery("SELECT `id`, `owner`, `new_owner`, `bidder`, `bidder_name`, `highest_bid`, `internal_bid`, `bid_end_date`, `state` FROM `houses`"); if (!result) { return false; } @@ -284,6 +284,13 @@ bool IOMapSerialize::loadHouseInfo() { if (house) { uint32_t owner = result->getNumber("owner"); int32_t newOwner = result->getNumber("new_owner"); + uint32_t bidder = result->getNumber("bidder"); + std::string bidderName = result->getString("bidder_name"); + uint32_t highestBid = result->getNumber("highest_bid"); + uint32_t internalBid = result->getNumber("internal_bid"); + uint32_t bidEndDate = result->getNumber("bid_end_date"); + uint32_t state = result->getNumber("state"); + const auto timeNow = OTSYS_TIME(true); // Transfer house owner auto isTransferOnRestart = g_configManager().getBoolean(TOGGLE_HOUSE_TRANSFER_ON_SERVER_RESTART); if (isTransferOnRestart && newOwner >= 0) { @@ -295,11 +302,32 @@ bool IOMapSerialize::loadHouseInfo() { g_logger().debug("Setting house id '{}' owner to player GUID '{}'", houseId, newOwner); house->setOwner(newOwner); } + } else if (state == 0 && bidder > 0 && timeNow > bidEndDate) { + if (highestBid < internalBid) { + uint32_t diff = internalBid - highestBid; + IOLoginData::increaseBankBalance(bidder, diff); + } + g_logger().debug("Setting house id '{}' owner to player GUID '{}'", houseId, bidder); + house->setOwner(bidder); + bidder = 0; + bidderName = ""; + highestBid = 0; + internalBid = 0; + bidEndDate = 0; + } else if (state == 2 && bidder == -1 && timeNow > bidEndDate) { + g_logger().debug("Removing house id '{}' owner", houseId); + house->setOwner(0); + bidEndDate = 0; + bidder = 0; } else { house->setOwner(owner, false); } - house->setPaidUntil(result->getNumber("paid")); - house->setPayRentWarnings(result->getNumber("warnings")); + house->setBidder(bidder); + house->setBidderName(bidderName); + house->setHighestBid(highestBid); + house->setInternalBid(internalBid); + house->setBidHolderLimit(internalBid); + house->setBidEndDate(bidEndDate); } } while (result->next()); @@ -331,11 +359,26 @@ bool IOMapSerialize::SaveHouseInfoGuard() { Database &db = Database::getInstance(); std::ostringstream query; - DBInsert houseUpdate("INSERT INTO `houses` (`id`, `owner`, `paid`, `warnings`, `name`, `town_id`, `rent`, `size`, `beds`) VALUES "); - houseUpdate.upsert({ "owner", "paid", "warnings", "name", "town_id", "rent", "size", "beds" }); + DBInsert houseUpdate("INSERT INTO `houses` (`id`, `owner`, `paid`, `warnings`, `name`, `town_id`, `rent`, `size`, `beds`, `bidder`, `bidder_name`, `highest_bid`, `internal_bid`, `bid_end_date`, `state`) VALUES "); + houseUpdate.upsert({ "owner", "paid", "warnings", "name", "town_id", "rent", "size", "beds", "bidder", "bidder_name", "highest_bid", "internal_bid", "bid_end_date", "state" }); for (const auto &[key, house] : g_game().map.houses.getHouses()) { - std::string values = fmt::format("{},{},{},{},{},{},{},{},{}", house->getId(), house->getOwner(), house->getPaidUntil(), house->getPayRentWarnings(), db.escapeString(house->getName()), house->getTownId(), house->getRent(), house->getSize(), house->getBedCount()); + std::string values = fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", + house->getId(), + house->getOwner(), + house->getPaidUntil(), + house->getPayRentWarnings(), + db.escapeString(house->getName()), + house->getTownId(), house->getRent(), + house->getSize(), + house->getBedCount(), + house->getBidder(), + db.escapeString(house->getBidderName()), + house->getHighestBid(), + house->getInternalBid(), + house->getBidEndDate(), + house->getState() + ); if (!houseUpdate.addRow(values)) { return false; diff --git a/src/lua/functions/map/house_functions.cpp b/src/lua/functions/map/house_functions.cpp index 597eec3975e..c9edf0c970a 100644 --- a/src/lua/functions/map/house_functions.cpp +++ b/src/lua/functions/map/house_functions.cpp @@ -197,7 +197,7 @@ int HouseFunctions::luaHouseStartTrade(lua_State* L) { return 1; } - if (IOLoginData::hasBiddedOnHouse(tradePartner->getGUID())) { + if (tradePartner->getAccount()->getHouseBidId() != 0) { lua_pushnumber(L, RETURNVALUE_TRADEPLAYERHIGHESTBIDDER); return 1; } diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index 9995862c679..c7530187df1 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -90,7 +90,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, std::shared Database &db = Database::getInstance(); std::ostringstream query; - query << "UPDATE `houses` SET `owner` = " << guid << ", `new_owner` = -1, `bid` = 0, `bid_end` = 0, `last_bid` = 0, `highest_bidder` = 0 WHERE `id` = " << id; + query << "UPDATE `houses` SET `owner` = " << guid << ", `new_owner` = -1, `paid` = 0, `bidder` = 0, `bidder_name` = '', `highest_bid` = 0, `internal_bid` = 0, `bid_end_date` = 0, `state` = 0 WHERE `id` = " << id; db.executeQuery(query.str()); } @@ -102,8 +102,10 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, std::shared if (owner != 0) { tryTransferOwnership(std::move(player), false); - } else { - std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD)); + } + + if (guid != 0) { + std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD, __FUNCTION__)); time_t currentTime = time(nullptr); if (strRentPeriod == "yearly") { currentTime += 24 * 60 * 60 * 365; @@ -118,6 +120,8 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, std::shared } paidUntil = currentTime; + } else { + paidUntil = 0; } rentWarnings = 0; @@ -136,6 +140,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, std::shared owner = guid; ownerName = name; ownerAccountId = result->getNumber("account_id"); + state = 2; } } @@ -150,15 +155,17 @@ void House::updateDoorDescription() const { ss << "It belongs to house '" << houseName << "'. Nobody owns this house."; } - ss << " It is " << getSize() << " square meters."; - const int32_t housePrice = getPrice(); - if (housePrice != -1) { - if (g_configManager().getBoolean(HOUSE_PURSHASED_SHOW_PRICE) || owner == 0) { - ss << " It costs " << formatNumber(getPrice()) << " gold coins."; - } - std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD)); - if (strRentPeriod != "never") { - ss << " The rent cost is " << formatNumber(getRent()) << " gold coins and it is billed " << strRentPeriod << "."; + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION, __FUNCTION__)) { + ss << " It is " << getSize() << " square meters."; + const int32_t housePrice = getPrice(); + if (housePrice != -1) { + if (g_configManager().getBoolean(HOUSE_PURSHASED_SHOW_PRICE, __FUNCTION__) || owner == 0) { + ss << " It costs " << formatNumber(getPrice()) << " gold coins."; + } + std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD, __FUNCTION__)); + if (strRentPeriod != "never") { + ss << " The rent cost is " << formatNumber(getRent()) << " gold coins and it is billed " << strRentPeriod << "."; + } } } @@ -474,6 +481,43 @@ void House::resetTransferItem() { } } +void House::calculateBidEndDate(uint8_t daysToEnd) { + auto currentTimeMs = std::chrono::system_clock::now().time_since_epoch(); + + std::chrono::system_clock::time_point now = std::chrono::system_clock::time_point( + std::chrono::duration_cast(currentTimeMs) + ); + + // Truncate to whole days since epoch + days daysSinceEpoch = std::chrono::duration_cast(now.time_since_epoch()); + + // Get today's date at 00:00:00 UTC + std::chrono::system_clock::time_point todayMidnight = std::chrono::system_clock::time_point(daysSinceEpoch); + + std::chrono::system_clock::time_point targetDay = todayMidnight + days(daysToEnd); + + const auto serverSaveTime = g_configManager().getString(GLOBAL_SERVER_SAVE_TIME, __FUNCTION__); + + std::vector params = vectorAtoi(explodeString(serverSaveTime, ":")); + int32_t hour = params.front(); + int32_t min = 0; + int32_t sec = 0; + if (params.size() > 1) { + min = params[1]; + + if (params.size() > 2) { + sec = params[2]; + } + } + std::chrono::system_clock::time_point targetTime = targetDay + std::chrono::hours(hour) + std::chrono::minutes(min) + std::chrono::seconds(sec); + + std::time_t resultTime = std::chrono::system_clock::to_time_t(targetTime); + std::tm* localTime = std::localtime(&resultTime); + uint32_t bidEndDate = static_cast(std::mktime(localTime)); + + this->bidEndDate = bidEndDate; +} + std::shared_ptr HouseTransferItem::createHouseTransferItem(std::shared_ptr house) { std::shared_ptr transferItem = std::make_shared(house); transferItem->setID(ITEM_DOCUMENT_RO); @@ -720,6 +764,35 @@ std::shared_ptr Houses::getHouseByPlayerId(uint32_t playerId) { return nullptr; } +std::vector> Houses::getAllHousesByPlayerId(uint32_t playerId) { + std::vector> playerHouses; + for (const auto &it : houseMap) { + if (it.second->getOwner() == playerId) { + playerHouses.emplace_back(it.second); + } + } + return playerHouses; +} + +std::shared_ptr Houses::getHouseByBidderName(std::string bidderName) { + for (const auto &it : houseMap) { + if (it.second->getBidderName() == bidderName) { + return it.second; + } + } + return nullptr; +} + +uint16_t Houses::getHouseCountByAccount(uint32_t accountId) { + uint16_t count = 0; + for (const auto& it : houseMap) { + if (it.second->getOwnerAccountId() == accountId) { + ++count; + } + } + return count; +} + bool Houses::loadHousesXML(const std::string &filename) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(filename.c_str()); @@ -759,6 +832,13 @@ bool Houses::loadHousesXML(const std::string &filename) { house->setRent(pugi::cast(houseNode.attribute("rent").value())); house->setSize(pugi::cast(houseNode.attribute("size").value())); house->setTownId(pugi::cast(houseNode.attribute("townid").value())); + house->setClientId(pugi::cast(houseNode.attribute("clientid").value())); + + auto guildhallAttr = houseNode.attribute("guildhall"); + if (!guildhallAttr.empty()) { + house->setGuildhall(static_cast(guildhallAttr.as_bool())); + } + auto maxBedsAttr = houseNode.attribute("beds"); int32_t maxBeds = -1; if (!maxBedsAttr.empty()) { @@ -767,6 +847,7 @@ bool Houses::loadHousesXML(const std::string &filename) { house->setMaxBeds(maxBeds); house->setOwner(0, false); + addHouseClientId(house->getClientId(), house); } return true; } diff --git a/src/map/house/house.hpp b/src/map/house/house.hpp index aa4b746cc0a..c763e5de595 100644 --- a/src/map/house/house.hpp +++ b/src/map/house/house.hpp @@ -18,6 +18,8 @@ class House; class BedItem; class Player; +using days = std::chrono::duration>; + class AccessList { public: void parseList(const std::string &list); @@ -233,6 +235,77 @@ class House : public SharedObject { bool hasNewOwnership() const; void setNewOwnership(); + void setClientId(uint32_t newClientId) { + this->clientId = newClientId; + } + uint32_t getClientId() const { + return clientId; + } + + void setBidder(int32_t bidder) { + this->bidder = bidder; + } + int32_t getBidder() const { + return bidder; + } + + void setBidderName(std::string bidderName) { + this->bidderName = bidderName; + } + std::string getBidderName() const { + return bidderName; + } + + void setHighestBid(uint64_t bidValue) { + this->highestBid = bidValue; + } + uint64_t getHighestBid() const { + return highestBid; + } + + void setInternalBid(uint64_t bidValue) { + this->internalBid = bidValue; + } + uint64_t getInternalBid() const { + return internalBid; + } + + void setBidHolderLimit(uint64_t bidValue) { + this->bidHolderLimit = bidValue; + } + uint64_t getBidHolderLimit() const { + return bidHolderLimit; + } + + void calculateBidEndDate(uint8_t daysToEnd); + void setBidEndDate(uint32_t bidEndDate) { + this->bidEndDate = bidEndDate; + }; + uint32_t getBidEndDate() const { + return bidEndDate; + } + + void setState(uint8_t state) { + this->state = state; + } + uint8_t getState() const { + return state; + } + + void setOwnerAccountId(uint32_t accountId) { + this->ownerAccountId = accountId; + } + uint32_t getOwnerAccountId() const { + return ownerAccountId; + } + + void setGuildhall(bool isGuildHall) { + this->guildHall = isGuildHall; + } + bool isGuildhall() const { + return guildHall; + } + private: bool transferToDepot() const; @@ -263,9 +336,20 @@ class House : public SharedObject { uint32_t townId = 0; uint32_t maxBeds = 4; int32_t bedsCount = -1; + bool guildHall = false; Position posEntry = {}; + // House Auction + uint32_t clientId; + int32_t bidder = 0; + std::string bidderName = ""; + uint64_t highestBid = 0; + uint64_t internalBid = 0; + uint64_t bidHolderLimit = 0; + uint32_t bidEndDate = 0; + uint8_t state = 0; + bool isLoaded = false; void handleContainer(ItemList &moveItemList, std::shared_ptr item) const; @@ -299,7 +383,26 @@ class Houses { return it->second; } + void addHouseClientId(uint32_t clientId, std::shared_ptr house) { + if (auto it = houseMapClientId.find(clientId); it != houseMapClientId.end()) { + return; + } + + houseMapClientId.emplace(clientId, house); + } + + std::shared_ptr getHouseByClientId(uint32_t clientId) { + auto it = houseMapClientId.find(clientId); + if (it == houseMapClientId.end()) { + return nullptr; + } + return it->second; + } + std::shared_ptr getHouseByPlayerId(uint32_t playerId); + std::vector> getAllHousesByPlayerId(uint32_t playerId); + std::shared_ptr getHouseByBidderName(std::string bidderName); + uint16_t getHouseCountByAccount(uint32_t accountId); bool loadHousesXML(const std::string &filename); @@ -311,4 +414,5 @@ class Houses { private: HouseMap houseMap; + HouseMap houseMapClientId; }; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index ae67bad447f..6a0e8fe4cc1 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -1225,6 +1225,9 @@ void ProtocolGame::parsePacketFromDispatcher(NetworkMessage &msg, uint8_t recvby case 0xAC: parseChannelExclude(msg); break; + case 0xAD: + parseCyclopediaHouseAuction(msg); + break; case 0xAE: parseSendBosstiary(); break; @@ -6826,6 +6829,7 @@ void ProtocolGame::sendAddCreature(std::shared_ptr creature, const Pos sendLootContainers(); sendBasicData(); + sendHousesInfo(); // Wheel of destiny cooldown if (!oldProtocol && g_configManager().getBoolean(TOGGLE_WHEELSYSTEM)) { player->wheel()->sendGiftOfLifeCooldown(); @@ -9256,3 +9260,126 @@ void ProtocolGame::sendTakeScreenshot(Screenshot_t screenshotType) { msg.addByte(screenshotType); writeToOutputBuffer(msg); } + +void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage& msg) { + if (oldProtocol) { + return; + } + + uint8_t houseActionType = msg.getByte(); + switch (houseActionType) { + case 0: { + const auto townName = msg.getString(); + g_game().playerCyclopediaHousesByTown(player->getID(), townName); + break; + } + case 1: { + const uint32_t houseId = msg.get(); + const uint64_t bidValue = msg.get(); + g_game().playerCyclopediaHouseBid(player->getID(), houseId, bidValue); + break; + } + case 2: { + const uint32_t houseId = msg.get(); + const uint32_t timestamp = msg.get(); + g_game().playerCyclopediaHouseLeave(player->getID(), houseId, timestamp); + break; + } + case 3: { + break; + } + } +} + +void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { + NetworkMessage msg; + msg.addByte(0xC7); + msg.add(houses.size()); + for (const auto& house : houses) { + const auto clientId = house.first; + const auto& houseData = house.second; + + msg.add(clientId); + msg.addByte(0x01); // 0x00 = Renovation; 0x01 = Available + + msg.addByte(houseData->getState()); + if (houseData->getState() == 0) { // Available + bool bidder = houseData->getBidderName() == player->getName(); + msg.addString(houseData->getBidderName()); + msg.addByte(bidder ? 1 : 0); + uint8_t disableIndex = enumToValue(player->canBidHouse(clientId)); + msg.addByte(disableIndex); + + if (!houseData->getBidderName().empty()) { + msg.add(houseData->getBidEndDate()); + msg.add(houseData->getHighestBid()); + if (bidder) { + msg.add(houseData->getBidHolderLimit()); + } + } + } else if (houseData->getState() == 2) { // Rented + auto ownerName = IOLoginData::getNameByGuid(houseData->getOwner()); + msg.addString(ownerName); + msg.add(houseData->getPaidUntil()); + + bool rented = ownerName.compare(player->getName()) == 0; + msg.addByte(rented); + if (rented) { + msg.addByte(0); + msg.addByte(0); + } + } + } + + writeToOutputBuffer(msg); +} + +void ProtocolGame::sendHouseAuctionMessage(uint32_t houseId, HouseAuctionType type, uint8_t index, bool bidSuccess /* = false*/) { + NetworkMessage msg; + const auto typeValue = enumToValue(type); + + msg.addByte(0xC3); + msg.add(houseId); + msg.addByte(typeValue); + if (bidSuccess && typeValue == 1) { + msg.addByte(0x00); + } + msg.addByte(index); + + writeToOutputBuffer(msg); +} + +void ProtocolGame::sendHousesInfo() { + NetworkMessage msg; + + uint32_t houseClientId = 0; + const auto accountHouseCount = g_game().map.houses.getHouseCountByAccount(player->getAccountId()); + const auto house = g_game().map.houses.getHouseByPlayerId(player->getGUID()); + if (house) { + houseClientId = house->getClientId(); + } + + msg.addByte(0xC6); + msg.add(houseClientId); + msg.addByte(0x00); + + msg.addByte(accountHouseCount); // Houses Account + + msg.addByte(0x00); + + msg.addByte(3); + msg.addByte(3); + + msg.addByte(0x01); + + msg.addByte(0x01); + msg.add(houseClientId); + + const auto& housesList = g_game().map.houses.getHouses(); + msg.add(housesList.size()); + for (const auto& it : housesList) { + msg.add(it.second->getClientId()); + } + + writeToOutputBuffer(msg); +} \ No newline at end of file diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index fc27cd3abfc..d33708232ab 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -330,6 +330,11 @@ class ProtocolGame final : public Protocol { void sendCyclopediaCharacterBadges(); void sendCyclopediaCharacterTitles(); + void sendHousesInfo(); + void parseCyclopediaHouseAuction(NetworkMessage& msg); + void sendCyclopediaHouseList(HouseMap houses); + void sendHouseAuctionMessage(uint32_t houseId, HouseAuctionType type, uint8_t index, bool bidSuccess); + void sendCreatureWalkthrough(std::shared_ptr creature, bool walkthrough); void sendCreatureShield(std::shared_ptr creature); void sendCreatureEmblem(std::shared_ptr creature); From f16662f077fcc376299eaf89b010e1964e7b8648 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 27 Oct 2024 03:27:43 +0000 Subject: [PATCH 02/28] Code format - (Clang-format) --- src/creatures/players/player.cpp | 4 ++-- src/enums/player_cyclopedia.hpp | 2 +- src/game/game.cpp | 14 ++++++------ src/io/iomapserialize.cpp | 17 +------------- src/map/house/house.cpp | 24 ++++++++++---------- src/server/network/protocol/protocolgame.cpp | 12 +++++----- src/server/network/protocol/protocolgame.hpp | 2 +- 7 files changed, 30 insertions(+), 45 deletions(-) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 4487523f395..d6ee3f5ad5f 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -8256,7 +8256,7 @@ BidErrorMessage Player::canBidHouse(uint32_t houseId) { } if (house->isGuildhall()) { - if (getGuildRank() && getGuildRank()->level != 3) { + if (getGuildRank() && getGuildRank()->level != 3) { return BidErrorMessage::Guildhall; } @@ -8266,4 +8266,4 @@ BidErrorMessage Player::canBidHouse(uint32_t houseId) { } return BidErrorMessage::NoError; -} \ No newline at end of file +} diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index fb2a97dac13..3f1aef3f0c1 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -80,4 +80,4 @@ enum class BidErrorMessage : uint8_t { NotEnoughMoney = 17, NotEnoughGuildMoney = 21, Internal = 24, -}; \ No newline at end of file +}; diff --git a/src/game/game.cpp b/src/game/game.cpp index 18281b3bc51..612aae6c297 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10242,7 +10242,7 @@ bool Game::removeFiendishMonster(uint32_t id, bool create /* = true*/) { void Game::updateForgeableMonsters() { if (auto influencedLimit = g_configManager().getNumber(FORGE_INFLUENCED_CREATURES_LIMIT, __FUNCTION__); - forgeableMonsters.size() < influencedLimit * 2) { + forgeableMonsters.size() < influencedLimit * 2) { forgeableMonsters.clear(); for (const auto &[monsterId, monster] : monsters) { auto monsterTile = monster->getTile(); @@ -10748,10 +10748,10 @@ void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string tow HouseMap houses; if (!townName.empty()) { - const auto& housesList = g_game().map.houses.getHouses(); - for (const auto& it : housesList) { - const auto& house = it.second; - const auto& town = g_game().map.towns.getTown(house->getTownId()); + const auto &housesList = g_game().map.houses.getHouses(); + for (const auto &it : housesList) { + const auto &house = it.second; + const auto &town = g_game().map.towns.getTown(house->getTownId()); if (!town) { return; } @@ -10802,7 +10802,7 @@ void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_ ret = BidErrorMessage::NotEnoughMoney; auto retSuccess = BidSuccessMessage::BidSuccess; - if(house->getBidderName().empty()) { + if (house->getBidderName().empty()) { if (!processBankAuction(player, house, bidValue)) { player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(ret)); return; @@ -10835,7 +10835,7 @@ void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_ house->setBidder(player->getGUID()); } - const auto& town = g_game().map.towns.getTown(house->getTownId()); + const auto &town = g_game().map.towns.getTown(house->getTownId()); if (!town) { return; } diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index 41087ed202a..f45048482fd 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -363,22 +363,7 @@ bool IOMapSerialize::SaveHouseInfoGuard() { houseUpdate.upsert({ "owner", "paid", "warnings", "name", "town_id", "rent", "size", "beds", "bidder", "bidder_name", "highest_bid", "internal_bid", "bid_end_date", "state" }); for (const auto &[key, house] : g_game().map.houses.getHouses()) { - std::string values = fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", - house->getId(), - house->getOwner(), - house->getPaidUntil(), - house->getPayRentWarnings(), - db.escapeString(house->getName()), - house->getTownId(), house->getRent(), - house->getSize(), - house->getBedCount(), - house->getBidder(), - db.escapeString(house->getBidderName()), - house->getHighestBid(), - house->getInternalBid(), - house->getBidEndDate(), - house->getState() - ); + std::string values = fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", house->getId(), house->getOwner(), house->getPaidUntil(), house->getPayRentWarnings(), db.escapeString(house->getName()), house->getTownId(), house->getRent(), house->getSize(), house->getBedCount(), house->getBidder(), db.escapeString(house->getBidderName()), house->getHighestBid(), house->getInternalBid(), house->getBidEndDate(), house->getState()); if (!houseUpdate.addRow(values)) { return false; diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index c7530187df1..f9cfe5f995c 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -482,11 +482,11 @@ void House::resetTransferItem() { } void House::calculateBidEndDate(uint8_t daysToEnd) { - auto currentTimeMs = std::chrono::system_clock::now().time_since_epoch(); - - std::chrono::system_clock::time_point now = std::chrono::system_clock::time_point( - std::chrono::duration_cast(currentTimeMs) - ); + auto currentTimeMs = std::chrono::system_clock::now().time_since_epoch(); + + std::chrono::system_clock::time_point now = std::chrono::system_clock::time_point( + std::chrono::duration_cast(currentTimeMs) + ); // Truncate to whole days since epoch days daysSinceEpoch = std::chrono::duration_cast(now.time_since_epoch()); @@ -784,13 +784,13 @@ std::shared_ptr Houses::getHouseByBidderName(std::string bidderName) { } uint16_t Houses::getHouseCountByAccount(uint32_t accountId) { - uint16_t count = 0; - for (const auto& it : houseMap) { - if (it.second->getOwnerAccountId() == accountId) { - ++count; - } - } - return count; + uint16_t count = 0; + for (const auto &it : houseMap) { + if (it.second->getOwnerAccountId() == accountId) { + ++count; + } + } + return count; } bool Houses::loadHousesXML(const std::string &filename) { diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 6a0e8fe4cc1..2fa8a4b3a4b 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -9261,7 +9261,7 @@ void ProtocolGame::sendTakeScreenshot(Screenshot_t screenshotType) { writeToOutputBuffer(msg); } -void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage& msg) { +void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage &msg) { if (oldProtocol) { return; } @@ -9295,9 +9295,9 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { NetworkMessage msg; msg.addByte(0xC7); msg.add(houses.size()); - for (const auto& house : houses) { + for (const auto &house : houses) { const auto clientId = house.first; - const auto& houseData = house.second; + const auto &houseData = house.second; msg.add(clientId); msg.addByte(0x01); // 0x00 = Renovation; 0x01 = Available @@ -9375,11 +9375,11 @@ void ProtocolGame::sendHousesInfo() { msg.addByte(0x01); msg.add(houseClientId); - const auto& housesList = g_game().map.houses.getHouses(); + const auto &housesList = g_game().map.houses.getHouses(); msg.add(housesList.size()); - for (const auto& it : housesList) { + for (const auto &it : housesList) { msg.add(it.second->getClientId()); } writeToOutputBuffer(msg); -} \ No newline at end of file +} diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index d33708232ab..8a272c8ea8c 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -331,7 +331,7 @@ class ProtocolGame final : public Protocol { void sendCyclopediaCharacterTitles(); void sendHousesInfo(); - void parseCyclopediaHouseAuction(NetworkMessage& msg); + void parseCyclopediaHouseAuction(NetworkMessage &msg); void sendCyclopediaHouseList(HouseMap houses); void sendHouseAuctionMessage(uint32_t houseId, HouseAuctionType type, uint8_t index, bool bidSuccess); From 8b3e60f848bab14aea39b577eed22e33fabe538e Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Sun, 27 Oct 2024 02:12:15 -0300 Subject: [PATCH 03/28] sonar issues --- src/creatures/players/player.hpp | 2 +- src/game/game.cpp | 10 ++-- src/game/game.hpp | 2 +- src/map/house/house.cpp | 38 +++++++------- src/map/house/house.hpp | 52 ++++++++++---------- src/server/network/protocol/protocolgame.cpp | 5 +- 6 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index dedf6b9d119..b3fb4ed79d9 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -1584,7 +1584,7 @@ class Player final : public Creature, public Cylinder, public Bankable { } BidErrorMessage canBidHouse(uint32_t houseId); - void sendCyclopediaHouseList(HouseMap houses) { + void sendCyclopediaHouseList(const HouseMap &houses) { if (client) { client->sendCyclopediaHouseList(houses); } diff --git a/src/game/game.cpp b/src/game/game.cpp index 612aae6c297..f1e58285a20 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10241,7 +10241,7 @@ bool Game::removeFiendishMonster(uint32_t id, bool create /* = true*/) { } void Game::updateForgeableMonsters() { - if (auto influencedLimit = g_configManager().getNumber(FORGE_INFLUENCED_CREATURES_LIMIT, __FUNCTION__); + if (auto influencedLimit = g_configManager().getNumber(FORGE_INFLUENCED_CREATURES_LIMIT); forgeableMonsters.size() < influencedLimit * 2) { forgeableMonsters.clear(); for (const auto &[monsterId, monster] : monsters) { @@ -10740,7 +10740,7 @@ const std::unordered_map &Game::getHirelingOutfits() { return m_hirelingOutfits; } -void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string townName) { +void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string &townName) { std::shared_ptr player = getPlayerByID(playerId); if (!player) { return; @@ -10756,7 +10756,7 @@ void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string tow return; } - const std::string houseTown = town->getName(); + const std::string &houseTown = town->getName(); if (houseTown == townName) { houses.emplace(house->getClientId(), house); } @@ -10781,7 +10781,7 @@ void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string tow } void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_t bidValue) { - if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION, __FUNCTION__)) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { return; } @@ -10846,7 +10846,7 @@ void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_ } void Game::playerCyclopediaHouseLeave(uint32_t playerId, uint32_t houseId, uint32_t timestamp) { - if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION, __FUNCTION__)) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { return; } diff --git a/src/game/game.hpp b/src/game/game.hpp index 1b0b9b369d3..5258d0f1fc6 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -316,7 +316,7 @@ class Game { static std::string getSkillNameById(uint8_t &skill); // House Auction - void playerCyclopediaHousesByTown(uint32_t playerId, const std::string townName); + void playerCyclopediaHousesByTown(uint32_t playerId, const std::string &townName); void playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_t bidValue); void playerCyclopediaHouseLeave(uint32_t playerId, uint32_t houseId, uint32_t timestamp); bool processBankAuction(std::shared_ptr player, std::shared_ptr house, uint64_t bid, bool replace = false); diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index f9cfe5f995c..9a140ee9b65 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -105,7 +105,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, std::shared } if (guid != 0) { - std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD, __FUNCTION__)); + std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD)); time_t currentTime = time(nullptr); if (strRentPeriod == "yearly") { currentTime += 24 * 60 * 60 * 365; @@ -140,7 +140,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, std::shared owner = guid; ownerName = name; ownerAccountId = result->getNumber("account_id"); - state = 2; + m_state = 2; } } @@ -155,14 +155,14 @@ void House::updateDoorDescription() const { ss << "It belongs to house '" << houseName << "'. Nobody owns this house."; } - if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION, __FUNCTION__)) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { ss << " It is " << getSize() << " square meters."; const int32_t housePrice = getPrice(); if (housePrice != -1) { - if (g_configManager().getBoolean(HOUSE_PURSHASED_SHOW_PRICE, __FUNCTION__) || owner == 0) { + if (g_configManager().getBoolean(HOUSE_PURSHASED_SHOW_PRICE) || owner == 0) { ss << " It costs " << formatNumber(getPrice()) << " gold coins."; } - std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD, __FUNCTION__)); + std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD)); if (strRentPeriod != "never") { ss << " The rent cost is " << formatNumber(getRent()) << " gold coins and it is billed " << strRentPeriod << "."; } @@ -484,7 +484,7 @@ void House::resetTransferItem() { void House::calculateBidEndDate(uint8_t daysToEnd) { auto currentTimeMs = std::chrono::system_clock::now().time_since_epoch(); - std::chrono::system_clock::time_point now = std::chrono::system_clock::time_point( + auto now = std::chrono::system_clock::time_point( std::chrono::duration_cast(currentTimeMs) ); @@ -492,11 +492,11 @@ void House::calculateBidEndDate(uint8_t daysToEnd) { days daysSinceEpoch = std::chrono::duration_cast(now.time_since_epoch()); // Get today's date at 00:00:00 UTC - std::chrono::system_clock::time_point todayMidnight = std::chrono::system_clock::time_point(daysSinceEpoch); + auto todayMidnight = std::chrono::system_clock::time_point(daysSinceEpoch); std::chrono::system_clock::time_point targetDay = todayMidnight + days(daysToEnd); - const auto serverSaveTime = g_configManager().getString(GLOBAL_SERVER_SAVE_TIME, __FUNCTION__); + const auto serverSaveTime = g_configManager().getString(GLOBAL_SERVER_SAVE_TIME); std::vector params = vectorAtoi(explodeString(serverSaveTime, ":")); int32_t hour = params.front(); @@ -513,9 +513,9 @@ void House::calculateBidEndDate(uint8_t daysToEnd) { std::time_t resultTime = std::chrono::system_clock::to_time_t(targetTime); std::tm* localTime = std::localtime(&resultTime); - uint32_t bidEndDate = static_cast(std::mktime(localTime)); + auto bidEndDate = static_cast(std::mktime(localTime)); - this->bidEndDate = bidEndDate; + this->m_bidEndDate = bidEndDate; } std::shared_ptr HouseTransferItem::createHouseTransferItem(std::shared_ptr house) { @@ -766,18 +766,18 @@ std::shared_ptr Houses::getHouseByPlayerId(uint32_t playerId) { std::vector> Houses::getAllHousesByPlayerId(uint32_t playerId) { std::vector> playerHouses; - for (const auto &it : houseMap) { - if (it.second->getOwner() == playerId) { - playerHouses.emplace_back(it.second); + for (const auto &[id, house] : houseMap) { + if (house->getOwner() == playerId) { + playerHouses.emplace_back(house); } } return playerHouses; } -std::shared_ptr Houses::getHouseByBidderName(std::string bidderName) { - for (const auto &it : houseMap) { - if (it.second->getBidderName() == bidderName) { - return it.second; +std::shared_ptr Houses::getHouseByBidderName(const std::string &bidderName) { + for (const auto &[id, house] : houseMap) { + if (house->getBidderName() == bidderName) { + return house; } } return nullptr; @@ -785,8 +785,8 @@ std::shared_ptr Houses::getHouseByBidderName(std::string bidderName) { uint16_t Houses::getHouseCountByAccount(uint32_t accountId) { uint16_t count = 0; - for (const auto &it : houseMap) { - if (it.second->getOwnerAccountId() == accountId) { + for (const auto &[id, house] : houseMap) { + if (house->getOwnerAccountId() == accountId) { ++count; } } diff --git a/src/map/house/house.hpp b/src/map/house/house.hpp index c763e5de595..8aefbf7002b 100644 --- a/src/map/house/house.hpp +++ b/src/map/house/house.hpp @@ -236,60 +236,60 @@ class House : public SharedObject { void setNewOwnership(); void setClientId(uint32_t newClientId) { - this->clientId = newClientId; + this->m_clientId = newClientId; } uint32_t getClientId() const { - return clientId; + return m_clientId; } void setBidder(int32_t bidder) { - this->bidder = bidder; + this->m_bidder = bidder; } int32_t getBidder() const { - return bidder; + return m_bidder; } - void setBidderName(std::string bidderName) { - this->bidderName = bidderName; + void setBidderName(const std::string &bidderName) { + this->m_bidderName = bidderName; } std::string getBidderName() const { - return bidderName; + return m_bidderName; } void setHighestBid(uint64_t bidValue) { - this->highestBid = bidValue; + this->m_highestBid = bidValue; } uint64_t getHighestBid() const { - return highestBid; + return m_highestBid; } void setInternalBid(uint64_t bidValue) { - this->internalBid = bidValue; + this->m_internalBid = bidValue; } uint64_t getInternalBid() const { - return internalBid; + return m_internalBid; } void setBidHolderLimit(uint64_t bidValue) { - this->bidHolderLimit = bidValue; + this->m_bidHolderLimit = bidValue; } uint64_t getBidHolderLimit() const { - return bidHolderLimit; + return m_bidHolderLimit; } void calculateBidEndDate(uint8_t daysToEnd); void setBidEndDate(uint32_t bidEndDate) { - this->bidEndDate = bidEndDate; + this->m_bidEndDate = bidEndDate; }; uint32_t getBidEndDate() const { - return bidEndDate; + return m_bidEndDate; } void setState(uint8_t state) { - this->state = state; + this->m_state = state; } uint8_t getState() const { - return state; + return m_state; } void setOwnerAccountId(uint32_t accountId) { @@ -341,14 +341,14 @@ class House : public SharedObject { Position posEntry = {}; // House Auction - uint32_t clientId; - int32_t bidder = 0; - std::string bidderName = ""; - uint64_t highestBid = 0; - uint64_t internalBid = 0; - uint64_t bidHolderLimit = 0; - uint32_t bidEndDate = 0; - uint8_t state = 0; + uint32_t m_clientId; + int32_t m_bidder = 0; + std::string m_bidderName = ""; + uint64_t m_highestBid = 0; + uint64_t m_internalBid = 0; + uint64_t m_bidHolderLimit = 0; + uint32_t m_bidEndDate = 0; + uint8_t m_state = 0; bool isLoaded = false; @@ -401,7 +401,7 @@ class Houses { std::shared_ptr getHouseByPlayerId(uint32_t playerId); std::vector> getAllHousesByPlayerId(uint32_t playerId); - std::shared_ptr getHouseByBidderName(std::string bidderName); + std::shared_ptr getHouseByBidderName(const std::string &bidderName); uint16_t getHouseCountByAccount(uint32_t accountId); bool loadHousesXML(const std::string &filename); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 2fa8a4b3a4b..2be8e4148cf 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -9295,10 +9295,7 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { NetworkMessage msg; msg.addByte(0xC7); msg.add(houses.size()); - for (const auto &house : houses) { - const auto clientId = house.first; - const auto &houseData = house.second; - + for (const auto &[clientId, houseData] : houses) { msg.add(clientId); msg.addByte(0x01); // 0x00 = Renovation; 0x01 = Available From bf2260295641a1f4592b8ba2210d869bc2200f35 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Mon, 28 Oct 2024 00:27:18 -0300 Subject: [PATCH 04/28] revert --- src/game/game.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index f1e58285a20..c45d9efa513 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10241,18 +10241,15 @@ bool Game::removeFiendishMonster(uint32_t id, bool create /* = true*/) { } void Game::updateForgeableMonsters() { - if (auto influencedLimit = g_configManager().getNumber(FORGE_INFLUENCED_CREATURES_LIMIT); - forgeableMonsters.size() < influencedLimit * 2) { - forgeableMonsters.clear(); - for (const auto &[monsterId, monster] : monsters) { - auto monsterTile = monster->getTile(); - if (!monsterTile) { - continue; - } + forgeableMonsters.clear(); + for (const auto &[monsterId, monster] : monsters) { + auto monsterTile = monster->getTile(); + if (!monsterTile) { + continue; + } - if (monster->canBeForgeMonster() && !monsterTile->hasFlag(TILESTATE_NOLOGOUT)) { - forgeableMonsters.push_back(monster->getID()); - } + if (monster->canBeForgeMonster() && !monsterTile->hasFlag(TILESTATE_NOLOGOUT)) { + forgeableMonsters.push_back(monster->getID()); } } From 75fc10d197f9a4a6a65e5a5e4bf48b406d4f7bd8 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Tue, 29 Oct 2024 19:16:39 -0300 Subject: [PATCH 05/28] fix: load state into house object --- src/io/iomapserialize.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index 1e5bed79d78..8313e2c26ac 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -326,6 +326,7 @@ bool IOMapSerialize::loadHouseInfo() { house->setInternalBid(internalBid); house->setBidHolderLimit(internalBid); house->setBidEndDate(bidEndDate); + house->setState(state); } } while (result->next()); From f6a76ff555be1682daa122555633ec7f0e8b157b Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Tue, 29 Oct 2024 22:15:14 -0300 Subject: [PATCH 06/28] feat: show move out info --- src/game/game.cpp | 25 +++++++++++++++++++- src/game/game.hpp | 3 ++- src/server/network/protocol/protocolgame.cpp | 23 +++++++++++++++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 4603e36a0dc..6f39e567cdd 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10842,7 +10842,7 @@ void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_ playerCyclopediaHousesByTown(playerId, houseTown); } -void Game::playerCyclopediaHouseLeave(uint32_t playerId, uint32_t houseId, uint32_t timestamp) { +void Game::playerCyclopediaHouseMoveOut(uint32_t playerId, uint32_t houseId, uint32_t timestamp) { if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { return; } @@ -10859,6 +10859,29 @@ void Game::playerCyclopediaHouseLeave(uint32_t playerId, uint32_t houseId, uint3 house->setBidEndDate(timestamp); house->setBidder(-1); + house->setState(4); + + playerCyclopediaHousesByTown(playerId, ""); +} + +void Game::playerCyclopediaHouseCancelMoveOut(uint32_t playerId, uint32_t houseId) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { + return; + } + + std::shared_ptr player = getPlayerByID(playerId); + if (!player) { + return; + } + + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house || house->getOwner() != player->getGUID()) { + return; + } + + house->setBidEndDate(0); + house->setBidder(0); + house->setState(2); playerCyclopediaHousesByTown(playerId, ""); } diff --git a/src/game/game.hpp b/src/game/game.hpp index 5258d0f1fc6..82eecf53812 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -318,7 +318,8 @@ class Game { // House Auction void playerCyclopediaHousesByTown(uint32_t playerId, const std::string &townName); void playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_t bidValue); - void playerCyclopediaHouseLeave(uint32_t playerId, uint32_t houseId, uint32_t timestamp); + void playerCyclopediaHouseMoveOut(uint32_t playerId, uint32_t houseId, uint32_t timestamp); + void playerCyclopediaHouseCancelMoveOut(uint32_t playerId, uint32_t houseId); bool processBankAuction(std::shared_ptr player, std::shared_ptr house, uint64_t bid, bool replace = false); void updatePlayerSaleItems(uint32_t playerId); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 2be8e4148cf..0c82f145fd8 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -9267,6 +9267,7 @@ void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage &msg) { } uint8_t houseActionType = msg.getByte(); + g_logger().warn("houseActionType {}", houseActionType); switch (houseActionType) { case 0: { const auto townName = msg.getString(); @@ -9282,12 +9283,17 @@ void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage &msg) { case 2: { const uint32_t houseId = msg.get(); const uint32_t timestamp = msg.get(); - g_game().playerCyclopediaHouseLeave(player->getID(), houseId, timestamp); + g_game().playerCyclopediaHouseMoveOut(player->getID(), houseId, timestamp); break; } case 3: { break; } + case 4: { + const uint32_t houseId = msg.get(); + g_game().playerCyclopediaHouseCancelMoveOut(player->getID(), houseId); + break; + } } } @@ -9325,6 +9331,21 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { msg.addByte(0); msg.addByte(0); } + } else if (houseData->getState() == 4) { // Move Out + auto ownerName = IOLoginData::getNameByGuid(houseData->getOwner()); + msg.addString(ownerName); + msg.add(houseData->getPaidUntil()); + + bool isOwner = ownerName.compare(player->getName()) == 0; + msg.addByte(isOwner); + if (isOwner) { + msg.addByte(0); // ? + msg.addByte(0); // ? + msg.add(houseData->getBidEndDate()); + msg.addByte(0); + } else { + msg.add(houseData->getBidEndDate()); + } } } From d27a2462def12a48c24fecd5f2f1003b4f99eb24 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Tue, 29 Oct 2024 23:53:07 -0300 Subject: [PATCH 07/28] fix days to end bid --- src/game/game.cpp | 2 +- src/server/network/protocol/protocolgame.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 6f39e567cdd..b49130a3407 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10809,7 +10809,7 @@ void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_ house->setBidHolderLimit(bidValue); house->setBidderName(player->getName()); house->setBidder(player->getGUID()); - house->calculateBidEndDate(1); + house->calculateBidEndDate(7); } else if (house->getBidderName() == player->getName()) { if (!processBankAuction(player, house, bidValue, true)) { player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(ret)); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 0c82f145fd8..a4031e097d0 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -9267,7 +9267,6 @@ void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage &msg) { } uint8_t houseActionType = msg.getByte(); - g_logger().warn("houseActionType {}", houseActionType); switch (houseActionType) { case 0: { const auto townName = msg.getString(); From 6a35471b46602000480d78e87b337b922ea91ed0 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 02:36:36 -0300 Subject: [PATCH 08/28] fix load house logic --- src/game/game.cpp | 8 +++----- src/game/game.hpp | 2 +- src/io/iomapserialize.cpp | 11 +++++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index eaaffb05059..915128d6388 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10904,12 +10904,11 @@ void Game::playerCyclopediaHouseMoveOut(uint32_t playerId, uint32_t houseId, uin } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != player->getGUID()) { + if (!house || house->getOwner() != player->getGUID() || house->getState() != 2) { return; } house->setBidEndDate(timestamp); - house->setBidder(-1); house->setState(4); playerCyclopediaHousesByTown(playerId, ""); @@ -10926,18 +10925,17 @@ void Game::playerCyclopediaHouseCancelMoveOut(uint32_t playerId, uint32_t houseI } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != player->getGUID()) { + if (!house || house->getOwner() != player->getGUID() || house->getState() != 4) { return; } house->setBidEndDate(0); - house->setBidder(0); house->setState(2); playerCyclopediaHousesByTown(playerId, ""); } -bool Game::processBankAuction(std::shared_ptr player, std::shared_ptr house, uint64_t bid, bool replace /* = false*/) { +bool Game::processBankAuction(std::shared_ptr player, const std::shared_ptr &house, uint64_t bid, bool replace /* = false*/) { if (!replace && player->getBankBalance() < (house->getRent() + bid)) { return false; } diff --git a/src/game/game.hpp b/src/game/game.hpp index 99790ce2f67..a631619f7ae 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -320,7 +320,7 @@ class Game { void playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_t bidValue); void playerCyclopediaHouseMoveOut(uint32_t playerId, uint32_t houseId, uint32_t timestamp); void playerCyclopediaHouseCancelMoveOut(uint32_t playerId, uint32_t houseId); - bool processBankAuction(std::shared_ptr player, std::shared_ptr house, uint64_t bid, bool replace = false); + bool processBankAuction(std::shared_ptr player, const std::shared_ptr &house, uint64_t bid, bool replace = false); void updatePlayerSaleItems(uint32_t playerId); diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index ef6fb1beee4..562aa02a0d7 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -300,25 +300,25 @@ bool IOMapSerialize::loadHouseInfo() { g_logger().debug("Setting house id '{}' owner to player GUID '{}'", houseId, newOwner); house->setOwner(newOwner); } - } else if (state == 0 && bidder > 0 && timeNow > bidEndDate) { + } else if (state == 0 && timeNow > bidEndDate && bidder > 0) { // Available + g_logger().debug("[BID] - Setting house id '{}' owner to player GUID '{}'", houseId, bidder); if (highestBid < internalBid) { uint32_t diff = internalBid - highestBid; IOLoginData::increaseBankBalance(bidder, diff); } - g_logger().debug("Setting house id '{}' owner to player GUID '{}'", houseId, bidder); house->setOwner(bidder); bidder = 0; bidderName = ""; highestBid = 0; internalBid = 0; bidEndDate = 0; - } else if (state == 2 && bidder == -1 && timeNow > bidEndDate) { - g_logger().debug("Removing house id '{}' owner", houseId); + } else if (state == 4 && timeNow > bidEndDate) { // Move Out + g_logger().debug("[MOVE OUT] - Removing house id '{}' owner", houseId); house->setOwner(0); bidEndDate = 0; - bidder = 0; } else { house->setOwner(owner, false); + house->setState(state); } house->setBidder(bidder); house->setBidderName(bidderName); @@ -326,7 +326,6 @@ bool IOMapSerialize::loadHouseInfo() { house->setInternalBid(internalBid); house->setBidHolderLimit(internalBid); house->setBidEndDate(bidEndDate); - house->setState(state); } } while (result->next()); From e057cd046a5e799489b9759f5034c9e7f8adc95c Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:42:00 -0300 Subject: [PATCH 09/28] feat: transfer --- data-otservbr-global/migrations/46.lua | 1 + src/enums/player_cyclopedia.hpp | 7 ++ src/game/game.cpp | 121 +++++++++++++++++-- src/game/game.hpp | 4 + src/io/iomapserialize.cpp | 30 +++-- src/map/house/house.cpp | 4 +- src/map/house/house.hpp | 15 ++- src/server/network/protocol/protocolgame.cpp | 57 ++++++++- 8 files changed, 213 insertions(+), 26 deletions(-) diff --git a/data-otservbr-global/migrations/46.lua b/data-otservbr-global/migrations/46.lua index 600bb3785ad..d1709730493 100644 --- a/data-otservbr-global/migrations/46.lua +++ b/data-otservbr-global/migrations/46.lua @@ -17,6 +17,7 @@ function onUpdateDatabase() ADD `internal_bid` int(11) NOT NULL DEFAULT '0', ADD `bid_end_date` int(11) NOT NULL DEFAULT '0', ADD `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0' + ADD `transfer_status` tinyint(1) DEFAULT '0' ]]) db.query([[ diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index 57c0c3d9176..3c515df8b66 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -61,6 +61,13 @@ enum class CyclopediaMapData_t : uint8_t { SetCurrentArea = 10, }; +enum class CyclopediaHouseState : uint8_t { + Available = 0, + Rented = 2, + Transfer = 3, + MoveOut = 4, +}; + enum class HouseAuctionType : uint8_t { Bid = 1, MoveOut = 2, diff --git a/src/game/game.cpp b/src/game/game.cpp index 915128d6388..63a5dc4df98 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10818,11 +10818,11 @@ void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string &to } houses.emplace(playerHouse->getClientId(), playerHouse); } - } else { - const auto house = g_game().map.houses.getHouseByBidderName(player->getName()); - if (house) { - houses.emplace(house->getClientId(), house); - } + } + + const auto house = g_game().map.houses.getHouseByBidderName(player->getName()); + if (house) { + houses.emplace(house->getClientId(), house); } } player->sendCyclopediaHouseList(houses); @@ -10904,12 +10904,12 @@ void Game::playerCyclopediaHouseMoveOut(uint32_t playerId, uint32_t houseId, uin } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != player->getGUID() || house->getState() != 2) { + if (!house || house->getOwner() != player->getGUID() || house->getState() != CyclopediaHouseState::Rented) { return; } house->setBidEndDate(timestamp); - house->setState(4); + house->setState(CyclopediaHouseState::MoveOut); playerCyclopediaHousesByTown(playerId, ""); } @@ -10925,12 +10925,115 @@ void Game::playerCyclopediaHouseCancelMoveOut(uint32_t playerId, uint32_t houseI } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != player->getGUID() || house->getState() != 4) { + if (!house || house->getOwner() != player->getGUID() || house->getState() != CyclopediaHouseState::MoveOut) { + return; + } + + house->setBidEndDate(0); + house->setState(CyclopediaHouseState::Rented); + + playerCyclopediaHousesByTown(playerId, ""); +} + +void Game::playerCyclopediaHouseTransfer(uint32_t playerId, uint32_t houseId, uint32_t timestamp, const std::string &newOwnerName, uint64_t bidValue) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { + return; + } + + const std::shared_ptr &owner = getPlayerByID(playerId); + if (!owner) { + return; + } + + const std::shared_ptr &newOwner = getPlayerByName(newOwnerName, true); + if (!newOwner) { + return; + } + + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house || house->getOwner() != owner->getGUID() || house->getState() != CyclopediaHouseState::Rented) { + return; + } + + house->setBidderName(newOwnerName); + house->setBidder(newOwner->getGUID()); + house->setInternalBid(bidValue); + house->setBidEndDate(timestamp); + house->setState(CyclopediaHouseState::Transfer); + + playerCyclopediaHousesByTown(playerId, ""); +} + +void Game::playerCyclopediaHouseCancelTransfer(uint32_t playerId, uint32_t houseId) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { + return; + } + + const std::shared_ptr &player = getPlayerByID(playerId); + if (!player) { + return; + } + + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house || house->getOwner() != player->getGUID() || house->getState() != CyclopediaHouseState::Transfer) { + return; + } + + house->setBidderName(""); + house->setBidder(0); + house->setInternalBid(0); + house->setBidEndDate(0); + house->setState(CyclopediaHouseState::Rented); + house->setTransferStatus(false); + + playerCyclopediaHousesByTown(playerId, ""); +} + +void Game::playerCyclopediaHouseAcceptTransfer(uint32_t playerId, uint32_t houseId) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { + return; + } + + const std::shared_ptr &player = getPlayerByID(playerId); + if (!player) { + return; + } + + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house || house->getBidder() != player->getGUID() || house->getState() != CyclopediaHouseState::Transfer) { + return; + } + + if (!processBankAuction(player, house, house->getInternalBid())) { + return; + } + + house->setTransferStatus(true); + + playerCyclopediaHousesByTown(playerId, ""); +} + +void Game::playerCyclopediaHouseRejectTransfer(uint32_t playerId, uint32_t houseId) { + if (!g_configManager().getBoolean(CYCLOPEDIA_HOUSE_AUCTION)) { + return; + } + + const std::shared_ptr &player = getPlayerByID(playerId); + if (!player) { + return; + } + + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house || house->getBidder() != player->getGUID() || house->getState() != CyclopediaHouseState::Transfer) { return; } + house->setBidderName(""); + house->setBidder(0); + house->setInternalBid(0); house->setBidEndDate(0); - house->setState(2); + house->setState(CyclopediaHouseState::Rented); + house->setTransferStatus(false); playerCyclopediaHousesByTown(playerId, ""); } diff --git a/src/game/game.hpp b/src/game/game.hpp index a631619f7ae..dea774b295c 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -320,6 +320,10 @@ class Game { void playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_t bidValue); void playerCyclopediaHouseMoveOut(uint32_t playerId, uint32_t houseId, uint32_t timestamp); void playerCyclopediaHouseCancelMoveOut(uint32_t playerId, uint32_t houseId); + void playerCyclopediaHouseTransfer(uint32_t playerId, uint32_t houseId, uint32_t timestamp, const std::string &newOwnerName, uint64_t bidValue); + void playerCyclopediaHouseCancelTransfer(uint32_t playerId, uint32_t houseId); + void playerCyclopediaHouseAcceptTransfer(uint32_t playerId, uint32_t houseId); + void playerCyclopediaHouseRejectTransfer(uint32_t playerId, uint32_t houseId); bool processBankAuction(std::shared_ptr player, const std::shared_ptr &house, uint64_t bid, bool replace = false); void updatePlayerSaleItems(uint32_t playerId); diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index 562aa02a0d7..2e3c0c9d16a 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -271,7 +271,7 @@ void IOMapSerialize::saveTile(PropWriteStream &stream, const std::shared_ptrgetNumber("highest_bid"); uint32_t internalBid = result->getNumber("internal_bid"); uint32_t bidEndDate = result->getNumber("bid_end_date"); - uint32_t state = result->getNumber("state"); - const auto timeNow = OTSYS_TIME(true); + auto state = static_cast(result->getNumber("state")); + const auto timeNow = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); // Transfer house owner auto isTransferOnRestart = g_configManager().getBoolean(TOGGLE_HOUSE_TRANSFER_ON_SERVER_RESTART); if (isTransferOnRestart && newOwner >= 0) { @@ -300,7 +300,7 @@ bool IOMapSerialize::loadHouseInfo() { g_logger().debug("Setting house id '{}' owner to player GUID '{}'", houseId, newOwner); house->setOwner(newOwner); } - } else if (state == 0 && timeNow > bidEndDate && bidder > 0) { // Available + } else if (state == CyclopediaHouseState::Available && timeNow > bidEndDate && bidder > 0) { g_logger().debug("[BID] - Setting house id '{}' owner to player GUID '{}'", houseId, bidder); if (highestBid < internalBid) { uint32_t diff = internalBid - highestBid; @@ -312,7 +312,20 @@ bool IOMapSerialize::loadHouseInfo() { highestBid = 0; internalBid = 0; bidEndDate = 0; - } else if (state == 4 && timeNow > bidEndDate) { // Move Out + } else if (state == CyclopediaHouseState::Transfer && timeNow > bidEndDate && bidder > 0) { + g_logger().debug("[TRANSFER] - Removing house id '{}' from owner GUID '{}' and transfering to new owner GUID '{}'", houseId, owner, bidder); + auto transferStatus = result->getNumber("transfer_status"); + if (transferStatus) { + house->setOwner(bidder); + IOLoginData::increaseBankBalance(owner, internalBid); + } else { + house->setOwner(owner); + } + bidder = 0; + bidderName = ""; + internalBid = 0; + bidEndDate = 0; + } else if (state == CyclopediaHouseState::MoveOut && timeNow > bidEndDate) { g_logger().debug("[MOVE OUT] - Removing house id '{}' owner", houseId); house->setOwner(0); bidEndDate = 0; @@ -357,11 +370,12 @@ bool IOMapSerialize::SaveHouseInfoGuard() { Database &db = Database::getInstance(); std::ostringstream query; - DBInsert houseUpdate("INSERT INTO `houses` (`id`, `owner`, `paid`, `warnings`, `name`, `town_id`, `rent`, `size`, `beds`, `bidder`, `bidder_name`, `highest_bid`, `internal_bid`, `bid_end_date`, `state`) VALUES "); - houseUpdate.upsert({ "owner", "paid", "warnings", "name", "town_id", "rent", "size", "beds", "bidder", "bidder_name", "highest_bid", "internal_bid", "bid_end_date", "state" }); + DBInsert houseUpdate("INSERT INTO `houses` (`id`, `owner`, `paid`, `warnings`, `name`, `town_id`, `rent`, `size`, `beds`, `bidder`, `bidder_name`, `highest_bid`, `internal_bid`, `bid_end_date`, `state`, `transfer_status`) VALUES "); + houseUpdate.upsert({ "owner", "paid", "warnings", "name", "town_id", "rent", "size", "beds", "bidder", "bidder_name", "highest_bid", "internal_bid", "bid_end_date", "state", "transfer_status" }); for (const auto &[key, house] : g_game().map.houses.getHouses()) { - std::string values = fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", house->getId(), house->getOwner(), house->getPaidUntil(), house->getPayRentWarnings(), db.escapeString(house->getName()), house->getTownId(), house->getRent(), house->getSize(), house->getBedCount(), house->getBidder(), db.escapeString(house->getBidderName()), house->getHighestBid(), house->getInternalBid(), house->getBidEndDate(), house->getState()); + auto stateValue = magic_enum::enum_integer(house->getState()); + std::string values = fmt::format("{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}", house->getId(), house->getOwner(), house->getPaidUntil(), house->getPayRentWarnings(), db.escapeString(house->getName()), house->getTownId(), house->getRent(), house->getSize(), house->getBedCount(), house->getBidder(), db.escapeString(house->getBidderName()), house->getHighestBid(), house->getInternalBid(), house->getBidEndDate(), std::to_string(stateValue), (house->getTransferStatus() ? 1 : 0)); if (!houseUpdate.addRow(values)) { return false; diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index 1c985cc562e..8fdbd4c9e7d 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -90,7 +90,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, const std:: Database &db = Database::getInstance(); std::ostringstream query; - query << "UPDATE `houses` SET `owner` = " << guid << ", `new_owner` = -1, `paid` = 0, `bidder` = 0, `bidder_name` = '', `highest_bid` = 0, `internal_bid` = 0, `bid_end_date` = 0, `state` = 0 WHERE `id` = " << id; + query << "UPDATE `houses` SET `owner` = " << guid << ", `new_owner` = -1, `paid` = 0, `bidder` = 0, `bidder_name` = '', `highest_bid` = 0, `internal_bid` = 0, `bid_end_date` = 0, `state` = " << (guid > 0 ? 2 : 0) << " WHERE `id` = " << id; db.executeQuery(query.str()); } @@ -140,7 +140,7 @@ void House::setOwner(uint32_t guid, bool updateDatabase /* = true*/, const std:: owner = guid; ownerName = name; ownerAccountId = result->getNumber("account_id"); - m_state = 2; + m_state = CyclopediaHouseState::Rented; } } diff --git a/src/map/house/house.hpp b/src/map/house/house.hpp index f67ecca5c6a..edbf6cced04 100644 --- a/src/map/house/house.hpp +++ b/src/map/house/house.hpp @@ -13,6 +13,7 @@ #include "declarations.hpp" #include "map/house/housetile.hpp" #include "game/movement/position.hpp" +#include "enums/player_cyclopedia.hpp" class House; class BedItem; @@ -285,13 +286,20 @@ class House final : public SharedObject { return m_bidEndDate; } - void setState(uint8_t state) { + void setState(CyclopediaHouseState state) { this->m_state = state; } - uint8_t getState() const { + CyclopediaHouseState getState() const { return m_state; } + void setTransferStatus(bool transferStatus) { + this->m_transferStatus = transferStatus; + } + bool getTransferStatus () const { + return m_transferStatus; + } + void setOwnerAccountId(uint32_t accountId) { this->ownerAccountId = accountId; } @@ -348,7 +356,8 @@ class House final : public SharedObject { uint64_t m_internalBid = 0; uint64_t m_bidHolderLimit = 0; uint32_t m_bidEndDate = 0; - uint8_t m_state = 0; + CyclopediaHouseState m_state = CyclopediaHouseState::Available; + bool m_transferStatus = false; bool isLoaded = false; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index ce36bdb2bd1..3816f82b3d1 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -39,6 +39,7 @@ #include "enums/account_group_type.hpp" #include "enums/account_coins.hpp" #include "enums/player_blessings.hpp" +#include "enums/player_cyclopedia.hpp" #include "creatures/players/highscore_category.hpp" @@ -9282,6 +9283,11 @@ void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage &msg) { break; } case 3: { + const uint32_t houseId = msg.get(); + const uint32_t timestamp = msg.get(); + const std::string &newOwner = msg.getString(); + const uint64_t bidValue = msg.get(); + g_game().playerCyclopediaHouseTransfer(player->getID(), houseId, timestamp, newOwner, bidValue); break; } case 4: { @@ -9289,6 +9295,21 @@ void ProtocolGame::parseCyclopediaHouseAuction(NetworkMessage &msg) { g_game().playerCyclopediaHouseCancelMoveOut(player->getID(), houseId); break; } + case 5: { + const uint32_t houseId = msg.get(); + g_game().playerCyclopediaHouseCancelTransfer(player->getID(), houseId); + break; + } + case 6: { + const uint32_t houseId = msg.get(); + g_game().playerCyclopediaHouseAcceptTransfer(player->getID(), houseId); + break; + } + case 7: { + const uint32_t houseId = msg.get(); + g_game().playerCyclopediaHouseRejectTransfer(player->getID(), houseId); + break; + } } } @@ -9300,8 +9321,10 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { msg.add(clientId); msg.addByte(0x01); // 0x00 = Renovation; 0x01 = Available - msg.addByte(houseData->getState()); - if (houseData->getState() == 0) { // Available + auto houseState = houseData->getState(); + auto stateValue = magic_enum::enum_integer(houseState); + msg.addByte(stateValue); + if (houseState == CyclopediaHouseState::Available) { bool bidder = houseData->getBidderName() == player->getName(); msg.addString(houseData->getBidderName()); msg.addByte(bidder ? 1 : 0); @@ -9315,7 +9338,7 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { msg.add(houseData->getBidHolderLimit()); } } - } else if (houseData->getState() == 2) { // Rented + } else if (houseState == CyclopediaHouseState::Rented) { auto ownerName = IOLoginData::getNameByGuid(houseData->getOwner()); msg.addString(ownerName); msg.add(houseData->getPaidUntil()); @@ -9326,7 +9349,33 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { msg.addByte(0); msg.addByte(0); } - } else if (houseData->getState() == 4) { // Move Out + } else if (houseState == CyclopediaHouseState::Transfer) { + auto ownerName = IOLoginData::getNameByGuid(houseData->getOwner()); + msg.addString(ownerName); + msg.add(houseData->getPaidUntil()); + + bool isOwner = ownerName.compare(player->getName()) == 0; + msg.addByte(isOwner); + if (isOwner) { + msg.addByte(0); // ? + msg.addByte(0); // ? + } + msg.add(houseData->getBidEndDate()); + msg.addString(houseData->getBidderName()); + msg.addByte(0); // ? + msg.add(houseData->getInternalBid()); + + bool isNewOwner = player->getName() == houseData->getBidderName(); + msg.addByte(isNewOwner); + if (isNewOwner) { + msg.addByte(0); // Accept Transfer Error + msg.addByte(0); // Reject Transfer Error + } + + if (isOwner) { + msg.addByte(0); // Cancel Transfer Error + } + } else if (houseState == CyclopediaHouseState::MoveOut) { auto ownerName = IOLoginData::getNameByGuid(houseData->getOwner()); msg.addString(ownerName); msg.add(houseData->getPaidUntil()); From 95c16ed88ceb31d40954f749176538a18341d9a5 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Oct 2024 19:00:12 +0000 Subject: [PATCH 10/28] Code format - (Clang-format) --- src/map/house/house.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map/house/house.hpp b/src/map/house/house.hpp index edbf6cced04..d994fdbe3b2 100644 --- a/src/map/house/house.hpp +++ b/src/map/house/house.hpp @@ -296,7 +296,7 @@ class House final : public SharedObject { void setTransferStatus(bool transferStatus) { this->m_transferStatus = transferStatus; } - bool getTransferStatus () const { + bool getTransferStatus() const { return m_transferStatus; } From 19ce3959123298b557630447accef48cdbb14745 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:02:28 -0300 Subject: [PATCH 11/28] missing column schema.sql --- schema.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/schema.sql b/schema.sql index 821b3bcff41..3b63cc67cb7 100644 --- a/schema.sql +++ b/schema.sql @@ -461,6 +461,7 @@ CREATE TABLE IF NOT EXISTS `houses` ( `internal_bid` int(11) NOT NULL DEFAULT '0', `bid_end_date` int(11) NOT NULL DEFAULT '0', `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0', + `transfer_status` tinyint(1) DEFAULT '0', INDEX `owner` (`owner`), INDEX `town_id` (`town_id`), CONSTRAINT `houses_pk` PRIMARY KEY (`id`) From 1a8c7617db4410f34f0197a3fb32dec24edf3182 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:24:46 -0300 Subject: [PATCH 12/28] some fixes --- src/game/game.cpp | 22 ++++++++++++++++++++++ src/io/iomapserialize.cpp | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 63a5dc4df98..bf05e2c7173 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10979,6 +10979,17 @@ void Game::playerCyclopediaHouseCancelTransfer(uint32_t playerId, uint32_t house return; } + if (house->getTransferStatus()) { + const auto &newOwner = getPlayerByGUID(house->getBidder()); + const auto amountPaid = house->getInternalBid() + house->getRent(); + if (newOwner) { + newOwner->setBankBalance(newOwner->getBankBalance() + amountPaid); + newOwner->sendResourceBalance(RESOURCE_BANK, newOwner->getBankBalance()); + } else { + IOLoginData::increaseBankBalance(house->getBidder(), amountPaid); + } + } + house->setBidderName(""); house->setBidder(0); house->setInternalBid(0); @@ -11028,6 +11039,17 @@ void Game::playerCyclopediaHouseRejectTransfer(uint32_t playerId, uint32_t house return; } + if (house->getTransferStatus()) { + const auto &newOwner = getPlayerByGUID(house->getBidder()); + const auto amountPaid = house->getInternalBid() + house->getRent(); + if (newOwner) { + newOwner->setBankBalance(newOwner->getBankBalance() + amountPaid); + newOwner->sendResourceBalance(RESOURCE_BANK, newOwner->getBankBalance()); + } else { + IOLoginData::increaseBankBalance(house->getBidder(), amountPaid); + } + } + house->setBidderName(""); house->setBidder(0); house->setInternalBid(0); diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index 2e3c0c9d16a..3857af533d0 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -288,6 +288,7 @@ bool IOMapSerialize::loadHouseInfo() { uint32_t internalBid = result->getNumber("internal_bid"); uint32_t bidEndDate = result->getNumber("bid_end_date"); auto state = static_cast(result->getNumber("state")); + auto transferStatus = result->getNumber("transfer_status"); const auto timeNow = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); // Transfer house owner auto isTransferOnRestart = g_configManager().getBoolean(TOGGLE_HOUSE_TRANSFER_ON_SERVER_RESTART); @@ -314,7 +315,6 @@ bool IOMapSerialize::loadHouseInfo() { bidEndDate = 0; } else if (state == CyclopediaHouseState::Transfer && timeNow > bidEndDate && bidder > 0) { g_logger().debug("[TRANSFER] - Removing house id '{}' from owner GUID '{}' and transfering to new owner GUID '{}'", houseId, owner, bidder); - auto transferStatus = result->getNumber("transfer_status"); if (transferStatus) { house->setOwner(bidder); IOLoginData::increaseBankBalance(owner, internalBid); @@ -325,6 +325,7 @@ bool IOMapSerialize::loadHouseInfo() { bidderName = ""; internalBid = 0; bidEndDate = 0; + transferStatus = false; } else if (state == CyclopediaHouseState::MoveOut && timeNow > bidEndDate) { g_logger().debug("[MOVE OUT] - Removing house id '{}' owner", houseId); house->setOwner(0); @@ -339,6 +340,7 @@ bool IOMapSerialize::loadHouseInfo() { house->setInternalBid(internalBid); house->setBidHolderLimit(internalBid); house->setBidEndDate(bidEndDate); + house->setTransferStatus(transferStatus); } } while (result->next()); From aab4b95727e78ca3fb8c5a148eb0d68051e43194 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:25:14 -0300 Subject: [PATCH 13/28] error handling --- src/creatures/players/player.cpp | 63 ++++++++++++++++++++ src/creatures/players/player.hpp | 2 + src/enums/player_cyclopedia.hpp | 29 +++++++++ src/game/game.cpp | 55 +++++++++++++++-- src/server/network/protocol/protocolgame.cpp | 3 +- 5 files changed, 146 insertions(+), 6 deletions(-) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 76b3b84fe1e..ca8107b4eb1 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -8304,3 +8304,66 @@ BidErrorMessage Player::canBidHouse(uint32_t houseId) { return BidErrorMessage::NoError; } + +TransferErrorMessage Player::canTransferHouse(uint32_t houseId, uint32_t newOwnerGUID) { + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house) { + return TransferErrorMessage::Internal; + } + + if (getGUID() != house->getOwner()) { + return TransferErrorMessage::NotHouseOwner; + } + + if (getGUID() == newOwnerGUID) { + return TransferErrorMessage::AlreadyTheOwner; + } + + const auto newOwner = g_game().getPlayerByGUID(newOwnerGUID, true); + if (!newOwner) { + return TransferErrorMessage::CharacterNotExist; + } + + if (newOwner->getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) { + return TransferErrorMessage::Rookgaard; + } + + if (!newOwner->isPremium()) { + return TransferErrorMessage::Premium; + } + + if (newOwner->getAccount()->getHouseBidId() != 0) { + return TransferErrorMessage::OnlyOneBid; + } + + return TransferErrorMessage::Success; +} + +AcceptTransferErrorMessage Player::canAcceptTransferHouse(uint32_t houseId) { + const auto house = g_game().map.houses.getHouseByClientId(houseId); + if (!house) { + return AcceptTransferErrorMessage::Internal; + } + + if (getGUID() != house->getBidder()) { + return AcceptTransferErrorMessage::NotNewOwner; + } + + if (!isPremium()) { + return AcceptTransferErrorMessage::Premium; + } + + if (getAccount()->getHouseBidId() != 0) { + return AcceptTransferErrorMessage::AlreadyBid; + } + + if (getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) { + return AcceptTransferErrorMessage::Rookgaard; + } + + if (house->getTransferStatus()) { + return AcceptTransferErrorMessage::AlreadyAccepted; + } + + return AcceptTransferErrorMessage::Success; +} \ No newline at end of file diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index fca0aedcaaf..de257a1717d 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -1576,6 +1576,8 @@ class Player final : public Creature, public Cylinder, public Bankable { } BidErrorMessage canBidHouse(uint32_t houseId); + TransferErrorMessage canTransferHouse(uint32_t houseId, uint32_t newOwnerGUID); + AcceptTransferErrorMessage canAcceptTransferHouse(uint32_t houseId); void sendCyclopediaHouseList(const HouseMap &houses) { if (client) { client->sendCyclopediaHouseList(houses); diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index 3c515df8b66..1a2813324ca 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -71,6 +71,11 @@ enum class CyclopediaHouseState : uint8_t { enum class HouseAuctionType : uint8_t { Bid = 1, MoveOut = 2, + Transfer = 3, + CancelMoveOut = 4, + CancelTransfer = 5, + AcceptTransfer = 6, + RejectTransfer = 7, }; enum class BidSuccessMessage : uint8_t { @@ -88,3 +93,27 @@ enum class BidErrorMessage : uint8_t { NotEnoughGuildMoney = 21, Internal = 24, }; + +// Bytes to: +// Move Out, Transfer +// Cancel Move Out/Transfer +enum class TransferErrorMessage : uint8_t { + Success = 0, + NotHouseOwner = 2, + CharacterNotExist = 4, + Premium = 7, + Rookgaard = 16, + AlreadyTheOwner = 19, + OnlyOneBid = 25, + Internal = 32, +}; + +enum class AcceptTransferErrorMessage : uint8_t { + Success = 0, + NotNewOwner = 2, + AlreadyBid = 3, + AlreadyAccepted = 7, + Rookgaard = 8, + Premium = 9, + Internal = 19, +}; \ No newline at end of file diff --git a/src/game/game.cpp b/src/game/game.cpp index bf05e2c7173..e2e0006ab0f 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10900,17 +10900,25 @@ void Game::playerCyclopediaHouseMoveOut(uint32_t playerId, uint32_t houseId, uin std::shared_ptr player = getPlayerByID(playerId); if (!player) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::MoveOut, enumToValue(TransferErrorMessage::Internal)); return; } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != player->getGUID() || house->getState() != CyclopediaHouseState::Rented) { + if (!house || house->getState() != CyclopediaHouseState::Rented) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::MoveOut, enumToValue(TransferErrorMessage::Internal)); + return; + } + + if (house->getOwner() != player->getGUID()) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::MoveOut, enumToValue(TransferErrorMessage::NotHouseOwner)); return; } house->setBidEndDate(timestamp); house->setState(CyclopediaHouseState::MoveOut); + player->sendHouseAuctionMessage(houseId, HouseAuctionType::MoveOut, enumToValue(TransferErrorMessage::Success)); playerCyclopediaHousesByTown(playerId, ""); } @@ -10921,17 +10929,25 @@ void Game::playerCyclopediaHouseCancelMoveOut(uint32_t playerId, uint32_t houseI std::shared_ptr player = getPlayerByID(playerId); if (!player) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelMoveOut, enumToValue(TransferErrorMessage::Internal)); return; } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != player->getGUID() || house->getState() != CyclopediaHouseState::MoveOut) { + if (!house || house->getState() != CyclopediaHouseState::MoveOut) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelMoveOut, enumToValue(TransferErrorMessage::Internal)); + return; + } + + if (house->getOwner() != player->getGUID()) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelMoveOut, enumToValue(TransferErrorMessage::NotHouseOwner)); return; } house->setBidEndDate(0); house->setState(CyclopediaHouseState::Rented); + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelMoveOut, enumToValue(TransferErrorMessage::Success)); playerCyclopediaHousesByTown(playerId, ""); } @@ -10942,16 +10958,25 @@ void Game::playerCyclopediaHouseTransfer(uint32_t playerId, uint32_t houseId, ui const std::shared_ptr &owner = getPlayerByID(playerId); if (!owner) { + owner->sendHouseAuctionMessage(houseId, HouseAuctionType::Transfer, enumToValue(TransferErrorMessage::Internal)); return; } const std::shared_ptr &newOwner = getPlayerByName(newOwnerName, true); if (!newOwner) { + owner->sendHouseAuctionMessage(houseId, HouseAuctionType::Transfer, enumToValue(TransferErrorMessage::CharacterNotExist)); return; } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != owner->getGUID() || house->getState() != CyclopediaHouseState::Rented) { + if (!house || house->getState() != CyclopediaHouseState::Rented) { + owner->sendHouseAuctionMessage(houseId, HouseAuctionType::Transfer, enumToValue(TransferErrorMessage::Internal)); + return; + } + + auto ret = owner->canTransferHouse(houseId, newOwner->getGUID()); + if (ret != TransferErrorMessage::Success) { + owner->sendHouseAuctionMessage(houseId, HouseAuctionType::Transfer, enumToValue(ret)); return; } @@ -10961,6 +10986,7 @@ void Game::playerCyclopediaHouseTransfer(uint32_t playerId, uint32_t houseId, ui house->setBidEndDate(timestamp); house->setState(CyclopediaHouseState::Transfer); + owner->sendHouseAuctionMessage(houseId, HouseAuctionType::Transfer, enumToValue(ret)); playerCyclopediaHousesByTown(playerId, ""); } @@ -10971,11 +10997,18 @@ void Game::playerCyclopediaHouseCancelTransfer(uint32_t playerId, uint32_t house const std::shared_ptr &player = getPlayerByID(playerId); if (!player) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelTransfer, enumToValue(TransferErrorMessage::Internal)); return; } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getOwner() != player->getGUID() || house->getState() != CyclopediaHouseState::Transfer) { + if (!house || house->getState() != CyclopediaHouseState::Transfer) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelTransfer, enumToValue(TransferErrorMessage::Internal)); + return; + } + + if (house->getOwner() != player->getGUID()) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelTransfer, enumToValue(TransferErrorMessage::NotHouseOwner)); return; } @@ -10997,6 +11030,7 @@ void Game::playerCyclopediaHouseCancelTransfer(uint32_t playerId, uint32_t house house->setState(CyclopediaHouseState::Rented); house->setTransferStatus(false); + player->sendHouseAuctionMessage(houseId, HouseAuctionType::CancelTransfer, enumToValue(TransferErrorMessage::Success)); playerCyclopediaHousesByTown(playerId, ""); } @@ -11007,11 +11041,18 @@ void Game::playerCyclopediaHouseAcceptTransfer(uint32_t playerId, uint32_t house const std::shared_ptr &player = getPlayerByID(playerId); if (!player) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::AcceptTransfer, enumToValue(AcceptTransferErrorMessage::Internal)); return; } const auto house = g_game().map.houses.getHouseByClientId(houseId); - if (!house || house->getBidder() != player->getGUID() || house->getState() != CyclopediaHouseState::Transfer) { + if (!house || house->getState() != CyclopediaHouseState::Transfer) { + return; + } + + auto ret = player->canAcceptTransferHouse(houseId); + if (ret != AcceptTransferErrorMessage::Success) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::AcceptTransfer, enumToValue(ret)); return; } @@ -11021,6 +11062,7 @@ void Game::playerCyclopediaHouseAcceptTransfer(uint32_t playerId, uint32_t house house->setTransferStatus(true); + player->sendHouseAuctionMessage(houseId, HouseAuctionType::AcceptTransfer, enumToValue(ret)); playerCyclopediaHousesByTown(playerId, ""); } @@ -11031,11 +11073,13 @@ void Game::playerCyclopediaHouseRejectTransfer(uint32_t playerId, uint32_t house const std::shared_ptr &player = getPlayerByID(playerId); if (!player) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::Transfer, enumToValue(TransferErrorMessage::Internal)); return; } const auto house = g_game().map.houses.getHouseByClientId(houseId); if (!house || house->getBidder() != player->getGUID() || house->getState() != CyclopediaHouseState::Transfer) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::Transfer, enumToValue(TransferErrorMessage::NotHouseOwner)); return; } @@ -11057,6 +11101,7 @@ void Game::playerCyclopediaHouseRejectTransfer(uint32_t playerId, uint32_t house house->setState(CyclopediaHouseState::Rented); house->setTransferStatus(false); + player->sendHouseAuctionMessage(houseId, HouseAuctionType::RejectTransfer, enumToValue(TransferErrorMessage::Success)); playerCyclopediaHousesByTown(playerId, ""); } diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 3816f82b3d1..78f5120eda7 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -9368,7 +9368,8 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { bool isNewOwner = player->getName() == houseData->getBidderName(); msg.addByte(isNewOwner); if (isNewOwner) { - msg.addByte(0); // Accept Transfer Error + uint8_t disableIndex = enumToValue(player->canAcceptTransferHouse(clientId)); + msg.addByte(disableIndex); // Accept Transfer Error msg.addByte(0); // Reject Transfer Error } From f53b628eac3c0937fab31d1456f70dfa77b3d5b3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Oct 2024 21:26:30 +0000 Subject: [PATCH 14/28] Code format - (Clang-format) --- src/creatures/players/player.cpp | 2 +- src/enums/player_cyclopedia.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index ca8107b4eb1..ae43e3e338e 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -8366,4 +8366,4 @@ AcceptTransferErrorMessage Player::canAcceptTransferHouse(uint32_t houseId) { } return AcceptTransferErrorMessage::Success; -} \ No newline at end of file +} diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index 1a2813324ca..9df484e417d 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -116,4 +116,4 @@ enum class AcceptTransferErrorMessage : uint8_t { Rookgaard = 8, Premium = 9, Internal = 19, -}; \ No newline at end of file +}; From f3667aacda218b530c43a34c4b41bbead3643e39 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:45:22 -0300 Subject: [PATCH 15/28] missing errors --- src/creatures/players/player.cpp | 4 ++++ src/enums/player_cyclopedia.hpp | 1 + src/game/game.cpp | 2 ++ src/server/network/protocol/protocolgame.cpp | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index ae43e3e338e..67b1587dd84 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -8361,6 +8361,10 @@ AcceptTransferErrorMessage Player::canAcceptTransferHouse(uint32_t houseId) { return AcceptTransferErrorMessage::Rookgaard; } + if (getBankBalance() < (house->getRent() + house->getInternalBid())) { + return AcceptTransferErrorMessage::Frozen; + } + if (house->getTransferStatus()) { return AcceptTransferErrorMessage::AlreadyAccepted; } diff --git a/src/enums/player_cyclopedia.hpp b/src/enums/player_cyclopedia.hpp index 9df484e417d..4d2227f8d48 100644 --- a/src/enums/player_cyclopedia.hpp +++ b/src/enums/player_cyclopedia.hpp @@ -115,5 +115,6 @@ enum class AcceptTransferErrorMessage : uint8_t { AlreadyAccepted = 7, Rookgaard = 8, Premium = 9, + Frozen = 15, Internal = 19, }; diff --git a/src/game/game.cpp b/src/game/game.cpp index e2e0006ab0f..121a598402d 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -11047,6 +11047,7 @@ void Game::playerCyclopediaHouseAcceptTransfer(uint32_t playerId, uint32_t house const auto house = g_game().map.houses.getHouseByClientId(houseId); if (!house || house->getState() != CyclopediaHouseState::Transfer) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::AcceptTransfer, enumToValue(AcceptTransferErrorMessage::Internal)); return; } @@ -11057,6 +11058,7 @@ void Game::playerCyclopediaHouseAcceptTransfer(uint32_t playerId, uint32_t house } if (!processBankAuction(player, house, house->getInternalBid())) { + player->sendHouseAuctionMessage(houseId, HouseAuctionType::AcceptTransfer, enumToValue(AcceptTransferErrorMessage::Frozen)); return; } diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 78f5120eda7..3bf79d51e64 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -9327,7 +9327,7 @@ void ProtocolGame::sendCyclopediaHouseList(HouseMap houses) { if (houseState == CyclopediaHouseState::Available) { bool bidder = houseData->getBidderName() == player->getName(); msg.addString(houseData->getBidderName()); - msg.addByte(bidder ? 1 : 0); + msg.addByte(bidder); uint8_t disableIndex = enumToValue(player->canBidHouse(clientId)); msg.addByte(disableIndex); From cbbdc2d4e79e5155dcf2d66c353244bb20d6d514 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 19:18:07 -0300 Subject: [PATCH 16/28] configurable days to close bid --- config.lua.dist | 1 + src/config/config_enums.hpp | 1 + src/config/configmanager.cpp | 1 + src/game/game.cpp | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config.lua.dist b/config.lua.dist index 5e8918452f5..7c891c84b5d 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -345,6 +345,7 @@ Setting this to false may pose risks; if a house is abandoned and contains a lar -- Periods: daily/weekly/monthly/yearly/never -- Base: sqm,rent,sqm+rent toggleCyclopediaHouseAuction = true +daysToCloseBid = 7 housePriceRentMultiplier = 0.0 housePriceEachSQM = 1000 houseRentPeriod = "monthly" diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index a3294d692dc..65e585159e8 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -111,6 +111,7 @@ enum ConfigKey_t : uint16_t { HAZARD_PODS_TIME_TO_DAMAGE, HAZARD_PODS_TIME_TO_SPAWN, HAZARD_SPAWN_PLUNDER_MULTIPLIER, + DAYS_TO_CLOSE_BID, HOUSE_BUY_LEVEL, HOUSE_LOSE_AFTER_INACTIVITY, HOUSE_OWNED_BY_ACCOUNT, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index f5bafa4fbc3..c060a44e07b 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -254,6 +254,7 @@ bool ConfigManager::load() { loadIntConfig(L, HAZARD_PODS_TIME_TO_DAMAGE, "hazardPodsTimeToDamage", 2000); loadIntConfig(L, HAZARD_PODS_TIME_TO_SPAWN, "hazardPodsTimeToSpawn", 4000); loadIntConfig(L, HAZARD_SPAWN_PLUNDER_MULTIPLIER, "hazardSpawnPlunderMultiplier", 25); + loadIntConfig(L, DAYS_TO_CLOSE_BID, "daysToCloseBid", 7); loadIntConfig(L, HOUSE_BUY_LEVEL, "houseBuyLevel", 0); loadIntConfig(L, HOUSE_LOSE_AFTER_INACTIVITY, "houseLoseAfterInactivity", 0); loadIntConfig(L, HOUSE_PRICE_PER_SQM, "housePriceEachSQM", 1000); diff --git a/src/game/game.cpp b/src/game/game.cpp index 121a598402d..97eff18b212 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10860,7 +10860,7 @@ void Game::playerCyclopediaHouseBid(uint32_t playerId, uint32_t houseId, uint64_ house->setBidHolderLimit(bidValue); house->setBidderName(player->getName()); house->setBidder(player->getGUID()); - house->calculateBidEndDate(7); + house->calculateBidEndDate(g_configManager().getNumber(DAYS_TO_CLOSE_BID)); } else if (house->getBidderName() == player->getName()) { if (!processBankAuction(player, house, bidValue, true)) { player->sendHouseAuctionMessage(houseId, HouseAuctionType::Bid, enumToValue(ret)); From 798ece791bda0170a9c8c61a8ad583dea079d054 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 19:48:23 -0300 Subject: [PATCH 17/28] fix compilation --- src/account/account.cpp | 4 ++-- src/creatures/players/player.cpp | 17 +++++++++++++ src/creatures/players/player.hpp | 25 ++++++++------------ src/server/network/protocol/protocolgame.cpp | 1 + src/server/network/protocol/protocolgame.hpp | 2 ++ 5 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/account/account.cpp b/src/account/account.cpp index 1a0419431e2..221e7fdb705 100644 --- a/src/account/account.cpp +++ b/src/account/account.cpp @@ -297,8 +297,8 @@ uint32_t Account::getAccountAgeInDays() const { } uint32_t Account::getHouseBidId() const { - return m_account.houseBidId; + return m_account->houseBidId; } void Account::setHouseBidId(uint32_t houseId) { - m_account.houseBidId = houseId; + m_account->houseBidId = houseId; } diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index fe611b0c2c7..6cb69074a85 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -36,6 +36,7 @@ #include "enums/object_category.hpp" #include "enums/player_blessings.hpp" #include "enums/player_icons.hpp" +#include "enums/player_cyclopedia.hpp" #include "game/game.hpp" #include "game/modal_window/modal_window.hpp" #include "game/scheduling/dispatcher.hpp" @@ -2264,6 +2265,22 @@ void Player::sendOutfitWindow() const { } } +void Player::sendCyclopediaHouseList(const HouseMap &houses) const { + if (client) { + client->sendCyclopediaHouseList(houses); + } +} +void Player::sendResourceBalance(Resource_t resourceType, uint64_t value) const { + if (client) { + client->sendResourceBalance(resourceType, value); + } +} +void Player::sendHouseAuctionMessage(uint32_t houseId, HouseAuctionType type, uint8_t index, bool bidSuccess /* = false*/) const { + if (client) { + client->sendHouseAuctionMessage(houseId, type, index, bidSuccess); + } +} + // Imbuements void Player::onApplyImbuement(const Imbuement* imbuement, const std::shared_ptr &item, uint8_t slot, bool protectionCharm) { diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 26f50137851..898e0b0e2b1 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -64,17 +64,23 @@ struct HighscoreCharacter; enum class PlayerIcon : uint8_t; enum class IconBakragore : uint8_t; +enum class HouseAuctionType : uint8_t; +enum class BidErrorMessage : uint8_t; +enum class TransferErrorMessage : uint8_t; +enum class AcceptTransferErrorMessage : uint8_t; enum ObjectCategory_t : uint8_t; enum PreySlot_t : uint8_t; enum SpeakClasses : uint8_t; enum ChannelEvent_t : uint8_t; enum SquareColor_t : uint8_t; +enum Resource_t : uint8_t; using GuildWarVector = std::vector; using StashContainerList = std::vector, uint32_t>>; using ItemVector = std::vector>; using UsersMap = std::map>; using InvitedMap = std::map>; +using HouseMap = std::map>; struct ForgeHistory { ForgeAction_t actionType = ForgeAction_t::FUSION; @@ -880,24 +886,13 @@ class Player final : public Creature, public Cylinder, public Bankable { void sendOpenPrivateChannel(const std::string &receiver) const; void sendExperienceTracker(int64_t rawExp, int64_t finalExp) const; void sendOutfitWindow() const; + // House Auction BidErrorMessage canBidHouse(uint32_t houseId); TransferErrorMessage canTransferHouse(uint32_t houseId, uint32_t newOwnerGUID); AcceptTransferErrorMessage canAcceptTransferHouse(uint32_t houseId); - void sendCyclopediaHouseList(const HouseMap &houses) { - if (client) { - client->sendCyclopediaHouseList(houses); - } - } - void sendResourceBalance(Resource_t resourceType, uint64_t value) { - if (client) { - client->sendResourceBalance(resourceType, value); - } - } - void sendHouseAuctionMessage(uint32_t houseId, HouseAuctionType type, uint8_t index, bool bidSuccess = false) { - if (client) { - client->sendHouseAuctionMessage(houseId, type, index, bidSuccess); - } - } + void sendCyclopediaHouseList(const HouseMap &houses) const; + void sendResourceBalance(Resource_t resourceType, uint64_t value) const; + void sendHouseAuctionMessage(uint32_t houseId, HouseAuctionType type, uint8_t index, bool bidSuccess = false) const; // Imbuements void onApplyImbuement(const Imbuement* imbuement, const std::shared_ptr &item, uint8_t slot, bool protectionCharm); void onClearImbuement(const std::shared_ptr &item, uint8_t slot); diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 242c5c83f41..1ef97af8c94 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -53,6 +53,7 @@ #include "enums/account_type.hpp" #include "enums/object_category.hpp" #include "enums/player_blessings.hpp" +#include "enums/player_cyclopedia.hpp" /* * NOTE: This namespace is used so that we can add functions without having to declare them in the ".hpp/.hpp" file diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index e42ae1d1ee8..22f135e05f1 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -29,6 +29,7 @@ enum Slots_t : uint8_t; enum CombatType_t : uint8_t; enum SoundEffect_t : uint16_t; enum class SourceEffect_t : uint8_t; +enum class HouseAuctionType : uint8_t; class NetworkMessage; class Player; @@ -68,6 +69,7 @@ using MarketOfferList = std::list; using HistoryMarketOfferList = std::list; using ItemsTierCountList = std::map>; using StashItemList = std::map; +using HouseMap = std::map>; struct TextMessage { TextMessage() = default; From da4398dba017dd74b8afbe20fa31b5d1ffc65eec Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:30:24 -0300 Subject: [PATCH 18/28] fix migration --- data-otservbr-global/migrations/46.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/migrations/46.lua b/data-otservbr-global/migrations/46.lua index d1709730493..dc79c7cee35 100644 --- a/data-otservbr-global/migrations/46.lua +++ b/data-otservbr-global/migrations/46.lua @@ -16,7 +16,7 @@ function onUpdateDatabase() ADD `highest_bid` int(11) NOT NULL DEFAULT '0', ADD `internal_bid` int(11) NOT NULL DEFAULT '0', ADD `bid_end_date` int(11) NOT NULL DEFAULT '0', - ADD `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0' + ADD `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0', ADD `transfer_status` tinyint(1) DEFAULT '0' ]]) From 6a5ecf2301c88bd17cf4d3bd10c54fbddb2f6c2b Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:41:12 -0300 Subject: [PATCH 19/28] sonar issue --- src/io/iomapserialize.cpp | 121 +++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index 0757095fc8e..c54f39f99b4 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -281,69 +281,72 @@ bool IOMapSerialize::loadHouseInfo() { do { auto houseId = result->getNumber("id"); const auto house = g_game().map.houses.getHouse(houseId); - if (house) { - auto owner = result->getNumber("owner"); - auto newOwner = result->getNumber("new_owner"); - uint32_t bidder = result->getNumber("bidder"); - std::string bidderName = result->getString("bidder_name"); - uint32_t highestBid = result->getNumber("highest_bid"); - uint32_t internalBid = result->getNumber("internal_bid"); - uint32_t bidEndDate = result->getNumber("bid_end_date"); - auto state = static_cast(result->getNumber("state")); - auto transferStatus = result->getNumber("transfer_status"); - const auto timeNow = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); - // Transfer house owner - auto isTransferOnRestart = g_configManager().getBoolean(TOGGLE_HOUSE_TRANSFER_ON_SERVER_RESTART); - if (isTransferOnRestart && newOwner >= 0) { - g_game().setTransferPlayerHouseItems(houseId, owner); - if (newOwner == 0) { - g_logger().debug("Removing house id '{}' owner", houseId); - house->setOwner(0); - } else { - g_logger().debug("Setting house id '{}' owner to player GUID '{}'", houseId, newOwner); - house->setOwner(newOwner); - } - } else if (state == CyclopediaHouseState::Available && timeNow > bidEndDate && bidder > 0) { - g_logger().debug("[BID] - Setting house id '{}' owner to player GUID '{}'", houseId, bidder); - if (highestBid < internalBid) { - uint32_t diff = internalBid - highestBid; - IOLoginData::increaseBankBalance(bidder, diff); - } - house->setOwner(bidder); - bidder = 0; - bidderName = ""; - highestBid = 0; - internalBid = 0; - bidEndDate = 0; - } else if (state == CyclopediaHouseState::Transfer && timeNow > bidEndDate && bidder > 0) { - g_logger().debug("[TRANSFER] - Removing house id '{}' from owner GUID '{}' and transfering to new owner GUID '{}'", houseId, owner, bidder); - if (transferStatus) { - house->setOwner(bidder); - IOLoginData::increaseBankBalance(owner, internalBid); - } else { - house->setOwner(owner); - } - bidder = 0; - bidderName = ""; - internalBid = 0; - bidEndDate = 0; - transferStatus = false; - } else if (state == CyclopediaHouseState::MoveOut && timeNow > bidEndDate) { - g_logger().debug("[MOVE OUT] - Removing house id '{}' owner", houseId); + if (!house) { + continue; + } + + auto owner = result->getNumber("owner"); + auto newOwner = result->getNumber("new_owner"); + uint32_t bidder = result->getNumber("bidder"); + std::string bidderName = result->getString("bidder_name"); + uint32_t highestBid = result->getNumber("highest_bid"); + uint32_t internalBid = result->getNumber("internal_bid"); + uint32_t bidEndDate = result->getNumber("bid_end_date"); + auto state = static_cast(result->getNumber("state")); + auto transferStatus = result->getNumber("transfer_status"); + const auto timeNow = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + + // Transfer house owner + auto isTransferOnRestart = g_configManager().getBoolean(TOGGLE_HOUSE_TRANSFER_ON_SERVER_RESTART); + if (isTransferOnRestart && newOwner >= 0) { + g_game().setTransferPlayerHouseItems(houseId, owner); + if (newOwner == 0) { + g_logger().debug("Removing house id '{}' owner", houseId); house->setOwner(0); - bidEndDate = 0; } else { - house->setOwner(owner, false); - house->setState(state); + g_logger().debug("Setting house id '{}' owner to player GUID '{}'", houseId, newOwner); + house->setOwner(newOwner); + } + } else if (state == CyclopediaHouseState::Available && timeNow > bidEndDate && bidder > 0) { + g_logger().debug("[BID] - Setting house id '{}' owner to player GUID '{}'", houseId, bidder); + if (highestBid < internalBid) { + uint32_t diff = internalBid - highestBid; + IOLoginData::increaseBankBalance(bidder, diff); + } + house->setOwner(bidder); + bidder = 0; + bidderName = ""; + highestBid = 0; + internalBid = 0; + bidEndDate = 0; + } else if (state == CyclopediaHouseState::Transfer && timeNow > bidEndDate && bidder > 0) { + g_logger().debug("[TRANSFER] - Removing house id '{}' from owner GUID '{}' and transfering to new owner GUID '{}'", houseId, owner, bidder); + if (transferStatus) { + house->setOwner(bidder); + IOLoginData::increaseBankBalance(owner, internalBid); + } else { + house->setOwner(owner); } - house->setBidder(bidder); - house->setBidderName(bidderName); - house->setHighestBid(highestBid); - house->setInternalBid(internalBid); - house->setBidHolderLimit(internalBid); - house->setBidEndDate(bidEndDate); - house->setTransferStatus(transferStatus); + bidder = 0; + bidderName = ""; + internalBid = 0; + bidEndDate = 0; + transferStatus = false; + } else if (state == CyclopediaHouseState::MoveOut && timeNow > bidEndDate) { + g_logger().debug("[MOVE OUT] - Removing house id '{}' owner", houseId); + house->setOwner(0); + bidEndDate = 0; + } else { + house->setOwner(owner, false); + house->setState(state); } + house->setBidder(bidder); + house->setBidderName(bidderName); + house->setHighestBid(highestBid); + house->setInternalBid(internalBid); + house->setBidHolderLimit(internalBid); + house->setBidEndDate(bidEndDate); + house->setTransferStatus(transferStatus); } while (result->next()); result = db.storeQuery("SELECT `house_id`, `listid`, `list` FROM `house_lists`"); From c75da854fe9589b2d86f3b1c8a253eed14f34d97 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:21:53 -0300 Subject: [PATCH 20/28] fix copy --- src/game/game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 1e2893bc371..20d11a9a155 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -10877,7 +10877,7 @@ void Game::playerCyclopediaHousesByTown(uint32_t playerId, const std::string &to } else { auto playerHouses = g_game().map.houses.getAllHousesByPlayerId(player->getGUID()); if (playerHouses.size()) { - for (const auto playerHouse : playerHouses) { + for (const auto &playerHouse : playerHouses) { if (!playerHouse) { continue; } From 1a2934de3dc5b53ce6d4f8df5b63355c1c350483 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 31 Oct 2024 03:32:00 +0000 Subject: [PATCH 21/28] Code format - (Clang-format) --- src/creatures/monsters/spawns/spawn_monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/creatures/monsters/spawns/spawn_monster.cpp b/src/creatures/monsters/spawns/spawn_monster.cpp index 153db66dee4..7d7bbc84e34 100644 --- a/src/creatures/monsters/spawns/spawn_monster.cpp +++ b/src/creatures/monsters/spawns/spawn_monster.cpp @@ -327,7 +327,7 @@ void SpawnMonster::scheduleSpawn(uint32_t spawnMonsterId, spawnBlock_t &sb, cons } void SpawnMonster::cleanup() { - for (auto it = spawnedMonsterMap.begin(); it != spawnedMonsterMap.end(); ) { + for (auto it = spawnedMonsterMap.begin(); it != spawnedMonsterMap.end();) { const auto &monster = it->second; if (!monster || monster->isRemoved()) { auto spawnIt = spawnMonsterMap.find(it->first); From 7370433f5809aba2f15230bf31290f468dd662b0 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:37:17 -0300 Subject: [PATCH 22/28] fix: using enum --- src/creatures/players/player.cpp | 51 +++++++++++++++++--------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 6cb69074a85..b42c3f17672 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -10448,103 +10448,106 @@ uint16_t Player::getPlayerVocationEnum() const { } BidErrorMessage Player::canBidHouse(uint32_t houseId) { + using enum BidErrorMessage; const auto house = g_game().map.houses.getHouseByClientId(houseId); if (!house) { - return BidErrorMessage::Internal; + return Internal; } if (getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) { - return BidErrorMessage::Rookgaard; + return Rookgaard; } if (!isPremium()) { - return BidErrorMessage::Premium; + return Premium; } if (getAccount()->getHouseBidId() != 0) { - return BidErrorMessage::OnlyOneBid; + return OnlyOneBid; } if (getBankBalance() < (house->getRent() + house->getHighestBid())) { - return BidErrorMessage::NotEnoughMoney; + return NotEnoughMoney; } if (house->isGuildhall()) { if (getGuildRank() && getGuildRank()->level != 3) { - return BidErrorMessage::Guildhall; + return Guildhall; } if (getGuild() && getGuild()->getBankBalance() < (house->getRent() + house->getHighestBid())) { - return BidErrorMessage::NotEnoughGuildMoney; + return NotEnoughGuildMoney; } } - return BidErrorMessage::NoError; + return NoError; } TransferErrorMessage Player::canTransferHouse(uint32_t houseId, uint32_t newOwnerGUID) { + using enum TransferErrorMessage; const auto house = g_game().map.houses.getHouseByClientId(houseId); if (!house) { - return TransferErrorMessage::Internal; + return Internal; } if (getGUID() != house->getOwner()) { - return TransferErrorMessage::NotHouseOwner; + return NotHouseOwner; } if (getGUID() == newOwnerGUID) { - return TransferErrorMessage::AlreadyTheOwner; + return AlreadyTheOwner; } const auto newOwner = g_game().getPlayerByGUID(newOwnerGUID, true); if (!newOwner) { - return TransferErrorMessage::CharacterNotExist; + return CharacterNotExist; } if (newOwner->getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) { - return TransferErrorMessage::Rookgaard; + return Rookgaard; } if (!newOwner->isPremium()) { - return TransferErrorMessage::Premium; + return Premium; } if (newOwner->getAccount()->getHouseBidId() != 0) { - return TransferErrorMessage::OnlyOneBid; + return OnlyOneBid; } - return TransferErrorMessage::Success; + return Success; } AcceptTransferErrorMessage Player::canAcceptTransferHouse(uint32_t houseId) { + using enum AcceptTransferErrorMessage; const auto house = g_game().map.houses.getHouseByClientId(houseId); if (!house) { - return AcceptTransferErrorMessage::Internal; + return Internal; } if (getGUID() != house->getBidder()) { - return AcceptTransferErrorMessage::NotNewOwner; + return NotNewOwner; } if (!isPremium()) { - return AcceptTransferErrorMessage::Premium; + return Premium; } if (getAccount()->getHouseBidId() != 0) { - return AcceptTransferErrorMessage::AlreadyBid; + return AlreadyBid; } if (getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) { - return AcceptTransferErrorMessage::Rookgaard; + return Rookgaard; } if (getBankBalance() < (house->getRent() + house->getInternalBid())) { - return AcceptTransferErrorMessage::Frozen; + return Frozen; } if (house->getTransferStatus()) { - return AcceptTransferErrorMessage::AlreadyAccepted; + return AlreadyAccepted; } - return AcceptTransferErrorMessage::Success; + return Success; } From 0fe8b2d161124a045fa1025c91556695f0032f77 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:42:18 -0300 Subject: [PATCH 23/28] fix: remove items from house when removing owner --- src/io/iomapserialize.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index c54f39f99b4..1479197c2c5 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -322,6 +322,7 @@ bool IOMapSerialize::loadHouseInfo() { } else if (state == CyclopediaHouseState::Transfer && timeNow > bidEndDate && bidder > 0) { g_logger().debug("[TRANSFER] - Removing house id '{}' from owner GUID '{}' and transfering to new owner GUID '{}'", houseId, owner, bidder); if (transferStatus) { + g_game().setTransferPlayerHouseItems(houseId, owner); house->setOwner(bidder); IOLoginData::increaseBankBalance(owner, internalBid); } else { @@ -334,6 +335,7 @@ bool IOMapSerialize::loadHouseInfo() { transferStatus = false; } else if (state == CyclopediaHouseState::MoveOut && timeNow > bidEndDate) { g_logger().debug("[MOVE OUT] - Removing house id '{}' owner", houseId); + g_game().setTransferPlayerHouseItems(houseId, owner); house->setOwner(0); bidEndDate = 0; } else { From e2e9ddf1f0ff8fa7ef9cbadaab604df4fa740241 Mon Sep 17 00:00:00 2001 From: Pedro Henrique Alves Cruz Date: Mon, 18 Nov 2024 22:01:25 -0300 Subject: [PATCH 24/28] fix: reversed houseBidId with accountId on db query --- src/account/account_repository_db.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/account/account_repository_db.cpp b/src/account/account_repository_db.cpp index 7674a8a08f4..b2e8fd80754 100644 --- a/src/account/account_repository_db.cpp +++ b/src/account/account_repository_db.cpp @@ -53,8 +53,8 @@ bool AccountRepositoryDB::save(const std::unique_ptr &accInfo) { accInfo->premiumLastDay, accInfo->creationTime, accInfo->premiumDaysPurchased, - accInfo->id, - accInfo->houseBidId + accInfo->houseBidId, + accInfo->id ) ); From c36436dd6b0604cbb24cd51d41d14fb4f67be814 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 9 Dec 2024 20:22:42 +0000 Subject: [PATCH 25/28] Lua code format - (Stylua) --- data-otservbr-global/migrations/46.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data-otservbr-global/migrations/46.lua b/data-otservbr-global/migrations/46.lua index e1de9f7e8f8..506da3a132b 100644 --- a/data-otservbr-global/migrations/46.lua +++ b/data-otservbr-global/migrations/46.lua @@ -4,4 +4,4 @@ function onUpdateDatabase() db.query("ALTER TABLE `players` MODIFY `conditions` mediumblob NOT NULL;") return true -end \ No newline at end of file +end From b4dc46bf1b345a1dc9597ecd64d7bec5a9eea9f8 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Mon, 9 Dec 2024 17:24:12 -0300 Subject: [PATCH 26/28] fix: files removed by resolving conflicts --- data-otservbr-global/migrations/47.lua | 28 +++++++++++++++++++++++++- data-otservbr-global/migrations/48.lua | 3 +++ schema.sql | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 data-otservbr-global/migrations/48.lua diff --git a/data-otservbr-global/migrations/47.lua b/data-otservbr-global/migrations/47.lua index 86a6d8ffec1..3fcf70a40c2 100644 --- a/data-otservbr-global/migrations/47.lua +++ b/data-otservbr-global/migrations/47.lua @@ -1,3 +1,29 @@ function onUpdateDatabase() - return false -- true = There are others migrations file | false = this is the last migration file + logger.info("Updating database to version 48 (House Auction)") + + db.query([[ + ALTER TABLE `houses` + DROP `bid`, + DROP `bid_end`, + DROP `last_bid`, + DROP `highest_bidder` + ]]) + + db.query([[ + ALTER TABLE `houses` + ADD `bidder` int(11) NOT NULL DEFAULT '0', + ADD `bidder_name` varchar(255) NOT NULL DEFAULT '', + ADD `highest_bid` int(11) NOT NULL DEFAULT '0', + ADD `internal_bid` int(11) NOT NULL DEFAULT '0', + ADD `bid_end_date` int(11) NOT NULL DEFAULT '0', + ADD `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0', + ADD `transfer_status` tinyint(1) DEFAULT '0' + ]]) + + db.query([[ + ALTER TABLE `accounts` + ADD `house_bid_id` int(11) NOT NULL DEFAULT '0' + ]]) + + return true end diff --git a/data-otservbr-global/migrations/48.lua b/data-otservbr-global/migrations/48.lua new file mode 100644 index 00000000000..86a6d8ffec1 --- /dev/null +++ b/data-otservbr-global/migrations/48.lua @@ -0,0 +1,3 @@ +function onUpdateDatabase() + return false -- true = There are others migrations file | false = this is the last migration file +end diff --git a/schema.sql b/schema.sql index 3620f0b3668..6fe1f21cbb8 100644 --- a/schema.sql +++ b/schema.sql @@ -7,7 +7,7 @@ CREATE TABLE IF NOT EXISTS `server_config` ( CONSTRAINT `server_config_pk` PRIMARY KEY (`config`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '47'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); +INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '48'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0'); -- Table structure `accounts` CREATE TABLE IF NOT EXISTS `accounts` ( From e9d6a3339f5aa25e4881bd7a8c4a7120ef7a5ac7 Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Mon, 30 Dec 2024 23:16:06 -0300 Subject: [PATCH 27/28] fix ubuntu build --- src/lua/functions/map/house_functions.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lua/functions/map/house_functions.cpp b/src/lua/functions/map/house_functions.cpp index b26db1661f3..dd20d6fdcf6 100644 --- a/src/lua/functions/map/house_functions.cpp +++ b/src/lua/functions/map/house_functions.cpp @@ -9,6 +9,7 @@ #include "lua/functions/map/house_functions.hpp" +#include "account/account.hpp" #include "config/configmanager.hpp" #include "items/bed.hpp" #include "game/game.hpp" From c81cf1a5d2c0b14e4b1841f7bf8e2100d0deed4e Mon Sep 17 00:00:00 2001 From: murilo09 <78226931+murilo09@users.noreply.github.com> Date: Mon, 30 Dec 2024 23:30:12 -0300 Subject: [PATCH 28/28] fix migration version log --- data-otservbr-global/migrations/10.lua | 2 +- data-otservbr-global/migrations/11.lua | 2 +- data-otservbr-global/migrations/12.lua | 2 +- data-otservbr-global/migrations/13.lua | 2 +- data-otservbr-global/migrations/14.lua | 2 +- data-otservbr-global/migrations/15.lua | 2 +- data-otservbr-global/migrations/16.lua | 2 +- data-otservbr-global/migrations/17.lua | 2 +- data-otservbr-global/migrations/18.lua | 2 +- data-otservbr-global/migrations/19.lua | 2 +- data-otservbr-global/migrations/2.lua | 2 +- data-otservbr-global/migrations/20.lua | 2 +- data-otservbr-global/migrations/21.lua | 2 +- data-otservbr-global/migrations/22.lua | 2 +- data-otservbr-global/migrations/23.lua | 2 +- data-otservbr-global/migrations/24.lua | 2 +- data-otservbr-global/migrations/25.lua | 2 +- data-otservbr-global/migrations/26.lua | 2 +- data-otservbr-global/migrations/27.lua | 2 +- data-otservbr-global/migrations/28.lua | 2 +- data-otservbr-global/migrations/29.lua | 2 +- data-otservbr-global/migrations/3.lua | 2 +- data-otservbr-global/migrations/30.lua | 2 +- data-otservbr-global/migrations/31.lua | 2 +- data-otservbr-global/migrations/32.lua | 2 +- data-otservbr-global/migrations/33.lua | 2 +- data-otservbr-global/migrations/34.lua | 2 +- data-otservbr-global/migrations/35.lua | 2 +- data-otservbr-global/migrations/36.lua | 2 +- data-otservbr-global/migrations/37.lua | 2 +- data-otservbr-global/migrations/38.lua | 2 +- data-otservbr-global/migrations/39.lua | 2 +- data-otservbr-global/migrations/4.lua | 2 +- data-otservbr-global/migrations/40.lua | 2 +- data-otservbr-global/migrations/41.lua | 2 +- data-otservbr-global/migrations/42.lua | 2 +- data-otservbr-global/migrations/43.lua | 2 +- data-otservbr-global/migrations/44.lua | 2 +- data-otservbr-global/migrations/45.lua | 2 +- data-otservbr-global/migrations/46.lua | 2 +- data-otservbr-global/migrations/47.lua | 2 +- data-otservbr-global/migrations/48.lua | 26 ++++++++++++- data-otservbr-global/migrations/5.lua | 2 +- data-otservbr-global/migrations/6.lua | 2 +- data-otservbr-global/migrations/7.lua | 2 +- data-otservbr-global/migrations/8.lua | 53 +++++++++++++------------- data-otservbr-global/migrations/9.lua | 2 +- 47 files changed, 97 insertions(+), 72 deletions(-) diff --git a/data-otservbr-global/migrations/10.lua b/data-otservbr-global/migrations/10.lua index 9dfded3813d..adfa41bb535 100644 --- a/data-otservbr-global/migrations/10.lua +++ b/data-otservbr-global/migrations/10.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 11 (Guilds Balance)") + logger.info("Updating database to version 10 (Guilds Balance)") db.query("ALTER TABLE `guilds` ADD `balance` bigint(20) UNSIGNED NOT NULL DEFAULT '0';") end diff --git a/data-otservbr-global/migrations/11.lua b/data-otservbr-global/migrations/11.lua index 08d40b66381..a10d3d2980c 100644 --- a/data-otservbr-global/migrations/11.lua +++ b/data-otservbr-global/migrations/11.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 12 (Player get daily reward)") + logger.info("Updating database to version 11 (Player get daily reward)") db.query("ALTER TABLE `players` ADD `isreward` tinyint(1) NOT NULL DEFAULT 1") end diff --git a/data-otservbr-global/migrations/12.lua b/data-otservbr-global/migrations/12.lua index e83ca4e51f8..20a2afc4582 100644 --- a/data-otservbr-global/migrations/12.lua +++ b/data-otservbr-global/migrations/12.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 13 (Boosted Creature Outfit)") + logger.info("Updating database to version 12 (Boosted Creature Outfit)") db.query("ALTER TABLE boosted_creature ADD `looktype` int(11) NOT NULL DEFAULT 136;") db.query("ALTER TABLE boosted_creature ADD `lookfeet` int(11) NOT NULL DEFAULT 0;") db.query("ALTER TABLE boosted_creature ADD `looklegs` int(11) NOT NULL DEFAULT 0;") diff --git a/data-otservbr-global/migrations/13.lua b/data-otservbr-global/migrations/13.lua index 479b28eda79..4747efdcb96 100644 --- a/data-otservbr-global/migrations/13.lua +++ b/data-otservbr-global/migrations/13.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 14 (Fixed mana spent)") + logger.info("Updating database to version 13 (Fixed mana spent)") db.query("ALTER TABLE `players` CHANGE `manaspent` `manaspent` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0';") end diff --git a/data-otservbr-global/migrations/14.lua b/data-otservbr-global/migrations/14.lua index 7c23d8053b5..281eb40722a 100644 --- a/data-otservbr-global/migrations/14.lua +++ b/data-otservbr-global/migrations/14.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 15 (Magic Shield Spell)") + logger.info("Updating database to version 14 (Magic Shield Spell)") db.query("ALTER TABLE `players` ADD `manashield` SMALLINT UNSIGNED NOT NULL DEFAULT '0' AFTER `skill_manaleech_amount`") db.query("ALTER TABLE `players` ADD `max_manashield` SMALLINT UNSIGNED NOT NULL DEFAULT '0' AFTER `manashield`") end diff --git a/data-otservbr-global/migrations/15.lua b/data-otservbr-global/migrations/15.lua index 73daf3c5b31..2c4a37ba315 100644 --- a/data-otservbr-global/migrations/15.lua +++ b/data-otservbr-global/migrations/15.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 16 (Rook sample and GOD player values)") + logger.info("Updating database to version 15 (Rook sample and GOD player values)") -- Rook Sample db.query("UPDATE `players` SET `maglevel` = 2, `manaspent` = 5936, `skill_club` = 12, `skill_club_tries` = 155, `skill_sword` = 12, `skill_sword_tries` = 155, `skill_axe` = 12, `skill_axe_tries` = 155, `skill_dist` = 12, `skill_dist_tries` = 93 WHERE `id` = 1;") -- GOD diff --git a/data-otservbr-global/migrations/16.lua b/data-otservbr-global/migrations/16.lua index a5766130bc3..027f2fe9822 100644 --- a/data-otservbr-global/migrations/16.lua +++ b/data-otservbr-global/migrations/16.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - print("Updating database to version 17 (Tutorial support)") + print("Updating database to version 16 (Tutorial support)") db.query("ALTER TABLE `players` ADD `istutorial` SMALLINT(1) NOT NULL DEFAULT '0'") end diff --git a/data-otservbr-global/migrations/17.lua b/data-otservbr-global/migrations/17.lua index 9d5f0d8d624..c84d6ec8ea6 100644 --- a/data-otservbr-global/migrations/17.lua +++ b/data-otservbr-global/migrations/17.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 18 (Fix guild creation myaac)") + logger.info("Updating database to version 17 (Fix guild creation myaac)") db.query("ALTER TABLE `guilds` ADD `level` int(11) NOT NULL DEFAULT 1") db.query("ALTER TABLE `guilds` ADD `points` int(11) NOT NULL DEFAULT 0") end diff --git a/data-otservbr-global/migrations/18.lua b/data-otservbr-global/migrations/18.lua index e017b86e05b..0f5777a2678 100644 --- a/data-otservbr-global/migrations/18.lua +++ b/data-otservbr-global/migrations/18.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 19 (Prey system rework + Task hunting system)") + logger.info("Updating database to version 18 (Prey system rework + Task hunting system)") db.query([[ ALTER TABLE `players` DROP `prey_stamina_1`, diff --git a/data-otservbr-global/migrations/19.lua b/data-otservbr-global/migrations/19.lua index e7d27a859ef..dd0c82d075f 100644 --- a/data-otservbr-global/migrations/19.lua +++ b/data-otservbr-global/migrations/19.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 20 (Gamestore accepting Tournament Coins)") + logger.info("Updating database to version 19 (Gamestore accepting Tournament Coins)") db.query("ALTER TABLE `accounts` ADD `tournament_coins` int(11) NOT NULL DEFAULT 0 AFTER `coins`") db.query("ALTER TABLE `store_history` ADD `coin_type` tinyint(1) NOT NULL DEFAULT 0 AFTER `description`") diff --git a/data-otservbr-global/migrations/2.lua b/data-otservbr-global/migrations/2.lua index 72c797b4b0e..b5674fecacc 100644 --- a/data-otservbr-global/migrations/2.lua +++ b/data-otservbr-global/migrations/2.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 3 (account refactor)") + logger.info("Updating database to version 2 (account refactor)") db.query([[ LOCK TABLES diff --git a/data-otservbr-global/migrations/20.lua b/data-otservbr-global/migrations/20.lua index daaefc6f041..f232bf2a7e8 100644 --- a/data-otservbr-global/migrations/20.lua +++ b/data-otservbr-global/migrations/20.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 21 (Fix market price size)") + logger.info("Updating database to version 20 (Fix market price size)") db.query("ALTER TABLE `market_history` CHANGE `price` `price` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0';") db.query("ALTER TABLE `market_offers` CHANGE `price` `price` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0';") end diff --git a/data-otservbr-global/migrations/21.lua b/data-otservbr-global/migrations/21.lua index cec635ed937..5c9e1a0ec8e 100644 --- a/data-otservbr-global/migrations/21.lua +++ b/data-otservbr-global/migrations/21.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 22 (forge and tier system)") + logger.info("Updating database to version 21 (forge and tier system)") db.query("ALTER TABLE `market_offers` ADD `tier` tinyint UNSIGNED NOT NULL DEFAULT '0';") db.query("ALTER TABLE `market_history` ADD `tier` tinyint UNSIGNED NOT NULL DEFAULT '0';") db.query("ALTER TABLE `players` ADD `forge_dusts` bigint(21) NOT NULL DEFAULT '0';") diff --git a/data-otservbr-global/migrations/22.lua b/data-otservbr-global/migrations/22.lua index c4c5bd385bc..9a2a4475a4b 100644 --- a/data-otservbr-global/migrations/22.lua +++ b/data-otservbr-global/migrations/22.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 23 (fix offline training skill size)") + logger.info("Updating database to version 22 (fix offline training skill size)") db.query([[ ALTER TABLE `players` MODIFY offlinetraining_skill tinyint(2) NOT NULL DEFAULT '-1'; diff --git a/data-otservbr-global/migrations/23.lua b/data-otservbr-global/migrations/23.lua index 8edac8cef47..dbf161bb474 100644 --- a/data-otservbr-global/migrations/23.lua +++ b/data-otservbr-global/migrations/23.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 24 (forge history)") + logger.info("Updating database to version 23 (forge history)") db.query([[ CREATE TABLE IF NOT EXISTS `forge_history` ( `id` int NOT NULL AUTO_INCREMENT, diff --git a/data-otservbr-global/migrations/24.lua b/data-otservbr-global/migrations/24.lua index fed9f189085..2d5286e5608 100644 --- a/data-otservbr-global/migrations/24.lua +++ b/data-otservbr-global/migrations/24.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 25 (random mount outfit window)") + logger.info("Updating database to version 24 (random mount outfit window)") db.query("ALTER TABLE `players` ADD `randomize_mount` SMALLINT(1) NOT NULL DEFAULT '0'") end diff --git a/data-otservbr-global/migrations/25.lua b/data-otservbr-global/migrations/25.lua index 4d229bb58e5..41f83e2b72b 100644 --- a/data-otservbr-global/migrations/25.lua +++ b/data-otservbr-global/migrations/25.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 26 (reward bag fix)") + logger.info("Updating database to version 25 (reward bag fix)") db.query("UPDATE player_rewards SET pid = 0 WHERE itemtype = 19202;") end diff --git a/data-otservbr-global/migrations/26.lua b/data-otservbr-global/migrations/26.lua index ddf821ca5cd..24db966339f 100644 --- a/data-otservbr-global/migrations/26.lua +++ b/data-otservbr-global/migrations/26.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 27 (towns)") + logger.info("Updating database to version 26 (towns)") db.query([[ CREATE TABLE IF NOT EXISTS `towns` ( diff --git a/data-otservbr-global/migrations/27.lua b/data-otservbr-global/migrations/27.lua index 73e7bf5c4f7..478e6da6207 100644 --- a/data-otservbr-global/migrations/27.lua +++ b/data-otservbr-global/migrations/27.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 28 (bosstiary system)") + logger.info("Updating database to version 27 (bosstiary system)") db.query("ALTER TABLE `players` ADD `boss_points` int NOT NULL DEFAULT '0';") db.query([[ CREATE TABLE IF NOT EXISTS `boosted_boss` ( diff --git a/data-otservbr-global/migrations/28.lua b/data-otservbr-global/migrations/28.lua index d7575edf3c8..06adece4d49 100644 --- a/data-otservbr-global/migrations/28.lua +++ b/data-otservbr-global/migrations/28.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 29 (transfer coins)") + logger.info("Updating database to version 28 (transfer coins)") db.query("ALTER TABLE `accounts` ADD `coins_transferable` int unsigned NOT NULL DEFAULT '0';") end diff --git a/data-otservbr-global/migrations/29.lua b/data-otservbr-global/migrations/29.lua index 0c633e46b5d..91834f4f2f6 100644 --- a/data-otservbr-global/migrations/29.lua +++ b/data-otservbr-global/migrations/29.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 30 (looktypeEx)") + logger.info("Updating database to version 29 (looktypeEx)") db.query("ALTER TABLE `boosted_boss` ADD `looktypeEx` int unsigned NOT NULL DEFAULT '0';") end diff --git a/data-otservbr-global/migrations/3.lua b/data-otservbr-global/migrations/3.lua index ae06343be07..0a1aec6f6df 100644 --- a/data-otservbr-global/migrations/3.lua +++ b/data-otservbr-global/migrations/3.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 4 (prey tick)") + logger.info("Updating database to version 3 (prey tick)") db.query([[ ALTER TABLE `prey_slots` diff --git a/data-otservbr-global/migrations/30.lua b/data-otservbr-global/migrations/30.lua index 4ee1632421d..4749f1588ac 100644 --- a/data-otservbr-global/migrations/30.lua +++ b/data-otservbr-global/migrations/30.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 31 (loyalty)") + logger.info("Updating database to version 30 (loyalty)") db.query([[ ALTER TABLE `accounts` ADD COLUMN `premdays_purchased` int(11) NOT NULL DEFAULT 0; ]]) diff --git a/data-otservbr-global/migrations/31.lua b/data-otservbr-global/migrations/31.lua index 5ba21bbe561..9659f296ac5 100644 --- a/data-otservbr-global/migrations/31.lua +++ b/data-otservbr-global/migrations/31.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 32 (account_sessions)") + logger.info("Updating database to version 31 (account_sessions)") db.query([[ CREATE TABLE IF NOT EXISTS `account_sessions` ( `id` VARCHAR(191) NOT NULL, diff --git a/data-otservbr-global/migrations/32.lua b/data-otservbr-global/migrations/32.lua index 078ef407da6..c90de61886b 100644 --- a/data-otservbr-global/migrations/32.lua +++ b/data-otservbr-global/migrations/32.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 33 (wheel of destiny)") + logger.info("Updating database to version 32 (wheel of destiny)") db.query([[ CREATE TABLE IF NOT EXISTS `player_wheeldata` ( `player_id` int(11) NOT NULL, diff --git a/data-otservbr-global/migrations/33.lua b/data-otservbr-global/migrations/33.lua index 2c77cbb6e24..7c0852a32bc 100644 --- a/data-otservbr-global/migrations/33.lua +++ b/data-otservbr-global/migrations/33.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 34 (add primary keys)") + logger.info("Updating database to version 33 (add primary keys)") db.query([[ ALTER TABLE `player_prey` ADD PRIMARY KEY (`player_id`, `slot`); diff --git a/data-otservbr-global/migrations/34.lua b/data-otservbr-global/migrations/34.lua index 7537f6e6582..c344eae6b8d 100644 --- a/data-otservbr-global/migrations/34.lua +++ b/data-otservbr-global/migrations/34.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 35 (bosstiary tracker)") + logger.info("Updating database to version 34 (bosstiary tracker)") db.query("ALTER TABLE `player_bosstiary` ADD `tracker` blob NOT NULL;") end diff --git a/data-otservbr-global/migrations/35.lua b/data-otservbr-global/migrations/35.lua index 70c820c32fd..9e2ab4dd1ba 100644 --- a/data-otservbr-global/migrations/35.lua +++ b/data-otservbr-global/migrations/35.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 36 (fix account premdays and lastday)") + logger.info("Updating database to version 35 (fix account premdays and lastday)") local resultQuery = db.storeQuery("SELECT `id`, `premdays`, `lastday` FROM `accounts` WHERE (`premdays` > 0 OR `lastday` > 0) AND `lastday` <= " .. os.time()) if resultQuery ~= false then diff --git a/data-otservbr-global/migrations/36.lua b/data-otservbr-global/migrations/36.lua index 5f912763cc8..5fab551e4c0 100644 --- a/data-otservbr-global/migrations/36.lua +++ b/data-otservbr-global/migrations/36.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 37 (add coin_type to accounts)") + logger.info("Updating database to version 36 (add coin_type to accounts)") db.query("ALTER TABLE `coins_transactions` ADD `coin_type` tinyint(1) UNSIGNED NOT NULL DEFAULT '1';") end diff --git a/data-otservbr-global/migrations/37.lua b/data-otservbr-global/migrations/37.lua index ae3dbefbc27..7219dfbbac2 100644 --- a/data-otservbr-global/migrations/37.lua +++ b/data-otservbr-global/migrations/37.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 38 (add pronoun to players)") + logger.info("Updating database to version 37 (add pronoun to players)") db.query("ALTER TABLE `players` ADD `pronoun` int(11) NOT NULL DEFAULT '0';") end diff --git a/data-otservbr-global/migrations/38.lua b/data-otservbr-global/migrations/38.lua index 3412e4d488f..7e9e3748175 100644 --- a/data-otservbr-global/migrations/38.lua +++ b/data-otservbr-global/migrations/38.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 39 (create kv store)") + logger.info("Updating database to version 38 (create kv store)") db.query([[ CREATE TABLE IF NOT EXISTS `kv_store` ( `key_name` varchar(191) NOT NULL, diff --git a/data-otservbr-global/migrations/39.lua b/data-otservbr-global/migrations/39.lua index 181994882db..f660e98eb37 100644 --- a/data-otservbr-global/migrations/39.lua +++ b/data-otservbr-global/migrations/39.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 40 (house transfer ownership on startup)") + logger.info("Updating database to version 39 (house transfer ownership on startup)") db.query("ALTER TABLE `houses` ADD `new_owner` int(11) NOT NULL DEFAULT '-1';") end diff --git a/data-otservbr-global/migrations/4.lua b/data-otservbr-global/migrations/4.lua index 891bc20915a..a7b04453374 100644 --- a/data-otservbr-global/migrations/4.lua +++ b/data-otservbr-global/migrations/4.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 5 (boosted creature)") + logger.info("Updating database to version 4 (boosted creature)") db.query([[CREATE TABLE IF NOT EXISTS `boosted_creature` ( `boostname` TEXT, `date` varchar(250) NOT NULL DEFAULT '', diff --git a/data-otservbr-global/migrations/40.lua b/data-otservbr-global/migrations/40.lua index be8794e7b25..a7d3ae6afc2 100644 --- a/data-otservbr-global/migrations/40.lua +++ b/data-otservbr-global/migrations/40.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 41 (optimize house_lists)") + logger.info("Updating database to version 40 (optimize house_lists)") db.query([[ ALTER TABLE `house_lists` diff --git a/data-otservbr-global/migrations/41.lua b/data-otservbr-global/migrations/41.lua index 1fa9a40e36d..504bd950073 100644 --- a/data-otservbr-global/migrations/41.lua +++ b/data-otservbr-global/migrations/41.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 42 (fix xpboost types)") + logger.info("Updating database to version 41 (fix xpboost types)") db.query([[ ALTER TABLE `players` diff --git a/data-otservbr-global/migrations/42.lua b/data-otservbr-global/migrations/42.lua index 4b0b97b9987..6bc750efa66 100644 --- a/data-otservbr-global/migrations/42.lua +++ b/data-otservbr-global/migrations/42.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 43 (fix guildwar_kills_unique)") + logger.info("Updating database to version 42 (fix guildwar_kills_unique)") db.query([[ ALTER TABLE `guildwar_kills` diff --git a/data-otservbr-global/migrations/43.lua b/data-otservbr-global/migrations/43.lua index 438ba91b713..bcf1658864d 100644 --- a/data-otservbr-global/migrations/43.lua +++ b/data-otservbr-global/migrations/43.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 44 (feat frags_limit, payment and duration_days in guild wars)") + logger.info("Updating database to version 43 (feat frags_limit, payment and duration_days in guild wars)") db.query([[ ALTER TABLE `guild_wars` diff --git a/data-otservbr-global/migrations/44.lua b/data-otservbr-global/migrations/44.lua index 0e2140c3183..acef11ceed9 100644 --- a/data-otservbr-global/migrations/44.lua +++ b/data-otservbr-global/migrations/44.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 45 (fix: mana shield column size for more than 65k)") + logger.info("Updating database to version 44 (fix: mana shield column size for more than 65k)") db.query([[ ALTER TABLE `players` diff --git a/data-otservbr-global/migrations/45.lua b/data-otservbr-global/migrations/45.lua index a88de886861..abed3464072 100644 --- a/data-otservbr-global/migrations/45.lua +++ b/data-otservbr-global/migrations/45.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 46 (feat: vip groups)") + logger.info("Updating database to version 45 (feat: vip groups)") db.query([[ CREATE TABLE IF NOT EXISTS `account_vipgroups` ( diff --git a/data-otservbr-global/migrations/46.lua b/data-otservbr-global/migrations/46.lua index da4ade8cbf3..d7f24765b8a 100644 --- a/data-otservbr-global/migrations/46.lua +++ b/data-otservbr-global/migrations/46.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 47 (fix: creature speed and conditions)") + logger.info("Updating database to version 46 (fix: creature speed and conditions)") db.query("ALTER TABLE `players` MODIFY `conditions` mediumblob NOT NULL;") end diff --git a/data-otservbr-global/migrations/47.lua b/data-otservbr-global/migrations/47.lua index 3c8908b5641..6b658e4085f 100644 --- a/data-otservbr-global/migrations/47.lua +++ b/data-otservbr-global/migrations/47.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 46 (hireling)") + logger.info("Updating database to version 47 (hireling)") db.query([[ CREATE TABLE IF NOT EXISTS `player_hirelings` ( diff --git a/data-otservbr-global/migrations/48.lua b/data-otservbr-global/migrations/48.lua index 86a6d8ffec1..53d6ba3a948 100644 --- a/data-otservbr-global/migrations/48.lua +++ b/data-otservbr-global/migrations/48.lua @@ -1,3 +1,27 @@ function onUpdateDatabase() - return false -- true = There are others migrations file | false = this is the last migration file + logger.info("Updating database to version 48 (House Auction)") + + db.query([[ + ALTER TABLE `houses` + DROP `bid`, + DROP `bid_end`, + DROP `last_bid`, + DROP `highest_bidder` + ]]) + + db.query([[ + ALTER TABLE `houses` + ADD `bidder` int(11) NOT NULL DEFAULT '0', + ADD `bidder_name` varchar(255) NOT NULL DEFAULT '', + ADD `highest_bid` int(11) NOT NULL DEFAULT '0', + ADD `internal_bid` int(11) NOT NULL DEFAULT '0', + ADD `bid_end_date` int(11) NOT NULL DEFAULT '0', + ADD `state` smallint(5) UNSIGNED NOT NULL DEFAULT '0', + ADD `transfer_status` tinyint(1) DEFAULT '0' + ]]) + + db.query([[ + ALTER TABLE `accounts` + ADD `house_bid_id` int(11) NOT NULL DEFAULT '0' + ]]) end diff --git a/data-otservbr-global/migrations/5.lua b/data-otservbr-global/migrations/5.lua index dbc324198dd..4b027c20085 100644 --- a/data-otservbr-global/migrations/5.lua +++ b/data-otservbr-global/migrations/5.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 6 (quickloot)") + logger.info("Updating database to version 5 (quickloot)") db.query("ALTER TABLE `players` ADD `quickloot_fallback` TINYINT DEFAULT 0") end diff --git a/data-otservbr-global/migrations/6.lua b/data-otservbr-global/migrations/6.lua index 91766a68ca7..cc3a3f76423 100644 --- a/data-otservbr-global/migrations/6.lua +++ b/data-otservbr-global/migrations/6.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 7 (Stash supply)") + logger.info("Updating database to version 6 (Stash supply)") db.query([[CREATE TABLE IF NOT EXISTS `player_stash` ( `player_id` INT(16) NOT NULL, `item_id` INT(16) NOT NULL, diff --git a/data-otservbr-global/migrations/7.lua b/data-otservbr-global/migrations/7.lua index cade1faae1f..0666d7cf9d8 100644 --- a/data-otservbr-global/migrations/7.lua +++ b/data-otservbr-global/migrations/7.lua @@ -1,4 +1,4 @@ function onUpdateDatabase() - logger.info("Updating database to version 8 (recruiter system)") + logger.info("Updating database to version 7 (recruiter system)") db.query("ALTER TABLE `accounts` ADD `recruiter` INT(6) DEFAULT 0") end diff --git a/data-otservbr-global/migrations/8.lua b/data-otservbr-global/migrations/8.lua index 523b705c0c7..a96db82e278 100644 --- a/data-otservbr-global/migrations/8.lua +++ b/data-otservbr-global/migrations/8.lua @@ -1,29 +1,30 @@ function onUpdateDatabase() - logger.info("Updating database to version 9 (Bestiary cpp)") + logger.info("Updating database to version 8 (Bestiary cpp)") db.query([[CREATE TABLE IF NOT EXISTS `player_charms` ( -`player_guid` INT(250) NOT NULL , -`charm_points` VARCHAR(250) NULL , -`charm_expansion` BOOLEAN NULL , -`rune_wound` INT(250) NULL , -`rune_enflame` INT(250) NULL , -`rune_poison` INT(250) NULL , -`rune_freeze` INT(250) NULL , -`rune_zap` INT(250) NULL , -`rune_curse` INT(250) NULL , -`rune_cripple` INT(250) NULL , -`rune_parry` INT(250) NULL , -`rune_dodge` INT(250) NULL , -`rune_adrenaline` INT(250) NULL , -`rune_numb` INT(250) NULL, -`rune_cleanse` INT(250) NULL , -`rune_bless` INT(250) NULL , -`rune_scavenge` INT(250) NULL , -`rune_gut` INT(250) NULL , -`rune_low_blow` INT(250) NULL , -`rune_divine` INT(250) NULL , -`rune_vamp` INT(250) NULL , -`rune_void` INT(250) NULL , -`UsedRunesBit` VARCHAR(250) NULL , -`UnlockedRunesBit` VARCHAR(250) NULL, -`tracker list` BLOB NULL ) ENGINE = InnoDB DEFAULT CHARSET=utf8;]]) + `player_guid` INT(250) NOT NULL , + `charm_points` VARCHAR(250) NULL , + `charm_expansion` BOOLEAN NULL , + `rune_wound` INT(250) NULL , + `rune_enflame` INT(250) NULL , + `rune_poison` INT(250) NULL , + `rune_freeze` INT(250) NULL , + `rune_zap` INT(250) NULL , + `rune_curse` INT(250) NULL , + `rune_cripple` INT(250) NULL , + `rune_parry` INT(250) NULL , + `rune_dodge` INT(250) NULL , + `rune_adrenaline` INT(250) NULL , + `rune_numb` INT(250) NULL, + `rune_cleanse` INT(250) NULL , + `rune_bless` INT(250) NULL , + `rune_scavenge` INT(250) NULL , + `rune_gut` INT(250) NULL , + `rune_low_blow` INT(250) NULL , + `rune_divine` INT(250) NULL , + `rune_vamp` INT(250) NULL , + `rune_void` INT(250) NULL , + `UsedRunesBit` VARCHAR(250) NULL , + `UnlockedRunesBit` VARCHAR(250) NULL, + `tracker list` BLOB NULL ) ENGINE = InnoDB DEFAULT CHARSET=utf8; + ]]) end diff --git a/data-otservbr-global/migrations/9.lua b/data-otservbr-global/migrations/9.lua index 7ce8e189768..23516833fbb 100644 --- a/data-otservbr-global/migrations/9.lua +++ b/data-otservbr-global/migrations/9.lua @@ -1,5 +1,5 @@ function onUpdateDatabase() - logger.info("Updating database to version 10 (Mount Colors and familiars)") + logger.info("Updating database to version 9 (Mount Colors and familiars)") db.query("ALTER TABLE `players` ADD `lookmountbody` tinyint(3) unsigned NOT NULL DEFAULT '0'") db.query("ALTER TABLE `players` ADD `lookmountfeet` tinyint(3) unsigned NOT NULL DEFAULT '0'") db.query("ALTER TABLE `players` ADD `lookmounthead` tinyint(3) unsigned NOT NULL DEFAULT '0'")