diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 7d9653f9..f69b8070 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -1442,6 +1442,54 @@ namespace Sapphire::Network::Packets::WorldPackets::Server { }; + template< int ArgCount > + struct FFXIVIpcEventLogMessageN + { + uint32_t handlerId; + uint32_t messageId; + uint8_t numOfArgs; + uint8_t __padding1; + uint8_t __padding2; + uint8_t __padding3; + uint32_t args[ArgCount]; + }; + + struct FFXIVIpcEventLogMessageHeader : + FFXIVIpcBasePacket< EventLogMessageHeader >, + FFXIVIpcEventLogMessageN< 1 > + { + }; + + struct FFXIVIpcEventLogMessage2 : + FFXIVIpcBasePacket< EventLogMessage2 >, + FFXIVIpcEventLogMessageN< 2 > + { + }; + + struct FFXIVIpcEventLogMessage4 : + FFXIVIpcBasePacket< EventLogMessage4 >, + FFXIVIpcEventLogMessageN< 4 > + { + }; + + struct FFXIVIpcEventLogMessage8 : + FFXIVIpcBasePacket< EventLogMessage8 >, + FFXIVIpcEventLogMessageN< 8 > + { + }; + + struct FFXIVIpcEventLogMessage16 : + FFXIVIpcBasePacket< EventLogMessage16 >, + FFXIVIpcEventLogMessageN< 16 > + { + }; + + struct FFXIVIpcEventLogMessage32 : + FFXIVIpcBasePacket< EventLogMessage32 >, + FFXIVIpcEventLogMessageN< 32 > + { + }; + template< int ArgCount > struct FFXIVIpcPlayEventSceneN { diff --git a/src/scripts/instances/dungeons/Sastasha.cpp b/src/scripts/instances/dungeons/Sastasha.cpp index 40fe8e96..d26a5b83 100644 --- a/src/scripts/instances/dungeons/Sastasha.cpp +++ b/src/scripts/instances/dungeons/Sastasha.cpp @@ -1,11 +1,20 @@ #include #include #include + #include #include #include +#include + +#include +#include +#include + using namespace Sapphire; +using namespace Sapphire::Network::Packets; +using namespace Sapphire::Network::Packets::WorldPackets; class Sastasha : public Sapphire::ScriptAPI::InstanceContentScript @@ -30,12 +39,17 @@ private: Seq2 = 3, Seq3 = 7, Seq4 = 15, - SeqFinish = 31 + SeqFinish = 255 }; static constexpr auto EventActionTouch = 24; static constexpr auto EventActionShort = 15; + Entity::BNpcPtr denn; + Entity::BNpcPtr madison2; + Entity::BNpcPtr madison; + Entity::BNpcPtr chopper; + public: Sastasha() : Sapphire::ScriptAPI::InstanceContentScript( 4 ) @@ -108,12 +122,31 @@ public: instance.registerEObj( "Unnaturalripples", 2000405, 3992454, 4, { -301.973206f, 6.500000f, 300.029388f }, 0.991789f, 0.000048f ); instance.registerEObj( "Unnaturalripples_1", 2000406, 3992452, 4, { -302.037598f, 6.500000f, 336.047302f }, 1.000000f, 0.000000f ); instance.registerEObj( "Unnaturalripples_2", 2000407, 3992449, 4, { -338.036499f, 6.500000f, 300.206512f }, 0.991789f, 0.000048f ); - instance.registerEObj( "Unnaturalripples_3", 2000408, 3992453, 4, { -337.929596f, 6.500000f, 335.975311f }, 1.000000f, 0.000000f ); + instance.registerEObj( "Unnaturalripples_3", 2000408, 3992453, 4, { -337.929596f, 6.500000f, 335.975311f }, 1.000000f, 0.000000f ); } void onUpdate( InstanceContent& instance, uint64_t tickCount ) override { + if( madison && !madison->isAlive() ) + { + instance.setVar( 0, Seq3 ); + instance.getEObjByName( "Rambadedoor" )->setState( 1 ); + madison2 = instance.createBNpcFromInstanceId( 4035056, 600, Common::BNpcType::Enemy ); + madison = nullptr; + } + if( madison2 && !madison2->isAlive() ) + { + instance.getEObjByName( "Rambadedoor_1" )->setState( 1 ); + madison2 = nullptr; + } + + if( denn && !denn->isAlive() ) + { + instance.setVar( 0, SeqFinish ); + instance.sendDutyComplete(); + denn = nullptr; + } } void onTalk( InstanceContent& instance, Entity::Player& player, Entity::EventObject& eobj, uint32_t eventId ) override @@ -137,10 +170,9 @@ public: if( eobj.getObjectId() == instance.getCustomVar( Coral ) ) { - // TODO: summon boss, do this after boss is defeated instance.registerEObj( "Inconspicuousswitch", 2000216, 3653858, 4, { 62.907951f, 33.969521f, -31.172279f }, 1.000000f, -1.396264f ); instance.setVar( 0, Seq1 ); - Logger::debug( "correct coral!" ); + instance.sendEventLogMessage( player, instance, 2034, { 0, 0 } ); } else { @@ -156,18 +188,23 @@ public: // Open the door and progress duty if( eobj.getName() == "Inconspicuousswitch" ) { - eventMgr().eventActionStart( player, getId(), EventActionTouch, - [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) - { - instance.getEObjByName( "Hiddendoor" )->setState( 1 ); - eobj.setState( 1 ); - instance.setVar( 0, Seq2 ); - }, - nullptr, getId() ); + if( !chopper ) + chopper = instance.createBNpcFromInstanceId( 4035011, 400, Common::BNpcType::Enemy ); + else if( chopper && !chopper->isAlive() ) + { + eventMgr().eventActionStart( player, getId(), EventActionTouch, + [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) + { + instance.getEObjByName( "Hiddendoor" )->setState( 1 ); + eobj.setState( 1 ); + instance.setVar( 0, Seq2 ); + instance.sendEventLogMessage( player, instance, 2064, { 0, 0 } ); + madison = instance.createBNpcFromInstanceId( 3988325, 600, Common::BNpcType::Enemy ); + }, + nullptr, getId() ); + } } - // TODO: set Seq3 and SeqFinish - // Pick up key and progress duty if( eobj.getName() == "Captainsquarterskey" ) { @@ -175,7 +212,8 @@ public: [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) { eobj.setState( 1 ); - instance.setVar( 0, Seq4 ); + instance.setCustomVar( ObtainedKey, true ); + instance.sendEventLogMessage( player, instance, 2031, { 34432 } ); }, nullptr, getId() ); } @@ -187,21 +225,34 @@ public: [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) { eobj.setState( 1 ); - instance.setCustomVar( ObtainedKey, true ); + instance.setVar( 0, Seq4 ); + instance.sendEventLogMessage( player, instance, 2031, { 34433 } ); + denn = instance.createBNpcFromInstanceId( 3978771, 1000, Common::BNpcType::Enemy ); }, nullptr, getId() ); } // Open the door if the right key has been obtained - if( ( eobj.getName() == "Captainsquarters" && instance.getDirectorVar( 0 ) == Seq4 ) || - ( eobj.getName() == "WaveriderGate" && instance.getCustomVar( ObtainedKey ) ) ) + if( ( eobj.getName() == "Captainsquarters" && instance.getCustomVar( ObtainedKey ) ) || + ( eobj.getName() == "WaveriderGate" && instance.getDirectorVar( 0 ) == Seq4 ) ) { - eventMgr().eventActionStart( player, getId(), EventActionTouch, - [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) + eventMgr().playScene( player, eventId, 1, HIDE_HOTBAR, { 1 }, + [ & ]( Entity::Player& player, const Event::SceneResult& result ) { - eobj.setState( 1 ); - }, - nullptr, getId() ); + if( result.getResult( 0 ) == 0 ) + { + eventMgr().eventActionStart( player, getId(), EventActionTouch, + [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) + { + eobj.setState( 1 ); + if( eobj.getName() == "Captainsquarters" ) + instance.sendEventLogMessage( player, instance, 2059, { 668 } ); + else + instance.sendEventLogMessage( player, instance, 2059, { 671 } ); + }, + nullptr, getId() ); + } + } ); } } @@ -213,10 +264,6 @@ public: void onLeaveTerritory( InstanceContent& instance, Entity::Player& player ) override { - // TODO: Set seq properly once bosses work - if( instance.getDirectorVar( 0 ) == Seq4 ) - instance.setVar( 0, SeqFinish ); - if( instance.getDirectorVar( 0 ) != SeqFinish ) return; diff --git a/src/world/Event/Director.cpp b/src/world/Event/Director.cpp index 24fc89d3..07906b01 100644 --- a/src/world/Event/Director.cpp +++ b/src/world/Event/Director.cpp @@ -1,11 +1,14 @@ #include "Director.h" +#include + #include #include #include #include "Actor/Player.h" +#include "Network/PacketDef/Zone/ServerZoneDef.h" #include "Network/PacketWrappers/ActorControlPacket.h" #include "Network/PacketWrappers/ActorControlSelfPacket.h" #include @@ -17,6 +20,7 @@ using namespace Sapphire::Common; using namespace Sapphire::Network::Packets; +using namespace Sapphire::Network::Packets::WorldPackets; using namespace Sapphire::Network::Packets::WorldPackets::Server; using namespace Sapphire::Network::ActorControl; @@ -45,6 +49,69 @@ uint8_t Sapphire::Event::Director::getSequence() const return m_sequence; } +void Sapphire::Event::Director::sendEventLogMessage( Sapphire::Entity::Player& player, Sapphire::InstanceContent& instance, uint32_t msgId, std::vector< uint32_t > args ) const +{ + if( args.size() == 0 ) + { + auto packet = makeZonePacket< Server::FFXIVIpcEventLogMessageHeader >( player.getId() ); + packet->data().handlerId = instance.getDirectorId(); + packet->data().messageId = msgId; + packet->data().numOfArgs = args.size(); + instance.queuePacketForZone( player, packet, true ); + } + else if( args.size() <= 2 ) + { + auto packet = makeZonePacket< Server::FFXIVIpcEventLogMessage2 >( player.getId() ); + packet->data().handlerId = instance.getDirectorId(); + packet->data().messageId = msgId; + packet->data().numOfArgs = args.size(); + std::copy( args.begin(), args.end(), packet->data().args ); + instance.queuePacketForZone( player, packet, true ); + Logger::debug( "arg size: {}", packet->data().numOfArgs ); + Logger::debug( + "Dump:\n{0}", + Util::binaryToHexDump( const_cast< uint8_t* >( &packet->getContent()[ 0 ] ), + static_cast< uint16_t >( packet->getContentSize() ) ) + ); + } + else if( args.size() <= 4 ) + { + auto packet = makeZonePacket< Server::FFXIVIpcEventLogMessage4 >( player.getId() ); + packet->data().handlerId = instance.getDirectorId(); + packet->data().messageId = msgId; + packet->data().numOfArgs = args.size(); + std::copy( args.begin(), args.end(), packet->data().args ); + instance.queuePacketForZone( player, packet, true ); + } + else if( args.size() <= 8 ) + { + auto packet = makeZonePacket< Server::FFXIVIpcEventLogMessage8 >( player.getId() ); + packet->data().handlerId = instance.getDirectorId(); + packet->data().messageId = msgId; + packet->data().numOfArgs = args.size(); + std::copy( args.begin(), args.end(), packet->data().args ); + instance.queuePacketForZone( player, packet, true ); + } + else if( args.size() <= 16 ) + { + auto packet = makeZonePacket< Server::FFXIVIpcEventLogMessage16 >( player.getId() ); + packet->data().handlerId = instance.getDirectorId(); + packet->data().messageId = msgId; + packet->data().numOfArgs = args.size(); + std::copy( args.begin(), args.end(), packet->data().args ); + instance.queuePacketForZone( player, packet, true ); + } + else if( args.size() <= 32 ) + { + auto packet = makeZonePacket< Server::FFXIVIpcEventLogMessage32 >( player.getId() ); + packet->data().handlerId = instance.getDirectorId(); + packet->data().messageId = msgId; + packet->data().numOfArgs = args.size(); + std::copy( args.begin(), args.end(), packet->data().args ); + instance.queuePacketForZone( player, packet, true ); + } +} + void Sapphire::Event::Director::sendDirectorClear( Sapphire::Entity::Player& player ) const { auto& server = Common::Service< World::WorldServer >::ref(); diff --git a/src/world/Event/Director.h b/src/world/Event/Director.h index 9664c72b..9665ff25 100644 --- a/src/world/Event/Director.h +++ b/src/world/Event/Director.h @@ -77,6 +77,8 @@ namespace Sapphire::Event void sendDirectorInit( Entity::Player& player ) const; + void sendEventLogMessage( Sapphire::Entity::Player& player, Sapphire::InstanceContent& instance, uint32_t msgId, const std::vector< uint32_t > args = {} ) const; + void sendDirectorClear( Entity::Player& player ) const; void sendDirectorVars( Entity::Player& player ) const; diff --git a/src/world/Territory/InstanceContent.h b/src/world/Territory/InstanceContent.h index c5b5b4db..8621dfc6 100644 --- a/src/world/Territory/InstanceContent.h +++ b/src/world/Territory/InstanceContent.h @@ -38,9 +38,9 @@ namespace Sapphire { DEBUG_TimeSync = 0xC0000001, DutyCommence = 0x40000001, - BattleGroundMusic = 0x40000002, + DutyComplete = 0x40000002, SetStringendoMode = 0x40000003, - DutyComplete = 0x40000004, + BattleGroundMusic = 0x40000004, InvalidateTodoList = 0x40000005, LoadingScreen = 0x40000007, Forward = 0x40000008,