diff --git a/src/servers/sapphire_api/PlayerMinimal.h b/src/servers/sapphire_api/PlayerMinimal.h index 38019e10..246a27bc 100644 --- a/src/servers/sapphire_api/PlayerMinimal.h +++ b/src/servers/sapphire_api/PlayerMinimal.h @@ -150,6 +150,16 @@ namespace Core { m_gmRank = rank; } + bool getGmInvis() const + { + return m_gmInvis; + } + + bool setGmInvis( bool invis ) + { + m_gmInvis = invis; + } + void createInvDbContainer( uint16_t slot ) const; uint32_t m_modelEquip[10]; @@ -177,6 +187,7 @@ namespace Core { uint8_t m_look[26]; uint8_t m_gmRank; + bool m_gmInvis; char m_name[34]; diff --git a/src/servers/sapphire_zone/Actor/Player.cpp b/src/servers/sapphire_zone/Actor/Player.cpp index 6ccc061f..1e72fcb3 100644 --- a/src/servers/sapphire_zone/Actor/Player.cpp +++ b/src/servers/sapphire_zone/Actor/Player.cpp @@ -132,6 +132,16 @@ void Core::Entity::Player::setGmRank( uint8_t rank ) m_gmRank = rank; } +bool Core::Entity::Player::getGmInvis() const +{ + return m_gmInvis; +} + +void Core::Entity::Player::setGmInvis( bool invis ) +{ + m_gmInvis = invis; +} + uint8_t Core::Entity::Player::getMode() const { return m_mode; @@ -159,43 +169,32 @@ bool Core::Entity::Player::isMarkedForRemoval() const Core::Common::OnlineStatus Core::Entity::Player::getOnlineStatus() { - uint64_t newMask = uint64_t( 1 ) << static_cast< uint32_t >( OnlineStatus::NewAdventurer ); - uint64_t afkMask = uint64_t( 1 ) << static_cast< uint32_t >( OnlineStatus::AwayfromKeyboard ); - uint64_t busyMask = uint64_t( 1 ) << static_cast< uint32_t >( OnlineStatus::Busy ); - uint64_t dcMask = uint64_t( 1 ) << static_cast< uint32_t >( OnlineStatus::Disconnected ); - uint64_t meldMask = uint64_t( 1 ) << static_cast< uint32_t >( OnlineStatus::LookingtoMeldMateria ); - uint64_t ptMask = uint64_t( 1 ) << static_cast< uint32_t >( OnlineStatus::LookingforParty ); - uint64_t rpMask = uint64_t( 1 ) << static_cast< uint32_t >( OnlineStatus::Roleplaying ); + auto pExdData = g_fw.get< Data::ExdDataGenerated >(); + if( !pExdData ) + return OnlineStatus::Online; - OnlineStatus status = OnlineStatus::Online; + uint32_t statusDisplayOrder = 0xFF14; + uint32_t applicableStatus = 0; - //if( hasStateFlag( Common::PlayerStateFlag::NewAdventurer ) ) - if( m_onlineStatus & newMask ) - status = OnlineStatus::NewAdventurer; + for( uint32_t i = 0; i < std::numeric_limits< decltype( m_onlineStatus ) >::digits; i++ ) + { + bool bit = ( m_onlineStatus >> i ) & 1; - if( m_onlineStatus & afkMask ) - status = OnlineStatus::AwayfromKeyboard; + if( !bit ) + continue; - if( m_onlineStatus & busyMask ) - status = OnlineStatus::Busy; + auto pOnlineStatus = pExdData->get< Data::OnlineStatus >( i ); + if( !pOnlineStatus ) + continue; - if( m_onlineStatus & dcMask ) - status = OnlineStatus::Disconnected; - - if( m_onlineStatus & meldMask ) - status = OnlineStatus::LookingtoMeldMateria; - - if( m_onlineStatus & ptMask ) - status = OnlineStatus::LookingforParty; - - if( m_onlineStatus & rpMask ) - status = OnlineStatus::Roleplaying; - - if( hasStateFlag( PlayerStateFlag::WatchingCutscene ) ) - status = OnlineStatus::ViewingCutscene; - - // TODO: add all the logic for returning the proper online status, there probably is a better way for this alltogether - return status; + if( pOnlineStatus->priority < statusDisplayOrder ) + { + // todo: also check that the status can actually be set here, otherwise we need to ignore it (and ban the player obv) + statusDisplayOrder = pOnlineStatus->priority; + applicableStatus = i; + return static_cast< OnlineStatus >( applicableStatus ); + } + } } void Core::Entity::Player::setOnlineStatusMask( uint64_t status ) @@ -1601,16 +1600,34 @@ void Core::Entity::Player::sendTitleList() queuePacket( titleListPacket ); } +void Core::Entity::Player::sendZoneInPackets( uint32_t param1, uint32_t param2 = 0, uint32_t param3 = 0, uint32_t param4 = 0, bool shouldSetStatus = false ) +{ + auto zoneInPacket = ActorControlPacket143( getId(), ZoneIn, param1, param2, param3, param4 ); + auto SetStatusPacket = ActorControlPacket142( getId(), SetStatus, static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle ) ); + + if( !getGmInvis() ) + sendToInRangeSet( zoneInPacket, true ); + if( shouldSetStatus ) + sendToInRangeSet( SetStatusPacket ); + else + queuePacket( zoneInPacket ); + if ( shouldSetStatus ) + queuePacket( SetStatusPacket ); + + setZoningType( Common::ZoneingType::None ); + unsetStateFlag( PlayerStateFlag::BetweenAreas ); +} + void Core::Entity::Player::finishZoning() { switch( getZoningType() ) { case ZoneingType::None: - sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01 ), true ); + sendZoneInPackets( 0x01 ); break; case ZoneingType::Teleport: - sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0, 0, 110 ), true ); + sendZoneInPackets( 0x01, 0, 0, 110 ); break; case ZoneingType::Return: @@ -1621,22 +1638,16 @@ void Core::Entity::Player::finishZoning() resetHp(); resetMp(); setStatus( Entity::Chara::ActorStatus::Idle ); - - sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0x01, 0, 111 ), true ); - sendToInRangeSet( ActorControlPacket142( getId(), SetStatus, - static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle ) ), true ); + sendZoneInPackets( 0x01, 0x01, 0, 111, true ); } else - sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0x00, 0, 111 ), true ); + sendZoneInPackets( 0x01, 0x00, 0, 111 ); } - break; + break; case ZoneingType::FadeIn: break; } - - setZoningType( Common::ZoneingType::None ); - unsetStateFlag( PlayerStateFlag::BetweenAreas ); } void Core::Entity::Player::emote( uint32_t emoteId, uint64_t targetId ) diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index 8a6da096..7bb5b8d0 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -509,6 +509,8 @@ public: void emote( uint32_t emoteId, uint64_t targetId ); + void sendZoneInPackets( uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4, bool pSetStatus ); + void finishZoning(); void sendZonePackets(); @@ -546,6 +548,9 @@ public: uint8_t getGmRank() const; void setGmRank( uint8_t rank ); + bool getGmInvis() const; + void setGmInvis( bool invis ); + uint8_t getMode() const; void setMode( uint8_t mode ); @@ -671,6 +676,7 @@ private: uint8_t m_stateFlags[12]; uint8_t m_gmRank; uint16_t zoneId; + bool m_gmInvis = false; uint8_t m_equipDisplayFlags; diff --git a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp index f1470ff9..7f1d99d0 100644 --- a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp @@ -224,6 +224,19 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac player.sendNotice( "Speed for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) ); break; } + case GmCommand::Invis: + { + player.setGmInvis( !player.getGmInvis() ); + player.sendNotice( "Invisibility flag for " + player.getName() + + " was toggled to " + std::to_string( !player.getGmInvis() ) ); + + for( auto actor : player.getInRangeActors() ) + { + player.despawn( actor->getAsPlayer() ); + player.spawn( actor->getAsPlayer() ); + } + break; + } case GmCommand::Kill: { targetActor->getAsChara()->takeDamage( 9999999 ); diff --git a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp index 4ad33d62..76fb6a99 100644 --- a/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/PacketHandlers.cpp @@ -515,16 +515,25 @@ void Core::Network::GameConnection::chatHandler( const Packets::GamePacket& inPa { case ChatType::Say: { + if (player.getGmRank() > 0) + chatPacket.data().chatType = ChatType::GMSay; + player.getCurrentZone()->queueOutPacketForRange( player, 50, chatPacket ); break; } case ChatType::Yell: { + if( player.getGmRank() > 0 ) + chatPacket.data().chatType = ChatType::GMYell; + player.getCurrentZone()->queueOutPacketForRange( player, 6000, chatPacket ); break; } case ChatType::Shout: { + if( player.getGmRank() > 0 ) + chatPacket.data().chatType = ChatType::GMShout; + player.getCurrentZone()->queueOutPacketForRange( player, 6000, chatPacket ); break; } diff --git a/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h b/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h index e3cdcb73..e35524b4 100644 --- a/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h @@ -91,7 +91,7 @@ namespace Server { // 0x20 == spawn hidden to be displayed by the spawneffect control m_data.displayFlags = player.getStance(); - if( player.getZoningType() != Common::ZoneingType::None ) + if( player.getZoningType() != Common::ZoneingType::None || player.getGmInvis() == true ) { m_data.displayFlags |= Entity::Chara::DisplayFlags::Invisible; }