From 2ac2ec1ea24edc0f4775bec3eb9dafed6744b722 Mon Sep 17 00:00:00 2001 From: Lucy <44952533+Skyliegirl33@users.noreply.github.com> Date: Thu, 19 Jan 2023 02:23:39 +0100 Subject: [PATCH 1/6] Fix quest bitflags to be retrieved in ascending order (cherry picked from commit 525c76dbf2bded510e6939fe7cf1dee561e2c903) --- src/world/Quest/Quest.cpp | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/world/Quest/Quest.cpp b/src/world/Quest/Quest.cpp index 2c012957..3f52ef9d 100644 --- a/src/world/Quest/Quest.cpp +++ b/src/world/Quest/Quest.cpp @@ -25,31 +25,31 @@ bool Sapphire::World::Quest::getBitFlag8( uint8_t index ) bool Sapphire::World::Quest::getBitFlag16( uint8_t index ) { - uint8_t realIdx = 8 - index; + uint8_t realIdx = 16 - index; return m_data.a.BitFlag16 & ( 1 << realIdx ); } bool Sapphire::World::Quest::getBitFlag24( uint8_t index ) { - uint8_t realIdx = 8 - index; + uint8_t realIdx = 24 - index; return m_data.a.BitFlag24 & ( 1 << realIdx ); } bool Sapphire::World::Quest::getBitFlag32( uint8_t index ) { - uint8_t realIdx = 8 - index; + uint8_t realIdx = 32 - index; return m_data.a.BitFlag32 & ( 1 << realIdx ); } bool Sapphire::World::Quest::getBitFlag40( uint8_t index ) { - uint8_t realIdx = 8 - index; + uint8_t realIdx = 40 - index; return m_data.a.BitFlag40 & ( 1 << realIdx ); } bool Sapphire::World::Quest::getBitFlag48( uint8_t index ) { - uint8_t realIdx = 8 - index; + uint8_t realIdx = 48 - index; return m_data.a.BitFlag48 & ( 1 << realIdx ); } @@ -312,7 +312,6 @@ void Sapphire::World::Quest::setUI32A( uint32_t val ) void Sapphire::World::Quest::setBitFlag8( uint8_t index, bool val ) { uint8_t realIdx = 8 - index; - if( val ) m_data.a.BitFlag8 |= ( 1 << realIdx ); else @@ -321,8 +320,7 @@ void Sapphire::World::Quest::setBitFlag8( uint8_t index, bool val ) void Sapphire::World::Quest::setBitFlag16( uint8_t index, bool val ) { - uint8_t realIdx = 8 - index; - + uint8_t realIdx = 16 - index; if( val ) m_data.a.BitFlag16 |= ( 1 << realIdx ); else @@ -331,8 +329,7 @@ void Sapphire::World::Quest::setBitFlag16( uint8_t index, bool val ) void Sapphire::World::Quest::setBitFlag24( uint8_t index, bool val ) { - uint8_t realIdx = 8 - index; - + uint8_t realIdx = 24 - index; if( val ) m_data.a.BitFlag24 |= ( 1 << realIdx ); else @@ -341,8 +338,7 @@ void Sapphire::World::Quest::setBitFlag24( uint8_t index, bool val ) void Sapphire::World::Quest::setBitFlag32( uint8_t index, bool val ) { - uint8_t realIdx = 8 - index; - + uint8_t realIdx = 32 - index; if( val ) m_data.a.BitFlag32 |= ( 1 << realIdx ); else @@ -351,8 +347,7 @@ void Sapphire::World::Quest::setBitFlag32( uint8_t index, bool val ) void Sapphire::World::Quest::setBitFlag40( uint8_t index, bool val ) { - uint8_t realIdx = 8 - index; - + uint8_t realIdx = 40 - index; if( val ) m_data.a.BitFlag40 |= ( 1 << realIdx ); else @@ -361,8 +356,7 @@ void Sapphire::World::Quest::setBitFlag40( uint8_t index, bool val ) void Sapphire::World::Quest::setBitFlag48( uint8_t index, bool val ) { - uint8_t realIdx = 8 - index; - + uint8_t realIdx = 48 - index; if( val ) m_data.a.BitFlag48 |= ( 1 << realIdx ); else From 6580fe1721de38f8b9bd7d9b5562e151636d91c6 Mon Sep 17 00:00:00 2001 From: Lucy <44952533+Skyliegirl33@users.noreply.github.com> Date: Thu, 19 Jan 2023 19:51:31 +0100 Subject: [PATCH 2/6] Finally fix TP being stuck at 0 --- src/world/Actor/Player.cpp | 1 + src/world/Manager/WarpMgr.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 827a71da..5fb10c09 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -1497,6 +1497,7 @@ void Player::sendZonePackets() initPacket->data().playerActorId = getId(); queuePacket( initPacket ); + sendStatusUpdate(); sendInventory(); if( isLogin() ) diff --git a/src/world/Manager/WarpMgr.cpp b/src/world/Manager/WarpMgr.cpp index b5b23f97..7dcd1f8b 100644 --- a/src/world/Manager/WarpMgr.cpp +++ b/src/world/Manager/WarpMgr.cpp @@ -85,6 +85,7 @@ void WarpMgr::finishWarp( Entity::Player& player ) player.sendToInRangeSet( zoneInPacket ); player.sendToInRangeSet( SetStatusPacket, true ); + player.sendStatusUpdate(); auto& server = Common::Service< WorldServer >::ref(); server.queueForPlayer( player.getCharacterId(), zoneInPacket ); From 5837b1b8b63b73fe008b9fdc83ba58eccd110ddb Mon Sep 17 00:00:00 2001 From: Lucy <44952533+Skyliegirl33@users.noreply.github.com> Date: Thu, 19 Jan 2023 02:23:39 +0100 Subject: [PATCH 3/6] Add quest event callbacks to yieldeventstring handler (cherry picked from commit aae05b9f6ecb3af20caa547f58bff2b465957b76) --- src/world/Manager/EventMgr.cpp | 54 ++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/src/world/Manager/EventMgr.cpp b/src/world/Manager/EventMgr.cpp index 79486695..1dbfa212 100644 --- a/src/world/Manager/EventMgr.cpp +++ b/src/world/Manager/EventMgr.cpp @@ -354,18 +354,62 @@ void EventMgr::handleReturnStringEventScene( Entity::Player& player, uint32_t ev result.sceneId = sceneId; result.resultString = resultString; - auto eventCallback = pEvent->getEventReturnCallback(); - if( eventCallback ) + if( eventType == Event::EventHandler::EventHandlerType::Quest ) { - eventCallback( player, result ); + auto questId = static_cast< uint16_t >( eventId ); + auto eventCallback = pEvent->getQuestEventReturnCallback(); + if( eventCallback ) + { + World::Quest preQ; + if( player.hasQuest( eventId ) ) + { + auto questIdx = player.getQuestIndex( questId ); + auto& quest = player.getQuestByIndex( questIdx ); + preQ = quest; + eventCallback( quest, player, result ); + if( quest != preQ ) + player.updateQuest( quest ); + } + else + { + auto newQuest = World::Quest( questId, 0, 0 ); + preQ = newQuest; + eventCallback( newQuest, player, result ); + if( newQuest != preQ ) + player.updateQuest( newQuest ); + } + } + else if( auto chainCallback = pEvent->getQuestSceneChainCallback() ) + { + if( player.hasQuest( eventId ) ) + { + auto questIdx = player.getQuestIndex( questId ); + auto& quest = player.getQuestByIndex( questIdx ); + chainCallback( quest, player ); + } + else + { + auto newQuest = World::Quest( questId, 0, 0 ); + chainCallback( newQuest, player ); + } + } } + else + { + auto eventCallback = pEvent->getEventReturnCallback(); + if( eventCallback ) + { + eventCallback( player, result ); + } // we might have a scene chain callback instead so check for that too - else if( auto chainCallback = pEvent->getSceneChainCallback() ) - chainCallback( player ); + else if( auto chainCallback = pEvent->getSceneChainCallback() ) + chainCallback( player ); + } } + checkEvent( player, eventId ); } void EventMgr::handleReturnIntAndStringEventScene( Entity::Player& player, uint32_t eventId, uint16_t sceneId, const std::string& resultString, uint64_t resultInt ) From 49aeb1ec43b6e58471f16e581c51d75314527d80 Mon Sep 17 00:00:00 2001 From: Lucy <44952533+Skyliegirl33@users.noreply.github.com> Date: Thu, 19 Jan 2023 19:38:43 +0100 Subject: [PATCH 4/6] Implement Lurkers in the Grotto QB (cherry picked from commit 4b2affb341e613bd99ccca54e0e0132a2bdb19e7) --- .../questbattles/LurkersintheGrotto.cpp | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/src/scripts/instances/questbattles/LurkersintheGrotto.cpp b/src/scripts/instances/questbattles/LurkersintheGrotto.cpp index cf6c6a2f..5bfaff2c 100644 --- a/src/scripts/instances/questbattles/LurkersintheGrotto.cpp +++ b/src/scripts/instances/questbattles/LurkersintheGrotto.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include using namespace Sapphire; @@ -16,6 +19,14 @@ private: static constexpr auto INIT_P_POP_01 = 4083622; static constexpr auto CUT_SCENE_01 = 133; static constexpr auto HOW_TO_QIB = 79; + static constexpr auto TEXT_YSHTOLA_BATTLETALK_01 = 82; + + enum Variables : uint8_t + { + SET_1_SPAWNED, + SET_2_SPAWNED, + SUCCESS_CALLED + }; public: LurkersintheGrotto() : Sapphire::ScriptAPI::QuestBattleScript( 35 ) @@ -135,15 +146,106 @@ public: } + void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) override + { + player.setRot( 0 ); + player.setPos( { -60, 25, -135 } ); + } + void onUpdate( QuestBattle& instance, uint64_t tickCount ) override { + auto set1Spawned = instance.getDirectorVar( Variables::SET_1_SPAWNED ); + auto set2Spawned = instance.getDirectorVar( Variables::SET_2_SPAWNED ); + auto successCalled = instance.getDirectorVar( Variables::SUCCESS_CALLED ); + auto boss = instance.getActiveBNpcByLayoutId( INIT_POP_BOSS ); + auto ysthola = instance.getActiveBNpcByLayoutId( INIT_P_POP_01 ); + auto pPlayer = instance.getPlayerPtr(); + + auto bossHp = boss ? boss->getHpPercent() : 0; + + if( pPlayer && !pPlayer->isAlive() ) + { + instance.fail(); + return; + } + + if( !set1Spawned && bossHp <= 75 ) + { + auto a1 = instance.createBNpcFromLayoutId( INIT_POP_01_01, 100, Common::BNpcType::Enemy ); + auto a2 = instance.createBNpcFromLayoutId( INIT_POP_01_02, 100, Common::BNpcType::Enemy ); + + a1->setFlag( Entity::NoDeaggro ); + a2->setFlag( Entity::NoDeaggro ); + + a1->hateListAdd( pPlayer, 1 ); + a2->hateListAdd( pPlayer, 1 ); + + instance.setDirectorVar( Variables::SET_1_SPAWNED, true ); + } + + if( !set2Spawned && bossHp <= 25 ) + { + auto a3 = instance.createBNpcFromLayoutId( INIT_POP_02_01, 150, Common::BNpcType::Enemy ); + auto a4 = instance.createBNpcFromLayoutId( INIT_POP_02_02, 150, Common::BNpcType::Enemy ); + auto a5 = instance.createBNpcFromLayoutId( INIT_POP_02_03, 100, Common::BNpcType::Enemy ); + auto a6 = instance.createBNpcFromLayoutId( INIT_POP_02_04, 100, Common::BNpcType::Enemy ); + + a3->setFlag( Entity::NoDeaggro ); + a4->setFlag( Entity::NoDeaggro ); + a5->setFlag( Entity::NoDeaggro ); + a6->setFlag( Entity::NoDeaggro ); + + a3->hateListAdd( pPlayer, 1 ); + a4->hateListAdd( pPlayer, 1 ); + a5->hateListAdd( pPlayer, 1 ); + a6->hateListAdd( pPlayer, 1 ); + + instance.setDirectorVar( Variables::SET_2_SPAWNED, true ); + } + + if( !successCalled && instance.getCountEnemyBNpc() == 0 ) + { + instance.setDirectorVar( Variables::SUCCESS_CALLED, true ); + instance.success(); + } } void onEnterTerritory( QuestBattle& instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override { + eventMgr().playScene( player, instance.getDirectorId(), 1, + NO_DEFAULT_CAMERA | CONDITION_CUTSCENE | SILENT_ENTER_TERRI_ENV | + HIDE_HOTBAR | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE | + DISABLE_STEALTH | 0x00100000 | LOCK_HUD | LOCK_HOTBAR | + // todo: wtf is 0x00100000 + DISABLE_CANCEL_EMOTE, [ & ]( Entity::Player& player, const Event::SceneResult& result ) + { + player.setOnEnterEventDone( true ); + } ); + } + void onDutyComplete( QuestBattle& instance, Entity::Player& player ) override + { + auto idx = player.getQuestIndex( instance.getQuestId() ); + if( idx == -1 ) + return; + auto& quest = player.getQuestByIndex( idx ); + quest.setSeq( 2 ); + } + + void onDutyCommence( QuestBattle& instance, Entity::Player& player ) override + { + auto boss = instance.createBNpcFromLayoutId( INIT_POP_BOSS, 2000, Common::BNpcType::Enemy ); + auto ysthola = instance.createBNpcFromLayoutId( INIT_P_POP_01, 27780, Common::BNpcType::Friendly ); + + boss->setFlag( Entity::NoDeaggro ); + ysthola->setFlag( Entity::NoDeaggro ); + + boss->hateListAdd( ysthola, 10000 ); + boss->hateListAdd( player.getAsPlayer(), 1 ); + + ysthola->hateListAdd( boss, 10000 ); } }; From 36554bf1f37ce8d517c3ee02fc07afc05c773062 Mon Sep 17 00:00:00 2001 From: Lucy <44952533+Skyliegirl33@users.noreply.github.com> Date: Thu, 19 Jan 2023 02:23:39 +0100 Subject: [PATCH 5/6] Fix player not being removed upon leaving territory (cherry picked from commit 1713523e197a225fc5ff5c61a7143dcec091ad59) --- src/world/Territory/Territory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/world/Territory/Territory.cpp b/src/world/Territory/Territory.cpp index c2a0c938..2012b6ed 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -490,7 +490,8 @@ void Territory::updateSessions( uint64_t tickCount, bool changedWeather ) } // this session is not linked to this area anymore, remove it from zone session list - if( pPlayer->getTerritoryId() != m_guId ) + // TODO: Retrieving the session is expensive, try to find a better method of removing invalid actors + if( pPlayer->getTerritoryId() != m_guId || !server.getSession( pPlayer->getId() ) ) { Logger::debug( "[{}] removeActor( pPlayer );", pPlayer->getId() ); removeActor( pPlayer ); From 347141f1cd3db8024aef7150fb03e9419c807138 Mon Sep 17 00:00:00 2001 From: Lucy <44952533+Skyliegirl33@users.noreply.github.com> Date: Thu, 19 Jan 2023 20:18:14 +0100 Subject: [PATCH 6/6] Use discardItem instead of dropInventoryItem --- src/world/Action/ItemAction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/Action/ItemAction.cpp b/src/world/Action/ItemAction.cpp index fb84c355..f2d51d86 100644 --- a/src/world/Action/ItemAction.cpp +++ b/src/world/Action/ItemAction.cpp @@ -86,5 +86,5 @@ void ItemAction::handleMountItem() auto player = getSourceChara()->getAsPlayer(); player->unlockMount( m_itemAction->data().Calcu0Arg[ 0 ] ); - player->dropInventoryItem( static_cast< Common::InventoryType >( m_itemSourceContainer ), static_cast< uint8_t >( m_itemSourceSlot ) ); + player->discardItem( m_itemSourceContainer, m_itemSourceSlot ); } \ No newline at end of file