From c0aed54dfee78cf0eb30f3da0b6216190b49d158 Mon Sep 17 00:00:00 2001 From: Mordred Date: Sat, 11 Jan 2025 21:58:27 +0100 Subject: [PATCH] Fixed spawning issues and navi problems in encounters --- src/common/Common.h | 1 + .../instances/trials/TheBowlofEmbers.cpp | 4 +- src/world/AI/Fsm/StateCombat.cpp | 12 ++-- src/world/AI/Fsm/StateRoam.cpp | 4 +- src/world/Actor/BNpc.cpp | 25 +++++++ src/world/Actor/Chara.h | 2 +- src/world/Actor/Npc.cpp | 10 +++ src/world/Actor/Npc.h | 6 ++ .../Encounter/InstanceContent/IfritNormal.h | 70 ------------------- src/world/Encounter/TimelineActor.cpp | 4 +- src/world/Encounter/Timepoint.cpp | 5 +- src/world/Territory/Territory.cpp | 18 ++++- src/world/Territory/Territory.h | 1 + 13 files changed, 75 insertions(+), 87 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 55c8b75d..4181202c 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -1867,6 +1867,7 @@ namespace Sapphire::Common CircularAOE = 2, RectangularAOE = 3, ConeAOE = 4, + CircularAOESelf = 5, CircularAoEPlaced = 7 }; diff --git a/src/scripts/instances/trials/TheBowlofEmbers.cpp b/src/scripts/instances/trials/TheBowlofEmbers.cpp index 57baba68..f9b151fc 100644 --- a/src/scripts/instances/trials/TheBowlofEmbers.cpp +++ b/src/scripts/instances/trials/TheBowlofEmbers.cpp @@ -11,9 +11,9 @@ public: void onInit( InstanceContent& instance ) override { - instance.addEObj( "Entrance", 2000182, 4177874, 4177871, 5, { -16.000000f, 0.000000f, 0.000000f }, 1.000000f, 0.000000f, 0); + instance.addEObj( "Entrance", 2000182, 4177874, 4177871, 5, { -16.000000f, 0.000000f, 0.000000f }, 1.000000f, 0.000000f, 0); // States -> vf_lock_on (id: 11) vf_lock_of (id: 12) - instance.addEObj( "Exit", 2000139, 0, 4177870, 4, { 16.000000f, 0.000000f, 0.000000f }, 1.000000f, 0.000000f, 0); +// instance.addEObj( "Exit", 2000139, 0, 4177870, 4, { 16.000000f, 0.000000f, 0.000000f }, 1.000000f, 0.000000f, 0); } diff --git a/src/world/AI/Fsm/StateCombat.cpp b/src/world/AI/Fsm/StateCombat.cpp index c905d05c..1a05f44c 100644 --- a/src/world/AI/Fsm/StateCombat.cpp +++ b/src/world/AI/Fsm/StateCombat.cpp @@ -22,7 +22,8 @@ void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) if( !pHatedActor ) return; - pNaviProvider->updateAgentParameters( bnpc ); + if( pNaviProvider && bnpc.pathingActive() ) + pNaviProvider->updateAgentParameters( bnpc ); auto distanceOrig = Common::Util::distance( bnpc.getPos(), bnpc.getSpawnPos() ); @@ -42,7 +43,9 @@ void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) } - if( !hasQueuedAction && !bnpc.hasFlag( Entity::Immobile ) && distance > ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) + if( bnpc.pathingActive() && !hasQueuedAction && + !bnpc.hasFlag( Entity::Immobile ) && + distance > ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) { if( pNaviProvider ) @@ -53,14 +56,13 @@ void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) pNaviProvider->syncPosToChara( bnpc ); - if( !hasQueuedAction && distance < ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) + if( !hasQueuedAction && (distance < ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) || !bnpc.pathingActive() ) ) { // todo: dont turn if facing if( !bnpc.hasFlag( Entity::TurningDisabled ) ) bnpc.face( pHatedActor->getPos() ); - if( !hasQueuedAction ) - bnpc.processGambits( tickCount ); + bnpc.processGambits( tickCount ); // in combat range. ATTACK! if( !bnpc.hasFlag( Entity::BNpcFlag::AutoAttackDisabled ) ) diff --git a/src/world/AI/Fsm/StateRoam.cpp b/src/world/AI/Fsm/StateRoam.cpp index d64fbee4..e570647d 100644 --- a/src/world/AI/Fsm/StateRoam.cpp +++ b/src/world/AI/Fsm/StateRoam.cpp @@ -15,7 +15,7 @@ void AI::Fsm::StateRoam::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() ); auto pNaviProvider = pZone->getNaviProvider(); - if( bnpc.hasFlag( Entity::NoRoam ) ) + if( bnpc.hasFlag( Entity::NoRoam ) || bnpc.hasFlag( Entity::Immobile ) || !bnpc.pathingActive() ) { bnpc.setRoamTargetReached( true ); return; @@ -38,7 +38,7 @@ void AI::Fsm::StateRoam::onEnter( Entity::BNpc& bnpc ) auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() ); auto pNaviProvider = pZone->getNaviProvider(); - if( !pNaviProvider ) + if( !pNaviProvider || bnpc.hasFlag( Entity::NoRoam ) || bnpc.hasFlag( Entity::Immobile ) ) { bnpc.setRoamTargetReached( true ); return; diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 82450f0a..5b1e06ba 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -88,6 +88,7 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_pos.x = pInfo->x; m_pos.y = pInfo->y; m_pos.z = pInfo->z; + m_lastPos = m_pos; m_rot = pInfo->rotation; m_level = pInfo->Level <= 0 ? 1 : pInfo->Level; m_invincibilityType = InvincibilityNone; @@ -203,6 +204,7 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_pos.x = pInfo->x; m_pos.y = pInfo->y; m_pos.z = pInfo->z; + m_lastPos = m_pos; m_rot = pInfo->rotation; m_level = pInfo->Level <= 0 ? 1 : pInfo->Level; m_invincibilityType = InvincibilityNone; @@ -832,7 +834,30 @@ bool BNpc::hasFlag( uint32_t flag ) const void BNpc::setFlag( uint32_t flag ) { + uint32_t oldFlags = m_flags; m_flags |= flag; + + auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref(); + auto pZone = teriMgr.getTerritoryByGuId( getTerritoryId() ); + + + if( pZone && ( oldFlags & Entity::Immobile ) != Entity::Immobile && + ( m_flags & Entity::Immobile ) == Entity::Immobile ) + { + auto pNaviProvider = pZone->getNaviProvider(); + pNaviProvider->removeAgent( *this ); + setAgentId( 0 ); + setPathingActive( false ); + } + else if( pZone && ( oldFlags & Entity::Immobile ) == Entity::Immobile && + ( m_flags & Entity::Immobile ) != Entity::Immobile ) + { + auto pNaviProvider = pZone->getNaviProvider(); + pNaviProvider->removeAgent( *this ); + auto agentId = pNaviProvider->addAgent( *this ); + setAgentId( agentId ); + setPathingActive( true ); + } } void BNpc::removeFlag( uint32_t flag ) diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index 98683952..1fdfae63 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -99,7 +99,7 @@ namespace Sapphire::Entity std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap; /*! Detour Crowd AgentId */ - uint32_t m_agentId; + uint32_t m_agentId{0}; /*! Detour Crowd actor scale */ float m_radius; diff --git a/src/world/Actor/Npc.cpp b/src/world/Actor/Npc.cpp index e6f63f65..a1ff0fc0 100644 --- a/src/world/Actor/Npc.cpp +++ b/src/world/Actor/Npc.cpp @@ -12,3 +12,13 @@ Npc::Npc( ObjKind type ) : Chara( type ) Npc::~Npc() { } + +bool Npc::pathingActive() const +{ + return m_bPathingActive; +} + +void Npc::setPathingActive( bool pathing ) +{ + m_bPathingActive = pathing; +} diff --git a/src/world/Actor/Npc.h b/src/world/Actor/Npc.h index 191fdf18..5b4a56d7 100644 --- a/src/world/Actor/Npc.h +++ b/src/world/Actor/Npc.h @@ -23,6 +23,12 @@ namespace Sapphire::Entity Npc( Common::ObjKind type ); virtual ~Npc() override; + bool pathingActive() const; + void setPathingActive( bool pathing ); + + private: + bool m_bPathingActive{true}; + }; diff --git a/src/world/Encounter/InstanceContent/IfritNormal.h b/src/world/Encounter/InstanceContent/IfritNormal.h index 7c45b535..5021a960 100644 --- a/src/world/Encounter/InstanceContent/IfritNormal.h +++ b/src/world/Encounter/InstanceContent/IfritNormal.h @@ -32,9 +32,6 @@ namespace Sapphire void start() override { - auto ifritInitState = makeIfritPhaseOneState(); - - addState( ifritInitState ); m_status = EncounterFightStatus::ACTIVE; } @@ -51,60 +48,6 @@ namespace Sapphire init(); } - EncounterStatePtr makeIfritPhaseOneState() - { - auto ifritInitState = std::make_shared< EncounterState >( shared_from_this() ); - ifritInitState->setOnUpdateCallback( [ & ]( EncounterFightPtr pEncounter, EncounterState state ) { - auto timeElapsedMs = state.getElapsedTime(); - - auto pIfrit = pEncounter->getBNpc( NPC_IFRIT ); - - pIfrit->setRot( pIfrit->getRot() + .2f ); - - // todo: use gambits+timelines for this - if( timeElapsedMs > 10000 ) - { - state.setFinishFlag(); - return; - } - - // todo: use gambits+timelines for this - if( timeElapsedMs > 5000 ) - { - auto ifritTwoState = makeIfritPhaseTwoState(); - pEncounter->addState( ifritTwoState ); - } - } ); - - ifritInitState->setOnFinishCallback( [ & ]( EncounterFightPtr pEncounter, EncounterState state ) { - Logger::info( "stage 1 finish - enrage" ); - - auto pIfrit = pEncounter->getBNpc( NPC_IFRIT ); - pIfrit->hateListGetHighest()->die(); - } ); - - return ifritInitState; - } - - EncounterStatePtr makeIfritPhaseTwoState() - { - auto ifritTwoState = std::make_shared< EncounterState >( shared_from_this() ); - ifritTwoState->setOnUpdateCallback( [ & ]( EncounterFightPtr pEncounter, EncounterState state ) { - auto timeElapsedMs = state.getElapsedTime(); - - auto pIfrit = pEncounter->getBNpc( NPC_IFRIT ); - - pIfrit->setRot( pIfrit->getRot() - .2f ); - - // todo: use gambits+timelines for this - if( timeElapsedMs > 5000 ) - { - state.setFinishFlag(); - } - } ); - - return ifritTwoState; - } void update( uint64_t deltaTime ) override { @@ -126,19 +69,6 @@ namespace Sapphire m_pInstance->getEncounterTimeline().update( getInstance(), deltaTime ); - //* - if( m_stateStack; !m_stateStack->empty() ) - { - if( m_stateStack->top()->shouldFinish() ) - { - m_stateStack->top()->finish(); - m_stateStack->pop(); - } - - if( !m_stateStack->empty() ) - m_stateStack->top()->update( deltaTime ); - } - //*/ } }; }// namespace Sapphire \ No newline at end of file diff --git a/src/world/Encounter/TimelineActor.cpp b/src/world/Encounter/TimelineActor.cpp index 37e48aab..83e8fffe 100644 --- a/src/world/Encounter/TimelineActor.cpp +++ b/src/world/Encounter/TimelineActor.cpp @@ -177,7 +177,7 @@ namespace Sapphire::Encounter auto pParent = pTeri->getActiveBNpcByLayoutId( m_layoutId ); Common::BNpcType type = pParent ? pParent->getBNpcType() : Common::BNpcType::Enemy; - pActor = pTeri->createBNpcFromLayoutId( m_layoutId, 1000, type ); + pActor = pTeri->createBNpcFromLayoutIdNoPush( m_layoutId, 1000, type ); m_subActors[ name ] = pActor; pActor->setInvincibilityType( Common::InvincibilityIgnoreDamage ); @@ -189,7 +189,7 @@ namespace Sapphire::Encounter auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref(); for( const auto& player : pTeri->getPlayers() ) { - pActor->spawn( player.second ); + // pActor->spawn( player.second ); playerMgr.sendDebug( *player.second, fmt::format( "Spawned subactor {}", name ) ); } } diff --git a/src/world/Encounter/Timepoint.cpp b/src/world/Encounter/Timepoint.cpp index cd238f47..7ae02fed 100644 --- a/src/world/Encounter/Timepoint.cpp +++ b/src/world/Encounter/Timepoint.cpp @@ -658,7 +658,7 @@ namespace Sapphire::Encounter // todo: probably have this info in the timepoint data if( !pBNpc ) - pBNpc = pTeri->createBNpcFromLayoutId( pSpawnData->m_layoutId, 100, Common::BNpcType::Enemy ); + pBNpc = pTeri->createBNpcFromLayoutIdNoPush( pSpawnData->m_layoutId, 100, Common::BNpcType::Enemy ); if( pBNpc ) { @@ -666,8 +666,7 @@ namespace Sapphire::Encounter pBNpc->setFlag( pSpawnData->m_flags ); pBNpc->init(); - for( const auto& player : pTeri->getPlayers() ) - pBNpc->spawn( player.second ); + pTeri->pushActor( pBNpc ); } } break; diff --git a/src/world/Territory/Territory.cpp b/src/world/Territory/Territory.cpp index c717a8ef..0d8b587d 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -259,9 +259,11 @@ void Territory::pushActor( const Entity::GameObjectPtr& pActor ) { auto pBNpc = pActor->getAsBNpc(); - if( m_pNaviProvider ) + if( m_pNaviProvider && pBNpc->pathingActive() ) + { agentId = m_pNaviProvider->addAgent( *pBNpc ); - pBNpc->setAgentId( agentId ); + pBNpc->setAgentId( agentId ); + } m_bNpcMap[ pBNpc->getId() ] = pBNpc; updateCellActivity( cx, cy, 1 ); @@ -854,6 +856,18 @@ Entity::BNpcPtr Territory::createBNpcFromLayoutId( uint32_t layoutId, uint32_t h return pBNpc; } +Entity::BNpcPtr Territory::createBNpcFromLayoutIdNoPush( uint32_t layoutId, uint32_t hp, Common::BNpcType bnpcType, uint32_t triggerOwnerId ) +{ + auto infoPtr = m_bNpcBaseMap.find( layoutId ); + if( infoPtr == m_bNpcBaseMap.end() ) + return nullptr; + + auto pBNpc = std::make_shared< Entity::BNpc >( getNextActorId(), infoPtr->second, *this, hp, bnpcType ); + pBNpc->init(); + pBNpc->setTriggerOwnerId( triggerOwnerId ); + return pBNpc; +} + Entity::BNpcPtr Territory::getActiveBNpcByEntityId( uint32_t entityId ) { auto it = m_bNpcMap.find( entityId ); diff --git a/src/world/Territory/Territory.h b/src/world/Territory/Territory.h index 8d645ee8..c1305903 100644 --- a/src/world/Territory/Territory.h +++ b/src/world/Territory/Territory.h @@ -180,6 +180,7 @@ namespace Sapphire void addEObj( Entity::EventObjectPtr object ); Entity::BNpcPtr createBNpcFromLayoutId( uint32_t levelId, uint32_t hp, Common::BNpcType bnpcType, uint32_t triggerOwnerId = 0 ); + Entity::BNpcPtr createBNpcFromLayoutIdNoPush( uint32_t levelId, uint32_t hp, Common::BNpcType bnpcType, uint32_t triggerOwnerId = 0 ); Entity::BNpcPtr getActiveBNpcByEntityId( uint32_t entityId );