1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-01 08:27:46 +00:00

Gambit packs added. Basic timelines for bnpc actions can be defined.

This commit is contained in:
Mordred 2023-03-24 22:52:38 +01:00
parent 4f3f866531
commit 928729326c
6 changed files with 223 additions and 21 deletions

135
src/world/AI/GambitPack.cpp Normal file
View file

@ -0,0 +1,135 @@
#include <cstdint>
#include <ForwardsZone.h>
#include <Service.h>
#include <Manager/ActionMgr.h>
#include <Action/Action.h>
#include "GambitTargetCondition.h"
#include "GambitRule.h"
#include "GambitPack.h"
using namespace Sapphire;
using namespace Sapphire::World;
AI::GambitTimeLinePack::GambitTimeLinePack( int8_t loopCount ) :
GambitPack( GambitPackType::TimeLine ),
m_loopCount( loopCount ),
m_currentIndex( 0 ),
m_currentLoop( 0 ),
m_startTimeMs( 0 )
{
}
void AI::GambitTimeLinePack::start()
{
m_startTimeMs = Common::Util::getTimeMs();
}
void AI::GambitTimeLinePack::addTimeLine( const GambitRulePtr& pRule, uint32_t offsetInSeconds )
{
auto timeLine = std::make_pair( pRule, offsetInSeconds );
m_gambits.push_back( timeLine );
}
void AI::GambitTimeLinePack::addTimeLine( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t offsetInSeconds )
{
auto pRule = make_GambitRule( targetCondition, action, 0 );
auto timeLine = std::make_pair( pRule, offsetInSeconds );
m_gambits.push_back( timeLine );
}
uint8_t AI::GambitTimeLinePack::getLoopCount() const
{
return m_loopCount;
}
uint8_t AI::GambitTimeLinePack::getCurrentIndex() const
{
return m_currentIndex;
}
void AI::GambitTimeLinePack::update( Entity::BNpc& bnpc, uint64_t tickCount )
{
if( m_startTimeMs == 0 || m_gambits.empty() )
return;
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
if( m_gambits.size() <= m_currentIndex )
{
if( m_currentLoop < m_loopCount || m_loopCount == -1 )
{
m_currentIndex = 0;
m_currentLoop++;
m_startTimeMs = Common::Util::getTimeMs();
}
else
{
m_startTimeMs = 0;
m_currentLoop = 0;
return;
}
}
auto currentTimeLine = m_gambits.at( m_currentIndex );
auto& pRule = currentTimeLine.first;
auto offset = currentTimeLine.second * 1000;
if( tickCount - m_startTimeMs >= offset )
{
if( pRule->getGambitTargetCondition()->isConditionMet( bnpc ) )
{
pRule->setLastExecutionMs( tickCount );
actionMgr.handleTargetedAction( bnpc, pRule->getActionPtr()->getId(), pRule->getGambitTargetCondition()->getTarget()->getId(), 0 );
}
m_currentIndex++;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AI::GambitRuleSetPack::GambitRuleSetPack() : GambitPack( GambitPackType::RuleSetList )
{
}
void AI::GambitRuleSetPack::addRule( const GambitRulePtr& pRule )
{
m_gambits.push_back( pRule );
}
void AI::GambitRuleSetPack::addRule( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t coolDown )
{
auto pRule = make_GambitRule( targetCondition, action, coolDown );
m_gambits.push_back( pRule );
}
void AI::GambitRuleSetPack::update( Entity::BNpc& bnpc, uint64_t tickCount )
{
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
for( auto& gambitRule : m_gambits )
{
if( !gambitRule->isEnabled() )
continue;
if( ( tickCount - gambitRule->getLastExecutionMs() ) > gambitRule->getCoolDown() )
{
if( !gambitRule->getGambitTargetCondition()->isConditionMet( bnpc ) )
continue;
gambitRule->setLastExecutionMs( tickCount );
actionMgr.handleTargetedAction( bnpc, gambitRule->getActionPtr()->getId(), gambitRule->getGambitTargetCondition()->getTarget()->getId(), 0 );
break;
}
}
}
AI::GambitTimeLinePackPtr AI::GambitPack::getAsTimeLine()
{
return std::dynamic_pointer_cast< GambitTimeLinePack, GambitPack >( shared_from_this() );
}
AI::GambitRuleSetPackPtr AI::GambitPack::getAsRuleSet()
{
return std::dynamic_pointer_cast< GambitRuleSetPack, GambitPack >( shared_from_this() );
}

60
src/world/AI/GambitPack.h Normal file
View file

@ -0,0 +1,60 @@
#include <cstdint>
#include <ForwardsZone.h>
#include "GambitTargetCondition.h"
#include "GambitRule.h"
#pragma once
namespace Sapphire::World::AI
{
enum class GambitPackType : uint8_t
{
None,
RuleSetList,
TimeLine
};
class GambitPack : public std::enable_shared_from_this< GambitPack >
{
public:
GambitPack( GambitPackType type ) : m_type( type ) { };
virtual ~GambitPack() = default;
GambitPackType getType() const { return m_type; }
virtual void update( Entity::BNpc& bnpc, uint64_t tickCount ) = 0;
GambitTimeLinePackPtr getAsTimeLine();
GambitRuleSetPackPtr getAsRuleSet();
private:
GambitPackType m_type;
};
class GambitTimeLinePack : public GambitPack
{
public:
GambitTimeLinePack( int8_t loopCount );
void update( Entity::BNpc& bnpc, uint64_t tickCount );
void addTimeLine( const GambitRulePtr& pRule, uint32_t offsetInSeconds );
void addTimeLine( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t offsetInSeconds );
uint8_t getLoopCount() const;
uint8_t getCurrentIndex() const;
void start();
private:
std::vector< std::pair< GambitRulePtr, uint32_t > > m_gambits;
uint64_t m_startTimeMs;
uint8_t m_currentIndex;
int8_t m_loopCount;
uint8_t m_currentLoop;
};
class GambitRuleSetPack : public GambitPack
{
public:
GambitRuleSetPack();
void addRule( const GambitRulePtr& pRule );
void addRule( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t coolDown );
void update( Entity::BNpc& bnpc, uint64_t tickCount );
private:
std::vector< GambitRulePtr > m_gambits;
};
}

View file

@ -46,6 +46,7 @@
#include <Action/Action.h>
#include <AI/GambitRule.h>
#include <AI/GambitPack.h>
#include <AI/GambitTargetCondition.h>
#include <AI/Fsm/StateMachine.h>
#include <AI/Fsm/Condition.h>
@ -598,6 +599,11 @@ void BNpc::aggro( const Sapphire::Entity::CharaPtr& pChara )
auto& pRNGMgr = Common::Service< World::Manager::RNGMgr >::ref();
auto variation = static_cast< uint32_t >( pRNGMgr.getRandGenerator< float >( 500, 1000 ).next() );
if( m_pGambitPack && m_pGambitPack->getAsTimeLine() )
{
m_pGambitPack->getAsTimeLine()->start();
}
m_lastAttack = Common::Util::getTimeMs() + variation;
setStance( Stance::Active );
@ -911,9 +917,22 @@ void BNpc::init()
//setup a test gambit
auto testGambitRule = AI::make_GambitRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 );
auto testGambitRule1 = AI::make_GambitRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 5000 );
/*
auto gambitPack = AI::make_GambitRuleSetPack();
gambitPack->addRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 );
gambitPack->addRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 10000 );
m_pGambitPack = gambitPack;
*/
m_gambits.push_back( testGambitRule );
m_gambits.push_back( testGambitRule1 );
auto gambitPack = AI::make_GambitTimeLinePack( -1 );
gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 2 );
gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 89, 0 ), 4 );
gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 90, 0 ), 6 );
gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 91, 0 ), 8 );
gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 92, 0 ), 10 );
gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 81, 0 ), 12 );
gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 82, 0 ), 14 );
m_pGambitPack = gambitPack;
using namespace AI::Fsm;
m_fsm = make_StateMachine();
@ -945,23 +964,8 @@ void BNpc::init()
void BNpc::processGambits( uint64_t tickCount )
{
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
for( auto& gambitRule : m_gambits )
{
if( !gambitRule->isEnabled() )
continue;
if( ( tickCount - gambitRule->getLastExecutionMs() ) > gambitRule->getCoolDown() )
{
if( !gambitRule->getGambitTargetCondition()->isConditionMet( *this ) )
continue;
gambitRule->setLastExecutionMs( tickCount );
actionMgr.handleTargetedAction( *this, gambitRule->getActionPtr()->getId(), gambitRule->getGambitTargetCondition()->getTarget()->getId(), 0 );
break;
}
}
m_tp = 1000;
m_pGambitPack->update( *this, tickCount );
}
uint32_t BNpc::getLastRoamTargetReachedTime() const

View file

@ -206,7 +206,7 @@ namespace Sapphire::Entity
Common::FFXIVARR_POSITION3 m_naviTarget;
CharaPtr m_pOwner;
std::vector< World::AI::GambitRulePtr > m_gambits;
World::AI::GambitPackPtr m_pGambitPack;
std::shared_ptr< World::AI::Fsm::StateMachine > m_fsm;

View file

@ -54,6 +54,9 @@ namespace World::AI
TYPE_FORWARD( HPSelfPctLessThanTargetCondition );
TYPE_FORWARD( GambitRule );
TYPE_FORWARD( GambitPack );
TYPE_FORWARD( GambitTimeLinePack );
TYPE_FORWARD( GambitRuleSetPack );
}
namespace World::AI::Fsm

View file

@ -313,7 +313,7 @@ void PlayerMgr::onUpdate( Entity::Player& player, uint64_t tickCount )
void PlayerMgr::checkAutoAttack( Entity::Player& player, uint64_t tickCount ) const
{
auto mainWeap = player.getItemAt( Common::GearSet0, Common::MainHand );
if( !mainWeap || !player.isAutoattackOn() || player.checkAction() || !player.getTargetId() || player.getStance() != Common::Active )
if( !mainWeap || player.checkAction() || !player.isAutoattackOn() || !player.getTargetId() || player.getStance() != Common::Active )
return;
for( const auto& actor : player.getInRangeActors() )