From 6c43c79af19265966bc83ca6e161aa96d66b4734 Mon Sep 17 00:00:00 2001 From: Mordred Date: Wed, 17 Apr 2019 00:10:32 +0200 Subject: [PATCH] First iteration of questbattle update logic --- .../Network/PacketDef/Zone/ServerZoneDef.h | 2 +- .../instances/questbattles/ChasingShadows.cpp | 91 +++++++++++++++---- src/world/Actor/BNpc.cpp | 18 +++- src/world/Actor/BNpc.h | 4 + src/world/Actor/Chara.cpp | 5 + src/world/Actor/Chara.h | 2 + src/world/Event/Director.cpp | 13 +++ src/world/Event/Director.h | 4 + .../Network/PacketWrappers/NpcSpawnPacket.h | 1 + src/world/Script/NativeScriptApi.cpp | 4 + src/world/Script/NativeScriptApi.h | 2 + src/world/Script/ScriptMgr.cpp | 14 +++ src/world/Script/ScriptMgr.h | 2 + src/world/Territory/InstanceContent.cpp | 1 + src/world/Territory/QuestBattle.cpp | 30 ++++++ src/world/Territory/QuestBattle.h | 5 + src/world/Territory/Zone.cpp | 3 +- 17 files changed, 180 insertions(+), 21 deletions(-) diff --git a/src/common/Network/PacketDef/Zone/ServerZoneDef.h b/src/common/Network/PacketDef/Zone/ServerZoneDef.h index 51c0b671..b6a6180c 100644 --- a/src/common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/common/Network/PacketDef/Zone/ServerZoneDef.h @@ -576,7 +576,7 @@ namespace Sapphire::Network::Packets::Server uint32_t u15; uint32_t bNPCBase; uint32_t bNPCName; - uint32_t u18; + uint32_t levelId; uint32_t u19; uint32_t directorId; uint32_t spawnerId; diff --git a/src/scripts/instances/questbattles/ChasingShadows.cpp b/src/scripts/instances/questbattles/ChasingShadows.cpp index ca04cfed..60f0702a 100644 --- a/src/scripts/instances/questbattles/ChasingShadows.cpp +++ b/src/scripts/instances/questbattles/ChasingShadows.cpp @@ -27,9 +27,14 @@ private: static constexpr auto CUT_SCENE_01 = 54; static constexpr auto HOW_TO_QIB = 79; + enum vars + { + SET_1_SPAWNED, + SET_2_SPAWNED + }; + public: - ChasingShadows() : Sapphire::ScriptAPI::QuestBattleScript( 11 ) - { } + ChasingShadows() : Sapphire::ScriptAPI::QuestBattleScript( 11 ) {} void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) { @@ -40,25 +45,35 @@ public: void onInit( QuestBattle& instance ) override { instance.registerEObj( "unknown_0", 2005192, 5760474, 4, { -51.493111f, 0.309087f, 71.436897f }, 1.000000f, -0.000006f ); - auto a1 = instance.createBNpcFromLevelEntry( INIT_POP_BOSS, 12, 0, 21141, 939, - instance.getDirectorId(), Common::BNpcType::Enemy ); - auto a2 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_B_01, 10, 0, 1440, 938, - instance.getDirectorId(), Common::BNpcType::Enemy ); - auto a3 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_B_02, 10, 0, 1440, 938, - instance.getDirectorId(), Common::BNpcType::Enemy ); - instance.pushActor( a1 ); - instance.pushActor( a2 ); - instance.pushActor( a3 ); - auto a4 = instance.createBNpcFromLevelEntry( INIT_P_POP_IDA, 50, 0, 27780, 1375, - instance.getDirectorId(), Common::BNpcType::Friendly ); - auto a5 = instance.createBNpcFromLevelEntry( INIT_P_POP_PAPARIMO, 50, 0, 27780, 1376, - instance.getDirectorId(), Common::BNpcType::Friendly ); - instance.pushActor( a4 ); - instance.pushActor( a5 ); + } void onUpdate( QuestBattle& instance, uint64_t tickCount ) override { + auto pair1Spawnd = instance.getCustomVar( SET_1_SPAWNED ); + + auto boss = instance.getActiveBNpcByLevelId( INIT_POP_BOSS ); + if( !boss ) + return; + + if( pair1Spawnd == 0 && boss->getHpPercent() <= 90 ) + { + instance.setCustomVar( SET_1_SPAWNED, 1 ); + auto a2 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_B_03, 10, 0, 1440, 938, + instance.getDirectorId(), Common::BNpcType::Enemy ); + auto a3 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_B_04, 10, 0, 1440, 938, + instance.getDirectorId(), Common::BNpcType::Enemy ); + + instance.pushActor( a2 ); + instance.pushActor( a3 ); + + auto pPlayer = instance.getPlayerPtr(); + a2->hateListAdd( pPlayer, 1 ); + pPlayer->hateListAdd( a2 ); + + a3->hateListAdd( pPlayer, 1 ); + pPlayer->hateListAdd( a3 ); + } } @@ -71,6 +86,7 @@ public: DISABLE_STEALTH | 0x00100000 | LOCK_HUD | LOCK_HOTBAR | // todo: wtf is 0x00100000 DISABLE_CANCEL_EMOTE, 0 ); + } void onDutyComplete( QuestBattle& instance, Entity::Player& player ) override @@ -78,6 +94,47 @@ public: player.updateQuest( instance.getQuestId(), 2 ); } + void onDutyCommence( QuestBattle& instance, Entity::Player& player ) override + { + auto a1 = instance.createBNpcFromLevelEntry( INIT_POP_BOSS, 12, 0, 21141, 939, + instance.getDirectorId(), Common::BNpcType::Enemy ); + auto a2 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_B_01, 10, 0, 1440, 938, + instance.getDirectorId(), Common::BNpcType::Enemy ); + auto a3 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_B_02, 10, 0, 1440, 938, + instance.getDirectorId(), Common::BNpcType::Enemy ); + + auto a4 = instance.createBNpcFromLevelEntry( INIT_P_POP_IDA, 50, 0, 27780, 1375, + instance.getDirectorId(), Common::BNpcType::Friendly ); + auto a5 = instance.createBNpcFromLevelEntry( INIT_P_POP_PAPARIMO, 50, 0, 27780, 1376, + instance.getDirectorId(), Common::BNpcType::Friendly ); + instance.pushActor( a1 ); + instance.pushActor( a2 ); + instance.pushActor( a3 ); + instance.pushActor( a4 ); + instance.pushActor( a5 ); + + a1->hateListAdd( a4, 10000 ); + a1->hateListAdd( a5, 10000 ); + + a2->hateListAdd( a4, 10000 ); + a2->hateListAdd( a5, 10000 ); + a2->hateListAdd( player.getAsPlayer(), 1 ); + player.hateListAdd( a2 ); + + a3->hateListAdd( a4, 10000 ); + a3->hateListAdd( a5, 10000 ); + a3->hateListAdd( player.getAsPlayer(), 1 ); + player.hateListAdd( a3 ); + + a4->hateListAdd( a1, 10000 ); + a4->hateListAdd( a2, 9999 ); + a4->hateListAdd( a3, 9999 ); + + a5->hateListAdd( a1, 10000 ); + a5->hateListAdd( a2, 9999 ); + a5->hateListAdd( a3, 9999 ); + } + }; EXPOSE_SCRIPT( ChasingShadows ); \ No newline at end of file diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 2691756a..6d3684dd 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -68,6 +68,7 @@ Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX m_level = level; m_invincibilityType = InvincibilityNone; m_currentStance = Common::Stance::Passive; + m_levelId = 0; m_pCurrentZone = pZone; @@ -157,6 +158,7 @@ uint32_t Sapphire::Entity::BNpc::getBNpcNameId() const void Sapphire::Entity::BNpc::spawn( PlayerPtr pTarget ) { + m_lastRoamTargetReached = Util::getTimeSeconds(); pTarget->queuePacket( std::make_shared< NpcSpawnPacket >( *this, *pTarget ) ); } @@ -393,11 +395,11 @@ void Sapphire::Entity::BNpc::aggro( Sapphire::Entity::CharaPtr pChara ) m_state = BNpcState::Combat; sendToInRangeSet( makeActorControl142( getId(), ActorControlType::ToggleWeapon, 1, 1, 0 ) ); + sendToInRangeSet( makeActorControl142( getId(), ActorControlType::ToggleAggro, 1, 0, 0 ) ); if( pChara->isPlayer() ) { PlayerPtr tmpPlayer = pChara->getAsPlayer(); - sendToInRangeSet( makeActorControl142( getId(), ActorControlType::ToggleAggro, 1, 0, 0 ) ); tmpPlayer->onMobAggro( getAsBNpc() ); } @@ -472,6 +474,10 @@ void Sapphire::Entity::BNpc::update( uint64_t tickCount ) case BNpcState::Idle: { + auto pHatedActor = hateListGetHighest(); + if( pHatedActor ) + aggro( pHatedActor ); + if( Util::getTimeSeconds() - m_lastRoamTargetReached > roamTick ) { auto pNaviMgr = m_pFw->get< World::Manager::NaviMgr >(); @@ -690,3 +696,13 @@ void Sapphire::Entity::BNpc::setOwner( Sapphire::Entity::CharaPtr m_pChara ) sendToInRangeSet( setOwnerPacket ); } } + +void Sapphire::Entity::BNpc::setLevelId( uint32_t levelId ) +{ + m_levelId = levelId; +} + +uint32_t Sapphire::Entity::BNpc::getLevelId() const +{ + return m_levelId; +} \ No newline at end of file diff --git a/src/world/Actor/BNpc.h b/src/world/Actor/BNpc.h index 439b915e..f756a2cc 100644 --- a/src/world/Actor/BNpc.h +++ b/src/world/Actor/BNpc.h @@ -102,6 +102,9 @@ namespace Sapphire::Entity void setOwner( CharaPtr m_pChara ); + void setLevelId( uint32_t levelId ); + uint32_t getLevelId() const; + private: uint32_t m_bNpcBaseId; uint32_t m_bNpcNameId; @@ -114,6 +117,7 @@ namespace Sapphire::Entity uint16_t m_modelChara; uint32_t m_displayFlags; uint8_t m_level; + uint32_t m_levelId; float m_scale; float m_naviTargetReachedDistance; diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 5d2ec509..7fcae496 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -81,6 +81,11 @@ uint32_t Sapphire::Entity::Chara::getHp() const return m_hp; } +uint32_t Sapphire::Entity::Chara::getHpPercent() const +{ + return ( m_hp * 100 ) / m_maxHp; +} + /*! \return current MP */ uint32_t Sapphire::Entity::Chara::getMp() const { diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index b6826325..0f219638 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -187,6 +187,8 @@ namespace Sapphire::Entity uint32_t getHp() const; + uint32_t getHpPercent() const; + uint32_t getMp() const; uint16_t getTp() const; diff --git a/src/world/Event/Director.cpp b/src/world/Event/Director.cpp index b5d4340c..00710e77 100644 --- a/src/world/Event/Director.cpp +++ b/src/world/Event/Director.cpp @@ -182,3 +182,16 @@ void Sapphire::Event::Director::setDirectorSequence( uint8_t value ) { m_sequence = value; } + +void Sapphire::Event::Director::setCustomVar( uint32_t varId, uint32_t value ) +{ + m_customVarMap[ varId ] = value; +} + +uint32_t Sapphire::Event::Director::getCustomVar( uint32_t varId ) +{ + auto it = m_customVarMap.find( varId ); + if( it != m_customVarMap.end() ) + return it->second; + return 0; +} \ No newline at end of file diff --git a/src/world/Event/Director.h b/src/world/Event/Director.h index 779efb78..101c7402 100644 --- a/src/world/Event/Director.h +++ b/src/world/Event/Director.h @@ -102,6 +102,9 @@ namespace Sapphire::Event void setDirectorBranch( uint8_t value ); + void setCustomVar( uint32_t varId, uint32_t value ); + uint32_t getCustomVar( uint32_t varId ); + private: /*! Id of the content of the director */ uint16_t m_contentId; @@ -178,6 +181,7 @@ namespace Sapphire::Event uint32_t m_elapsedTime; + std::unordered_map< uint32_t, uint32_t > m_customVarMap; }; diff --git a/src/world/Network/PacketWrappers/NpcSpawnPacket.h b/src/world/Network/PacketWrappers/NpcSpawnPacket.h index b9d585fd..8f952c77 100644 --- a/src/world/Network/PacketWrappers/NpcSpawnPacket.h +++ b/src/world/Network/PacketWrappers/NpcSpawnPacket.h @@ -50,6 +50,7 @@ namespace Sapphire::Network::Packets::Server m_data.pos.y = bnpc.getPos().y; m_data.pos.z = bnpc.getPos().z; m_data.rotation = Util::floatToUInt16Rot( bnpc.getRot() ); + m_data.levelId = bnpc.getLevelId(); m_data.enemyType = bnpc.getEnemyType(); m_data.mainWeaponModel = bnpc.getWeaponMain(); diff --git a/src/world/Script/NativeScriptApi.cpp b/src/world/Script/NativeScriptApi.cpp index 661a1923..75d63621 100644 --- a/src/world/Script/NativeScriptApi.cpp +++ b/src/world/Script/NativeScriptApi.cpp @@ -218,6 +218,10 @@ namespace Sapphire::ScriptAPI { } + void QuestBattleScript::onDutyCommence( QuestBattle& instance, Entity::Player& player ) + { + } + void QuestBattleScript::onEnterTerritory( QuestBattle& instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) { diff --git a/src/world/Script/NativeScriptApi.h b/src/world/Script/NativeScriptApi.h index 7a2f5ba5..4d31b5df 100644 --- a/src/world/Script/NativeScriptApi.h +++ b/src/world/Script/NativeScriptApi.h @@ -241,6 +241,8 @@ namespace Sapphire::ScriptAPI virtual void onDutyComplete( Sapphire::QuestBattle& instance, Entity::Player& player ); + virtual void onDutyCommence( QuestBattle& instance, Entity::Player& player ); + virtual void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ); virtual void onInit( Sapphire::QuestBattle& instance ); diff --git a/src/world/Script/ScriptMgr.cpp b/src/world/Script/ScriptMgr.cpp index e6e71352..bb2a86e2 100644 --- a/src/world/Script/ScriptMgr.cpp +++ b/src/world/Script/ScriptMgr.cpp @@ -499,6 +499,20 @@ bool Sapphire::Scripting::ScriptMgr::onInstanceUpdate( QuestBattlePtr instance, return false; } + +bool Sapphire::Scripting::ScriptMgr::onDutyCommence( QuestBattle& instance, Entity::Player& player ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::QuestBattleScript >( instance.getDirectorId() ); + + if( script ) + { + script->onDutyCommence( instance, player ); + return true; + } + + return false; +} + bool Sapphire::Scripting::ScriptMgr::onInstanceEnterTerritory( QuestBattlePtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) { diff --git a/src/world/Script/ScriptMgr.h b/src/world/Script/ScriptMgr.h index e333a39f..546ec425 100644 --- a/src/world/Script/ScriptMgr.h +++ b/src/world/Script/ScriptMgr.h @@ -106,6 +106,8 @@ namespace Sapphire::Scripting bool onInstanceUpdate( QuestBattlePtr instance, uint64_t tickCount ); + bool onDutyCommence( QuestBattle& instance, Entity::Player& player ); + bool onInstanceEnterTerritory( QuestBattlePtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ); diff --git a/src/world/Territory/InstanceContent.cpp b/src/world/Territory/InstanceContent.cpp index 285469e6..f6c0e77a 100644 --- a/src/world/Territory/InstanceContent.cpp +++ b/src/world/Territory/InstanceContent.cpp @@ -145,6 +145,7 @@ void Sapphire::InstanceContent::onUpdate( uint64_t tickCount ) case DutyInProgress: { + updateBNpcs( tickCount ); break; } diff --git a/src/world/Territory/QuestBattle.cpp b/src/world/Territory/QuestBattle.cpp index 17693c6d..5a01f32c 100644 --- a/src/world/Territory/QuestBattle.cpp +++ b/src/world/Territory/QuestBattle.cpp @@ -119,6 +119,8 @@ void Sapphire::QuestBattle::onUpdate( uint64_t tickCount ) return; onEnterSceneFinish( *m_pPlayer ); + auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >(); + pScriptMgr->onDutyCommence( *this, *m_pPlayer ); m_state = DutyInProgress; m_instanceExpireTime = Util::getTimeSeconds() + ( m_pBattleDetails->timeLimit * 60u ); @@ -129,6 +131,7 @@ void Sapphire::QuestBattle::onUpdate( uint64_t tickCount ) break; case DutyInProgress: + updateBNpcs( tickCount ); break; case DutyFinished: @@ -464,5 +467,32 @@ Sapphire::Entity::BNpcPtr levelData->yaw, level, hp, shared_from_this(), m_pFw ); bnpc->setDirectorId( directorId ); + bnpc->setLevelId( levelId ); return bnpc; } + +Sapphire::Entity::BNpcPtr Sapphire::QuestBattle::getActiveBNpcByLevelId( uint32_t levelId ) +{ + for( auto bnpcIt : m_bNpcMap ) + { + if( bnpcIt.second->getLevelId() == levelId ) + return bnpcIt.second; + } + return nullptr; +} + +uint32_t Sapphire::QuestBattle::getCountEnemyBNpc() +{ + uint32_t count = 0; + for( auto bnpcIt : m_bNpcMap ) + { + if( bnpcIt.second->getEnemyType() == 4 ) + count++; + } + return count; +} + +Sapphire::Entity::PlayerPtr Sapphire::QuestBattle::getPlayerPtr() +{ + return m_pPlayer; +} diff --git a/src/world/Territory/QuestBattle.h b/src/world/Territory/QuestBattle.h index 1f5395c8..843f9fdb 100644 --- a/src/world/Territory/QuestBattle.h +++ b/src/world/Territory/QuestBattle.h @@ -66,6 +66,9 @@ namespace Sapphire void fail(); void success(); + Entity::BNpcPtr getActiveBNpcByLevelId( uint32_t levelId ); + uint32_t getCountEnemyBNpc(); + void clearDirector( Entity::Player& player ); Event::Director::DirectorState getState() const; @@ -83,6 +86,8 @@ namespace Sapphire uint32_t hp, uint16_t nameId, uint32_t directorId, uint8_t bnpcType ); + Entity::PlayerPtr getPlayerPtr(); + private: std::shared_ptr< Sapphire::Data::QuestBattle > m_pBattleDetails; uint32_t m_questBattleId; diff --git a/src/world/Territory/Zone.cpp b/src/world/Territory/Zone.cpp index b4fa93c1..e9f05ff3 100644 --- a/src/world/Territory/Zone.cpp +++ b/src/world/Territory/Zone.cpp @@ -451,7 +451,6 @@ bool Sapphire::Zone::update( uint64_t tickCount ) bool changedWeather = checkWeather(); updateSessions( tickCount, changedWeather ); - updateBNpcs( tickCount ); onUpdate( tickCount ); updateSpawnPoints(); @@ -708,7 +707,7 @@ void Sapphire::Zone::onLeaveTerritory( Entity::Player& player ) void Sapphire::Zone::onUpdate( uint64_t tickCount ) { - + updateBNpcs( tickCount ); } void Sapphire::Zone::onFinishLoading( Entity::Player& player )