diff --git a/src/common/Exd/ExdDataGenerated.cpp b/src/common/Exd/ExdDataGenerated.cpp index 130023d6..b6f845ca 100644 --- a/src/common/Exd/ExdDataGenerated.cpp +++ b/src/common/Exd/ExdDataGenerated.cpp @@ -4582,9 +4582,11 @@ Sapphire::Data::GuildleveAssignment::GuildleveAssignment( uint32_t row_id, Sapph { auto row = exdData->m_GuildleveAssignmentDat.get_row( row_id ); type = exdData->getField< std::string >( row, 0 ); + typeId = exdData->getField< uint8_t >( row, 1 ); assignmentTalk = exdData->getField< uint32_t >( row, 2 ); quest.push_back( exdData->getField< uint32_t >( row, 3 ) ); quest.push_back( exdData->getField< uint32_t >( row, 4 ) ); + grandCompanyRank = exdData->getField< uint8_t >( row, 10 ); } Sapphire::Data::GuildleveAssignmentCategory::GuildleveAssignmentCategory( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData ) @@ -7669,13 +7671,16 @@ Sapphire::Data::Quest::Quest( uint32_t row_id, Sapphire::Data::ExdDataGenerated* classJobCategory1 = exdData->getField< uint8_t >( row, 6 ); classJobLevel1 = exdData->getField< uint16_t >( row, 7 ); previousQuestJoin = exdData->getField< uint8_t >( row, 8 ); - previousQuest0 = exdData->getField< uint32_t >( row, 9 ); - previousQuest1 = exdData->getField< uint32_t >( row, 11 ); - previousQuest2 = exdData->getField< uint32_t >( row, 12 ); + previousQuest.push_back( exdData->getField< uint32_t >( row, 9 ) ); + previousQuest0Sequence = exdData->getField< uint8_t >( row, 10 ); + previousQuest.push_back( exdData->getField< uint32_t >( row, 11 ) ); + previousQuest.push_back( exdData->getField< uint32_t >( row, 12 ) ); questLockJoin = exdData->getField< uint8_t >( row, 13 ); questLock.push_back( exdData->getField< uint32_t >( row, 14 ) ); questLock.push_back( exdData->getField< uint32_t >( row, 15 ) ); header = exdData->getField< uint16_t >( row, 16 ); + startTown = exdData->getField< uint8_t >( row, 17 ); + classJobUnlockFlag = exdData->getField< uint8_t >( row, 18 ); classJobUnlock = exdData->getField< uint8_t >( row, 19 ); grandCompany = exdData->getField< uint8_t >( row, 20 ); grandCompanyRank = exdData->getField< uint8_t >( row, 21 ); @@ -7691,6 +7696,8 @@ Sapphire::Data::Quest::Quest( uint32_t row_id, Sapphire::Data::ExdDataGenerated* beastTribe = exdData->getField< uint8_t >( row, 31 ); beastReputationRank = exdData->getField< uint8_t >( row, 32 ); beastReputationValue = exdData->getField< uint16_t >( row, 33 ); + satisfactionNpc = exdData->getField< uint8_t >( row, 34 ); + satisfactionLevel = exdData->getField< uint8_t >( row, 35 ); mountRequired = exdData->getField< int32_t >( row, 36 ); isHouseRequired = exdData->getField< bool >( row, 37 ); deliveryQuest = exdData->getField< uint8_t >( row, 38 ); diff --git a/src/common/Exd/ExdDataGenerated.h b/src/common/Exd/ExdDataGenerated.h index b670239f..7f890fdd 100644 --- a/src/common/Exd/ExdDataGenerated.h +++ b/src/common/Exd/ExdDataGenerated.h @@ -4366,8 +4366,10 @@ struct GuideTitle struct GuildleveAssignment { std::string type; + uint8_t typeId; uint32_t assignmentTalk; std::vector< uint32_t > quest; + uint8_t grandCompanyRank; GuildleveAssignment( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData ); }; @@ -6324,12 +6326,13 @@ struct Quest uint8_t classJobCategory1; uint16_t classJobLevel1; uint8_t previousQuestJoin; - uint32_t previousQuest0; - uint32_t previousQuest1; - uint32_t previousQuest2; + std::vector< uint32_t > previousQuest; + uint8_t previousQuest0Sequence; uint8_t questLockJoin; std::vector< uint32_t > questLock; uint16_t header; + uint8_t startTown; + uint8_t classJobUnlockFlag; uint8_t classJobUnlock; uint8_t grandCompany; uint8_t grandCompanyRank; @@ -6343,6 +6346,8 @@ struct Quest uint8_t beastTribe; uint8_t beastReputationRank; uint16_t beastReputationValue; + uint8_t satisfactionNpc; + uint8_t satisfactionLevel; int32_t mountRequired; bool isHouseRequired; uint8_t deliveryQuest; diff --git a/src/common/Network/CommonActorControl.h b/src/common/Network/CommonActorControl.h index 27657d42..c713148c 100644 --- a/src/common/Network/CommonActorControl.h +++ b/src/common/Network/CommonActorControl.h @@ -215,7 +215,19 @@ namespace Sapphire::Network::ActorControl SetFavorite = 0x1FC, LearnTeleport = 0x1FD, - OpenRecommendationGuide = 0x200, + /*! + * param1 = event type bitmask + * 1 = Quest + * 2 = GuildLeveAssignment + * 4 = GuildOrderGuide + * 8 = TripleTriad + * 16 = CustomTalk + * 32 = PreHandler + */ + BeginMapUpdate = 0x1FF, + FinishMapUpdate = 0x200, + + //OpenRecommendationGuide = 0x200, ArmoryErrorMsg = 0x201, AchievementPopup = 0x203, diff --git a/src/common/Network/PacketDef/Ipcs.h b/src/common/Network/PacketDef/Ipcs.h index 7bce247e..6d61cc27 100644 --- a/src/common/Network/PacketDef/Ipcs.h +++ b/src/common/Network/PacketDef/Ipcs.h @@ -282,6 +282,14 @@ namespace Sapphire::Network::Packets DailyQuests = 0x0331, // updated 5.58 DailyQuestRepeatFlags = 0x01D1, // updated 5.58 + MapUpdate = 0x03A2, // updated 5.58 + MapUpdate4 = 0x0284, // updated 5.58 + MapUpdate8 = 0x01BC, // updated 5.58 + MapUpdate16 = 0x02D1, // updated 5.58 + MapUpdate32 = 0x00DB, // updated 5.58 + MapUpdate64 = 0x0368, // updated 5.58 + MapUpdate128 = 0x0349, // updated 5.58 + /// Doman Mahjong ////////////////////////////////////// MahjongOpenGui = 0x02A4, // only available in mahjong instance MahjongNextRound = 0x02BD, // initial hands(baipai), # of riichi(wat), winds, honba, score and stuff diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index c0899b1e..84794646 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -928,12 +928,11 @@ namespace Sapphire::Network::Packets::Server uint8_t unknown5; uint32_t unknown8; - uint16_t festivalId; - uint16_t additionalFestivalId; uint32_t unknown9; uint32_t unknown10; - uint32_t unknown11; - uint32_t unknown12[4]; + uint32_t festivalId; + uint32_t unknown12[3]; + uint32_t additionalFestivalId; uint32_t unknown13[3]; Common::FFXIVARR_POSITION3 pos; uint32_t unknown14[3]; @@ -2289,6 +2288,60 @@ namespace Sapphire::Network::Packets::Server uint16_t padding3; } actors[2]; }; + + //For quests this is only used for pre-accepted ones. Accepted quests are getting handled by the client. + template< int ArgCount > + struct FFXIVIpcMapUpdateN + { + uint8_t entryCount; + uint8_t padding[ 3 ]; + uint32_t iconIds[ ArgCount ]; + uint32_t levelIds[ ArgCount ]; + uint32_t eventIds[ ArgCount ]; // possible event ids for this: Quest, GuildLeveAssignment, GuildOrderGuide, TripleTriad, CustomTalk, PreHandler + uint8_t additionalData[ ArgCount ]; // use unknown + }; + + struct FFXIVIpcMapUpdate : + FFXIVIpcBasePacket< MapUpdate >, + FFXIVIpcMapUpdateN< 2 > + { + }; + + struct FFXIVIpcMapUpdate4 : + FFXIVIpcBasePacket< MapUpdate4 >, + FFXIVIpcMapUpdateN< 4 > + { + }; + + struct FFXIVIpcMapUpdate8 : + FFXIVIpcBasePacket< MapUpdate8 >, + FFXIVIpcMapUpdateN< 8 > + { + }; + + struct FFXIVIpcMapUpdate16 : + FFXIVIpcBasePacket< MapUpdate16 >, + FFXIVIpcMapUpdateN< 16 > + { + }; + + struct FFXIVIpcMapUpdate32 : + FFXIVIpcBasePacket< MapUpdate32 >, + FFXIVIpcMapUpdateN< 32 > + { + }; + + struct FFXIVIpcMapUpdate64 : + FFXIVIpcBasePacket< MapUpdate64 >, + FFXIVIpcMapUpdateN< 64 > + { + }; + + struct FFXIVIpcMapUpdate128 : + FFXIVIpcBasePacket< MapUpdate128 >, + FFXIVIpcMapUpdateN< 128 > + { + }; } #endif /*_CORE_NETWORK_PACKETS_SERVER_IPC_H*/ diff --git a/src/common/Util/Util.cpp b/src/common/Util/Util.cpp index 2be5d946..5aa64bf6 100644 --- a/src/common/Util/Util.cpp +++ b/src/common/Util/Util.cpp @@ -129,7 +129,7 @@ uint32_t Util::getTimeSeconds() uint64_t Util::getEorzeanTimeStamp() { - return static_cast< uint64_t >( getTimeSeconds() * 20.571428571428573f ); + return static_cast< uint64_t >( getTimeSeconds() * 20.571428571428573 ); } void Util::valueToFlagByteIndexValue( uint32_t inVal, uint8_t& outVal, uint16_t& outIndex ) diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index a71184a5..1ef07103 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -19,6 +19,7 @@ #include "Manager/HousingMgr.h" #include "Manager/TerritoryMgr.h" #include "Manager/RNGMgr.h" +#include "Manager/MapMgr.h" #include "Territory/Territory.h" #include "Territory/ZonePosition.h" @@ -730,7 +731,7 @@ void Sapphire::Entity::Player::learnSong( uint8_t songId, uint32_t itemId ) queuePacket( makeActorControlSelf( getId(), ToggleOrchestrionUnlock, songId, 1, itemId ) ); } -bool Sapphire::Entity::Player::isActionLearned( uint8_t actionId ) const +bool Sapphire::Entity::Player::isActionLearned( uint32_t actionId ) const { uint16_t index; uint8_t value; @@ -1286,6 +1287,17 @@ const uint8_t* Sapphire::Entity::Player::getMountGuideBitmask() const return m_mountGuide; } +const bool Sapphire::Entity::Player::hasMount( uint32_t mountId ) const +{ + auto& exdData = Common::Service< Data::ExdDataGenerated >::ref(); + auto mount = exdData.get< Data::Mount >( mountId ); + + if( mount->order == -1 || mount->modelChara == 0 ) + return false; + + return m_mountGuide[ mount->order / 8 ] & ( 1 << ( mount->order % 8 ) ); +} + uint64_t Sapphire::Entity::Player::getContentId() const { return m_contentId; @@ -1890,6 +1902,8 @@ Sapphire::Entity::Player::sendZoneInPackets( uint32_t param1, uint32_t param2 = setZoningType( Common::ZoneingType::None ); unsetStateFlag( PlayerStateFlag::BetweenAreas ); + + Common::Service< MapMgr >::ref().updateAll( *this ); } void Sapphire::Entity::Player::finishZoning() diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 63f41eb6..3aa474de 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -194,6 +194,8 @@ namespace Sapphire::Entity /*! remove a given quest */ void removeQuest( uint16_t questId ); + bool isQuestCompleted( uint16_t questId ); + /*! add a quest to the completed quests mask */ void updateQuestsCompleted( uint32_t questId ); @@ -644,7 +646,7 @@ namespace Sapphire::Entity void learnSong( uint8_t songId, uint32_t itemId ); /*! check if an action is already unlocked in the bitmask. */ - bool isActionLearned( uint8_t actionId ) const; + bool isActionLearned( uint32_t actionId ) const; /*! return a const pointer to the unlock bitmask array */ const uint8_t* getUnlockBitmask() const; @@ -655,6 +657,8 @@ namespace Sapphire::Entity /*! return a const pointer to the mount guide bitmask array */ const uint8_t* getMountGuideBitmask() const; + const bool hasMount( uint32_t mountId ) const; + bool checkAction() override; bool hasQueuedAction() const; @@ -950,6 +954,7 @@ namespace Sapphire::Entity uint16_t calculateEquippedGearItemLevel(); ItemPtr getEquippedWeapon(); + ItemPtr getEquippedSecondaryWeapon(); /*! return the current amount of currency of type */ uint32_t getCurrency( Common::CurrencyType type ); diff --git a/src/world/Actor/PlayerInventory.cpp b/src/world/Actor/PlayerInventory.cpp index 2d4763fc..f342ea00 100644 --- a/src/world/Actor/PlayerInventory.cpp +++ b/src/world/Actor/PlayerInventory.cpp @@ -939,6 +939,11 @@ Sapphire::ItemPtr Sapphire::Entity::Player::getEquippedWeapon() return m_storageMap[ GearSet0 ]->getItem( GearSetSlot::MainHand ); } +Sapphire::ItemPtr Sapphire::Entity::Player::getEquippedSecondaryWeapon() +{ + return m_storageMap[ InventoryType::GearSet0 ]->getItem( GearSetSlot::OffHand ); +} + uint8_t Sapphire::Entity::Player::getFreeSlotsInBags() { uint8_t slots = 0; diff --git a/src/world/Actor/PlayerQuest.cpp b/src/world/Actor/PlayerQuest.cpp index 6eaafc91..e99d27f9 100644 --- a/src/world/Actor/PlayerQuest.cpp +++ b/src/world/Actor/PlayerQuest.cpp @@ -7,6 +7,8 @@ #include "Network/GameConnection.h" #include "Network/PacketWrappers/QuestMessagePacket.h" +#include "Manager/MapMgr.h" + #include "Session.h" using namespace Sapphire::Common; @@ -42,6 +44,11 @@ void Sapphire::Entity::Player::removeQuest( uint16_t questId ) if( ( idx != -1 ) && ( m_activeQuests[ idx ] != nullptr ) ) { + std::shared_ptr< QuestActive > pQuest = m_activeQuests[ idx ]; + m_activeQuests[ idx ].reset(); + + Common::Service< World::Manager::MapMgr >::ref().updateQuests( *this ); + auto questUpdatePacket = makeZonePacket< FFXIVIpcQuestUpdate >( getId() ); questUpdatePacket->data().slot = static_cast< uint8_t >( idx ); questUpdatePacket->data().questInfo.c.questId = 0; @@ -54,9 +61,6 @@ void Sapphire::Entity::Player::removeQuest( uint16_t questId ) m_questTracking[ ii ] = -1; } - std::shared_ptr< QuestActive > pQuest = m_activeQuests[ idx ]; - m_activeQuests[ idx ].reset(); - m_questIdToQuestIdx.erase( questId ); m_questIdxToQuestId.erase( idx ); @@ -916,6 +920,8 @@ void Sapphire::Entity::Player::updateQuest( uint16_t questId, uint8_t sequence ) m_questIdToQuestIdx[ questId ] = idx; m_questIdxToQuestId[ idx ] = questId; + Common::Service< World::Manager::MapMgr >::ref().updateQuests( *this ); + auto questUpdatePacket = makeZonePacket< FFXIVIpcQuestUpdate >( getId() ); questUpdatePacket->data().slot = idx; questUpdatePacket->data().questInfo = *pNewQuest; @@ -1013,6 +1019,11 @@ Sapphire::Entity::Player::sendQuestMessage( uint32_t questId, int8_t msgId, uint } +bool Sapphire::Entity::Player::isQuestCompleted( uint16_t questId ) +{ + return ( m_questCompleteFlags[ questId / 8 ] & ( 0x80 >> ( questId % 8 ) ) ); +} + void Sapphire::Entity::Player::updateQuestsCompleted( uint32_t questId ) { uint16_t index = questId / 8; @@ -1032,6 +1043,8 @@ void Sapphire::Entity::Player::removeQuestsCompleted( uint32_t questId ) m_questCompleteFlags[ index ] ^= value; + Common::Service< World::Manager::MapMgr >::ref().updateQuests( *this ); + } bool Sapphire::Entity::Player::giveQuestRewards( uint32_t questId, uint32_t optionalChoice ) diff --git a/src/world/Event/EventHandler.h b/src/world/Event/EventHandler.h index 4afc4480..0990ec87 100644 --- a/src/world/Event/EventHandler.h +++ b/src/world/Event/EventHandler.h @@ -78,11 +78,20 @@ namespace Sapphire::Event FcTalk = 0x001F, Adventure = 0x0021, DailyQuestSupply = 0x0022, + TripleTriad = 0x0023, + PreHandler = 0x0036, ICDirector = 0x8003, PublicContentDirector = 0x8004, QuestBattleDirector = 0x8006, }; + enum class QuestAvailability : uint8_t + { + Invisible, + Available, + Locked + }; + using SceneReturnCallback = std::function< void( Entity::Player&, const SceneResult& ) >; using SceneChainCallback = std::function< void( Entity::Player& ) >; using EventFinishCallback = std::function< void( Entity::Player&, uint64_t ) >; diff --git a/src/world/Manager/MapMgr.cpp b/src/world/Manager/MapMgr.cpp new file mode 100644 index 00000000..462f9b3d --- /dev/null +++ b/src/world/Manager/MapMgr.cpp @@ -0,0 +1,685 @@ +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#include + +#include