diff --git a/data/XML/groups.xml b/data/XML/groups.xml index 935cb2c..bdd3c44 100644 --- a/data/XML/groups.xml +++ b/data/XML/groups.xml @@ -142,6 +142,7 @@ + diff --git a/data/chatchannels/chatchannels.xml b/data/chatchannels/chatchannels.xml index 66e0a41..877d47d 100644 --- a/data/chatchannels/chatchannels.xml +++ b/data/chatchannels/chatchannels.xml @@ -5,7 +5,7 @@ - + - + diff --git a/data/chatchannels/scripts/execute.lua b/data/chatchannels/scripts/execute.lua index 47b18c9..fcbd312 100644 --- a/data/chatchannels/scripts/execute.lua +++ b/data/chatchannels/scripts/execute.lua @@ -1,4 +1,4 @@ -local CHAT_ID = 9 +local CHAT_ID = 7 function canJoin(player) return player:getAccountType() >= ACCOUNT_TYPE_GOD end diff --git a/data/scripts/eventcallbacks/account_manager.lua b/data/scripts/eventcallbacks/account_manager.lua index 47fb200..056df53 100644 --- a/data/scripts/eventcallbacks/account_manager.lua +++ b/data/scripts/eventcallbacks/account_manager.lua @@ -1,7 +1,12 @@ -- #region Configuration local ACCOUNT_MANAGER_ACCOUNT_ID = 1 local ACCOUNT_MANAGER_STORAGE = {} -local ACCOUNT_MANAGER_LOGOUT_DELAY = 60 -- 60 seconds +local ACCOUNT_MANAGER_LOGOUT_DELAY = 1 * 60 -- 1 minute + +local ACCOUNT_MANAGER_LOGINS = {} +local ACCOUNT_MANAGER_LOGIN_TRIES = 5 +local ACCOUNT_MANAGER_LOGIN_TIMEOUT = 30 -- 30 seconds +local ACCOUNT_MANAGER_BAN_TIME = 1 * 60 -- 10 minutes local CREATE_ACCOUNT_TABLE = {} local CREATE_ACCOUNT_EXHAUST = 30 * 60 -- 30 minutes @@ -449,13 +454,50 @@ local function logoutEvent(player, playerId) if player then player:remove() end end +---@param player Player +---@param days integer +---@param reason string +---@return boolean +function banIp(player, days, reason) + local ip = player:getIp() + local resultId = db.storeQuery("SELECT 1 FROM `ip_bans` WHERE `ip` = " .. ip) + if resultId then + result.free(resultId) + return false + end + + local timeNow = os.time() + db.query(string.format( + "INSERT INTO `ip_bans` (`ip`, `reason`, `banned_at`, `expires_at`, `banned_by`) VALUES (%d, %s, %d, %d, %d)", + ip, db.escapeString(reason), timeNow, timeNow + (days * 86400), + player:getGuid())) + return true +end + local login = CreatureEvent("Account Manager Login") function login.onLogin(player) if player:isAccountManager() then + local playerIp = player:getIp() + -- Protect + local tries = ACCOUNT_MANAGER_LOGINS[playerIp] + if tries and tries >= ACCOUNT_MANAGER_LOGIN_TRIES then + banIp(player, ACCOUNT_MANAGER_BAN_TIME, "Too many login attempts.") + return false + end + + ACCOUNT_MANAGER_LOGINS[playerIp] = tries and tries + 1 or 1 + -- Decrease Tries + addEvent(function(playerIp) + ACCOUNT_MANAGER_LOGINS[playerIp] = ACCOUNT_MANAGER_LOGINS[playerIp] - 1 + if ACCOUNT_MANAGER_LOGINS[playerIp] <= 0 then + ACCOUNT_MANAGER_LOGINS[playerIp] = nil + end + end, ACCOUNT_MANAGER_LOGIN_TIMEOUT * 1000, playerIp) + -- Logout Event addEvent(logoutEvent, ACCOUNT_MANAGER_LOGOUT_DELAY * 1000, player, - player:getId()) + player:getIp()) -- Initial Message local send = sender(player) diff --git a/data/scripts/eventcallbacks/player/default_onReportBug.lua b/data/scripts/eventcallbacks/player/default_onReportBug.lua index bb04c3b..0a64c2c 100644 --- a/data/scripts/eventcallbacks/player/default_onReportBug.lua +++ b/data/scripts/eventcallbacks/player/default_onReportBug.lua @@ -12,19 +12,18 @@ event.onReportBug = function(self, message, position, category) return true end - io.output(file) - io.write("------------------------------\n") - io.write("Name: " .. name) + file:write("------------------------------\n") + file:write("Name: " .. name) if category == BUG_CATEGORY_MAP then - io.write(" [Map position: " .. position.x .. ", " .. position.y .. ", " .. + file:write(" [Map position: " .. position.x .. ", " .. position.y .. ", " .. position.z .. "]") end local playerPosition = self:getPosition() - io.write( + file:write( " [Player Position: " .. playerPosition.x .. ", " .. playerPosition.y .. ", " .. playerPosition.z .. "]\n") - io.write("Comment: " .. message .. "\n") - io.close(file) + file:write("Comment: " .. message .. "\n") + file:close() self:sendTextMessage(MESSAGE_EVENT_DEFAULT, "Your report has been sent to " .. configManager.getString(configKeys.SERVER_NAME) .. ".") diff --git a/data/scripts/eventcallbacks/player/default_onReportRuleViolation.lua b/data/scripts/eventcallbacks/player/default_onReportRuleViolation.lua index ab22e7c..d6fa7e5 100644 --- a/data/scripts/eventcallbacks/player/default_onReportRuleViolation.lua +++ b/data/scripts/eventcallbacks/player/default_onReportRuleViolation.lua @@ -2,7 +2,7 @@ local function hasPendingReport(name, targetName, reportType) local f = io.open(string.format("data/reports/players/%s-%s-%d.txt", name, targetName, reportType), "r") if f then - io.close(f) + f:close() return true else return false @@ -27,18 +27,17 @@ event.onReportRuleViolation = function(self, targetName, reportType, return end - io.output(file) - io.write("------------------------------\n") - io.write("Reported by: " .. name .. "\n") - io.write("Target: " .. targetName .. "\n") - io.write("Type: " .. reportType .. "\n") - io.write("Reason: " .. reportReason .. "\n") - io.write("Comment: " .. comment .. "\n") + file:write("------------------------------\n") + file:write("Reported by: " .. name .. "\n") + file:write("Target: " .. targetName .. "\n") + file:write("Type: " .. reportType .. "\n") + file:write("Reason: " .. reportReason .. "\n") + file:write("Comment: " .. comment .. "\n") if reportType ~= REPORT_TYPE_BOT then - io.write("Translation: " .. translation .. "\n") + file:write("Translation: " .. translation .. "\n") end - io.write("------------------------------\n") - io.close(file) + file:write("------------------------------\n") + file:close() self:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format( "Thank you for reporting %s. Your report will be processed by %s team as soon as possible.", targetName, diff --git a/src/const.h b/src/const.h index cce3252..353686c 100644 --- a/src/const.h +++ b/src/const.h @@ -457,6 +457,7 @@ enum PlayerFlags : uint64_t PlayerFlag_IsAlwaysPremium = static_cast(1) << 37, PlayerFlag_IgnoreYellCheck = static_cast(1) << 38, PlayerFlag_IgnoreSendPrivateCheck = static_cast(1) << 39, + PlayerFlag_CanThrowFar = static_cast(1) << 40, }; enum ReloadTypes_t : uint8_t diff --git a/src/game.cpp b/src/game.cpp index 0cc6b67..166748c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -546,7 +546,7 @@ bool Game::removeCreature(Creature* creature, bool isLogout /* = true*/) for (Creature* spectator : spectators) { if (Player* player = spectator->getPlayer()) { if (player->canSeeCreature(creature)) { - player->sendRemoveTileCreature(creature, tilePosition, oldStackPosVector[i++]); + player->sendRemoveTileThing(tilePosition, oldStackPosVector[i++]); } } } @@ -672,9 +672,11 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po return; } + const bool canThrowFar = player->hasFlag(PlayerFlag_CanThrowFar); + player->setNextActionTask(nullptr); - if (!Position::areInRange<1, 1, 0>(movingCreatureOrigPos, player->getPosition())) { + if (!canThrowFar && !Position::areInRange<1, 1, 0>(movingCreatureOrigPos, player->getPosition())) { // need to walk to the creature first before moving it std::vector listDir; if (player->getPathTo(movingCreatureOrigPos, listDir, 0, 1, true, true)) { @@ -693,31 +695,35 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po return; } - if ((!movingCreature->isPushable() && !player->hasFlag(PlayerFlag_CanPushAllCreatures)) || - (movingCreature->isInGhostMode() && !player->canSeeGhostMode(movingCreature))) { - player->sendCancelMessage(RETURNVALUE_NOTMOVEABLE); - return; + if (!canThrowFar) { + if ((!movingCreature->isPushable() && !player->hasFlag(PlayerFlag_CanPushAllCreatures)) || + (movingCreature->isInGhostMode() && !player->canSeeGhostMode(movingCreature))) { + player->sendCancelMessage(RETURNVALUE_NOTMOVEABLE); + return; + } } // check throw distance const Position& movingCreaturePos = movingCreature->getPosition(); const Position& toPos = toTile->getPosition(); - if ((Position::getDistanceX(movingCreaturePos, toPos) > movingCreature->getThrowRange()) || - (Position::getDistanceY(movingCreaturePos, toPos) > movingCreature->getThrowRange()) || - (Position::getDistanceZ(movingCreaturePos, toPos) * 4 > movingCreature->getThrowRange())) { - player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH); - return; + if (!canThrowFar) { + if ((Position::getDistanceX(movingCreaturePos, toPos) > movingCreature->getThrowRange()) || + (Position::getDistanceY(movingCreaturePos, toPos) > movingCreature->getThrowRange()) || + (Position::getDistanceZ(movingCreaturePos, toPos) * 4 > movingCreature->getThrowRange())) { + player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH); + return; + } } if (player != movingCreature) { - if (toTile->hasFlag(TILESTATE_BLOCKPATH)) { + if (!canThrowFar && toTile->hasFlag(TILESTATE_BLOCKPATH)) { player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM); return; } else if ((movingCreature->getZone() == ZONE_PROTECTION && !toTile->hasFlag(TILESTATE_PROTECTIONZONE)) || (movingCreature->getZone() == ZONE_NOPVP && !toTile->hasFlag(TILESTATE_NOPVPZONE))) { player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE); return; - } else { + } else if (!canThrowFar) { if (CreatureVector* tileCreatures = toTile->getCreatures()) { for (Creature* tileCreature : *tileCreatures) { if (!tileCreature->isInGhostMode()) { @@ -739,7 +745,7 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po return; } - ReturnValue ret = internalMoveCreature(*movingCreature, *toTile); + ReturnValue ret = internalMoveCreature(*movingCreature, *toTile, canThrowFar ? FLAG_NOLIMIT : 0); if (ret != RETURNVALUE_NOERROR) { player->sendCancelMessage(ret); } @@ -913,15 +919,17 @@ void Game::playerMoveItem(Player* player, const Position& fromPos, uint16_t spri return; } + const bool canThrowFar = player->hasFlag(PlayerFlag_CanThrowFar); + const Position& playerPos = player->getPosition(); const Position& mapFromPos = fromCylinder->getTile()->getPosition(); - if (playerPos.z != mapFromPos.z) { + if (!canThrowFar && playerPos.z != mapFromPos.z) { player->sendCancelMessage(playerPos.z > mapFromPos.z ? RETURNVALUE_FIRSTGOUPSTAIRS : RETURNVALUE_FIRSTGODOWNSTAIRS); return; } - if (!Position::areInRange<1, 1>(playerPos, mapFromPos)) { + if (!canThrowFar && !Position::areInRange<1, 1>(playerPos, mapFromPos)) { // need to walk to the item first before using it std::vector listDir; if (player->getPathTo(item->getPosition(), listDir, 0, 1, true, true)) { @@ -1004,21 +1012,23 @@ void Game::playerMoveItem(Player* player, const Position& fromPos, uint16_t spri } } - if (!item->isPickupable() && playerPos.z != mapToPos.z) { + if (!canThrowFar && !item->isPickupable() && playerPos.z != mapToPos.z) { player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH); return; } - int32_t throwRange = item->getThrowRange(); - if ((Position::getDistanceX(playerPos, mapToPos) > throwRange) || - (Position::getDistanceY(playerPos, mapToPos) > throwRange)) { - player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH); - return; - } + if (!canThrowFar) { + int32_t throwRange = item->getThrowRange(); + if ((Position::getDistanceX(playerPos, mapToPos) > throwRange) || + (Position::getDistanceY(playerPos, mapToPos) > throwRange)) { + player->sendCancelMessage(RETURNVALUE_DESTINATIONOUTOFREACH); + return; + } - if (!canThrowObjectTo(mapFromPos, mapToPos, true, false, throwRange, throwRange)) { - player->sendCancelMessage(RETURNVALUE_CANNOTTHROW); - return; + if (!canThrowObjectTo(mapFromPos, mapToPos, true, false, throwRange, throwRange)) { + player->sendCancelMessage(RETURNVALUE_CANNOTTHROW); + return; + } } uint8_t toIndex = 0; @@ -1030,8 +1040,8 @@ void Game::playerMoveItem(Player* player, const Position& fromPos, uint16_t spri } } - ReturnValue ret = - internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, nullptr, 0, player, nullptr, &fromPos, &toPos); + ReturnValue ret = internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, nullptr, + canThrowFar ? FLAG_NOLIMIT : 0, player, nullptr, &fromPos, &toPos); if (ret != RETURNVALUE_NOERROR) { player->sendCancelMessage(ret); } @@ -1105,7 +1115,7 @@ ReturnValue Game::internalMoveItem(Cylinder* fromCylinder, Cylinder* toCylinder, fromCylinder->postAddNotification(toItem, toCylinder, newToItemIndex); } - ret = toCylinder->queryAdd(index, *item, count, flags); + ret = toCylinder->queryAdd(index, *item, count, flags, actor); if (actorPlayer && fromPos && toPos && !toItem->isRemoved()) { g_events->eventPlayerOnItemMoved(actorPlayer, toItem, static_cast(count), *toPos, diff --git a/src/groups.cpp b/src/groups.cpp index 33a4581..57570b9 100644 --- a/src/groups.cpp +++ b/src/groups.cpp @@ -48,7 +48,8 @@ const std::unordered_map ParsePlayerFlagMap = { {"cannotbemuted", PlayerFlag_CannotBeMuted}, {"isalwayspremium", PlayerFlag_IsAlwaysPremium}, {"ignoreyellcheck", PlayerFlag_IgnoreYellCheck}, - {"ignoresendprivatecheck", PlayerFlag_IgnoreSendPrivateCheck}}; + {"ignoresendprivatecheck", PlayerFlag_IgnoreSendPrivateCheck}, + {"canthrowfar", PlayerFlag_CanThrowFar}}; bool Groups::load() { diff --git a/src/luascript.cpp b/src/luascript.cpp index 6477ee8..cc40418 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -9737,7 +9737,7 @@ int LuaScriptInterface::luaPlayerSetGhostMode(lua_State* L) Player* tmpPlayer = static_cast(spectator); if (tmpPlayer != player && !tmpPlayer->isAccessPlayer()) { if (enabled) { - tmpPlayer->sendRemoveTileCreature(player, position, tile->getClientIndexOfCreature(tmpPlayer, player)); + tmpPlayer->sendRemoveTileThing(position, tile->getClientIndexOfCreature(tmpPlayer, player)); } else { tmpPlayer->sendCreatureAppear(player, position, showEffect); } diff --git a/src/map.cpp b/src/map.cpp index ce540fd..0f12e9d 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -313,11 +313,8 @@ void Map::moveCreature(Creature& creature, Tile& newTile, bool forceTeleport /* for (Creature* spectator : spectators) { if (Player* tmpPlayer = spectator->getPlayer()) { // Use the correct stackpos - int32_t stackpos = oldStackPosVector[i++]; - if (stackpos != -1) { - tmpPlayer->sendCreatureMove(&creature, newPos, newTile.getClientIndexOfCreature(tmpPlayer, &creature), - oldPos, stackpos, teleport); - } + tmpPlayer->sendCreatureMove(&creature, newPos, newTile.getClientIndexOfCreature(tmpPlayer, &creature), + oldPos, oldStackPosVector[i++], teleport); } } diff --git a/src/player.h b/src/player.h index 75cad9e..2b39308 100644 --- a/src/player.h +++ b/src/player.h @@ -533,12 +533,6 @@ class Player final : public Creature, public Cylinder creature->getTile()->getClientIndexOfCreature(this, creature), creature); } } - void sendRemoveTileCreature(const Creature* creature, const Position& pos, int32_t stackpos) - { - if (client) { - client->sendRemoveTileCreature(creature, pos, stackpos); - } - } void sendUpdateTile(const Tile* tile, const Position& pos) { if (client) { @@ -624,7 +618,7 @@ class Player final : public Creature, public Cylinder if (visible) { client->sendAddCreature(creature, creature->getPosition(), stackpos, false); } else { - client->sendRemoveTileCreature(creature, creature->getPosition(), stackpos); + client->sendRemoveTileThing(creature->getPosition(), stackpos); } } } diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp index c21ff76..1591fef 100644 --- a/src/protocolgame.cpp +++ b/src/protocolgame.cpp @@ -764,38 +764,48 @@ void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg) count = 0; } + const bool isStacked = player->getPosition() == tile->getPosition(); + const TileItemVector* items = tile->getItemList(); if (items) { for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) { msg.addItem(*it); - if (++count == 10) { + if (++count == 9 && isStacked) { break; + } else if (count == MAX_STACKPOS_THINGS) { + return; } } } const CreatureVector* creatures = tile->getCreatures(); if (creatures) { + bool playerAdded = false; for (auto it = creatures->rbegin(), end = creatures->rend(); it != end; ++it) { const Creature* creature = (*it); if (!player->canSeeCreature(creature)) { continue; } - bool known; - uint32_t removedKnown; - checkCreatureAsKnown(creature->getID(), known, removedKnown); + if (count == 9 && isStacked && !playerAdded) { + playerAdded = true; + creature = player; + } + + auto [known, removedKnown] = isKnownCreature(creature->getID()); AddCreature(msg, creature, known, removedKnown); - ++count; + if (++count == MAX_STACKPOS_THINGS) { + return; + } } } - if (items && count < 10) { + if (items) { for (auto it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) { msg.addItem(*it); - if (++count == 10) { + if (++count == MAX_STACKPOS_THINGS) { return; } } @@ -854,38 +864,33 @@ void ProtocolGame::GetFloorDescription(NetworkMessage& msg, int32_t x, int32_t y } } -void ProtocolGame::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown) +std::pair ProtocolGame::isKnownCreature(uint32_t id) { auto result = knownCreatureSet.insert(id); if (!result.second) { - known = true; - return; + return std::make_pair(true, 0); } - known = false; - if (knownCreatureSet.size() > 250) { // Look for a creature to remove - for (auto it = knownCreatureSet.begin(), end = knownCreatureSet.end(); it != end; ++it) { - Creature* creature = g_game.getCreatureByID(*it); + for (const uint32_t& creatureId : knownCreatureSet) { + Creature* creature = g_game.getCreatureByID(creatureId); if (!canSee(creature)) { - removedKnown = *it; - knownCreatureSet.erase(it); - return; + knownCreatureSet.erase(creatureId); + return std::make_pair(false, creatureId); } } // Bad situation. Let's just remove anyone. - auto it = knownCreatureSet.begin(); - if (*it == id) { - ++it; + auto creatureId = knownCreatureSet.begin(); + if (*creatureId == id) { + ++creatureId; } - removedKnown = *it; - knownCreatureSet.erase(it); - } else { - removedKnown = 0; + knownCreatureSet.erase(creatureId); + return std::make_pair(false, *creatureId); } + return {}; } bool ProtocolGame::canSee(const Creature* c) const @@ -1775,7 +1780,11 @@ void ProtocolGame::sendCreatureSay(const Creature* creature, SpeakClasses type, // Add level only for players if (const Player* speaker = creature->getPlayer()) { - msg.add(static_cast(speaker->getLevel())); + if (!speaker->isAccessPlayer() && !speaker->isAccountManager()) { + msg.add(static_cast(speaker->getLevel())); + } else { + msg.add(0x00); + } } else { msg.add(0x00); } @@ -1808,7 +1817,11 @@ void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, st msg.addString(creature->getName()); // Add level only for players if (const Player* speaker = creature->getPlayer()) { - msg.add(static_cast(speaker->getLevel())); + if (!speaker->isAccessPlayer() && !speaker->isAccountManager()) { + msg.add(static_cast(speaker->getLevel())); + } else { + msg.add(0x00); + } } else { msg.add(0x00); } @@ -1828,7 +1841,11 @@ void ProtocolGame::sendPrivateMessage(const Player* speaker, SpeakClasses type, msg.add(++statementId); if (speaker) { msg.addString(speaker->getName()); - msg.add(static_cast(speaker->getLevel())); + if (!speaker->isAccessPlayer() && !speaker->isAccountManager()) { + msg.add(static_cast(speaker->getLevel())); + } else { + msg.add(0x00); + } } else { msg.add(0x00); } @@ -1983,34 +2000,12 @@ void ProtocolGame::sendUpdateTileCreature(const Position& pos, uint32_t stackpos msg.addPosition(pos); msg.addByte(static_cast(stackpos)); - bool known; - uint32_t removedKnown; - checkCreatureAsKnown(creature->getID(), known, removedKnown); + auto [known, removedKnown] = isKnownCreature(creature->getID()); AddCreature(msg, creature, false, removedKnown); writeToOutputBuffer(msg); } -void ProtocolGame::sendRemoveTileCreature(const Creature* creature, const Position& pos, uint32_t stackpos) -{ - if (stackpos < 10) { - if (!canSee(pos)) { - return; - } - - NetworkMessage msg; - RemoveTileThing(msg, pos, stackpos); - writeToOutputBuffer(msg); - return; - } - - NetworkMessage msg; - msg.addByte(0x6C); - msg.add(0xFFFF); - msg.add(creature->getID()); - writeToOutputBuffer(msg); -} - void ProtocolGame::sendUpdateTile(const Tile* tile, const Position& pos) { if (!canSee(pos)) { @@ -2050,27 +2045,13 @@ void ProtocolGame::sendAddCreature(const Creature* creature, const Position& pos } if (creature != player) { - // stack pos is always real index now, so it can exceed the limit - // if stack pos exceeds the limit, we need to refresh the tile instead - // 1. this is a rare case, and is only triggered by forcing summon in a position - // 2. since no stackpos will be send to the client about that creature, removing - // it must be done with its id if its stackpos remains >= 10. this is done to - // add creatures to battle list instead of rendering on screen - if (stackpos >= 10) { - // @todo: should we avoid this check? - if (const Tile* tile = creature->getTile()) { - sendUpdateTile(tile, pos); - } - } else { - // if stackpos is -1, the client will automatically detect it + if (stackpos != -1 && stackpos < 10) { NetworkMessage msg; msg.addByte(0x6A); msg.addPosition(pos); msg.addByte(static_cast(stackpos)); - bool known; - uint32_t removedKnown; - checkCreatureAsKnown(creature->getID(), known, removedKnown); + auto [known, removedKnown] = isKnownCreature(creature->getID()); AddCreature(msg, creature, known, removedKnown); writeToOutputBuffer(msg); } @@ -2130,22 +2111,19 @@ void ProtocolGame::sendMoveCreature(const Creature* creature, const Position& ne const Position& oldPos, int32_t oldStackPos, bool teleport) { if (creature == player) { - if (teleport) { - sendRemoveTileCreature(creature, oldPos, oldStackPos); + if (oldStackPos >= MAX_STACKPOS_THINGS) { + sendMapDescription(newPos); + } else if (teleport) { + sendRemoveTileThing(oldPos, oldStackPos); sendMapDescription(newPos); } else { NetworkMessage msg; if (oldPos.z == 7 && newPos.z >= 8) { - RemoveTileCreature(msg, creature, oldPos, oldStackPos); + RemoveTileThing(msg, oldPos, oldStackPos); } else { msg.addByte(0x6D); - if (oldStackPos < 10) { - msg.addPosition(oldPos); - msg.addByte(static_cast(oldStackPos)); - } else { - msg.add(0xFFFF); - msg.add(creature->getID()); - } + msg.addPosition(oldPos); + msg.addByte(static_cast(oldStackPos)); msg.addPosition(newPos); } @@ -2177,24 +2155,19 @@ void ProtocolGame::sendMoveCreature(const Creature* creature, const Position& ne writeToOutputBuffer(msg); } } else if (canSee(oldPos) && canSee(creature->getPosition())) { - if (teleport || (oldPos.z == 7 && newPos.z >= 8)) { - sendRemoveTileCreature(creature, oldPos, oldStackPos); + if (teleport || (oldPos.z == 7 && newPos.z >= 8) || oldStackPos >= MAX_STACKPOS_THINGS) { + sendRemoveTileThing(oldPos, oldStackPos); sendAddCreature(creature, newPos, newStackPos, false); } else { NetworkMessage msg; msg.addByte(0x6D); - if (oldStackPos < 10) { - msg.addPosition(oldPos); - msg.addByte(static_cast(oldStackPos)); - } else { - msg.add(0xFFFF); - msg.add(creature->getID()); - } + msg.addPosition(oldPos); + msg.addByte(static_cast(oldStackPos)); msg.addPosition(creature->getPosition()); writeToOutputBuffer(msg); } } else if (canSee(oldPos)) { - sendRemoveTileCreature(creature, oldPos, oldStackPos); + sendRemoveTileThing(oldPos, oldStackPos); } else if (canSee(creature->getPosition())) { sendAddCreature(creature, newPos, newStackPos, false); } @@ -2517,19 +2490,6 @@ void ProtocolGame::RemoveTileThing(NetworkMessage& msg, const Position& pos, uin msg.addByte(static_cast(stackpos)); } -void ProtocolGame::RemoveTileCreature(NetworkMessage& msg, const Creature* creature, const Position& pos, - uint32_t stackpos) -{ - if (stackpos < 10) { - RemoveTileThing(msg, pos, stackpos); - return; - } - - msg.addByte(0x6C); - msg.add(0xFFFF); - msg.add(creature->getID()); -} - void ProtocolGame::MoveUpCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos) { diff --git a/src/protocolgame.h b/src/protocolgame.h index 24ce286..65c86ac 100644 --- a/src/protocolgame.h +++ b/src/protocolgame.h @@ -70,7 +70,7 @@ class ProtocolGame final : public Protocol void release() override; - void checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown); + std::pair isKnownCreature(uint32_t id); bool canSee(int32_t x, int32_t y, int32_t z) const; bool canSee(const Creature*) const; @@ -198,7 +198,6 @@ class ProtocolGame final : public Protocol void sendUpdateTileItem(const Position& pos, uint32_t stackpos, const Item* item); void sendRemoveTileThing(const Position& pos, uint32_t stackpos); void sendUpdateTileCreature(const Position& pos, uint32_t stackpos, const Creature* creature); - void sendRemoveTileCreature(const Creature* creature, const Position& pos, uint32_t stackpos); void sendUpdateTile(const Tile* tile, const Position& pos); void sendAddCreature(const Creature* creature, const Position& pos, int32_t stackpos, bool isLogin); @@ -237,8 +236,6 @@ class ProtocolGame final : public Protocol // tiles static void RemoveTileThing(NetworkMessage& msg, const Position& pos, uint32_t stackpos); - static void RemoveTileCreature(NetworkMessage& msg, const Creature* creature, const Position& pos, - uint32_t stackpos); void MoveUpCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, const Position& oldPos); void MoveDownCreature(NetworkMessage& msg, const Creature* creature, const Position& newPos, diff --git a/src/tile.cpp b/src/tile.cpp index 86b23a6..396b72b 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -1204,13 +1204,13 @@ int32_t Tile::getStackposOfItem(const Player* player, const Item* item) const for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) { if (*it == item) { return n; - } else if (++n == 10) { + } else if (++n == MAX_STACKPOS_THINGS) { return -1; } } } else { n += items->getTopItemCount(); - if (n >= 10) { + if (n >= MAX_STACKPOS_THINGS) { return -1; } } @@ -1219,7 +1219,7 @@ int32_t Tile::getStackposOfItem(const Player* player, const Item* item) const if (const CreatureVector* creatures = getCreatures()) { for (const Creature* creature : *creatures) { if (player->canSeeCreature(creature)) { - if (++n >= 10) { + if (++n >= MAX_STACKPOS_THINGS) { return -1; } } @@ -1230,7 +1230,7 @@ int32_t Tile::getStackposOfItem(const Player* player, const Item* item) const for (auto it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; ++it) { if (*it == item) { return n; - } else if (++n >= 10) { + } else if (++n >= MAX_STACKPOS_THINGS) { return -1; } } diff --git a/src/tile.h b/src/tile.h index cc731ce..3673e03 100644 --- a/src/tile.h +++ b/src/tile.h @@ -20,6 +20,8 @@ class BedItem; using CreatureVector = std::vector; using ItemVector = std::vector; +static constexpr int32_t MAX_STACKPOS_THINGS = 10; + enum tileflags_t : uint32_t { TILESTATE_NONE = 0,