From bf96cedf92af9c5d5086cd7b51d5b33c26e576ac Mon Sep 17 00:00:00 2001 From: Elson Costa Date: Thu, 18 Jul 2024 08:56:09 -0300 Subject: [PATCH] fix: config to avoid the support outfit crashes on login (#2526) --- config.lua.dist | 2 + data/scripts/creaturescripts/player/login.lua | 8 +++ src/config/config_enums.hpp | 1 + src/config/configmanager.cpp | 1 + src/creatures/creature.hpp | 4 ++ src/creatures/players/player.cpp | 4 ++ src/game/game.cpp | 7 ++- src/server/network/protocol/protocolgame.cpp | 55 ++++++++++--------- 8 files changed, 56 insertions(+), 26 deletions(-) diff --git a/config.lua.dist b/config.lua.dist index 9d1ed2fa681..6823be5e0b1 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -254,6 +254,7 @@ onlyPremiumAccount = false -- NOTE: startStreakLevel will make a reward streak level for new players who never logged in -- NOTE: if showLootsInBestiary is true, will cause all loots to be shown in the bestiary even if the player has not reached the required number of kills -- NOTE: minTownIdToBankTransfer blocks towns less than defined from receiving money transfers +-- NOTE: enableSupportOutfit enable GODS and GMS to select support outfit (gamemaster, customer support or community manager) stashMoving = false depotChest = 4 autoLoot = false @@ -273,6 +274,7 @@ enablePlayerPutItemInAmmoSlot = false startStreakLevel = 0 showLootsInBestiary = false minTownIdToBankTransfer = 3 +enableSupportOutfit = true -- Teleport summon -- Set to true will never remove the summon diff --git a/data/scripts/creaturescripts/player/login.lua b/data/scripts/creaturescripts/player/login.lua index 41676066975..5f9f0e695f4 100644 --- a/data/scripts/creaturescripts/player/login.lua +++ b/data/scripts/creaturescripts/player/login.lua @@ -169,6 +169,14 @@ function playerLoginGlobal.onLogin(player) onMovementRemoveProtection(playerId, player:getPosition(), 10) end + -- Change support outfit to a normal outfit to open customize character without crashes + local playerOutfit = player:getOutfit() + if table.contains({ 75, 266, 302 }, playerOutfit.lookType) then + playerOutfit.lookType = 136 + playerOutfit.lookAddons = 0 + player:setOutfit(playerOutfit) + end + player:initializeLoyaltySystem() player:registerEvent("PlayerDeath") player:registerEvent("DropLoot") diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp index 6a6f12f890e..b414815429c 100644 --- a/src/config/config_enums.hpp +++ b/src/config/config_enums.hpp @@ -66,6 +66,7 @@ enum ConfigKey_t : uint16_t { DISCORD_WEBHOOK_URL, EMOTE_SPELLS, ENABLE_PLAYER_PUT_ITEM_IN_AMMO_SLOT, + ENABLE_SUPPORT_OUTFIT, EX_ACTIONS_DELAY_INTERVAL, EXP_FROM_PLAYERS_LEVEL_RANGE, EXPERIENCE_FROM_PLAYERS, diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp index 2b4d1ae960f..d653031125c 100644 --- a/src/config/configmanager.cpp +++ b/src/config/configmanager.cpp @@ -99,6 +99,7 @@ bool ConfigManager::load() { loadBoolConfig(L, DISCORD_SEND_FOOTER, "discordSendFooter", true); loadBoolConfig(L, EMOTE_SPELLS, "emoteSpells", false); loadBoolConfig(L, ENABLE_PLAYER_PUT_ITEM_IN_AMMO_SLOT, "enablePlayerPutItemInAmmoSlot", false); + loadBoolConfig(L, ENABLE_SUPPORT_OUTFIT, "enableSupportOutfit", true); loadBoolConfig(L, EXPERIENCE_FROM_PLAYERS, "experienceByKillingPlayers", false); loadBoolConfig(L, FORCE_MONSTERTYPE_LOAD, "forceMonsterTypesOnLoad", true); loadBoolConfig(L, FREE_PREMIUM, "freePremium", false); diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index c41429a60cd..68c7f01e12e 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -282,6 +282,10 @@ class Creature : virtual public Thing, public SharedObject { const Outfit_t getDefaultOutfit() const { return defaultOutfit; } + bool isWearingSupportOutfit() const { + auto outfit = currentOutfit.lookType; + return outfit == 75 || outfit == 266 || outfit == 302; + } bool isInvisible() const; ZoneType_t getZoneType() { if (getTile()) { diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 2660c039110..a6db39f587d 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -5826,6 +5826,10 @@ bool Player::toggleMount(bool mount) { return false; } + if (isWearingSupportOutfit()) { + return false; + } + if (mount) { if (isMounted()) { return false; diff --git a/src/game/game.cpp b/src/game/game.cpp index 40b82d6b47e..949da71c0a3 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -4266,7 +4266,7 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos } const auto mount = mounts.getMountByClientID(outfit.lookMount); - if (!mount || !player->hasMount(mount)) { + if (!mount || !player->hasMount(mount) || player->isWearingSupportOutfit()) { outfit.lookMount = 0; } @@ -5963,6 +5963,11 @@ void Game::playerChangeOutfit(uint32_t playerId, Outfit_t outfit, uint8_t isMoun return; } + if (player->isWearingSupportOutfit()) { + outfit.lookMount = 0; + isMountRandomized = 0; + } + player->setRandomMount(isMountRandomized); if (isMountRandomized && outfit.lookMount != 0 && player->hasAnyMount()) { diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index f3a4bcef3ac..46ccb14db77 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -3203,15 +3203,22 @@ void ProtocolGame::sendCreatureOutfit(std::shared_ptr creature, const return; } + Outfit_t newOutfit = outfit; + if (player->isWearingSupportOutfit()) { + player->setCurrentMount(0); + newOutfit.lookMount = 0; + } + NetworkMessage msg; msg.addByte(0x8E); msg.add(creature->getID()); - AddOutfit(msg, outfit); - if (!oldProtocol && outfit.lookMount != 0) { - msg.addByte(outfit.lookMountHead); - msg.addByte(outfit.lookMountBody); - msg.addByte(outfit.lookMountLegs); - msg.addByte(outfit.lookMountFeet); + AddOutfit(msg, newOutfit); + + if (!oldProtocol && newOutfit.lookMount != 0) { + msg.addByte(newOutfit.lookMountHead); + msg.addByte(newOutfit.lookMountBody); + msg.addByte(newOutfit.lookMountLegs); + msg.addByte(newOutfit.lookMountFeet); } writeToOutputBuffer(msg); } @@ -6949,15 +6956,23 @@ void ProtocolGame::sendOutfitWindow() { NetworkMessage msg; msg.addByte(0xC8); - if (oldProtocol) { - Outfit_t currentOutfit = player->getDefaultOutfit(); + Outfit_t currentOutfit = player->getDefaultOutfit(); + auto isSupportOutfit = player->isWearingSupportOutfit(); + bool mounted = false; + + if (!isSupportOutfit) { const auto currentMount = g_game().mounts.getMountByID(player->getLastMount()); if (currentMount) { + mounted = (currentOutfit.lookMount == currentMount->clientId); currentOutfit.lookMount = currentMount->clientId; } + } else { + currentOutfit.lookMount = 0; + } - AddOutfit(msg, currentOutfit); + AddOutfit(msg, currentOutfit); + if (oldProtocol) { std::vector protocolOutfits; const auto outfits = Outfits::getInstance().getOutfits(player->getSex()); protocolOutfits.reserve(outfits.size()); @@ -6998,20 +7013,10 @@ void ProtocolGame::sendOutfitWindow() { return; } - bool mounted = false; - Outfit_t currentOutfit = player->getDefaultOutfit(); - const auto currentMount = g_game().mounts.getMountByID(player->getLastMount()); - if (currentMount) { - mounted = (currentOutfit.lookMount == currentMount->clientId); - currentOutfit.lookMount = currentMount->clientId; - } - - AddOutfit(msg, currentOutfit); - - msg.addByte(currentOutfit.lookMountHead); - msg.addByte(currentOutfit.lookMountBody); - msg.addByte(currentOutfit.lookMountLegs); - msg.addByte(currentOutfit.lookMountFeet); + msg.addByte(isSupportOutfit ? 0 : currentOutfit.lookMountHead); + msg.addByte(isSupportOutfit ? 0 : currentOutfit.lookMountBody); + msg.addByte(isSupportOutfit ? 0 : currentOutfit.lookMountLegs); + msg.addByte(isSupportOutfit ? 0 : currentOutfit.lookMountFeet); msg.add(currentOutfit.lookFamiliarsType); auto startOutfits = msg.getBufferPosition(); @@ -7020,7 +7025,7 @@ void ProtocolGame::sendOutfitWindow() { uint16_t outfitSize = 0; msg.skipBytes(2); - if (player->isAccessPlayer()) { + if (player->isAccessPlayer() && g_configManager().getBoolean(ENABLE_SUPPORT_OUTFIT, __FUNCTION__)) { msg.add(75); msg.addString("Gamemaster", "ProtocolGame::sendOutfitWindow - Gamemaster"); msg.addByte(0); @@ -7144,7 +7149,7 @@ void ProtocolGame::sendOutfitWindow() { msg.addByte(mounted ? 0x01 : 0x00); // Version 12.81 - Random mount 'bool' - msg.addByte(player->isRandomMounted() ? 0x01 : 0x00); + msg.addByte(isSupportOutfit ? 0x00 : (player->isRandomMounted() ? 0x01 : 0x00)); writeToOutputBuffer(msg); }