diff --git a/src/servers/Server_Common/Common.h b/src/servers/Server_Common/Common.h index f5b72fd6..2c584f18 100644 --- a/src/servers/Server_Common/Common.h +++ b/src/servers/Server_Common/Common.h @@ -602,7 +602,8 @@ namespace Core { MpGain = 11, TpLoss = 12, TpGain = 13, - GpGain = 14 + GpGain = 14, + Mount = 38 }; enum class ActionHitSeverityType : uint8_t @@ -1068,6 +1069,12 @@ namespace Core { Visor = 0x40, }; + enum SkillType : uint8_t + { + Normal = 0x1, + MountSkill = 0xD, + }; + struct ServerEntry { uint32_t serverId; diff --git a/src/servers/Server_Common/Network/GamePacket.cpp b/src/servers/Server_Common/Network/GamePacket.cpp index e820c85e..a9e54877 100644 --- a/src/servers/Server_Common/Network/GamePacket.cpp +++ b/src/servers/Server_Common/Network/GamePacket.cpp @@ -98,5 +98,5 @@ void Core::Network::Packets::GamePacket::savePacket() std::string Core::Network::Packets::GamePacket::toString() const { - return Core::Util::binaryToHexDump( const_cast(&m_dataBuf[0]), getSize() ); + return Core::Util::binaryToHexString( const_cast(&m_dataBuf[0]), getSize() ); } diff --git a/src/servers/Server_Common/Network/PacketDef/Ipcs.h b/src/servers/Server_Common/Network/PacketDef/Ipcs.h index bf479ec8..eefd987a 100644 --- a/src/servers/Server_Common/Network/PacketDef/Ipcs.h +++ b/src/servers/Server_Common/Network/PacketDef/Ipcs.h @@ -116,6 +116,7 @@ namespace Packets { ActorSpawn = 0x0190, // todo: split into playerspawn/actorspawn and use opcode 0x110/0x111 ActorFreeSpawn = 0x0191, // unchanged for sb InitZone = 0x019A, // unchanged for sb + Mount = 0x019F, // unchanged for sb WeatherChange = 0x01AF, // updated for sb PlayerTitleList = 0x01BD, // updated for 4.1 Discovery = 0x01BE, // updated for 4.1 diff --git a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h index 142975b4..66d4d54a 100644 --- a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1303,6 +1303,15 @@ struct FFXIVIpcEquipDisplayFlags : FFXIVIpcBasePacket uint8_t bitmask; }; +/** +* Structural representation of the packet sent by the server +* to mount a player +*/ +struct FFXIVIpcMount : FFXIVIpcBasePacket +{ + uint32_t id; +}; + } /* Server */ } /* Packets */ diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp index 0199f3ca..816e0edd 100644 --- a/src/servers/Server_Zone/Actor/Player.cpp +++ b/src/servers/Server_Zone/Actor/Player.cpp @@ -1486,6 +1486,13 @@ uint8_t Core::Entity::Player::getEquipDisplayFlags() const return m_equipDisplayFlags; } +void Core::Entity::Player::mount( uint32_t id ) +{ + GamePacketNew< FFXIVIpcMount, ServerZoneIpcType > mountPacket( getId() ); + mountPacket.data().id = id; + sendToInRangeSet(mountPacket, true ); +} + void Core::Entity::Player::autoAttack( ActorPtr pTarget ) { diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h index 488065df..f9d471ea 100644 --- a/src/servers/Server_Zone/Actor/Player.h +++ b/src/servers/Server_Zone/Actor/Player.h @@ -340,6 +340,8 @@ public: void setEquipDisplayFlags( uint8_t state ); /*! get gear param state and send update to inRangeSet */ uint8_t getEquipDisplayFlags() const; + /*! mount the specified mount and send the packet */ + void mount( uint32_t id ); void calculateStats() override; void sendStats(); diff --git a/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp b/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp index 457aa855..f2e46f51 100644 --- a/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp +++ b/src/servers/Server_Zone/Network/Handlers/SkillHandler.cpp @@ -28,6 +28,7 @@ #include "src/servers/Server_Zone/Action/ActionTeleport.h" #include "src/servers/Server_Zone/Action/ActionCast.h" #include "src/servers/Server_Zone/Script/ScriptManager.h" +#include "Server_Zone/Network/PacketWrappers/MoveActorPacket.h" extern Core::Scripting::ScriptManager g_scriptMgr; @@ -42,11 +43,21 @@ void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inP Entity::PlayerPtr pPlayer ) { + g_log.debug( inPacket.toString() ); + + uint8_t type = inPacket.getValAt< uint32_t >( 0x21 ); + uint32_t action = inPacket.getValAt< uint32_t >( 0x24 ); uint32_t useCount = inPacket.getValAt< uint32_t >( 0x28 ); uint64_t targetId = inPacket.getValAt< uint64_t >( 0x30 ); + pPlayer->sendDebug( "Skill type:" + std::to_string( type ) ); + + switch( type ) + { + case Common::SkillType::Normal: + if( action < 1000000 ) // normal action { std::string actionIdStr = boost::str( boost::format( "%|04X|" ) % action ); @@ -104,4 +115,30 @@ void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inP } + break; + + case Common::SkillType::MountSkill: + + pPlayer->sendDebug( "Request mount " + std::to_string( action ) ); + + GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket(pPlayer->getId()); + effectPacket.data().targetId = pPlayer->getId(); + effectPacket.data().actionAnimationId = action; + effectPacket.data().unknown_62 = 13; // Affects displaying action name next to number in floating text + effectPacket.data().actionTextId = 4; + effectPacket.data().numEffects = 1; + effectPacket.data().rotation = Math::Util::floatToUInt16Rot(pPlayer->getRotation()); + effectPacket.data().effectTarget = INVALID_GAME_OBJECT_ID; + effectPacket.data().effects[0].effectType = ActionEffectType::Mount; + effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::CritDamage; + effectPacket.data().effects[0].value = action; + + pPlayer->mount( action ); + pPlayer->sendToInRangeSet( effectPacket, true ); + + + break; + + } + } \ No newline at end of file diff --git a/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h b/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h index 60b69f1d..19c0f8d2 100644 --- a/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h +++ b/src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h @@ -64,6 +64,9 @@ private: memcpy( m_data.orchestrionMask, player->getOrchestrionBitmask(), sizeof( m_data.orchestrionMask ) ); + memset( m_data.mountGuideMask, 0xFF, sizeof( m_data.mountGuideMask) ); + memset(m_data.fishingGuideMask, 0xFF, sizeof(m_data.fishingGuideMask)); + memcpy( m_data.unlockBitmask, player->getUnlockBitmask(), sizeof( m_data.unlockBitmask ) ); memcpy( m_data.discovery, player->getDiscoveryBitmask(), sizeof( m_data.discovery ) );