1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-22 04:37:47 +00:00
sapphire/src/world/Network/Handlers/GMCommandHandlers.cpp

712 lines
22 KiB
C++
Raw Normal View History

2018-03-06 22:22:19 +01:00
#include <Common.h>
#include <Network/CommonNetwork.h>
2019-03-08 15:34:38 +01:00
#include <Network/GamePacket.h>
2018-03-06 22:22:19 +01:00
#include <Logging/Logger.h>
#include <Network/PacketContainer.h>
#include <Network/CommonActorControl.h>
2018-07-06 19:47:35 +10:00
#include <Network/PacketDef/Zone/ClientZoneDef.h>
#include <Exd/ExdDataGenerated.h>
#include <unordered_map>
2020-02-29 22:30:10 +11:00
#include <Service.h>
#include "Network/GameConnection.h"
#include "Session.h"
#include "Manager/TerritoryMgr.h"
2019-07-21 22:33:33 +10:00
#include "Territory/Territory.h"
#include "Territory/InstanceContent.h"
#include "Network/PacketWrappers/PlayerSetupPacket.h"
#include "Network/PacketWrappers/PingPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
#include "Network/PacketWrappers/ChatPacket.h"
#include "Network/PacketWrappers/ServerNoticePacket.h"
#include "Network/PacketWrappers/ActorControlPacket.h"
#include "Network/PacketWrappers/ActorControlSelfPacket.h"
#include "Network/PacketWrappers/ActorControlTargetPacket.h"
#include "Network/PacketWrappers/EventStartPacket.h"
#include "Network/PacketWrappers/EventFinishPacket.h"
#include "Network/PacketWrappers/PlayerStateFlagsPacket.h"
2018-11-20 21:32:13 +01:00
#include "ServerMgr.h"
using namespace Sapphire::Common;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::Network::Packets::Server;
using namespace Sapphire::Network::ActorControl;
using namespace Sapphire::World::Manager;
enum GmCommand
{
Pos = 0x0000,
Lv = 0x0001,
Race = 0x0002,
Tribe = 0x0003,
Sex = 0x0004,
Time = 0x0005,
Weather = 0x0006,
Call = 0x0007,
Inspect = 0x0008,
Speed = 0x0009,
Invis = 0x000D,
Raise = 0x0010,
Kill = 0x000E,
Icon = 0x0012,
Hp = 0x0064,
Mp = 0x0065,
Tp = 0x0066,
Gp = 0x0067,
Exp = 0x0068,
Inv = 0x006A,
Orchestrion = 0x0074,
Item = 0x00C8,
Gil = 0x00C9,
Collect = 0x00CA,
QuestAccept = 0x012C,
QuestCancel = 0x012D,
QuestComplete = 0x012E,
QuestIncomplete = 0x012F,
QuestSequence = 0x0130,
QuestInspect = 0x0131,
GC = 0x0154,
GCRank = 0x0155,
Aetheryte = 0x015E,
Wireframe = 0x0226,
Teri = 0x0258,
Kick = 0x025C,
TeriInfo = 0x025D,
Jump = 0x025E,
JumpNpc = 0x025F,
};
2020-03-01 01:00:57 +11:00
void Sapphire::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
2018-12-23 03:53:08 +01:00
Entity::Player& player )
{
if( player.getGmRank() <= 0 )
return;
2019-07-29 22:22:45 +10:00
const auto packet = ZoneChannelPacket< Client::FFXIVIpcGmCommand1 >( inPacket );
2018-10-14 23:31:52 +11:00
const auto commandId = packet.data().commandId;
const auto param1 = packet.data().param1;
const auto param2 = packet.data().param2;
const auto param3 = packet.data().param3;
const auto param4 = packet.data().param4;
const auto target = packet.data().target;
Logger::info( "{0} used GM1 commandId: {1}, params: {2}, {3}, {4}, {5}, target: {6}",
player.getName(), commandId,
param1, param2, param3, param4, target );
Sapphire::Entity::ActorPtr targetActor;
2018-10-14 12:52:06 +11:00
if( player.getId() == target )
{
targetActor = player.getAsPlayer();
}
else
{
auto inRange = player.getInRangeActors();
for( auto& actor : inRange )
{
2018-10-14 12:52:06 +11:00
if( actor->getId() == target )
targetActor = actor;
}
}
if( !targetActor )
return;
auto targetPlayer = targetActor->getAsPlayer();
switch( commandId )
{
case GmCommand::Lv:
{
targetPlayer->setLevel( static_cast< uint8_t >( param1 ) );
player.sendNotice( "Level for {0} was set to {1}", targetPlayer->getName(), param1 );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Race:
{
targetPlayer->setLookAt( CharaLook::Race, static_cast< uint8_t >( param1 ) );
player.sendNotice( "Race for {0} was set to {1}", targetPlayer->getName(), param1 );
targetPlayer->spawn( targetPlayer );
auto inRange = targetPlayer->getInRangeActors();
for( auto actor : inRange )
{
if( actor->isPlayer() )
{
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Tribe:
{
targetPlayer->setLookAt( CharaLook::Tribe, static_cast< uint8_t >( param1 ) );
player.sendNotice( "Tribe for {0} was set to ", targetPlayer->getName(), param1 );
targetPlayer->spawn( targetPlayer );
auto inRange = targetPlayer->getInRangeActors();
for( auto actor : inRange )
{
if( actor->isPlayer() )
{
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Sex:
{
targetPlayer->setLookAt( CharaLook::Gender, static_cast< uint8_t >( param1 ) );
player.sendNotice( "Sex for {0} was set to ", targetPlayer->getName(), param1 );
targetPlayer->spawn( targetPlayer );
auto inRange = targetActor->getInRangeActors();
for( auto actor : inRange )
{
if( actor->isPlayer() )
{
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Time:
{
player.setEorzeaTimeOffset( param2 );
player.sendNotice( "Eorzea time offset: {0}", param2 );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Weather:
{
targetPlayer->getCurrentTerritory()->setWeatherOverride( static_cast< Common::Weather >( param1 ) );
2019-07-21 22:33:33 +10:00
player.sendNotice( "Weather in Territory \"{0}\" of {1} set in range.",
targetPlayer->getCurrentTerritory()->getName(), targetPlayer->getName() );
break;
}
case GmCommand::Call:
{
if( targetPlayer->getZoneId() != player.getZoneId() )
targetPlayer->setZone( player.getZoneId() );
2018-01-20 02:04:38 +11:00
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() );
player.sendNotice( "Calling {0}", targetPlayer->getName() );
2018-01-20 02:04:38 +11:00
break;
}
case GmCommand::Inspect:
{
player.sendNotice( "Name: {0}"
"\nGil: {1}"
2019-07-21 22:33:33 +10:00
"\nTerritory: {2}"
"({3})"
"\nClass: {4}"
"\nLevel: {5}"
"\nExp: {6}"
"\nSearchMessage: {7}"
"\nPlayTime: {8}",
targetPlayer->getName(),
targetPlayer->getCurrency( CurrencyType::Gil ),
targetPlayer->getCurrentTerritory()->getName(),
targetPlayer->getZoneId(),
static_cast< uint8_t >( targetPlayer->getClass() ),
targetPlayer->getLevel(),
targetPlayer->getExp(),
targetPlayer->getSearchMessage(),
targetPlayer->getPlayTime() );
break;
}
case GmCommand::Speed:
{
2019-10-09 18:42:25 +02:00
targetPlayer->queuePacket( makeActorControlSelf( player.getId(), Flee, param1 ) );
player.sendNotice( "Speed for {0} was set to {1}", targetPlayer->getName(), param1 );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Invis:
{
2018-04-19 22:47:03 +10:00
player.setGmInvis( !player.getGmInvis() );
player.sendNotice( "Invisibility flag for {0} was toggled to {1}", player.getName(), !player.getGmInvis() );
2018-04-19 22:47:03 +10:00
for( auto actor : player.getInRangeActors() )
{
if( actor->isPlayer() )
{
targetPlayer->despawn( actor->getAsPlayer() );
targetPlayer->spawn( actor->getAsPlayer() );
}
}
2018-04-19 22:47:03 +10:00
break;
}
case GmCommand::Kill:
{
targetActor->getAsChara()->takeDamage( 9999999 );
player.sendNotice( "Killed {0}", targetActor->getId() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Icon:
{
targetPlayer->setOnlineStatusMask( param1 );
2019-07-29 22:22:45 +10:00
auto statusPacket = makeZonePacket< FFXIVIpcSetOnlineStatus >( player.getId() );
2018-06-28 00:07:07 +02:00
statusPacket->data().onlineStatusFlags = param1;
queueOutPacket( statusPacket );
2019-07-29 22:22:45 +10:00
auto searchInfoPacket = makeZonePacket< FFXIVIpcSetSearchInfo >( player.getId() );
2018-06-28 00:07:07 +02:00
searchInfoPacket->data().onlineStatusFlags = param1;
searchInfoPacket->data().selectRegion = targetPlayer->getSearchSelectRegion();
strcpy( searchInfoPacket->data().searchMessage, targetPlayer->getSearchMessage() );
targetPlayer->queuePacket( searchInfoPacket );
2019-10-09 18:42:25 +02:00
targetPlayer->sendToInRangeSet( makeActorControl( player.getId(), SetStatusIcon,
static_cast< uint8_t >( player.getOnlineStatus() ) ),
true );
player.sendNotice( "Icon for {0} was set to {1}", targetPlayer->getName(), param1 );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Hp:
{
auto chara = targetActor->getAsChara();
if( chara )
{
chara->setHp( param1 );
player.sendNotice( "Hp for {0} was set to {1}", chara->getName(), param1 );
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Mp:
{
2017-09-11 18:59:50 +02:00
targetPlayer->setMp( param1 );
player.sendNotice( "Mp for {0} was set to {1}", targetPlayer->getName(), param1 );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Gp:
{
2017-09-11 18:59:50 +02:00
targetPlayer->setHp( param1 );
player.sendNotice( "Gp for {0} was set to {1}", targetPlayer->getName(), param1 );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Exp:
{
targetPlayer->gainExp( param1 );
player.sendNotice( "{0} Exp was added to {1}", param1, targetPlayer->getName() );
break;
}
case GmCommand::Inv:
{
if( targetActor->getAsChara()->getInvincibilityType() == Common::InvincibilityType::InvincibilityRefill )
targetActor->getAsChara()->setInvincibilityType( Common::InvincibilityType::InvincibilityNone );
else
targetActor->getAsChara()->setInvincibilityType( Common::InvincibilityType::InvincibilityRefill );
player.sendNotice( "Invincibility for {0} was switched.", targetPlayer->getName() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Orchestrion:
{
if( param1 == 1 )
2017-09-11 18:59:50 +02:00
{
if( param2 == 0 )
{
for( uint8_t i = 0; i < 255; i++ )
targetActor->getAsPlayer()->learnSong( i, 0 );
player.sendNotice( "All Songs for {0} were turned on.", targetPlayer->getName() );
}
else
{
targetActor->getAsPlayer()->learnSong( static_cast< uint8_t >( param2 ), 0 );
player.sendNotice( "Song {0} for {1} was turned on.", param2, targetPlayer->getName() );
}
2017-09-11 18:59:50 +02:00
}
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Item:
{
auto quantity = param2;
if( quantity < 1 || quantity > 999 )
2017-09-11 18:59:50 +02:00
{
quantity = 1;
2017-09-11 18:59:50 +02:00
}
if( ( param1 == 0xcccccccc ) )
{
player.sendUrgent( "Syntaxerror." );
return;
2017-09-11 18:59:50 +02:00
}
if( param1 <= 0x12 ) // crystal
{
targetPlayer->addCrystal( static_cast< Common::CrystalType >( param1 ), quantity, true );
}
else // item
{
// decode using the epic SE style HQ item id
bool isHq = param1 > 1000000;
2017-09-11 18:59:50 +02:00
if( !targetPlayer->addItem( isHq ? param1 - 1000000 : param1, quantity, isHq, false, true, true ) )
player.sendUrgent( "Item #{0} could not be added to inventory.", isHq ? param1 - 1000000 : param1 );
}
2020-06-14 23:32:56 +09:00
break;
}
case GmCommand::Gil:
{
targetPlayer->addCurrency( CurrencyType::Gil, param1, true );
player.sendNotice( "Added {0} Gil for {1}", param1, targetPlayer->getName() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Collect:
{
uint32_t gil = targetPlayer->getCurrency( CurrencyType::Gil );
2017-09-11 18:59:50 +02:00
if( gil < param1 )
2017-09-11 18:59:50 +02:00
{
player.sendUrgent( "Player does not have enough Gil({0})", gil );
2017-09-11 18:59:50 +02:00
}
else
{
targetPlayer->removeCurrency( CurrencyType::Gil, param1 );
player.sendNotice( "Removed {0} Gil from {1} ({2} before)", param1, targetPlayer->getName(), gil );
2017-09-11 18:59:50 +02:00
}
break;
}
case GmCommand::QuestAccept:
{
targetPlayer->updateQuest( static_cast< uint16_t >( param1 ), 1 );
break;
}
case GmCommand::QuestCancel:
{
targetPlayer->removeQuest( static_cast< uint16_t >( param1 ) );
break;
}
case GmCommand::QuestComplete:
{
targetPlayer->finishQuest( static_cast< uint16_t >( param1 ) );
break;
}
case GmCommand::QuestIncomplete:
{
targetPlayer->unfinishQuest( static_cast< uint16_t >( param1 ) );
break;
}
case GmCommand::QuestSequence:
{
targetPlayer->updateQuest( static_cast< uint16_t >( param1 ), static_cast< uint8_t >( param2 ) );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::GC:
{
if( param1 > 3 )
{
player.sendUrgent( "Invalid Grand Company ID: {0}", param1 );
return;
}
targetPlayer->setGc( static_cast< uint8_t >( param1 ) );
// if we're changing them to a GC, check if they have a rank and if not, set it to the lowest rank
if( param1 > 0 )
{
auto gcRankIdx = static_cast< uint8_t >( param1 ) - 1;
if( targetPlayer->getGcRankArray()[ gcRankIdx ] == 0 )
{
player.setGcRankAt( static_cast< uint8_t >( gcRankIdx ), 1 );
}
}
player.sendNotice( "GC for {0} was set to {1}", targetPlayer->getName(), targetPlayer->getGc() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::GCRank:
{
auto gcId = targetPlayer->getGc() - 1;
if( gcId > 2 )
{
player.sendUrgent( "{0} has an invalid Grand Company ID: {0}", targetPlayer->getName(), gcId );
return;
}
targetPlayer->setGcRankAt( static_cast< uint8_t >( gcId ), static_cast< uint8_t >( param1 ) );
player.sendNotice( "GC Rank for {0} for GC {1} was set to {2}", targetPlayer->getName(), targetPlayer->getGc(),
targetPlayer->getGcRankArray()[ targetPlayer->getGc() - 1 ] );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Aetheryte:
{
if( param1 == 0 )
2017-10-04 11:48:58 +02:00
{
if( param2 == 0 )
{
for( uint8_t i = 0; i < 255; i++ )
targetActor->getAsPlayer()->registerAetheryte( i );
player.sendNotice( "All Aetherytes for {0} were turned on.", targetPlayer->getName() );
}
else
{
targetActor->getAsPlayer()->registerAetheryte( static_cast< uint8_t >( param2 ) );
player.sendNotice( "Aetheryte {0} for {1} was turned on.", param2, targetPlayer->getName() );
}
2017-10-04 11:48:58 +02:00
}
2017-10-09 20:09:49 +02:00
break;
}
case GmCommand::Wireframe:
{
player.queuePacket(
std::make_shared< ActorControlSelfPacket >( player.getId(), ActorControlType::ToggleWireframeRendering ) );
player.sendNotice( "Wireframe Rendering for {0} was toggled", player.getName() );
break;
}
case GmCommand::Teri:
{
2020-03-01 01:00:57 +11:00
auto& teriMgr = Common::Service< TerritoryMgr >::ref();
if( auto instance = teriMgr.getTerritoryByGuId( param1 ) )
2017-10-09 20:09:49 +02:00
{
2019-01-05 12:32:10 +01:00
player.sendDebug( "Found instance: {0}, id#{1}", instance->getName(), param1 );
// if the zone is an instanceContent instance, make sure the player is actually bound to it
auto pInstance = instance->getAsInstanceContent();
// pInstance will be nullptr if you're accessing a normal zone via its allocated instance id rather than its zoneid
if( pInstance && !pInstance->isPlayerBound( player.getId() ) )
{
player.sendUrgent( "Not able to join instance#{0}", param1 );
player.sendUrgent( "Player not bound! ( run !instance bind <instanceId> first ) {0}", param1 );
break;
}
2018-03-15 23:37:21 +01:00
player.setInstance( instance );
}
2020-03-01 01:00:57 +11:00
else if( !teriMgr.isValidTerritory( param1 ) )
2017-10-09 20:09:49 +02:00
{
player.sendUrgent( "Invalid zone {0}", param1 );
}
else
{
2020-03-01 01:00:57 +11:00
auto pZone = teriMgr.getZoneByTerritoryTypeId( param1 );
if( !pZone )
{
player.sendUrgent( "No zone instance found for {0}", param1 );
break;
}
2020-03-01 01:00:57 +11:00
if( !teriMgr.isDefaultTerritory( param1 ) )
{
player.sendUrgent( "{0} is an instanced area - instance ID required to zone in.", pZone->getName() );
break;
}
bool doTeleport = false;
uint16_t teleport;
2020-03-01 01:00:57 +11:00
auto& exdData = Common::Service< Data::ExdDataGenerated >::ref();
auto idList = exdData.getAetheryteIdList();
for( auto i : idList )
{
2020-03-01 01:00:57 +11:00
auto data = exdData.get< Sapphire::Data::Aetheryte >( i );
2018-09-21 03:50:38 +10:00
if( !data )
{
continue;
}
2018-09-21 03:50:38 +10:00
if( data->territory == param1 )
{
if( data->isAetheryte )
{
doTeleport = true;
teleport = static_cast< uint16_t >( i );
break;
}
}
}
if( doTeleport )
{
player.teleport( teleport );
}
else
{
targetPlayer->setPos( targetPlayer->getPos() );
targetPlayer->performZoning( static_cast< uint16_t >( param1 ), targetPlayer->getPos(), 0 );
}
player.sendNotice( "{0} was warped to zone {1}", targetPlayer->getName(), param1, pZone->getName() );
2017-10-09 20:09:49 +02:00
}
2017-10-04 11:48:58 +02:00
break;
}
case GmCommand::Kick:
{
// todo: this doesn't kill their session straight away, should do this properly but its good for when you get stuck for now
targetPlayer->setMarkedForRemoval();
player.sendNotice( "Kicked {0}", targetPlayer->getName() );
break;
}
case GmCommand::TeriInfo:
{
auto pCurrentZone = player.getCurrentTerritory();
player.sendNotice( "ZoneId: {0}"
"\nName: {1}"
"\nInternalName: {2}"
"\nGuId: {3}"
"\nPopCount: {4}"
"\nCurrentWeather: {5}"
"\nNextWeather: {6}",
player.getZoneId(),
pCurrentZone->getName(),
pCurrentZone->getInternalName(),
pCurrentZone->getGuId(),
pCurrentZone->getPopCount(),
static_cast< uint8_t >( pCurrentZone->getCurrentWeather() ),
static_cast< uint8_t >( pCurrentZone->getNextWeather() ) );
break;
}
case GmCommand::Jump:
{
2017-09-11 18:59:50 +02:00
auto inRange = player.getInRangeActors();
player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z,
targetActor->getRot() );
player.sendNotice( "Jumping to {0} in range.", targetPlayer->getName() );
break;
}
default:
player.sendUrgent( "GM1 Command not implemented: {0}", commandId );
2017-09-11 18:59:50 +02:00
break;
}
2017-09-11 18:59:50 +02:00
}
2020-03-01 01:00:57 +11:00
void Sapphire::Network::GameConnection::gm2Handler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
2018-12-23 03:53:08 +01:00
Entity::Player& player )
{
if( player.getGmRank() <= 0 )
return;
2017-09-11 18:59:50 +02:00
2020-02-29 22:30:10 +11:00
auto& serverMgr = Common::Service< World::ServerMgr >::ref();
2019-07-29 22:22:45 +10:00
const auto packet = ZoneChannelPacket< Client::FFXIVIpcGmCommand2 >( inPacket );
2017-09-11 18:59:50 +02:00
2018-10-14 23:31:52 +11:00
const auto commandId = packet.data().commandId;
const auto param1 = packet.data().param1;
const auto param2 = packet.data().param2;
const auto param3 = packet.data().param3;
const auto param4 = packet.data().param4;
const auto target = std::string( packet.data().target );
2017-09-11 18:59:50 +02:00
Logger::debug( "{0} used GM2 commandId: {1}, params: {2}, {3}, {4}, {5}, target: {6}",
player.getName(), commandId, param1, param2, param3, param4, target );
2017-09-11 18:59:50 +02:00
2020-02-29 22:30:10 +11:00
auto targetSession = serverMgr.getSession( target );
Sapphire::Entity::CharaPtr targetActor;
2017-09-11 18:59:50 +02:00
if( targetSession != nullptr )
{
targetActor = targetSession->getPlayer();
}
else
{
2018-10-14 12:52:06 +11:00
if( target == "self" )
{
targetActor = player.getAsPlayer();
}
else
{
player.sendUrgent( "Player {0} not found on this server.", target );
2017-09-11 18:59:50 +02:00
return;
}
}
if( !targetActor )
return;
auto targetPlayer = targetActor->getAsPlayer();
2017-09-11 18:59:50 +02:00
switch( commandId )
{
case GmCommand::Raise:
{
2017-09-11 18:59:50 +02:00
targetPlayer->resetHp();
targetPlayer->resetMp();
2018-08-28 19:05:52 +02:00
targetPlayer->setStatus( Common::ActorStatus::Idle );
targetPlayer->sendZoneInPackets( 0x01, 0x01, 0, 113, true );
2017-09-11 18:59:50 +02:00
2018-08-28 19:05:52 +02:00
2019-10-09 18:42:25 +02:00
targetPlayer->sendToInRangeSet( makeActorControlSelf( player.getId(), ZoneIn, 0x01, 0x01, 0, 113 ), true );
targetPlayer->sendToInRangeSet( makeActorControl( player.getId(), SetStatus,
static_cast< uint8_t >( Common::ActorStatus::Idle ) ),
true );
player.sendNotice( "Raised {0}", targetPlayer->getName() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Jump:
{
player.prepareZoning( targetPlayer->getZoneId(), true, 1, 0 );
if( player.getCurrentInstance() )
{
player.exitInstance();
}
if( targetPlayer->getCurrentTerritory()->getGuId() != player.getCurrentTerritory()->getGuId() )
{
2019-07-21 22:33:33 +10:00
// Checks if the target player is in an InstanceContent to avoid binding to a Territory or PublicContent
2019-01-06 16:25:51 +01:00
if( targetPlayer->getCurrentInstance() )
{
auto pInstanceContent = targetPlayer->getCurrentInstance()->getAsInstanceContent();
// Not sure if GMs actually get bound to an instance they jump to on retail. It's mostly here to avoid a crash for now
pInstanceContent->bindPlayer( player.getId() );
}
player.setInstance( targetPlayer->getCurrentTerritory()->getGuId() );
2017-09-11 18:59:50 +02:00
}
player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z,
2018-08-28 19:05:52 +02:00
targetActor->getRot() );
player.sendZoneInPackets( 0x00, 0x00, 0, 0, false );
player.sendNotice( "Jumping to {0}", targetPlayer->getName() );
2017-09-11 18:59:50 +02:00
break;
}
case GmCommand::Call:
{
// We shouldn't be able to call a player into an instance, only call them out of one
if( player.getCurrentInstance() )
{
player.sendUrgent( "You are unable to call a player while bound to a battle instance." );
return;
}
targetPlayer->prepareZoning( player.getZoneId(), true, 1, 0 );
if( targetPlayer->getCurrentInstance() )
{
targetPlayer->exitInstance();
}
if( targetPlayer->getCurrentTerritory()->getGuId() != player.getCurrentTerritory()->getGuId() )
{
targetPlayer->setInstance( player.getCurrentTerritory()->getGuId() );
}
targetPlayer->changePosition( player.getPos().x, player.getPos().y, player.getPos().z, player.getRot() );
targetPlayer->sendZoneInPackets( 0x00, 0x00, 0, 0, false );
player.sendNotice( "Calling {0}", targetPlayer->getName() );
break;
}
default:
player.sendUrgent( "GM2 Command not implemented: {0}", commandId );
2017-09-11 18:59:50 +02:00
break;
}
2017-09-11 18:59:50 +02:00
}