diff --git a/src/world/AI/Fsm/StateCombat.cpp b/src/world/AI/Fsm/StateCombat.cpp index 85bb4ca58..b67f48b31 100644 --- a/src/world/AI/Fsm/StateCombat.cpp +++ b/src/world/AI/Fsm/StateCombat.cpp @@ -16,6 +16,8 @@ void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() ); auto pNaviProvider = pZone->getNaviProvider(); + bool hasQueuedAction = bnpc.checkAction(); + auto pHatedActor = bnpc.hateListGetHighest(); if( !pHatedActor ) return; @@ -56,7 +58,7 @@ void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) if( !bnpc.hasFlag( Entity::TurningDisabled ) ) bnpc.face( pHatedActor->getPos() ); - if( !bnpc.checkAction() ) + if( !hasQueuedAction ) bnpc.processGambits( tickCount ); // in combat range. ATTACK! diff --git a/src/world/AI/Fsm/StateIdle.cpp b/src/world/AI/Fsm/StateIdle.cpp index 957e4c885..0536cd299 100644 --- a/src/world/AI/Fsm/StateIdle.cpp +++ b/src/world/AI/Fsm/StateIdle.cpp @@ -6,7 +6,7 @@ using namespace Sapphire::World; void AI::Fsm::StateIdle::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) { - + bool hasQueuedAction = bnpc.checkAction(); } void AI::Fsm::StateIdle::onEnter( Entity::BNpc& bnpc ) diff --git a/src/world/AI/Fsm/StateRoam.cpp b/src/world/AI/Fsm/StateRoam.cpp index 1b6848179..d64fbee4b 100644 --- a/src/world/AI/Fsm/StateRoam.cpp +++ b/src/world/AI/Fsm/StateRoam.cpp @@ -15,6 +15,12 @@ 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 ) ) + { + bnpc.setRoamTargetReached( true ); + return; + } + if( pNaviProvider ) pNaviProvider->setMoveTarget( bnpc, bnpc.getRoamTargetPos() ); diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index bd84aa5c4..82450f0a3 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -115,7 +115,7 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_enemyType = bNpcBaseData->data().Battalion; if( pInfo->WanderingRange == 0 || pInfo->BoundInstanceID != 0 || m_enemyType == 0 ) - setFlag( Immobile ); + setFlag( NoRoam | Immobile ); m_class = ClassJob::Gladiator; @@ -215,7 +215,7 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_territoryId = zone.getGuId(); if( pInfo->WanderingRange == 0 || pInfo->BoundInstanceID != 0 ) - setFlag( Immobile ); + setFlag( Immobile | NoRoam ); auto& exdData = Common::Service< Data::ExdData >::ref(); @@ -434,8 +434,12 @@ void BNpc::sendPositionUpdate() if( m_state == BNpcState::Combat || m_state == BNpcState::Retreat ) animationType = 0; - auto movePacket = std::make_shared< MoveActorPacket >( *getAsChara(), 0x3A, animationType, 0, 0x5A / 4 ); - server().queueForPlayers( getInRangePlayerIds(), movePacket ); + if( m_lastPos.x != m_pos.x || m_lastPos.y != m_pos.y || m_lastPos.z != m_lastPos.z ) + { + auto movePacket = std::make_shared< MoveActorPacket >( *getAsChara(), 0x3A, animationType, 0, 0x5A / 4 ); + server().queueForPlayers( getInRangePlayerIds(), movePacket ); + } + m_lastPos = m_pos; } const std::set< std::shared_ptr< HateListEntry > >& BNpc::getHateList() const @@ -656,8 +660,9 @@ void BNpc::update( uint64_t tickCount ) { Chara::update( tickCount ); - if( m_dirtyFlag & DirtyFlag::Position ) - sendPositionUpdate(); + // removed check for now, replaced by position check to last position + //if( m_dirtyFlag & DirtyFlag::Position ) + sendPositionUpdate(); m_fsm->update( *this, tickCount ); } @@ -950,12 +955,17 @@ void BNpc::init() gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 82, 0 ), 14 ); m_pGambitPack = gambitPack; */ + initFsm(); +} + +void BNpc::initFsm() +{ using namespace AI::Fsm; m_fsm = make_StateMachine(); auto stateIdle = make_StateIdle(); auto stateCombat = make_StateCombat(); auto stateDead = make_StateDead(); - if( !hasFlag( Immobile ) ) + if( !hasFlag( Immobile ) && !hasFlag( NoRoam ) ) { auto stateRoam = make_StateRoam(); stateIdle->addTransition( stateRoam, make_RoamNextTimeReachedCondition() ); diff --git a/src/world/Actor/BNpc.h b/src/world/Actor/BNpc.h index 540a624fb..0460231eb 100644 --- a/src/world/Actor/BNpc.h +++ b/src/world/Actor/BNpc.h @@ -32,14 +32,15 @@ namespace Sapphire::Entity enum BNpcFlag { - Immobile = 0x01, - TurningDisabled = 0x02, - Invincible = 0x04, - StayAlive = 0x08, - NoDeaggro = 0x10, - Untargetable = 0x20, - AutoAttackDisabled = 0x40, - Invisible = 0x80, + Immobile = 0x001, + TurningDisabled = 0x002, + Invincible = 0x004, + StayAlive = 0x008, + NoDeaggro = 0x010, + Untargetable = 0x020, + AutoAttackDisabled = 0x040, + Invisible = 0x080, + NoRoam = 0x100, Intermission = 0x77 // for transition phases to ensure boss only moves/acts when scripted }; @@ -170,6 +171,7 @@ namespace Sapphire::Entity const Common::FFXIVARR_POSITION3& getRoamTargetPos() const; const Common::FFXIVARR_POSITION3& getSpawnPos() const; + void initFsm(); private: uint32_t m_bNpcBaseId; @@ -203,6 +205,7 @@ namespace Sapphire::Entity Common::FFXIVARR_POSITION3 m_spawnPos; Common::FFXIVARR_POSITION3 m_roamPos; + Common::FFXIVARR_POSITION3 m_lastPos; BNpcState m_state; std::set< std::shared_ptr< HateListEntry > > m_hateList; @@ -217,6 +220,7 @@ namespace Sapphire::Entity std::shared_ptr< World::AI::Fsm::StateMachine > m_fsm; + }; } \ No newline at end of file diff --git a/src/world/Encounter/Timepoint.cpp b/src/world/Encounter/Timepoint.cpp index 3cacd7741..b9e1a47e4 100644 --- a/src/world/Encounter/Timepoint.cpp +++ b/src/world/Encounter/Timepoint.cpp @@ -421,10 +421,10 @@ namespace Sapphire::Encounter // todo: this really shouldnt exist, but need to figure out why actions interrupt else if( pAction->getId() == pActionData->m_actionId ) { - pAction->setInterrupted( Common::ActionInterruptType::RegularInterrupt ); - pAction->interrupt(); - pBNpc->setCurrentAction( nullptr ); - return false; + // pAction->setInterrupted( Common::ActionInterruptType::RegularInterrupt ); + // pAction->interrupt(); + // pBNpc->setCurrentAction( nullptr ); + // return false; } else {