1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-09 04:07:46 +00:00

allow bnpc to perform actions

This commit is contained in:
collett 2023-03-12 00:39:46 +09:00
parent 8e77266b30
commit 542f37fb3d
6 changed files with 97 additions and 81 deletions

View file

@ -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() )
{

View file

@ -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.

View file

@ -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;

View file

@ -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?

View file

@ -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 );

View file

@ -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 );
}