mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-26 22:37:45 +00:00
Basic gambit work, still needs cleanup and improvements
This commit is contained in:
parent
5cc7b0c87b
commit
d6918a88e0
8 changed files with 218 additions and 18 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"7": {
|
||||
"name": "Attack",
|
||||
"potency": 0,
|
||||
"potency": 110,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"8": {
|
||||
"name": "Shot",
|
||||
"potency": 0,
|
||||
"potency": 100,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
|
|
52
src/world/AI/GambitRule.cpp
Normal file
52
src/world/AI/GambitRule.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include "GambitTargetCondition.h"
|
||||
#include "GambitRule.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World;
|
||||
|
||||
AI::GambitRule::GambitRule( const GambitTargetConditionPtr targetCondition, Action::ActionPtr action, uint32_t coolDown ) :
|
||||
m_targetCondition( targetCondition ),
|
||||
m_pAction( std::move( action ) ),
|
||||
m_lastExecutionMs( 0 ),
|
||||
m_coolDownMs( coolDown ),
|
||||
m_isEnabled( true )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AI::GambitRule::toggleEnabled()
|
||||
{
|
||||
m_isEnabled = !m_isEnabled;
|
||||
}
|
||||
|
||||
bool AI::GambitRule::isEnabled() const
|
||||
{
|
||||
return m_isEnabled;
|
||||
}
|
||||
|
||||
uint64_t AI::GambitRule::getLastExecutionMs() const
|
||||
{
|
||||
return m_lastExecutionMs;
|
||||
}
|
||||
|
||||
void AI::GambitRule::setLastExecutionMs( uint64_t lastExecution )
|
||||
{
|
||||
m_lastExecutionMs = lastExecution;
|
||||
}
|
||||
|
||||
uint32_t AI::GambitRule::getCoolDown() const
|
||||
{
|
||||
return m_coolDownMs;
|
||||
}
|
||||
|
||||
AI::GambitTargetConditionPtr AI::GambitRule::getGambitTargetCondition()
|
||||
{
|
||||
return m_targetCondition;
|
||||
}
|
||||
|
||||
Action::ActionPtr AI::GambitRule::getActionPtr()
|
||||
{
|
||||
return m_pAction;
|
||||
}
|
33
src/world/AI/GambitRule.h
Normal file
33
src/world/AI/GambitRule.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include "GambitTargetCondition.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI
|
||||
{
|
||||
class GambitRule
|
||||
{
|
||||
public:
|
||||
GambitRule( GambitTargetConditionPtr targetCondition, Action::ActionPtr action, uint32_t coolDown );
|
||||
~GambitRule() = default;
|
||||
|
||||
bool isEnabled() const;
|
||||
void toggleEnabled();
|
||||
|
||||
uint64_t getLastExecutionMs() const;
|
||||
void setLastExecutionMs( uint64_t lastExecution );
|
||||
|
||||
uint32_t getCoolDown() const;
|
||||
|
||||
GambitTargetConditionPtr getGambitTargetCondition();
|
||||
|
||||
Action::ActionPtr getActionPtr();
|
||||
private:
|
||||
GambitTargetConditionPtr m_targetCondition;
|
||||
Action::ActionPtr m_pAction;
|
||||
uint32_t m_coolDownMs;
|
||||
uint64_t m_lastExecutionMs;
|
||||
bool m_isEnabled;
|
||||
};
|
||||
}
|
66
src/world/AI/GambitTargetCondition.h
Normal file
66
src/world/AI/GambitTargetCondition.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include <Actor/BNpc.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI
|
||||
{
|
||||
enum GambitTargetType : uint8_t
|
||||
{
|
||||
Self,
|
||||
Player,
|
||||
PlayerAndAlly,
|
||||
Ally,
|
||||
BNpc
|
||||
};
|
||||
|
||||
class GambitTargetCondition
|
||||
{
|
||||
public:
|
||||
GambitTargetCondition( GambitTargetType targetType ) : m_targetType( targetType ) {};
|
||||
virtual ~GambitTargetCondition() = default;
|
||||
|
||||
virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) { return false; };
|
||||
Sapphire::Entity::CharaPtr getTarget() const { return m_pTarget; };
|
||||
protected:
|
||||
GambitTargetType m_targetType;
|
||||
Sapphire::Entity::CharaPtr m_pTarget;
|
||||
};
|
||||
|
||||
class TopHateTargetCondition : public GambitTargetCondition
|
||||
{
|
||||
public:
|
||||
TopHateTargetCondition() : GambitTargetCondition( PlayerAndAlly ) {};
|
||||
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) override
|
||||
{
|
||||
auto foundChara = src.hateListGetHighest();
|
||||
if( foundChara )
|
||||
{
|
||||
m_pTarget = foundChara;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
class HPSelfPctLessThan : public GambitTargetCondition
|
||||
{
|
||||
public:
|
||||
HPSelfPctLessThan( uint8_t pct ) : GambitTargetCondition( Self ), m_HpPct( pct ) {};
|
||||
|
||||
virtual bool isConditionMet( Sapphire::Entity::BNpc& src )
|
||||
{
|
||||
if( src.getHpPercent() < m_HpPct )
|
||||
{
|
||||
m_pTarget = src.getAsBNpc();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
private:
|
||||
uint8_t m_HpPct;
|
||||
};
|
||||
|
||||
}
|
|
@ -44,7 +44,12 @@
|
|||
#include <Task/ActionIntegrityTask.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include <Action/Action.h>
|
||||
#include <AI/GambitRule.h>
|
||||
#include <AI/GambitTargetCondition.h>
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World;
|
||||
using namespace Sapphire::Common;
|
||||
using namespace Sapphire::Entity;
|
||||
using namespace Sapphire::Network::Packets;
|
||||
|
@ -319,7 +324,7 @@ uint32_t BNpc::getBNpcNameId() const
|
|||
|
||||
void BNpc::spawn( PlayerPtr pTarget )
|
||||
{
|
||||
m_lastRoamTargetReached = Util::getTimeSeconds();
|
||||
m_lastRoamTargetReached = Common::Util::getTimeSeconds();
|
||||
|
||||
auto& server = Common::Service< World::WorldServer >::ref();
|
||||
server.queueForPlayer( pTarget->getCharacterId(), std::make_shared< NpcSpawnPacket >( *this, *pTarget ) );
|
||||
|
@ -355,7 +360,7 @@ bool BNpc::moveTo( const FFXIVARR_POSITION3& pos )
|
|||
}
|
||||
|
||||
auto pos1 = pNaviProvider->getMovePos( *this );
|
||||
auto distance = Util::distance( pos1, pos );
|
||||
auto distance = Common::Util::distance( pos1, pos );
|
||||
|
||||
if( distance < getNaviTargetReachedDistance() )
|
||||
{
|
||||
|
@ -393,7 +398,7 @@ bool BNpc::moveTo( const Chara& targetChara )
|
|||
}
|
||||
|
||||
auto pos1 = pNaviProvider->getMovePos( *this );
|
||||
auto distance = Util::distance( pos1, targetChara.getPos() );
|
||||
auto distance = Common::Util::distance( pos1, targetChara.getPos() );
|
||||
|
||||
if( distance <= ( getNaviTargetReachedDistance() + targetChara.getRadius() ) )
|
||||
{
|
||||
|
@ -584,7 +589,7 @@ 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() );
|
||||
|
||||
m_lastAttack = Util::getTimeMs() + variation;
|
||||
m_lastAttack = Common::Util::getTimeMs() + variation;
|
||||
|
||||
setStance( Stance::Active );
|
||||
m_state = BNpcState::Combat;
|
||||
|
@ -644,7 +649,8 @@ void BNpc::update( uint64_t tickCount )
|
|||
if( !pNaviProvider )
|
||||
return;
|
||||
|
||||
checkAction();
|
||||
if( !checkAction() )
|
||||
processGambits( tickCount );
|
||||
|
||||
switch( m_state )
|
||||
{
|
||||
|
@ -665,7 +671,7 @@ void BNpc::update( uint64_t tickCount )
|
|||
|
||||
// retail doesn't seem to roam straight after retreating
|
||||
// todo: perhaps requires more investigation?
|
||||
m_lastRoamTargetReached = Util::getTimeSeconds();
|
||||
m_lastRoamTargetReached = Common::Util::getTimeSeconds();
|
||||
|
||||
// resetHp
|
||||
setHp( getMaxHp() );
|
||||
|
@ -684,7 +690,7 @@ void BNpc::update( uint64_t tickCount )
|
|||
|
||||
if( moveTo( m_roamPos ) )
|
||||
{
|
||||
m_lastRoamTargetReached = Util::getTimeSeconds();
|
||||
m_lastRoamTargetReached = Common::Util::getTimeSeconds();
|
||||
m_state = BNpcState::Idle;
|
||||
}
|
||||
|
||||
|
@ -701,12 +707,12 @@ void BNpc::update( uint64_t tickCount )
|
|||
if( pNaviProvider->syncPosToChara( *this ) )
|
||||
sendPositionUpdate();
|
||||
|
||||
if( !hasFlag( Immobile ) && ( Util::getTimeSeconds() - m_lastRoamTargetReached > roamTick ) )
|
||||
if( !hasFlag( Immobile ) && ( Common::Util::getTimeSeconds() - m_lastRoamTargetReached > roamTick ) )
|
||||
{
|
||||
|
||||
if( !pNaviProvider )
|
||||
{
|
||||
m_lastRoamTargetReached = Util::getTimeSeconds();
|
||||
m_lastRoamTargetReached = Common::Util::getTimeSeconds();
|
||||
break;
|
||||
}
|
||||
if( m_pInfo->WanderingRange != 0 && getEnemyType() != 0 )
|
||||
|
@ -732,7 +738,7 @@ void BNpc::update( uint64_t tickCount )
|
|||
|
||||
pNaviProvider->updateAgentParameters( *this );
|
||||
|
||||
auto distanceOrig = Util::distance( getPos().x, getPos().y, getPos().z, m_spawnPos.x, m_spawnPos.y, m_spawnPos.z );
|
||||
auto distanceOrig = Common::Util::distance( getPos(), m_spawnPos );
|
||||
|
||||
if( pHatedActor && !pHatedActor->isAlive() )
|
||||
{
|
||||
|
@ -742,8 +748,7 @@ void BNpc::update( uint64_t tickCount )
|
|||
|
||||
if( pHatedActor )
|
||||
{
|
||||
auto distance = Util::distance( getPos().x, getPos().y, getPos().z,
|
||||
pHatedActor->getPos().x, pHatedActor->getPos().y, pHatedActor->getPos().z );
|
||||
auto distance = Common::Util::distance( getPos(), pHatedActor->getPos() );
|
||||
|
||||
if( !hasFlag( NoDeaggro ) && ( ( distanceOrig > maxDistanceToOrigin ) || distance > 30.0f ) )
|
||||
{
|
||||
|
@ -828,7 +833,7 @@ void BNpc::onDeath()
|
|||
setTargetId( INVALID_GAME_OBJECT_ID64 );
|
||||
m_currentStance = Stance::Passive;
|
||||
m_state = BNpcState::Dead;
|
||||
m_timeOfDeath = Util::getTimeSeconds();
|
||||
m_timeOfDeath = Common::Util::getTimeSeconds();
|
||||
setOwner( nullptr );
|
||||
|
||||
taskMgr.queueTask( World::makeFadeBNpcTask( 10000, getAsBNpc() ) );
|
||||
|
@ -885,7 +890,7 @@ void BNpc::checkAggro()
|
|||
range = std::max< float >( 0.f, range - std::pow( 1.53f, static_cast< float >( levelDiff ) * 0.6f ) );
|
||||
}
|
||||
|
||||
auto distance = Util::distance( getPos(), pClosestChara->getPos() );
|
||||
auto distance = Common::Util::distance( getPos(), pClosestChara->getPos() );
|
||||
|
||||
if( distance < range )
|
||||
{
|
||||
|
@ -916,7 +921,7 @@ void BNpc::checkAggro()
|
|||
range = std::max< float >( 0.f, range - std::pow( 1.53f, static_cast< float >( levelDiff ) * 0.6f ) );
|
||||
}
|
||||
|
||||
auto distance = Util::distance( getPos(), pClosestChara->getPos() );
|
||||
auto distance = Common::Util::distance( getPos(), pClosestChara->getPos() );
|
||||
|
||||
if( distance < range )
|
||||
{
|
||||
|
@ -969,7 +974,7 @@ void BNpc::autoAttack( CharaPtr pTarget )
|
|||
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
|
||||
uint64_t tick = Util::getTimeMs();
|
||||
uint64_t tick = Common::Util::getTimeMs();
|
||||
|
||||
// todo: this needs to use the auto attack delay for the equipped weapon
|
||||
if( ( tick - m_lastAttack ) > 2500 )
|
||||
|
@ -1046,6 +1051,39 @@ uint32_t BNpc::getLayoutId() const
|
|||
|
||||
void BNpc::init()
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
m_maxHp = Math::CalcStats::calculateMaxHp( *getAsChara() );
|
||||
m_hp = m_maxHp;
|
||||
|
||||
//setup a test gambit
|
||||
auto testGambitRule = std::make_shared< AI::GambitRule >( std::make_shared< AI::TopHateTargetCondition >(),
|
||||
Action::make_Action( getAsChara(), 88, 0, exdData.getRow< Excel::Action >( 88 ) ), 5000 );
|
||||
|
||||
auto testGambitRule1 = std::make_shared< AI::GambitRule >( std::make_shared< AI::HPSelfPctLessThan >( 50 ),
|
||||
Action::make_Action( getAsChara(), 120, 0, exdData.getRow< Excel::Action >( 120 ) ), 5000 );
|
||||
|
||||
m_gambits.push_back( testGambitRule );
|
||||
m_gambits.push_back( testGambitRule1 );
|
||||
}
|
||||
|
||||
void BNpc::processGambits( uint64_t tickCount )
|
||||
{
|
||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||
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(), exdData.getRow< Excel::Action >( gambitRule->getActionPtr()->getId() ),
|
||||
gambitRule->getGambitTargetCondition()->getTarget()->getId(), 0 );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <Common.h>
|
||||
|
||||
#include "Forwards.h"
|
||||
#include "ForwardsZone.h"
|
||||
#include "Chara.h"
|
||||
#include "Npc.h"
|
||||
#include <set>
|
||||
|
@ -148,6 +149,8 @@ namespace Sapphire::Entity
|
|||
|
||||
uint32_t getLayoutId() const;
|
||||
|
||||
void processGambits( uint64_t tickCount );
|
||||
|
||||
private:
|
||||
uint32_t m_bNpcBaseId;
|
||||
uint32_t m_bNpcNameId;
|
||||
|
@ -189,6 +192,7 @@ namespace Sapphire::Entity
|
|||
Common::FFXIVARR_POSITION3 m_naviTarget;
|
||||
|
||||
CharaPtr m_pOwner;
|
||||
std::vector< World::AI::GambitRulePtr > m_gambits;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ file( GLOB SERVER_SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
|||
*.cpp
|
||||
Actor/*.cpp
|
||||
Action/*.cpp
|
||||
AI/*.cpp
|
||||
ContentFinder/*.cpp
|
||||
DebugCommand/*.cpp
|
||||
Event/*.cpp
|
||||
|
|
|
@ -47,6 +47,12 @@ namespace World::Territory::Housing
|
|||
TYPE_FORWARD( HousingInteriorTerritory );
|
||||
}
|
||||
|
||||
namespace World::AI
|
||||
{
|
||||
TYPE_FORWARD( GambitTargetCondition );
|
||||
TYPE_FORWARD( GambitRule );
|
||||
}
|
||||
|
||||
namespace Inventory
|
||||
{
|
||||
using InventoryContainerPair = std::pair< Common::InventoryType, uint8_t >;
|
||||
|
|
Loading…
Add table
Reference in a new issue