diff --git a/config.lua.dist b/config.lua.dist index 8c0498d196..e8689ed213 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -92,10 +92,8 @@ forceMonsterTypesOnLoad = true cleanProtectionZones = false checkDuplicateStorageKeys = false --- VIP and Depot limits +-- Depot limits -- NOTE: you can set custom limits per group in data/XML/groups.xml -vipFreeLimit = 20 -vipPremiumLimit = 100 depotFreeLimit = 2000 depotPremiumLimit = 15000 diff --git a/data/cpplinter.lua b/data/cpplinter.lua index 17624824de..d422d6d398 100644 --- a/data/cpplinter.lua +++ b/data/cpplinter.lua @@ -40,14 +40,14 @@ DBTransaction = {} ---@field query fun(query: string): any ---@field storeQuery fun(query: string): any ---@field escapeString fun(value: string): string ----@field asyncQuery fun(query: string): boolean +---@field asyncQuery fun(query: string, callback?: function): boolean db = {} ---@class result ---@field free fun(resultId: number) ---@field next fun(resultId: number): number ---@field getNumber fun(resultId: number, column: string): number ----@field getString fun(resultId: number, column: number): string +---@field getString fun(resultId: number, column: string): string ---@field getBoolean fun(resultId: number, column: number): boolean ---@field getStream fun(resultId: number, column: number): string result = {} @@ -289,7 +289,7 @@ Podium = {} ---@field isImmune fun(self: Creature): boolean ---@field canSee fun(self: Creature, position: Position): boolean ---@field canSeeCreature fun(self: Creature, creature: Creature): boolean ----@field canSeeGhostMode fun(self: Creature): boolean +---@field canSeeGhostMode fun(self: Creature, otherCreature?: Creature): boolean ---@field canSeeInvisibility fun(self: Creature): boolean ---@field getParent fun(self: Creature): Creature ---@field getId fun(self: Creature): number @@ -2259,14 +2259,12 @@ configKeys = { SERVER_SAVE_NOTIFY_DURATION = 34, YELL_MINIMUM_LEVEL = 35, MINIMUM_LEVEL_TO_SEND_PRIVATE = 36, - VIP_FREE_LIMIT = 37, - VIP_PREMIUM_LIMIT = 38, - DEPOT_FREE_LIMIT = 39, - DEPOT_PREMIUM_LIMIT = 40, - QUEST_TRACKER_FREE_LIMIT = 41, - QUEST_TRACKER_PREMIUM_LIMIT = 42, - STAMINA_REGEN_MINUTE = 43, - STAMINA_REGEN_PREMIUM = 44, + DEPOT_FREE_LIMIT = 37, + DEPOT_PREMIUM_LIMIT = 38, + QUEST_TRACKER_FREE_LIMIT = 39, + QUEST_TRACKER_PREMIUM_LIMIT = 40, + STAMINA_REGEN_MINUTE = 41, + STAMINA_REGEN_PREMIUM = 42, } ITEM_TYPE_NONE = 0 @@ -2465,3 +2463,5 @@ SPELLGROUP_ULTIMATESTRIKES = 8 WORLD_TYPE_NO_PVP = 1 WORLD_TYPE_PVP = 2 WORLD_TYPE_PVP_ENFORCED = 3 + +PLAYER_NAME_LENGTH = 25 diff --git a/data/lib/core/constants.lua b/data/lib/core/constants.lua index 65aada9491..4ba4c47f14 100644 --- a/data/lib/core/constants.lua +++ b/data/lib/core/constants.lua @@ -41,3 +41,8 @@ CYCLOPEDIA_SKILL_FIST = 11 CYCLOPEDIA_SKILL_FISHING = 13 CYCLOPEDIA_SKILL_AMOUNT = 8 + +VIPSTATUS_OFFLINE = 0 +VIPSTATUS_ONLINE = 1 +VIPSTATUS_PENDING = 2 +VIPSTATUS_TRAINING = 3 diff --git a/data/lib/core/core.lua b/data/lib/core/core.lua index e3c3992702..074fa569aa 100644 --- a/data/lib/core/core.lua +++ b/data/lib/core/core.lua @@ -20,5 +20,6 @@ dofile('data/lib/core/quests.lua') dofile('data/lib/core/raids.lua') dofile('data/lib/core/teleport.lua') dofile('data/lib/core/tile.lua') +dofile('data/lib/core/vip.lua') dofile('data/lib/core/town.lua') dofile('data/lib/core/vocation.lua') diff --git a/data/lib/core/player.lua b/data/lib/core/player.lua index 65c36c6150..8fd051379b 100644 --- a/data/lib/core/player.lua +++ b/data/lib/core/player.lua @@ -749,3 +749,141 @@ function Player.sendInboxItems(self, items, containerId) end container:moveTo(inbox) end + +function Player.getMaxVipEntries(self) + local groupMaxVipEntries = self:getGroup():getMaxVipEntries() + if groupMaxVipEntries > 0 then + return groupMaxVipEntries + end + return self:isPremium() and VIP_PREMIUM_LIMIT or VIP_FREE_LIMIT +end + +function Player.addVip(self, name) + if name:len() > PLAYER_NAME_LENGTH then + return + end + + local vipGuid + local vipName + local status + + -- check if the Vip is online + local vipPlayer = Player(name) + if vipPlayer then + if vipPlayer:hasFlag(PlayerFlag_SpecialVIP) and not self:hasFlag(PlayerFlag_SpecialVIP) then + self:sendTextMessage(MESSAGE_STATUS_SMALL, "You can not add this player.") + return + end + + vipGuid = vipPlayer:getGuid() + vipName = vipPlayer:getName() + status = (not vipPlayer:isInGhostMode() or self:canSeeGhostMode(vipPlayer)) and VIPSTATUS_ONLINE or VIPSTATUS_OFFLINE + else + -- if not online, attempt to load by name + local resultId = db.storeQuery("SELECT `name`, `id`, `group_id` FROM `players` WHERE `name` = " .. db.escapeString(name)) + if not resultId then + self:sendTextMessage(MESSAGE_STATUS_SMALL, "A player with this name does not exist.") + return + end + + -- find Vip group and check if exists + local groupId = result.getNumber(resultId, "group_id") + local group = Group(groupId) + if not group then + return + end + + if group:hasFlag(PlayerFlag_SpecialVIP) and not self:hasFlag(PlayerFlag_SpecialVIP) then + self:sendTextMessage(MESSAGE_STATUS_SMALL, "You can not add this player.") + return + end + + vipGuid = result.getNumber(resultId, "id") + vipName = result.getString(resultId, "name") + status = VIPSTATUS_OFFLINE + end + + local playerVip = Vip(self:getGuid()) + if not playerVip:canAdd() then + self:sendTextMessage(MESSAGE_STATUS_SMALL, "You cannot add more buddies.") + return + end + + if playerVip:has(vipGuid) then + self:sendTextMessage(MESSAGE_STATUS_SMALL, "This player is already in your list.") + return + end + + local description = "" + local icon = 0 + local notify = false + + playerVip:add(vipGuid) + self:sendVip(vipGuid, vipName, description, icon, notify, status) + + local accountId = self:getAccountId() + db.asyncQuery("INSERT INTO `account_viplist` (`account_id`, `player_id`) VALUES (" .. accountId .. ", " .. vipGuid .. ")") +end + +function Player.removeVip(self, vipGuid) + local playerVip = Vip(self:getGuid()) + playerVip:remove(vipGuid) + + local accountId = self:getAccountId() + db.asyncQuery("DELETE FROM `account_viplist` WHERE `account_id` = " .. accountId .. " AND `player_id` = " .. vipGuid) +end + +function Player.editVip(self, vipGuid, description, icon, notify) + local playerVip = Vip(self:getGuid()) + if not playerVip:has(vipGuid) then + return + end + + local accountId = self:getAccountId() + db.asyncQuery("UPDATE `account_viplist` SET `description` = " .. db.escapeString(description) ..", `icon` = " .. icon .. ", `notify` = " .. (notify and 1 or 0) .. " WHERE `account_id` = " .. accountId .. " AND `player_id` = " .. vipGuid .. "") +end + +function Player.notifyVipStatusChange(self, vipGuid, status) + local vipPlayer = Player(vipGuid) + if not vipPlayer then + return + end + + local playerVip = Vip(self:getGuid()) + if not playerVip:has(vipGuid) then + return + end + + self:sendUpdatedVipStatus(vipGuid, status) + + if status == VIPSTATUS_ONLINE then + self:sendTextMessage(MESSAGE_STATUS_SMALL, vipPlayer:getName() .. " has logged in.") + elseif status == VIPSTATUS_OFFLINE then + self:sendTextMessage(MESSAGE_STATUS_SMALL, vipPlayer:getName() .. " has logged out.") + end +end + +function Player.sendVip(self, guid, name, description, icon, notify, status) + local msg = NetworkMessage() + msg:addByte(0xD2) + msg:addU32(guid) + msg:addString(name) + msg:addString(description) + msg:addU32(math.min(10, icon)) + msg:addByte(notify and 1 or 0) + msg:addByte(status) + msg:addByte(0x00) -- vipGroups (placeholder) + msg:sendToPlayer(self) + msg:delete() + return true +end + +function Player.sendUpdatedVipStatus(self, guid, status) + local msg = NetworkMessage() + msg:addByte(0xD3) + msg:addU32(guid) + msg:addByte(status) + msg:sendToPlayer(self) + msg:delete() + return true +end diff --git a/data/lib/core/vip.lua b/data/lib/core/vip.lua new file mode 100644 index 0000000000..680901972b --- /dev/null +++ b/data/lib/core/vip.lua @@ -0,0 +1,53 @@ +do + -- VIP limits + VIP_FREE_LIMIT = 20 + VIP_PREMIUM_LIMIT = 100 + + Vips = {} + + local function clear(self) + Vips[self.guid] = nil + end + + local function getList(self) + return self.vips + end + + local function add(self, vip) + self.vips[vip] = vip + end + + local function remove(self, vip) + self.vips[vip] = nil + end + + local function has(self, vip) + return self.vips[vip] ~= nil + end + + local function canAdd(self) + local player = Player(self.guid) + if not player then + debugPrint("[Error - Vip::canAdd] null player (" .. self.guid .. ") when check if can add Vip.") + return 0 + end + + return #self.vips < player:getMaxVipEntries() + end + + function Vip(guid) + if not Vips[guid] then + Vips[guid] = { + guid = guid, + clear = clear, + getList = getList, + add = add, + remove = remove, + has = has, + canAdd = canAdd, + vips = {} + } + end + return Vips[guid] + end +end diff --git a/data/scripts/creaturescripts/player/viplist.lua b/data/scripts/creaturescripts/player/viplist.lua new file mode 100644 index 0000000000..976273c61d --- /dev/null +++ b/data/scripts/creaturescripts/player/viplist.lua @@ -0,0 +1,67 @@ +local function notifyAllPlayers(guid, status) + for _, player in ipairs(Game.getPlayers()) do + if player:getGuid() ~= guid then + player:notifyVipStatusChange(guid, status) + end + end +end + +do + local event = CreatureEvent("OnlineVip") + + function event.onLogin(player) + local playerGuid = player:getGuid() + notifyAllPlayers(playerGuid, VIPSTATUS_ONLINE) + + local accountId = player:getAccountId() + local resultId = db.storeQuery("SELECT `player_id`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `name`, `description`, `icon`, `notify` FROM `account_viplist` WHERE `account_id` = " .. accountId) + if not resultId then + return true + end + + local playerVip = Vip(playerGuid) + repeat + local vipGuid = result.getNumber(resultId, "player_id") + local vipName = result.getString(resultId, "name") + local description = result.getString(resultId, "description") + local icon = result.getNumber(resultId, "icon") + local notify = result.getNumber(resultId, "notify") ~= 0 + + -- add to player Vip cache + playerVip:add(vipGuid) + + -- calculate the Vip status + local status + local vipPlayer = Player(vipGuid) + if vipPlayer and player:canSeeCreature(vipPlayer) then + status = VIPSTATUS_ONLINE + else + status = VIPSTATUS_OFFLINE + end + + -- send to client + player:sendVip(vipGuid, vipName, description, icon, notify, status) + until not result.next(resultId) + result.free(resultId) + + return true + end + + event:register() +end + +do + local event = CreatureEvent("OfflineVip") + + function event.onLogout(player) + local playerGuid = player:getGuid() + notifyAllPlayers(playerGuid, VIPSTATUS_OFFLINE) + + local playerVip = Vip(playerGuid) + playerVip:clear() + return true + end + + event:register() +end + diff --git a/data/scripts/network/viplist.lua b/data/scripts/network/viplist.lua new file mode 100644 index 0000000000..73bd5dd3f8 --- /dev/null +++ b/data/scripts/network/viplist.lua @@ -0,0 +1,39 @@ + +do + -- Request add vip + local handler = PacketHandler(0xDC) + + function handler.onReceive(player, msg) + local name = msg:getString() + player:addVip(name) + end + + handler:register() +end + +do + -- Request remove vip + local handler = PacketHandler(0xDD) + + function handler.onReceive(player, msg) + local vipGuid = msg:getU32() + player:removeVip(vipGuid) + end + + handler:register() +end + +do + -- Request edit vip + local handler = PacketHandler(0xDE) + + function handler.onReceive(player, msg) + local vipGuid = msg:getU32() + local description = msg:getString() + local icon = math.min(10, msg:getU32()) -- 10 is max icon in 9.63 + local notify = msg:getByte() ~= 0 + player:editVip(vipGuid, description, icon, notify) + end + + handler:register() +end diff --git a/src/configmanager.cpp b/src/configmanager.cpp index f3ec1170f0..dc25b14982 100644 --- a/src/configmanager.cpp +++ b/src/configmanager.cpp @@ -284,8 +284,6 @@ bool ConfigManager::load() integer[SERVER_SAVE_NOTIFY_DURATION] = getGlobalNumber(L, "serverSaveNotifyDuration", 5); integer[YELL_MINIMUM_LEVEL] = getGlobalNumber(L, "yellMinimumLevel", 2); integer[MINIMUM_LEVEL_TO_SEND_PRIVATE] = getGlobalNumber(L, "minimumLevelToSendPrivate", 1); - integer[VIP_FREE_LIMIT] = getGlobalNumber(L, "vipFreeLimit", 20); - integer[VIP_PREMIUM_LIMIT] = getGlobalNumber(L, "vipPremiumLimit", 100); integer[DEPOT_FREE_LIMIT] = getGlobalNumber(L, "depotFreeLimit", 2000); integer[DEPOT_PREMIUM_LIMIT] = getGlobalNumber(L, "depotPremiumLimit", 15000); integer[QUEST_TRACKER_FREE_LIMIT] = getGlobalNumber(L, "questTrackerFreeLimit", 10); diff --git a/src/configmanager.h b/src/configmanager.h index 8268afc107..28eff446ed 100644 --- a/src/configmanager.h +++ b/src/configmanager.h @@ -113,8 +113,6 @@ enum integer_config_t SERVER_SAVE_NOTIFY_DURATION, YELL_MINIMUM_LEVEL, MINIMUM_LEVEL_TO_SEND_PRIVATE, - VIP_FREE_LIMIT, - VIP_PREMIUM_LIMIT, DEPOT_FREE_LIMIT, DEPOT_PREMIUM_LIMIT, QUEST_TRACKER_FREE_LIMIT, diff --git a/src/enums.h b/src/enums.h index 9c8cf1ffe8..2a6044dd1f 100644 --- a/src/enums.h +++ b/src/enums.h @@ -81,14 +81,6 @@ enum itemAttrTypes : uint32_t ITEM_ATTRIBUTE_CUSTOM = 1U << 31 }; -enum VipStatus_t : uint8_t -{ - VIPSTATUS_OFFLINE = 0, - VIPSTATUS_ONLINE = 1, - VIPSTATUS_PENDING = 2, - VIPSTATUS_TRAINING = 3 -}; - enum MarketAction_t { MARKETACTION_BUY = 0, diff --git a/src/game.cpp b/src/game.cpp index 01a1ed565a..3b4af5b34e 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3280,68 +3280,6 @@ void Game::playerSetFightModes(uint32_t playerId, fightMode_t fightMode, bool ch player->setSecureMode(secureMode); } -void Game::playerRequestAddVip(uint32_t playerId, const std::string& name) -{ - if (name.length() > PLAYER_NAME_LENGTH) { - return; - } - - Player* player = getPlayerByID(playerId); - if (!player) { - return; - } - - Player* vipPlayer = getPlayerByName(name); - if (!vipPlayer) { - uint32_t guid; - bool specialVip; - std::string formattedName = name; - if (!IOLoginData::getGuidByNameEx(guid, specialVip, formattedName)) { - player->sendTextMessage(MESSAGE_STATUS_SMALL, "A player with this name does not exist."); - return; - } - - if (specialVip && !player->hasFlag(PlayerFlag_SpecialVIP)) { - player->sendTextMessage(MESSAGE_STATUS_SMALL, "You can not add this player."); - return; - } - - player->addVIP(guid, formattedName, VIPSTATUS_OFFLINE); - } else { - if (vipPlayer->hasFlag(PlayerFlag_SpecialVIP) && !player->hasFlag(PlayerFlag_SpecialVIP)) { - player->sendTextMessage(MESSAGE_STATUS_SMALL, "You can not add this player."); - return; - } - - if (!vipPlayer->isInGhostMode() || player->canSeeGhostMode(vipPlayer)) { - player->addVIP(vipPlayer->getGUID(), vipPlayer->getName(), VIPSTATUS_ONLINE); - } else { - player->addVIP(vipPlayer->getGUID(), vipPlayer->getName(), VIPSTATUS_OFFLINE); - } - } -} - -void Game::playerRequestRemoveVip(uint32_t playerId, uint32_t guid) -{ - Player* player = getPlayerByID(playerId); - if (!player) { - return; - } - - player->removeVIP(guid); -} - -void Game::playerRequestEditVip(uint32_t playerId, uint32_t guid, const std::string& description, uint32_t icon, - bool notify) -{ - Player* player = getPlayerByID(playerId); - if (!player) { - return; - } - - player->editVIP(guid, description, icon, notify); -} - void Game::playerTurn(uint32_t playerId, Direction dir) { Player* player = getPlayerByID(playerId); diff --git a/src/game.h b/src/game.h index 40881a29a1..ccb7621e5f 100644 --- a/src/game.h +++ b/src/game.h @@ -362,10 +362,6 @@ class Game void playerSetFightModes(uint32_t playerId, fightMode_t fightMode, bool chaseMode, bool secureMode); void playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos); void playerLookInBattleList(uint32_t playerId, uint32_t creatureId); - void playerRequestAddVip(uint32_t playerId, const std::string& name); - void playerRequestRemoveVip(uint32_t playerId, uint32_t guid); - void playerRequestEditVip(uint32_t playerId, uint32_t guid, const std::string& description, uint32_t icon, - bool notify); void playerTurn(uint32_t playerId, Direction dir); void playerRequestOutfit(uint32_t playerId); void playerRequestEditPodium(uint32_t playerId, const Position& position, uint8_t stackPos, diff --git a/src/iologindata.cpp b/src/iologindata.cpp index 5d90e837b6..59c713716b 100644 --- a/src/iologindata.cpp +++ b/src/iologindata.cpp @@ -496,14 +496,6 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result) } while (result->next()); } - // load vip list - if ((result = db.storeQuery(fmt::format("SELECT `player_id` FROM `account_viplist` WHERE `account_id` = {:d}", - player->getAccount())))) { - do { - player->addVIPInternal(result->getNumber("player_id")); - } while (result->next()); - } - // load outfits & addons if ((result = db.storeQuery(fmt::format( "SELECT `outfit_id`, `addons` FROM `player_outfits` WHERE `player_id` = {:d}", player->getGUID())))) { @@ -912,31 +904,6 @@ uint32_t IOLoginData::getGuidByName(const std::string& name) return result->getNumber("id"); } -bool IOLoginData::getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name) -{ - Database& db = Database::getInstance(); - - DBResult_ptr result = db.storeQuery(fmt::format( - "SELECT `name`, `id`, `group_id`, `account_id` FROM `players` WHERE `name` = {:s}", db.escapeString(name))); - if (!result) { - return false; - } - - name = result->getString("name"); - guid = result->getNumber("id"); - Group* group = g_game.groups.getGroup(result->getNumber("group_id")); - - uint64_t flags; - if (group) { - flags = group->flags; - } else { - flags = 0; - } - - specialVip = (flags & PlayerFlag_SpecialVIP) != 0; - return true; -} - bool IOLoginData::formatPlayerName(std::string& name) { Database& db = Database::getInstance(); @@ -987,47 +954,6 @@ bool IOLoginData::hasBiddedOnHouse(uint32_t guid) return db.storeQuery(fmt::format("SELECT `id` FROM `houses` WHERE `highest_bidder` = {:d} LIMIT 1", guid)).get(); } -std::forward_list IOLoginData::getVIPEntries(uint32_t accountId) -{ - std::forward_list entries; - - DBResult_ptr result = Database::getInstance().storeQuery(fmt::format( - "SELECT `player_id`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `name`, `description`, `icon`, `notify` FROM `account_viplist` WHERE `account_id` = {:d}", - accountId)); - if (result) { - do { - entries.emplace_front(result->getNumber("player_id"), result->getString("name"), - result->getString("description"), result->getNumber("icon"), - result->getNumber("notify") != 0); - } while (result->next()); - } - return entries; -} - -void IOLoginData::addVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, - bool notify) -{ - Database& db = Database::getInstance(); - db.executeQuery(fmt::format( - "INSERT INTO `account_viplist` (`account_id`, `player_id`, `description`, `icon`, `notify`) VALUES ({:d}, {:d}, {:s}, {:d}, {:d})", - accountId, guid, db.escapeString(description), icon, notify)); -} - -void IOLoginData::editVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, - bool notify) -{ - Database& db = Database::getInstance(); - db.executeQuery(fmt::format( - "UPDATE `account_viplist` SET `description` = {:s}, `icon` = {:d}, `notify` = {:d} WHERE `account_id` = {:d} AND `player_id` = {:d}", - db.escapeString(description), icon, notify, accountId, guid)); -} - -void IOLoginData::removeVIPEntry(uint32_t accountId, uint32_t guid) -{ - Database::getInstance().executeQuery( - fmt::format("DELETE FROM `account_viplist` WHERE `account_id` = {:d} AND `player_id` = {:d}", accountId, guid)); -} - void IOLoginData::updatePremiumTime(uint32_t accountId, time_t endTime) { Database::getInstance().executeQuery( diff --git a/src/iologindata.h b/src/iologindata.h index 312481d751..2e541519b5 100644 --- a/src/iologindata.h +++ b/src/iologindata.h @@ -10,7 +10,6 @@ class Item; class Player; class PropWriteStream; -struct VIPEntry; using ItemBlockList = std::list>; @@ -30,19 +29,11 @@ class IOLoginData static bool loadPlayer(Player* player, DBResult_ptr result); static bool savePlayer(Player* player); static uint32_t getGuidByName(const std::string& name); - static bool getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name); 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::forward_list getVIPEntries(uint32_t accountId); - static void addVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, - bool notify); - static void editVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, - bool notify); - static void removeVIPEntry(uint32_t accountId, uint32_t guid); - static void updatePremiumTime(uint32_t accountId, time_t endTime); private: diff --git a/src/luascript.cpp b/src/luascript.cpp index d26c126a68..28ef335fa4 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -2275,6 +2275,8 @@ void LuaScriptInterface::registerFunctions() registerEnum(L, MONSTER_ICON_FIRST); registerEnum(L, MONSTER_ICON_LAST); + registerEnum(L, PLAYER_NAME_LENGTH); + // _G registerGlobalVariable(L, "INDEX_WHEREEVER", INDEX_WHEREEVER); registerGlobalBoolean(L, "VIRTUAL_PARENT", true); @@ -11029,21 +11031,8 @@ int LuaScriptInterface::luaPlayerSetGhostMode(lua_State* L) } } - if (player->isInGhostMode()) { - for (const auto& it : g_game.getPlayers()) { - if (!it.second->isAccessPlayer()) { - it.second->notifyStatusChange(player, VIPSTATUS_OFFLINE); - } - } - IOLoginData::updateOnlineStatus(player->getGUID(), false); - } else { - for (const auto& it : g_game.getPlayers()) { - if (!it.second->isAccessPlayer()) { - it.second->notifyStatusChange(player, VIPSTATUS_ONLINE); - } - } - IOLoginData::updateOnlineStatus(player->getGUID(), true); - } + IOLoginData::updateOnlineStatus(player->getGUID(), !player->isInGhostMode()); + tfs::lua::pushBoolean(L, true); return 1; } diff --git a/src/player.cpp b/src/player.cpp index 380bd802c3..1b7126755c 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2261,23 +2261,9 @@ void Player::addInFightTicks(bool pzlock /*= false*/) addCondition(condition); } -void Player::removeList() -{ - g_game.removePlayer(this); - - for (const auto& it : g_game.getPlayers()) { - it.second->notifyStatusChange(this, VIPSTATUS_OFFLINE); - } -} - -void Player::addList() -{ - for (const auto& it : g_game.getPlayers()) { - it.second->notifyStatusChange(this, VIPSTATUS_ONLINE); - } +void Player::removeList() { g_game.removePlayer(this); } - g_game.addPlayer(this); -} +void Player::addList() { g_game.addPlayer(this); } void Player::kickPlayer(bool displayEffect) { @@ -2289,76 +2275,6 @@ void Player::kickPlayer(bool displayEffect) } } -void Player::notifyStatusChange(Player* loginPlayer, VipStatus_t status) -{ - if (!client) { - return; - } - - auto it = VIPList.find(loginPlayer->guid); - if (it == VIPList.end()) { - return; - } - - client->sendUpdatedVIPStatus(loginPlayer->guid, status); - - if (status == VIPSTATUS_ONLINE) { - client->sendTextMessage(TextMessage(MESSAGE_STATUS_SMALL, loginPlayer->getName() + " has logged in.")); - } else if (status == VIPSTATUS_OFFLINE) { - client->sendTextMessage(TextMessage(MESSAGE_STATUS_SMALL, loginPlayer->getName() + " has logged out.")); - } -} - -bool Player::removeVIP(uint32_t vipGuid) -{ - if (VIPList.erase(vipGuid) == 0) { - return false; - } - - IOLoginData::removeVIPEntry(accountNumber, vipGuid); - return true; -} - -bool Player::addVIP(uint32_t vipGuid, const std::string& vipName, VipStatus_t status) -{ - if (VIPList.size() >= getMaxVIPEntries()) { - sendTextMessage(MESSAGE_STATUS_SMALL, "You cannot add more buddies."); - return false; - } - - auto result = VIPList.insert(vipGuid); - if (!result.second) { - sendTextMessage(MESSAGE_STATUS_SMALL, "This player is already in your list."); - return false; - } - - IOLoginData::addVIPEntry(accountNumber, vipGuid, "", 0, false); - if (client) { - client->sendVIP(vipGuid, vipName, "", 0, false, status); - } - return true; -} - -bool Player::addVIPInternal(uint32_t vipGuid) -{ - if (VIPList.size() >= getMaxVIPEntries()) { - return false; - } - - return VIPList.insert(vipGuid).second; -} - -bool Player::editVIP(uint32_t vipGuid, const std::string& description, uint32_t icon, bool notify) -{ - auto it = VIPList.find(vipGuid); - if (it == VIPList.end()) { - return false; // player is not in VIP - } - - IOLoginData::editVIPEntry(accountNumber, vipGuid, description, icon, notify); - return true; -} - // close container and its child containers void Player::autoCloseContainers(const Container* container) { @@ -4646,15 +4562,6 @@ uint64_t Player::getMoney() const return moneyCount; } -size_t Player::getMaxVIPEntries() const -{ - if (group->maxVipEntries != 0) { - return group->maxVipEntries; - } - - return getNumber(isPremium() ? ConfigManager::VIP_PREMIUM_LIMIT : ConfigManager::VIP_FREE_LIMIT); -} - size_t Player::getMaxDepotItems() const { if (group->maxDepotItems != 0) { diff --git a/src/player.h b/src/player.h index 572942aeab..6637389fb7 100644 --- a/src/player.h +++ b/src/player.h @@ -53,19 +53,6 @@ enum tradestate_t : uint8_t TRADE_TRANSFER, }; -struct VIPEntry -{ - VIPEntry(uint32_t guid, std::string_view name, std::string_view description, uint32_t icon, bool notify) : - guid{guid}, name{name}, description{description}, icon{icon}, notify{notify} - {} - - uint32_t guid; - std::string name; - std::string description; - uint32_t icon; - bool notify; -}; - struct OpenContainer { Container* container; @@ -398,13 +385,6 @@ class Player final : public Creature, public Cylinder return shopOwner; } - // V.I.P. functions - void notifyStatusChange(Player* loginPlayer, VipStatus_t status); - bool removeVIP(uint32_t vipGuid); - bool addVIP(uint32_t vipGuid, const std::string& vipName, VipStatus_t status); - bool addVIPInternal(uint32_t vipGuid); - bool editVIP(uint32_t vipGuid, const std::string& description, uint32_t icon, bool notify); - // follow functions bool setFollowCreature(Creature* creature) override; void goToFollowCreature() override; @@ -528,7 +508,6 @@ class Player final : public Creature, public Cylinder bool removeOutfitAddon(uint16_t lookType, uint8_t addons); bool getOutfitAddons(const Outfit& outfit, uint8_t& addons) const; - size_t getMaxVIPEntries() const; size_t getMaxDepotItems() const; // tile @@ -1163,7 +1142,6 @@ class Player final : public Creature, public Cylinder void internalAddThing(uint32_t index, Thing* thing) override; std::unordered_set attackedSet; - std::unordered_set VIPList; std::map openContainers; std::map depotChests; diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp index 5edfbb3dcb..c0ae81982b 100644 --- a/src/protocolgame.cpp +++ b/src/protocolgame.cpp @@ -736,15 +736,6 @@ void ProtocolGame::parsePacket(NetworkMessage& msg) // case 0xD5: break; // apply imbuement // case 0xD6: break; // clear imbuement // case 0xD7: break; // close imbuing window - case 0xDC: - parseAddVip(msg); - break; - case 0xDD: - parseRemoveVip(msg); - break; - case 0xDE: - parseEditVip(msg); - break; // case 0xDF: break; // premium shop (?) // case 0xE0: break; // premium shop (?) // case 0xE4: break; // buy charm rune @@ -1379,30 +1370,6 @@ void ProtocolGame::parseLookInTrade(NetworkMessage& msg) }); } -void ProtocolGame::parseAddVip(NetworkMessage& msg) -{ - auto name = msg.getString(); - g_dispatcher.addTask( - [playerID = player->getID(), name = std::string{name}]() { g_game.playerRequestAddVip(playerID, name); }); -} - -void ProtocolGame::parseRemoveVip(NetworkMessage& msg) -{ - uint32_t guid = msg.get(); - g_dispatcher.addTask([=, playerID = player->getID()]() { g_game.playerRequestRemoveVip(playerID, guid); }); -} - -void ProtocolGame::parseEditVip(NetworkMessage& msg) -{ - uint32_t guid = msg.get(); - auto description = msg.getString(); - uint32_t icon = std::min(10, msg.get()); // 10 is max icon in 9.63 - bool notify = msg.getByte() != 0; - g_dispatcher.addTask([=, playerID = player->getID(), description = std::string{description}]() { - g_game.playerRequestEditVip(playerID, guid, description, icon, notify); - }); -} - void ProtocolGame::parseRotateItem(NetworkMessage& msg) { Position pos = msg.getPosition(); @@ -2807,9 +2774,6 @@ void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos // player light level sendCreatureLight(creature); - // player vip list - sendVIPEntries(); - // tiers for forge and market sendItemClasses(); @@ -3275,47 +3239,6 @@ void ProtocolGame::sendPodiumWindow(const Item* item) writeToOutputBuffer(msg); } -void ProtocolGame::sendUpdatedVIPStatus(uint32_t guid, VipStatus_t newStatus) -{ - NetworkMessage msg; - msg.addByte(0xD3); - msg.add(guid); - msg.addByte(newStatus); - writeToOutputBuffer(msg); -} - -void ProtocolGame::sendVIP(uint32_t guid, const std::string& name, const std::string& description, uint32_t icon, - bool notify, VipStatus_t status) -{ - NetworkMessage msg; - msg.addByte(0xD2); - msg.add(guid); - msg.addString(name); - msg.addString(description); - msg.add(std::min(10, icon)); - msg.addByte(notify ? 0x01 : 0x00); - msg.addByte(status); - msg.addByte(0x00); // vipGroups (placeholder) - writeToOutputBuffer(msg); -} - -void ProtocolGame::sendVIPEntries() -{ - const std::forward_list& vipEntries = IOLoginData::getVIPEntries(player->getAccount()); - - for (const VIPEntry& entry : vipEntries) { - VipStatus_t vipStatus = VIPSTATUS_ONLINE; - - Player* vipPlayer = g_game.getPlayerByGUID(entry.guid); - - if (!vipPlayer || !player->canSeeCreature(vipPlayer)) { - vipStatus = VIPSTATUS_OFFLINE; - } - - sendVIP(entry.guid, entry.name, entry.description, entry.icon, entry.notify, vipStatus); - } -} - void ProtocolGame::sendItemClasses() { NetworkMessage msg; diff --git a/src/protocolgame.h b/src/protocolgame.h index f6c792ad21..48062fe250 100644 --- a/src/protocolgame.h +++ b/src/protocolgame.h @@ -140,11 +140,6 @@ class ProtocolGame final : public Protocol void parseMarketCancelOffer(NetworkMessage& msg); void parseMarketAcceptOffer(NetworkMessage& msg); - // VIP methods - void parseAddVip(NetworkMessage& msg); - void parseRemoveVip(NetworkMessage& msg); - void parseEditVip(NetworkMessage& msg); - void parseRotateItem(NetworkMessage& msg); // Channel tabs @@ -220,11 +215,6 @@ class ProtocolGame final : public Protocol void sendPodiumWindow(const Item* item); - void sendUpdatedVIPStatus(uint32_t guid, VipStatus_t newStatus); - void sendVIP(uint32_t guid, const std::string& name, const std::string& description, uint32_t icon, bool notify, - VipStatus_t status); - void sendVIPEntries(); - void sendItemClasses(); void sendPendingStateEntered();