Skip to content

Commit

Permalink
feat: cyclopedia house auction from opentibiabr#3022
Browse files Browse the repository at this point in the history
  • Loading branch information
Corlyone committed Nov 20, 2024
1 parent 1691d2c commit 107f597
Show file tree
Hide file tree
Showing 26 changed files with 2,125 additions and 1,033 deletions.
28 changes: 27 additions & 1 deletion data-otservbr-global/migrations/47.lua
Original file line number Diff line number Diff line change
@@ -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 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',
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
3 changes: 3 additions & 0 deletions data-otservbr-global/migrations/48.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function onUpdateDatabase()
return false -- true = There are others migrations file | false = this is the last migration file
end
1,968 changes: 984 additions & 984 deletions data-otservbr-global/world/otservbr-house.xml

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions data/scripts/globalevents/server_initialization.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ local function moveExpiredBansToHistory()
end

-- Function to check and process house auctions
local function processHouseAuctions()
--[[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
Expand All @@ -48,7 +48,7 @@ local function processHouseAuctions()
Result.free(resultId)
end
end
end]]--

-- Function to store towns in the database
local function storeTownsInDatabase()
Expand Down Expand Up @@ -150,7 +150,7 @@ function serverInitialization.onStartup()

cleanupDatabase()
moveExpiredBansToHistory()
processHouseAuctions()
--processHouseAuctions()
storeTownsInDatabase()
checkAndLogDuplicateValues({ "Global", "GlobalStorage", "Storage" })
updateEventRates()
Expand Down
8 changes: 5 additions & 3 deletions data/scripts/talkactions/player/buy_house.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 5 additions & 3 deletions data/scripts/talkactions/player/leave_house.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 5 additions & 3 deletions data/scripts/talkactions/player/sell_house.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 7 additions & 0 deletions src/account/account.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,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;
}
3 changes: 3 additions & 0 deletions src/account/account.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ class Account {

std::tuple<phmap::flat_hash_map<std::string, uint64_t>, AccountErrors_t> getAccountPlayers() const;

void setHouseBidId(uint32_t houseId);
uint32_t getHouseBidId() const;

// Old protocol compat
void setProtocolCompat(bool toggle);

Expand Down
1 change: 1 addition & 0 deletions src/account/account_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ struct AccountInfo {
time_t sessionExpires = 0;
uint32_t premiumDaysPurchased = 0;
uint32_t creationTime = 0;
uint32_t houseBidId = 0;
};
4 changes: 3 additions & 1 deletion src/account/account_repository_db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ bool AccountRepositoryDB::loadBySession(const std::string &sessionKey, std::uniq
bool AccountRepositoryDB::save(const std::unique_ptr<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` = {} 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->houseBidId,
accInfo->id
)
);
Expand Down
2 changes: 2 additions & 0 deletions src/config/config_enums.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -110,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,
Expand Down
2 changes: 2 additions & 0 deletions src/config/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,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);
Expand Down Expand Up @@ -255,6 +256,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);
Expand Down
133 changes: 130 additions & 3 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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"
Expand Down Expand Up @@ -2273,6 +2274,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> &item, uint8_t slot, bool protectionCharm) {
Expand Down Expand Up @@ -5327,9 +5344,14 @@ void Player::getPathSearchParams(const std::shared_ptr<Creature> &creature, Find

uint64_t Player::getGainedExperience(const std::shared_ptr<Creature> &attacker) const {
if (g_configManager().getBoolean(EXPERIENCE_FROM_PLAYERS)) {
const auto &attackerPlayer = attacker->getPlayer();
if (attackerPlayer && attackerPlayer.get() != this && skillLoss && std::abs(static_cast<int32_t>(attackerPlayer->getLevel() - level)) <= g_configManager().getNumber(EXP_FROM_PLAYERS_LEVEL_RANGE)) {
return std::max<uint64_t>(0, std::floor(getLostExperience() * getDamageRatio(attacker) * 0.75));
auto attackerPlayer = attacker->getPlayer();
if (attackerPlayer && attackerPlayer.get() != this) {
if (attackerPlayer->getLevel() > level) {
return 0;
}
if (skillLoss && std::abs(static_cast<int32_t>(attackerPlayer->getLevel() - level)) <= g_configManager().getNumber(EXP_FROM_PLAYERS_LEVEL_RANGE)) {
return std::max<uint64_t>(0, std::floor(getLostExperience() * getDamageRatio(attacker) * 0.75));
}
}
}
return 0;
Expand Down Expand Up @@ -11257,3 +11279,108 @@ uint16_t Player::getPlayerVocationEnum() const {

return Vocation_t::VOCATION_NONE;
}

BidErrorMessage Player::canBidHouse(uint32_t houseId) {
using enum BidErrorMessage;
const auto house = g_game().map.houses.getHouseByClientId(houseId);
if (!house) {
return Internal;
}

if (getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) {
return Rookgaard;
}

if (!isPremium()) {
return Premium;
}

if (getAccount()->getHouseBidId() != 0) {
return OnlyOneBid;
}

if (getBankBalance() < (house->getRent() + house->getHighestBid())) {
return NotEnoughMoney;
}

if (house->isGuildhall()) {
if (getGuildRank() && getGuildRank()->level != 3) {
return Guildhall;
}

if (getGuild() && getGuild()->getBankBalance() < (house->getRent() + house->getHighestBid())) {
return NotEnoughGuildMoney;
}
}

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 Internal;
}

if (getGUID() != house->getOwner()) {
return NotHouseOwner;
}

if (getGUID() == newOwnerGUID) {
return AlreadyTheOwner;
}

const auto newOwner = g_game().getPlayerByGUID(newOwnerGUID, true);
if (!newOwner) {
return CharacterNotExist;
}

if (newOwner->getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) {
return Rookgaard;
}

if (!newOwner->isPremium()) {
return Premium;
}

if (newOwner->getAccount()->getHouseBidId() != 0) {
return OnlyOneBid;
}

return Success;
}

AcceptTransferErrorMessage Player::canAcceptTransferHouse(uint32_t houseId) {
using enum AcceptTransferErrorMessage;
const auto house = g_game().map.houses.getHouseByClientId(houseId);
if (!house) {
return Internal;
}

if (getGUID() != house->getBidder()) {
return NotNewOwner;
}

if (!isPremium()) {
return Premium;
}

if (getAccount()->getHouseBidId() != 0) {
return AlreadyBid;
}

if (getPlayerVocationEnum() == Vocation_t::VOCATION_NONE) {
return Rookgaard;
}

if (getBankBalance() < (house->getRent() + house->getInternalBid())) {
return Frozen;
}

if (house->getTransferStatus()) {
return AlreadyAccepted;
}

return Success;
}
13 changes: 13 additions & 0 deletions src/creatures/players/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,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<uint32_t>;
using StashContainerList = std::vector<std::pair<std::shared_ptr<Item>, uint32_t>>;
using ItemVector = std::vector<std::shared_ptr<Item>>;
using UsersMap = std::map<uint32_t, std::shared_ptr<Player>>;
using InvitedMap = std::map<uint32_t, std::shared_ptr<Player>>;
using HouseMap = std::map<uint32_t, std::shared_ptr<House>>;

struct ForgeHistory {
ForgeAction_t actionType = ForgeAction_t::FUSION;
Expand Down Expand Up @@ -949,6 +955,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) 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> &item, uint8_t slot, bool protectionCharm);
void onClearImbuement(const std::shared_ptr<Item> &item, uint8_t slot);
Expand Down
Loading

0 comments on commit 107f597

Please sign in to comment.