mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-09 12:17:45 +00:00
allow bnpc to perform actions
This commit is contained in:
parent
8e77266b30
commit
542f37fb3d
6 changed files with 97 additions and 81 deletions
|
@ -401,7 +401,7 @@ void Action::Action::execute()
|
|||
assert( m_pSource );
|
||||
|
||||
// subtract costs first, if somehow the caster stops meeting those requirements cancel the cast
|
||||
if( !consumeResources() )
|
||||
if( m_pSource->getAsPlayer() && !consumeResources() )
|
||||
{
|
||||
interrupt();
|
||||
return;
|
||||
|
@ -422,13 +422,6 @@ void Action::Action::execute()
|
|||
}
|
||||
}
|
||||
|
||||
if( isCorrectCombo() )
|
||||
{
|
||||
auto player = m_pSource->getAsPlayer();
|
||||
|
||||
player->sendDebug( "action combo success from action#{0}", player->getLastComboActionId() );
|
||||
}
|
||||
|
||||
if( !hasClientsideTarget() )
|
||||
{
|
||||
buildEffects();
|
||||
|
@ -638,14 +631,11 @@ void Action::Action::buildEffects()
|
|||
if( isCorrectCombo() )
|
||||
m_effectBuilder->comboSucceed( actor );
|
||||
|
||||
if( m_isAutoAttack && m_pSource->isPlayer() )
|
||||
if( m_isAutoAttack && player )
|
||||
{
|
||||
if( auto player = m_pSource->getAsPlayer() )
|
||||
if( player->getClass() == Common::ClassJob::Paladin )
|
||||
{
|
||||
if( player->getClass() == Common::ClassJob::Paladin )
|
||||
{
|
||||
player->gaugePldSetOath( std::min( 100, player->gaugePldGetOath() + 5 ) );
|
||||
}
|
||||
player->gaugePldSetOath( std::min( 100, player->gaugePldGetOath() + 5 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -655,7 +645,7 @@ void Action::Action::buildEffects()
|
|||
m_effectBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.getMPGainPercentage() / 100, Common::ActionEffectResultFlag::EffectOnSource );
|
||||
}
|
||||
|
||||
if( m_lutEntry.bonusEffect & Common::ActionBonusEffect::GainJobResource )
|
||||
if( ( m_lutEntry.bonusEffect & Common::ActionBonusEffect::GainJobResource ) && player )
|
||||
{
|
||||
if( checkActionBonusRequirement() )
|
||||
{
|
||||
|
@ -686,7 +676,7 @@ void Action::Action::buildEffects()
|
|||
}
|
||||
}
|
||||
|
||||
if( m_lutEntry.bonusEffect & Common::ActionBonusEffect::GainJobTimer )
|
||||
if( ( m_lutEntry.bonusEffect & Common::ActionBonusEffect::GainJobTimer ) && player )
|
||||
{
|
||||
if( checkActionBonusRequirement() )
|
||||
{
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <Manager/NaviMgr.h>
|
||||
#include <Manager/TerritoryMgr.h>
|
||||
#include <Manager/RNGMgr.h>
|
||||
#include <Manager/ActionMgr.h>
|
||||
#include <Service.h>
|
||||
|
||||
using namespace Sapphire::Common;
|
||||
|
@ -407,6 +408,13 @@ void Sapphire::Entity::BNpc::update( uint64_t tickCount )
|
|||
const uint8_t maxDistanceToOrigin = 40;
|
||||
const uint32_t roamTick = 20;
|
||||
|
||||
if( getCurrentAction() && getCurrentAction()->hasCastTime() )
|
||||
{
|
||||
if( m_pCurrentAction->update() )
|
||||
m_pCurrentAction = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto pNaviProvider = m_pCurrentTerritory->getNaviProvider();
|
||||
|
||||
if( !pNaviProvider )
|
||||
|
@ -485,66 +493,63 @@ void Sapphire::Entity::BNpc::update( uint64_t tickCount )
|
|||
|
||||
case BNpcState::Combat:
|
||||
{
|
||||
auto pHatedActor = hateListGetHighest();
|
||||
if( !pHatedActor )
|
||||
return;
|
||||
|
||||
pNaviProvider->updateAgentParameters( *this );
|
||||
|
||||
auto distanceOrig = Util::distance( getPos().x, getPos().y, getPos().z,
|
||||
m_spawnPos.x, m_spawnPos.y, m_spawnPos.z );
|
||||
|
||||
if( pHatedActor && !pHatedActor->isAlive() )
|
||||
auto pHatedActor = hateListGetHighest();
|
||||
|
||||
while( pHatedActor && !pHatedActor->isAlive() )
|
||||
{
|
||||
hateListRemove( pHatedActor );
|
||||
pHatedActor = hateListGetHighest();
|
||||
}
|
||||
|
||||
if( !pHatedActor )
|
||||
{
|
||||
hateListClear();
|
||||
changeTarget( INVALID_GAME_OBJECT_ID64 );
|
||||
setStance( Stance::Passive );
|
||||
setOwner( nullptr );
|
||||
m_state = BNpcState::Retreat;
|
||||
return;
|
||||
}
|
||||
|
||||
if( pNaviProvider->syncPosToChara( *this ) )
|
||||
sendPositionUpdate();
|
||||
|
||||
if( pHatedActor )
|
||||
{
|
||||
auto distance = Util::distance( getPos().x, getPos().y, getPos().z,
|
||||
pHatedActor->getPos().x, pHatedActor->getPos().y, pHatedActor->getPos().z );
|
||||
|
||||
if( !hasFlag( NoDeaggro ) && ( distanceOrig > maxDistanceToOrigin ) )
|
||||
{
|
||||
hateListClear();
|
||||
changeTarget( INVALID_GAME_OBJECT_ID64 );
|
||||
setStance( Stance::Passive );
|
||||
setOwner( nullptr );
|
||||
m_state = BNpcState::Retreat;
|
||||
break;
|
||||
}
|
||||
|
||||
if( distance > ( getRadius() + pHatedActor->getRadius() ) )
|
||||
{
|
||||
if( hasFlag( Immobile ) )
|
||||
break;
|
||||
|
||||
if( pNaviProvider )
|
||||
pNaviProvider->setMoveTarget( *this, pHatedActor->getPos() );
|
||||
|
||||
moveTo( *pHatedActor );
|
||||
}
|
||||
|
||||
if( distance < ( getRadius() + pHatedActor->getRadius() + 3.f ) )
|
||||
{
|
||||
if( !hasFlag( TurningDisabled ) && face( pHatedActor->getPos() ) )
|
||||
sendPositionUpdate();
|
||||
|
||||
// in combat range. ATTACK!
|
||||
autoAttack( pHatedActor );
|
||||
}
|
||||
}
|
||||
else
|
||||
auto distance = Util::distance( getPos().x, getPos().y, getPos().z,
|
||||
pHatedActor->getPos().x, pHatedActor->getPos().y, pHatedActor->getPos().z );
|
||||
|
||||
if( !hasFlag( NoDeaggro ) && ( distanceOrig > maxDistanceToOrigin ) )
|
||||
{
|
||||
hateListClear();
|
||||
changeTarget( INVALID_GAME_OBJECT_ID64 );
|
||||
setStance( Stance::Passive );
|
||||
//setOwner( nullptr );
|
||||
setOwner( nullptr );
|
||||
m_state = BNpcState::Retreat;
|
||||
pNaviProvider->updateAgentParameters( *this );
|
||||
break;
|
||||
}
|
||||
|
||||
if( distance > ( getRadius() + pHatedActor->getRadius() ) )
|
||||
{
|
||||
if( hasFlag( Immobile ) )
|
||||
break;
|
||||
|
||||
if( pNaviProvider )
|
||||
pNaviProvider->setMoveTarget( *this, pHatedActor->getPos() );
|
||||
|
||||
moveTo( *pHatedActor );
|
||||
}
|
||||
|
||||
if( distance < ( getRadius() + pHatedActor->getRadius() + 3.f ) )
|
||||
{
|
||||
if( !hasFlag( TurningDisabled ) && face( pHatedActor->getPos() ) )
|
||||
sendPositionUpdate();
|
||||
|
||||
// in combat range. ATTACK!
|
||||
autoAttack( pHatedActor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -653,7 +658,7 @@ void Sapphire::Entity::BNpc::setOwner( Sapphire::Entity::CharaPtr m_pChara )
|
|||
else
|
||||
{
|
||||
auto setOwnerPacket = makeZonePacket< FFXIVIpcActorOwner >( getId() );
|
||||
setOwnerPacket->data().type = 0x01;
|
||||
setOwnerPacket->data().type = 0x00;
|
||||
setOwnerPacket->data().actorId = static_cast< uint32_t >( INVALID_GAME_OBJECT_ID );
|
||||
sendToInRangeSet( setOwnerPacket );
|
||||
}
|
||||
|
@ -679,6 +684,11 @@ void Sapphire::Entity::BNpc::setFlag( uint32_t flag )
|
|||
m_flags |= flag;
|
||||
}
|
||||
|
||||
void Sapphire::Entity::BNpc::unsetFlag( uint32_t flag )
|
||||
{
|
||||
m_flags = m_flags & ( 0xFFFFFFFF - flag );
|
||||
}
|
||||
|
||||
/*!
|
||||
TODO: this only solves attacks from melee classes.
|
||||
Will have to be extended for ranged attacks.
|
||||
|
|
|
@ -117,6 +117,7 @@ namespace Sapphire::Entity
|
|||
|
||||
bool hasFlag( uint32_t flag ) const;
|
||||
void setFlag( uint32_t flags );
|
||||
void unsetFlag( uint32_t flag );
|
||||
|
||||
void calculateStats() override;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "Action/MountAction.h"
|
||||
#include "Script/ScriptMgr.h"
|
||||
#include "Actor/Player.h"
|
||||
|
||||
#include "Service.h"
|
||||
#include "StatusEffect/StatusEffect.h"
|
||||
|
||||
#include <Exd/ExdDataGenerated.h>
|
||||
|
@ -15,14 +15,15 @@
|
|||
|
||||
using namespace Sapphire;
|
||||
|
||||
void World::Manager::ActionMgr::handlePlacedPlayerAction( Entity::Player& player, uint32_t actionId,
|
||||
void World::Manager::ActionMgr::handlePlacedAction( Entity::Chara& chara, uint32_t actionId,
|
||||
Data::ActionPtr actionData, Common::FFXIVARR_POSITION3 pos,
|
||||
uint16_t sequence )
|
||||
{
|
||||
player.sendDebug( "got aoe act: {0}", actionData->name );
|
||||
if( auto player = chara.getAsPlayer() )
|
||||
player->sendDebug( "got aoe act: {0}", actionData->name );
|
||||
|
||||
|
||||
auto action = Action::make_Action( player.getAsPlayer(), actionId, sequence, actionData );
|
||||
auto action = Action::make_Action( chara.getAsChara(), actionId, sequence, actionData );
|
||||
|
||||
action->setPos( pos );
|
||||
|
||||
|
@ -36,18 +37,30 @@ void World::Manager::ActionMgr::handlePlacedPlayerAction( Entity::Player& player
|
|||
return;
|
||||
}
|
||||
|
||||
bootstrapAction( player, action, *actionData );
|
||||
bootstrapAction( chara, action, *actionData );
|
||||
}
|
||||
|
||||
void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& player, uint32_t actionId,
|
||||
void World::Manager::ActionMgr::handleTargetedAction( Entity::Chara& chara, uint32_t actionId,
|
||||
Data::ActionPtr actionData, uint64_t targetId,
|
||||
uint16_t sequence )
|
||||
{
|
||||
auto action = Action::make_Action( player.getAsPlayer(), actionId, sequence, actionData );
|
||||
if( !actionData )
|
||||
{
|
||||
actionData = Common::Service< Data::ExdDataGenerated >::ref().get< Data::Action >( actionId );
|
||||
}
|
||||
|
||||
if( !actionData )
|
||||
{
|
||||
if( auto player = chara.getAsPlayer() )
|
||||
player->sendUrgent( "Cannot find action {}.", actionId );
|
||||
return;
|
||||
}
|
||||
|
||||
auto action = Action::make_Action( chara.getAsChara(), actionId, sequence, actionData );
|
||||
|
||||
action->setTargetId( targetId );
|
||||
|
||||
action->setPos( player.getPos() );
|
||||
action->setPos( chara.getPos() );
|
||||
|
||||
if( !action->init() )
|
||||
return;
|
||||
|
@ -59,7 +72,7 @@ void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& play
|
|||
return;
|
||||
}
|
||||
|
||||
bootstrapAction( player, action, *actionData );
|
||||
bootstrapAction( chara, action, *actionData );
|
||||
}
|
||||
|
||||
void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& player, uint32_t itemId,
|
||||
|
@ -105,11 +118,11 @@ void World::Manager::ActionMgr::handleMountAction( Entity::Player& player, uint1
|
|||
bootstrapAction( player, action, *actionData );
|
||||
}
|
||||
|
||||
void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player,
|
||||
void World::Manager::ActionMgr::bootstrapAction( Entity::Chara& chara,
|
||||
Action::ActionPtr currentAction,
|
||||
Data::Action& actionData )
|
||||
{
|
||||
for( const auto& statusIt : player.getStatusEffectMap() )
|
||||
for( const auto& statusIt : chara.getStatusEffectMap() )
|
||||
{
|
||||
statusIt.second->onBeforeActionStart( currentAction.get() );
|
||||
}
|
||||
|
@ -119,23 +132,25 @@ void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player,
|
|||
|
||||
if( !currentAction->preCheck() )
|
||||
{
|
||||
player.sendDebug( "preCheck failed" );
|
||||
// forcefully interrupt the action and reset the cooldown
|
||||
currentAction->interrupt();
|
||||
return;
|
||||
}
|
||||
|
||||
if( player.getCurrentAction() )
|
||||
if( chara.getCurrentAction() )
|
||||
{
|
||||
player.sendDebug( "Skill queued: {0}", currentAction->getId() );
|
||||
player.setQueuedAction( currentAction );
|
||||
if( auto player = chara.getAsPlayer() )
|
||||
{
|
||||
player->sendDebug( "Skill queued: {0}", currentAction->getId() );
|
||||
player->setQueuedAction( currentAction );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we have a cast time we want to associate the action with the player so update is called
|
||||
if( currentAction->hasCastTime() )
|
||||
{
|
||||
player.setCurrentAction( currentAction );
|
||||
chara.setCurrentAction( currentAction );
|
||||
}
|
||||
|
||||
// todo: what do in cases of swiftcast/etc? script callback?
|
||||
|
|
|
@ -23,9 +23,9 @@ namespace Sapphire::World::Manager
|
|||
ActionMgr() = default;
|
||||
~ActionMgr() = default;
|
||||
|
||||
void handleTargetedPlayerAction( Entity::Player& player, uint32_t actionId,
|
||||
void handleTargetedAction( Entity::Chara& chara, uint32_t actionId,
|
||||
Data::ActionPtr actionData, uint64_t targetId, uint16_t sequence );
|
||||
void handlePlacedPlayerAction( Entity::Player& player, uint32_t actionId,
|
||||
void handlePlacedAction( Entity::Chara& chara, uint32_t actionId,
|
||||
Data::ActionPtr actionData, Common::FFXIVARR_POSITION3 pos, uint16_t sequence );
|
||||
|
||||
void handleItemAction( Entity::Player& player, uint32_t itemId, Data::ItemActionPtr itemActionData,
|
||||
|
@ -37,7 +37,7 @@ namespace Sapphire::World::Manager
|
|||
Data::ActionPtr actionData, uint64_t targetId, uint16_t sequence );
|
||||
|
||||
private:
|
||||
void bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData );
|
||||
void bootstrapAction( Entity::Chara& chara, Action::ActionPtr currentAction, Data::Action& actionData );
|
||||
|
||||
// item action handlers
|
||||
void handleItemActionVFX( Entity::Player& player, uint32_t itemId, uint16_t vfxId );
|
||||
|
|
|
@ -45,7 +45,7 @@ void Sapphire::Network::GameConnection::actionHandler( const Packets::FFXIVARR_P
|
|||
if( !action )
|
||||
return;
|
||||
|
||||
actionMgr.handleTargetedPlayerAction( player, actionId, action, targetId, sequence );
|
||||
actionMgr.handleTargetedAction( player, actionId, action, targetId, sequence );
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -117,5 +117,5 @@ void Sapphire::Network::GameConnection::placedActionHandler( const Packets::FFXI
|
|||
return;
|
||||
|
||||
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
|
||||
actionMgr.handlePlacedPlayerAction( player, actionId, action, pos, sequence );
|
||||
actionMgr.handlePlacedAction( player, actionId, action, pos, sequence );
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue