mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-05 02:07:46 +00:00
Merge pull request #922 from collett8192/Sapphire5.58_action
Allow bnpc to perform actions and basic BattleNpcScript support.
This commit is contained in:
commit
c37e8e1272
16 changed files with 353 additions and 156 deletions
|
@ -84,10 +84,10 @@ public:
|
||||||
a2->setFlag( Entity::NoDeaggro );
|
a2->setFlag( Entity::NoDeaggro );
|
||||||
a3->setFlag( Entity::NoDeaggro );
|
a3->setFlag( Entity::NoDeaggro );
|
||||||
|
|
||||||
a2->hateListAdd( ida, 10000 );
|
a2->hateListAddOrUpdate( ida, 10000 );
|
||||||
a3->hateListAdd( ida, 10000 );
|
a3->hateListAddOrUpdate( ida, 10000 );
|
||||||
a2->hateListAdd( papa, 10000 );
|
a2->hateListAddOrUpdate( papa, 10000 );
|
||||||
a3->hateListAdd( papa, 10000 );
|
a3->hateListAddOrUpdate( papa, 10000 );
|
||||||
|
|
||||||
|
|
||||||
auto a4 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_A_01, 5, 0, 300, 937,
|
auto a4 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_A_01, 5, 0, 300, 937,
|
||||||
|
@ -98,8 +98,8 @@ public:
|
||||||
a5->setFlag( Entity::NoDeaggro );
|
a5->setFlag( Entity::NoDeaggro );
|
||||||
|
|
||||||
auto pPlayer = instance.getPlayerPtr();
|
auto pPlayer = instance.getPlayerPtr();
|
||||||
a4->hateListAdd( pPlayer, 1 );
|
a4->hateListAddOrUpdate( pPlayer, 1 );
|
||||||
a5->hateListAdd( pPlayer, 1 );
|
a5->hateListAddOrUpdate( pPlayer, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pair2Spawnd == 0 && bossHpPercent <= 50 )
|
if( pair2Spawnd == 0 && bossHpPercent <= 50 )
|
||||||
|
@ -112,10 +112,10 @@ public:
|
||||||
a2->setFlag( Entity::NoDeaggro );
|
a2->setFlag( Entity::NoDeaggro );
|
||||||
a3->setFlag( Entity::NoDeaggro );
|
a3->setFlag( Entity::NoDeaggro );
|
||||||
|
|
||||||
a2->hateListAdd( ida, 10000 );
|
a2->hateListAddOrUpdate( ida, 10000 );
|
||||||
a3->hateListAdd( ida, 10000 );
|
a3->hateListAddOrUpdate( ida, 10000 );
|
||||||
a2->hateListAdd( papa, 10000 );
|
a2->hateListAddOrUpdate( papa, 10000 );
|
||||||
a3->hateListAdd( papa, 10000 );
|
a3->hateListAddOrUpdate( papa, 10000 );
|
||||||
|
|
||||||
auto a4 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_A_03, 5, 0, 300, 937,
|
auto a4 = instance.createBNpcFromLevelEntry( INIT_POP_ENEMY_A_03, 5, 0, 300, 937,
|
||||||
instance.getDirectorId(), Common::BNpcType::Enemy );
|
instance.getDirectorId(), Common::BNpcType::Enemy );
|
||||||
|
@ -125,8 +125,8 @@ public:
|
||||||
a5->setFlag( Entity::NoDeaggro );
|
a5->setFlag( Entity::NoDeaggro );
|
||||||
|
|
||||||
auto pPlayer = instance.getPlayerPtr();
|
auto pPlayer = instance.getPlayerPtr();
|
||||||
a4->hateListAdd( pPlayer, 1 );
|
a4->hateListAddOrUpdate( pPlayer, 1 );
|
||||||
a5->hateListAdd( pPlayer, 1 );
|
a5->hateListAddOrUpdate( pPlayer, 1 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,8 +142,8 @@ public:
|
||||||
a5->setFlag( Entity::NoDeaggro );
|
a5->setFlag( Entity::NoDeaggro );
|
||||||
|
|
||||||
auto pPlayer = instance.getPlayerPtr();
|
auto pPlayer = instance.getPlayerPtr();
|
||||||
a4->hateListAdd( pPlayer, 1 );
|
a4->hateListAddOrUpdate( pPlayer, 1 );
|
||||||
a5->hateListAdd( pPlayer, 1 );
|
a5->hateListAddOrUpdate( pPlayer, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( instance.getCountEnemyBNpc() == 0 && successCalled == 0 )
|
if( instance.getCountEnemyBNpc() == 0 && successCalled == 0 )
|
||||||
|
@ -189,24 +189,24 @@ public:
|
||||||
a3->setFlag( Entity::NoDeaggro );
|
a3->setFlag( Entity::NoDeaggro );
|
||||||
a4->setFlag( Entity::NoDeaggro );
|
a4->setFlag( Entity::NoDeaggro );
|
||||||
a5->setFlag( Entity::NoDeaggro );
|
a5->setFlag( Entity::NoDeaggro );
|
||||||
a1->hateListAdd( a4, 10000 );
|
a1->hateListAddOrUpdate( a4, 10000 );
|
||||||
a1->hateListAdd( a5, 10000 );
|
a1->hateListAddOrUpdate( a5, 10000 );
|
||||||
|
|
||||||
a2->hateListAdd( player.getAsPlayer(), 1 );
|
a2->hateListAddOrUpdate( player.getAsPlayer(), 1 );
|
||||||
a2->hateListAdd( a4, 10000 );
|
a2->hateListAddOrUpdate( a4, 10000 );
|
||||||
a2->hateListAdd( a5, 10000 );
|
a2->hateListAddOrUpdate( a5, 10000 );
|
||||||
|
|
||||||
a3->hateListAdd( player.getAsPlayer(), 1 );
|
a3->hateListAddOrUpdate( player.getAsPlayer(), 1 );
|
||||||
a3->hateListAdd( a4, 10000 );
|
a3->hateListAddOrUpdate( a4, 10000 );
|
||||||
a3->hateListAdd( a5, 10000 );
|
a3->hateListAddOrUpdate( a5, 10000 );
|
||||||
|
|
||||||
a4->hateListAdd( a1, 10000 );
|
a4->hateListAddOrUpdate( a1, 10000 );
|
||||||
a4->hateListAdd( a2, 9999 );
|
a4->hateListAddOrUpdate( a2, 9999 );
|
||||||
a4->hateListAdd( a3, 9999 );
|
a4->hateListAddOrUpdate( a3, 9999 );
|
||||||
|
|
||||||
a5->hateListAdd( a1, 10000 );
|
a5->hateListAddOrUpdate( a1, 10000 );
|
||||||
a5->hateListAdd( a2, 9999 );
|
a5->hateListAddOrUpdate( a2, 9999 );
|
||||||
a5->hateListAdd( a3, 9999 );
|
a5->hateListAddOrUpdate( a3, 9999 );
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -401,7 +401,7 @@ void Action::Action::execute()
|
||||||
assert( m_pSource );
|
assert( m_pSource );
|
||||||
|
|
||||||
// subtract costs first, if somehow the caster stops meeting those requirements cancel the cast
|
// subtract costs first, if somehow the caster stops meeting those requirements cancel the cast
|
||||||
if( !consumeResources() )
|
if( m_pSource->getAsPlayer() && !consumeResources() )
|
||||||
{
|
{
|
||||||
interrupt();
|
interrupt();
|
||||||
return;
|
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() )
|
if( !hasClientsideTarget() )
|
||||||
{
|
{
|
||||||
buildEffects();
|
buildEffects();
|
||||||
|
@ -638,16 +631,13 @@ void Action::Action::buildEffects()
|
||||||
if( isCorrectCombo() )
|
if( isCorrectCombo() )
|
||||||
m_effectBuilder->comboSucceed( actor );
|
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 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if( m_lutEntry.bonusEffect & Common::ActionBonusEffect::GainMPPercentage )
|
if( m_lutEntry.bonusEffect & Common::ActionBonusEffect::GainMPPercentage )
|
||||||
{
|
{
|
||||||
|
@ -655,7 +645,7 @@ void Action::Action::buildEffects()
|
||||||
m_effectBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.getMPGainPercentage() / 100, Common::ActionEffectResultFlag::EffectOnSource );
|
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() )
|
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() )
|
if( checkActionBonusRequirement() )
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,6 +45,11 @@ uint32_t EffectResult::getValue() const
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Common::ActionEffectType Sapphire::World::Action::EffectResult::getType() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t EffectResult::getDelay()
|
uint64_t EffectResult::getDelay()
|
||||||
{
|
{
|
||||||
return m_delayMs;
|
return m_delayMs;
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace Sapphire::World::Action
|
||||||
Entity::CharaPtr getTarget() const;
|
Entity::CharaPtr getTarget() const;
|
||||||
|
|
||||||
uint32_t getValue() const;
|
uint32_t getValue() const;
|
||||||
|
Common::ActionEffectType getType() const;
|
||||||
uint64_t getDelay();
|
uint64_t getDelay();
|
||||||
|
|
||||||
Common::EffectEntry buildEffectEntry() const;
|
Common::EffectEntry buildEffectEntry() const;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "BNpc.h"
|
#include "BNpc.h"
|
||||||
#include "BNpcTemplate.h"
|
#include "BNpcTemplate.h"
|
||||||
|
#include "Script/ScriptMgr.h"
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
#include <Manager/NaviMgr.h>
|
#include <Manager/NaviMgr.h>
|
||||||
#include <Manager/TerritoryMgr.h>
|
#include <Manager/TerritoryMgr.h>
|
||||||
#include <Manager/RNGMgr.h>
|
#include <Manager/RNGMgr.h>
|
||||||
|
#include <Manager/ActionMgr.h>
|
||||||
#include <Service.h>
|
#include <Service.h>
|
||||||
|
|
||||||
using namespace Sapphire::Common;
|
using namespace Sapphire::Common;
|
||||||
|
@ -119,6 +121,8 @@ Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX
|
||||||
m_naviTargetReachedDistance = 4.f;
|
m_naviTargetReachedDistance = 4.f;
|
||||||
|
|
||||||
calculateStats();
|
calculateStats();
|
||||||
|
auto& scriptMgr = Common::Service< Sapphire::Scripting::ScriptMgr >::ref();
|
||||||
|
scriptMgr.onBNpcInit( *this );
|
||||||
}
|
}
|
||||||
|
|
||||||
Sapphire::Entity::BNpc::~BNpc() = default;
|
Sapphire::Entity::BNpc::~BNpc() = default;
|
||||||
|
@ -254,6 +258,15 @@ bool Sapphire::Entity::BNpc::moveTo( const Entity::Chara& targetChara )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::BNpc::stopMoving()
|
||||||
|
{
|
||||||
|
auto pNaviProvider = m_pCurrentTerritory->getNaviProvider();
|
||||||
|
if( !pNaviProvider )
|
||||||
|
return;
|
||||||
|
sendPositionUpdate();
|
||||||
|
pNaviProvider->updateAgentPosition( *this );
|
||||||
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::sendPositionUpdate()
|
void Sapphire::Entity::BNpc::sendPositionUpdate()
|
||||||
{
|
{
|
||||||
uint8_t unk1 = 0x3a;
|
uint8_t unk1 = 0x3a;
|
||||||
|
@ -268,13 +281,14 @@ void Sapphire::Entity::BNpc::sendPositionUpdate()
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::hateListClear()
|
void Sapphire::Entity::BNpc::hateListClear()
|
||||||
{
|
{
|
||||||
auto it = m_hateList.begin();
|
if( m_hateList.empty() )
|
||||||
for( auto& listEntry : m_hateList )
|
return;
|
||||||
|
|
||||||
|
auto hateListCopy = m_hateList;
|
||||||
|
for( auto& listEntry : hateListCopy )
|
||||||
{
|
{
|
||||||
if( isInRangeSet( listEntry->m_pChara ) )
|
|
||||||
deaggro( listEntry->m_pChara );
|
deaggro( listEntry->m_pChara );
|
||||||
}
|
}
|
||||||
m_hateList.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Sapphire::Entity::CharaPtr Sapphire::Entity::BNpc::hateListGetHighest()
|
Sapphire::Entity::CharaPtr Sapphire::Entity::BNpc::hateListGetHighest()
|
||||||
|
@ -297,25 +311,11 @@ Sapphire::Entity::CharaPtr Sapphire::Entity::BNpc::hateListGetHighest()
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::hateListAdd( Sapphire::Entity::CharaPtr pChara, int32_t hateAmount )
|
void Sapphire::Entity::BNpc::hateListAddOrUpdate( Sapphire::Entity::CharaPtr pChara, int32_t hateAmount )
|
||||||
{
|
|
||||||
auto hateEntry = std::make_shared< HateListEntry >();
|
|
||||||
hateEntry->m_hateAmount = static_cast< uint32_t >( hateAmount );
|
|
||||||
hateEntry->m_pChara = pChara;
|
|
||||||
|
|
||||||
m_hateList.insert( hateEntry );
|
|
||||||
if( pChara->isPlayer() )
|
|
||||||
{
|
|
||||||
auto pPlayer = pChara->getAsPlayer();
|
|
||||||
pPlayer->hateListAdd( getAsBNpc() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::hateListUpdate( Sapphire::Entity::CharaPtr pChara, int32_t hateAmount )
|
|
||||||
{
|
{
|
||||||
for( auto listEntry : m_hateList )
|
for( auto listEntry : m_hateList )
|
||||||
{
|
{
|
||||||
if( listEntry->m_pChara == pChara )
|
if( listEntry->m_pChara->getId() == pChara->getId() )
|
||||||
{
|
{
|
||||||
listEntry->m_hateAmount += static_cast< uint32_t >( hateAmount );
|
listEntry->m_hateAmount += static_cast< uint32_t >( hateAmount );
|
||||||
return;
|
return;
|
||||||
|
@ -326,21 +326,29 @@ void Sapphire::Entity::BNpc::hateListUpdate( Sapphire::Entity::CharaPtr pChara,
|
||||||
hateEntry->m_hateAmount = static_cast< uint32_t >( hateAmount );
|
hateEntry->m_hateAmount = static_cast< uint32_t >( hateAmount );
|
||||||
hateEntry->m_pChara = pChara;
|
hateEntry->m_pChara = pChara;
|
||||||
m_hateList.insert( hateEntry );
|
m_hateList.insert( hateEntry );
|
||||||
|
if( pChara->isPlayer() )
|
||||||
|
{
|
||||||
|
auto pPlayer = pChara->getAsPlayer();
|
||||||
|
pPlayer->hateListAdd( getAsBNpc() );
|
||||||
|
}
|
||||||
|
auto& scriptMgr = Common::Service< Sapphire::Scripting::ScriptMgr >::ref();
|
||||||
|
scriptMgr.onBNpcHateListAdd( *this, *pChara );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::hateListRemove( Sapphire::Entity::CharaPtr pChara )
|
void Sapphire::Entity::BNpc::hateListRemove( Sapphire::Entity::CharaPtr pChara )
|
||||||
{
|
{
|
||||||
for( auto listEntry : m_hateList )
|
for( auto listEntry : m_hateList )
|
||||||
{
|
{
|
||||||
if( listEntry->m_pChara == pChara )
|
if( listEntry->m_pChara->getId() == pChara->getId() )
|
||||||
{
|
{
|
||||||
|
|
||||||
m_hateList.erase( listEntry );
|
m_hateList.erase( listEntry );
|
||||||
if( pChara->isPlayer() )
|
if( pChara->isPlayer() )
|
||||||
{
|
{
|
||||||
PlayerPtr tmpPlayer = pChara->getAsPlayer();
|
PlayerPtr tmpPlayer = pChara->getAsPlayer();
|
||||||
tmpPlayer->onMobDeaggro( getAsBNpc() );
|
tmpPlayer->onMobDeaggro( getAsBNpc() );
|
||||||
}
|
}
|
||||||
|
auto& scriptMgr = Common::Service< Sapphire::Scripting::ScriptMgr >::ref();
|
||||||
|
scriptMgr.onBNpcHateListRemove( *this, *pChara );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,34 +370,28 @@ void Sapphire::Entity::BNpc::aggro( Sapphire::Entity::CharaPtr pChara )
|
||||||
auto variation = static_cast< uint32_t >( pRNGMgr.getRandGenerator< float >( 500, 1000 ).next() );
|
auto variation = static_cast< uint32_t >( pRNGMgr.getRandGenerator< float >( 500, 1000 ).next() );
|
||||||
|
|
||||||
m_lastAttack = Util::getTimeMs() + variation;
|
m_lastAttack = Util::getTimeMs() + variation;
|
||||||
hateListUpdate( pChara, 1 );
|
|
||||||
|
|
||||||
changeTarget( pChara->getId() );
|
changeTarget( pChara->getId() );
|
||||||
setStance( Stance::Active );
|
setStance( Stance::Active );
|
||||||
m_state = BNpcState::Combat;
|
m_state = BNpcState::Combat;
|
||||||
|
|
||||||
|
if( m_hateList.empty() )
|
||||||
|
{
|
||||||
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleWeapon, 1, 1, 0 ) );
|
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleWeapon, 1, 1, 0 ) );
|
||||||
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleAggro, 1, 0, 0 ) );
|
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleAggro, 1, 0, 0 ) );
|
||||||
|
|
||||||
if( pChara->isPlayer() )
|
|
||||||
{
|
|
||||||
PlayerPtr tmpPlayer = pChara->getAsPlayer();
|
|
||||||
tmpPlayer->onMobAggro( getAsBNpc() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hateListAddOrUpdate( pChara, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::deaggro( Sapphire::Entity::CharaPtr pChara )
|
void Sapphire::Entity::BNpc::deaggro( Sapphire::Entity::CharaPtr pChara )
|
||||||
{
|
{
|
||||||
if( !hateListHasActor( pChara ) )
|
|
||||||
hateListRemove( pChara );
|
hateListRemove( pChara );
|
||||||
|
|
||||||
if( pChara->isPlayer() )
|
if( m_hateList.empty() )
|
||||||
{
|
{
|
||||||
PlayerPtr tmpPlayer = pChara->getAsPlayer();
|
|
||||||
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleWeapon, 0, 1, 1 ) );
|
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleWeapon, 0, 1, 1 ) );
|
||||||
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleAggro, 0, 0, 0 ) );
|
sendToInRangeSet( makeActorControl( getId(), ActorControlType::ToggleAggro, 0, 0, 0 ) );
|
||||||
tmpPlayer->onMobDeaggro( getAsBNpc() );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,6 +405,22 @@ void Sapphire::Entity::BNpc::onTick()
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::update( uint64_t tickCount )
|
void Sapphire::Entity::BNpc::update( uint64_t tickCount )
|
||||||
|
{
|
||||||
|
if( getCurrentAction() && getCurrentAction()->hasCastTime() )
|
||||||
|
{
|
||||||
|
if( m_pCurrentAction->update() )
|
||||||
|
m_pCurrentAction = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& scriptMgr = Common::Service< Sapphire::Scripting::ScriptMgr >::ref();
|
||||||
|
if( !scriptMgr.onBNpcUpdate( *this, tickCount ) )
|
||||||
|
doDefaultBNpcUpdate( tickCount );
|
||||||
|
|
||||||
|
Chara::update( tickCount );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::BNpc::doDefaultBNpcUpdate( uint64_t tickCount )
|
||||||
{
|
{
|
||||||
const uint8_t maxDistanceToOrigin = 40;
|
const uint8_t maxDistanceToOrigin = 40;
|
||||||
const uint32_t roamTick = 20;
|
const uint32_t roamTick = 20;
|
||||||
|
@ -482,29 +500,36 @@ void Sapphire::Entity::BNpc::update( uint64_t tickCount )
|
||||||
|
|
||||||
checkAggro();
|
checkAggro();
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case BNpcState::Combat:
|
case BNpcState::Combat:
|
||||||
{
|
{
|
||||||
auto pHatedActor = hateListGetHighest();
|
|
||||||
if( !pHatedActor )
|
|
||||||
return;
|
|
||||||
|
|
||||||
pNaviProvider->updateAgentParameters( *this );
|
pNaviProvider->updateAgentParameters( *this );
|
||||||
|
|
||||||
auto distanceOrig = Util::distance( getPos().x, getPos().y, getPos().z,
|
auto distanceOrig = Util::distance( getPos().x, getPos().y, getPos().z,
|
||||||
m_spawnPos.x, m_spawnPos.y, m_spawnPos.z );
|
m_spawnPos.x, m_spawnPos.y, m_spawnPos.z );
|
||||||
|
|
||||||
if( pHatedActor && !pHatedActor->isAlive() )
|
auto pHatedActor = hateListGetHighest();
|
||||||
|
|
||||||
|
while( pHatedActor && !pHatedActor->isAlive() )
|
||||||
{
|
{
|
||||||
hateListRemove( pHatedActor );
|
hateListRemove( pHatedActor );
|
||||||
pHatedActor = hateListGetHighest();
|
pHatedActor = hateListGetHighest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !pHatedActor )
|
||||||
|
{
|
||||||
|
hateListClear();
|
||||||
|
changeTarget( INVALID_GAME_OBJECT_ID64 );
|
||||||
|
setStance( Stance::Passive );
|
||||||
|
setOwner( nullptr );
|
||||||
|
m_state = BNpcState::Retreat;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if( pNaviProvider->syncPosToChara( *this ) )
|
if( pNaviProvider->syncPosToChara( *this ) )
|
||||||
sendPositionUpdate();
|
sendPositionUpdate();
|
||||||
|
|
||||||
if( pHatedActor )
|
|
||||||
{
|
|
||||||
auto distance = Util::distance( getPos().x, getPos().y, getPos().z,
|
auto distance = Util::distance( getPos().x, getPos().y, getPos().z,
|
||||||
pHatedActor->getPos().x, pHatedActor->getPos().y, pHatedActor->getPos().z );
|
pHatedActor->getPos().x, pHatedActor->getPos().y, pHatedActor->getPos().z );
|
||||||
|
|
||||||
|
@ -538,20 +563,8 @@ void Sapphire::Entity::BNpc::update( uint64_t tickCount )
|
||||||
autoAttack( pHatedActor );
|
autoAttack( pHatedActor );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
changeTarget( INVALID_GAME_OBJECT_ID64 );
|
|
||||||
setStance( Stance::Passive );
|
|
||||||
//setOwner( nullptr );
|
|
||||||
m_state = BNpcState::Retreat;
|
|
||||||
pNaviProvider->updateAgentParameters( *this );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Chara::update( tickCount );
|
|
||||||
}
|
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::regainHp()
|
void Sapphire::Entity::BNpc::regainHp()
|
||||||
{
|
{
|
||||||
|
@ -585,6 +598,9 @@ void Sapphire::Entity::BNpc::onDeath()
|
||||||
m_timeOfDeath = Util::getTimeSeconds();
|
m_timeOfDeath = Util::getTimeSeconds();
|
||||||
setOwner( nullptr );
|
setOwner( nullptr );
|
||||||
|
|
||||||
|
auto& scriptMgr = Common::Service< Sapphire::Scripting::ScriptMgr >::ref();
|
||||||
|
scriptMgr.onBNpcDeath( *this );
|
||||||
|
|
||||||
for( auto& pHateEntry : m_hateList )
|
for( auto& pHateEntry : m_hateList )
|
||||||
{
|
{
|
||||||
// TODO: handle drops
|
// TODO: handle drops
|
||||||
|
@ -642,6 +658,8 @@ void Sapphire::Entity::BNpc::checkAggro()
|
||||||
|
|
||||||
void Sapphire::Entity::BNpc::setOwner( Sapphire::Entity::CharaPtr m_pChara )
|
void Sapphire::Entity::BNpc::setOwner( Sapphire::Entity::CharaPtr m_pChara )
|
||||||
{
|
{
|
||||||
|
if( ( !m_pOwner && !m_pChara ) || ( m_pOwner && m_pChara && m_pOwner->getId() == m_pChara->getId() ) )
|
||||||
|
return;
|
||||||
m_pOwner = m_pChara;
|
m_pOwner = m_pChara;
|
||||||
if( m_pChara != nullptr )
|
if( m_pChara != nullptr )
|
||||||
{
|
{
|
||||||
|
@ -653,7 +671,7 @@ void Sapphire::Entity::BNpc::setOwner( Sapphire::Entity::CharaPtr m_pChara )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto setOwnerPacket = makeZonePacket< FFXIVIpcActorOwner >( getId() );
|
auto setOwnerPacket = makeZonePacket< FFXIVIpcActorOwner >( getId() );
|
||||||
setOwnerPacket->data().type = 0x01;
|
setOwnerPacket->data().type = 0x00;
|
||||||
setOwnerPacket->data().actorId = static_cast< uint32_t >( INVALID_GAME_OBJECT_ID );
|
setOwnerPacket->data().actorId = static_cast< uint32_t >( INVALID_GAME_OBJECT_ID );
|
||||||
sendToInRangeSet( setOwnerPacket );
|
sendToInRangeSet( setOwnerPacket );
|
||||||
}
|
}
|
||||||
|
@ -679,6 +697,11 @@ void Sapphire::Entity::BNpc::setFlag( uint32_t flag )
|
||||||
m_flags |= 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.
|
TODO: this only solves attacks from melee classes.
|
||||||
Will have to be extended for ranged attacks.
|
Will have to be extended for ranged attacks.
|
||||||
|
@ -745,3 +768,16 @@ void Sapphire::Entity::BNpc::calculateStats()
|
||||||
m_baseStats.attackPotMagic = m_baseStats.inte;
|
m_baseStats.attackPotMagic = m_baseStats.inte;
|
||||||
m_baseStats.healingPotMagic = m_baseStats.mnd;
|
m_baseStats.healingPotMagic = m_baseStats.mnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::BNpc::setCustomVar( uint32_t varId, uint64_t value )
|
||||||
|
{
|
||||||
|
m_customVarMap[ varId ] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Sapphire::Entity::BNpc::getCustomVar( uint32_t varId )
|
||||||
|
{
|
||||||
|
auto it = m_customVarMap.find( varId );
|
||||||
|
if( it != m_customVarMap.end() )
|
||||||
|
return it->second;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -79,6 +79,8 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
bool moveTo( const Entity::Chara& targetChara );
|
bool moveTo( const Entity::Chara& targetChara );
|
||||||
|
|
||||||
|
void stopMoving();
|
||||||
|
|
||||||
void sendPositionUpdate();
|
void sendPositionUpdate();
|
||||||
|
|
||||||
BNpcState getState() const;
|
BNpcState getState() const;
|
||||||
|
@ -86,8 +88,7 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
void hateListClear();
|
void hateListClear();
|
||||||
CharaPtr hateListGetHighest();
|
CharaPtr hateListGetHighest();
|
||||||
void hateListAdd( CharaPtr pChara, int32_t hateAmount );
|
void hateListAddOrUpdate( CharaPtr pChara, int32_t hateAmount );
|
||||||
void hateListUpdate( CharaPtr pChara, int32_t hateAmount );
|
|
||||||
void hateListRemove( CharaPtr pChara );
|
void hateListRemove( CharaPtr pChara );
|
||||||
bool hateListHasActor( CharaPtr pChara );
|
bool hateListHasActor( CharaPtr pChara );
|
||||||
|
|
||||||
|
@ -95,6 +96,7 @@ namespace Sapphire::Entity
|
||||||
void deaggro( CharaPtr pChara );
|
void deaggro( CharaPtr pChara );
|
||||||
|
|
||||||
void update( uint64_t tickCount ) override;
|
void update( uint64_t tickCount ) override;
|
||||||
|
void doDefaultBNpcUpdate( uint64_t tickCount );
|
||||||
void onTick() override;
|
void onTick() override;
|
||||||
|
|
||||||
void onActionHostile( CharaPtr pSource ) override;
|
void onActionHostile( CharaPtr pSource ) override;
|
||||||
|
@ -117,9 +119,13 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
bool hasFlag( uint32_t flag ) const;
|
bool hasFlag( uint32_t flag ) const;
|
||||||
void setFlag( uint32_t flags );
|
void setFlag( uint32_t flags );
|
||||||
|
void unsetFlag( uint32_t flag );
|
||||||
|
|
||||||
void calculateStats() override;
|
void calculateStats() override;
|
||||||
|
|
||||||
|
void setCustomVar( uint32_t varId, uint64_t value );
|
||||||
|
uint64_t getCustomVar( uint32_t varId );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_bNpcBaseId;
|
uint32_t m_bNpcBaseId;
|
||||||
uint32_t m_bNpcNameId;
|
uint32_t m_bNpcNameId;
|
||||||
|
@ -154,6 +160,7 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
CharaPtr m_pOwner;
|
CharaPtr m_pOwner;
|
||||||
|
|
||||||
|
std::unordered_map< uint32_t, uint64_t > m_customVarMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -374,6 +374,8 @@ Change the current target and propagate to in range players
|
||||||
*/
|
*/
|
||||||
void Sapphire::Entity::Chara::changeTarget( uint64_t targetId )
|
void Sapphire::Entity::Chara::changeTarget( uint64_t targetId )
|
||||||
{
|
{
|
||||||
|
if( m_targetId == targetId )
|
||||||
|
return;
|
||||||
setTargetId( targetId );
|
setTargetId( targetId );
|
||||||
FFXIVPacketBasePtr packet = makeActorControlTarget( m_id, SetTarget, 0, 0, 0, 0, targetId );
|
FFXIVPacketBasePtr packet = makeActorControlTarget( m_id, SetTarget, 0, 0, 0, 0, targetId );
|
||||||
sendToInRangeSet( packet );
|
sendToInRangeSet( packet );
|
||||||
|
|
|
@ -1035,14 +1035,16 @@ void Sapphire::Entity::Player::despawn( Entity::PlayerPtr pTarget )
|
||||||
|
|
||||||
Sapphire::Entity::ActorPtr Sapphire::Entity::Player::lookupTargetById( uint64_t targetId )
|
Sapphire::Entity::ActorPtr Sapphire::Entity::Player::lookupTargetById( uint64_t targetId )
|
||||||
{
|
{
|
||||||
ActorPtr targetActor;
|
if( targetId == 0 || targetId == INVALID_GAME_OBJECT_ID64 )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
auto inRange = getInRangeActors( true );
|
auto inRange = getInRangeActors( true );
|
||||||
for( auto actor : inRange )
|
for( auto actor : inRange )
|
||||||
{
|
{
|
||||||
if( actor->getId() == targetId )
|
if( actor->getId() == targetId )
|
||||||
targetActor = actor;
|
return actor;
|
||||||
}
|
}
|
||||||
return targetActor;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Player::setLastPing( uint32_t ping )
|
void Sapphire::Entity::Player::setLastPing( uint32_t ping )
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "Action/MountAction.h"
|
#include "Action/MountAction.h"
|
||||||
#include "Script/ScriptMgr.h"
|
#include "Script/ScriptMgr.h"
|
||||||
#include "Actor/Player.h"
|
#include "Actor/Player.h"
|
||||||
|
#include "Service.h"
|
||||||
#include "StatusEffect/StatusEffect.h"
|
#include "StatusEffect/StatusEffect.h"
|
||||||
|
|
||||||
#include <Exd/ExdDataGenerated.h>
|
#include <Exd/ExdDataGenerated.h>
|
||||||
|
@ -15,14 +15,19 @@
|
||||||
|
|
||||||
using namespace Sapphire;
|
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,
|
Data::ActionPtr actionData, Common::FFXIVARR_POSITION3 pos,
|
||||||
uint16_t sequence )
|
uint16_t sequence )
|
||||||
{
|
{
|
||||||
player.sendDebug( "got aoe act: {0}", actionData->name );
|
if( auto player = chara.getAsPlayer() )
|
||||||
|
player->sendDebug( "got aoe act: {0}", actionData->name );
|
||||||
|
|
||||||
|
if( !actionData )
|
||||||
|
{
|
||||||
|
actionData = Common::Service< Data::ExdDataGenerated >::ref().get< Data::Action >( actionId );
|
||||||
|
}
|
||||||
|
|
||||||
auto action = Action::make_Action( player.getAsPlayer(), actionId, sequence, actionData );
|
auto action = Action::make_Action( chara.getAsChara(), actionId, sequence, actionData );
|
||||||
|
|
||||||
action->setPos( pos );
|
action->setPos( pos );
|
||||||
|
|
||||||
|
@ -36,18 +41,30 @@ void World::Manager::ActionMgr::handlePlacedPlayerAction( Entity::Player& player
|
||||||
return;
|
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,
|
Data::ActionPtr actionData, uint64_t targetId,
|
||||||
uint16_t sequence )
|
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->setTargetId( targetId );
|
||||||
|
|
||||||
action->setPos( player.getPos() );
|
action->setPos( chara.getPos() );
|
||||||
|
|
||||||
if( !action->init() )
|
if( !action->init() )
|
||||||
return;
|
return;
|
||||||
|
@ -59,7 +76,7 @@ void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& play
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrapAction( player, action, *actionData );
|
bootstrapAction( chara, action, *actionData );
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& player, uint32_t itemId,
|
void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& player, uint32_t itemId,
|
||||||
|
@ -105,11 +122,11 @@ void World::Manager::ActionMgr::handleMountAction( Entity::Player& player, uint1
|
||||||
bootstrapAction( player, action, *actionData );
|
bootstrapAction( player, action, *actionData );
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player,
|
void World::Manager::ActionMgr::bootstrapAction( Entity::Chara& chara,
|
||||||
Action::ActionPtr currentAction,
|
Action::ActionPtr currentAction,
|
||||||
Data::Action& actionData )
|
Data::Action& actionData )
|
||||||
{
|
{
|
||||||
for( const auto& statusIt : player.getStatusEffectMap() )
|
for( const auto& statusIt : chara.getStatusEffectMap() )
|
||||||
{
|
{
|
||||||
statusIt.second->onBeforeActionStart( currentAction.get() );
|
statusIt.second->onBeforeActionStart( currentAction.get() );
|
||||||
}
|
}
|
||||||
|
@ -119,23 +136,25 @@ void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player,
|
||||||
|
|
||||||
if( !currentAction->preCheck() )
|
if( !currentAction->preCheck() )
|
||||||
{
|
{
|
||||||
player.sendDebug( "preCheck failed" );
|
|
||||||
// forcefully interrupt the action and reset the cooldown
|
// forcefully interrupt the action and reset the cooldown
|
||||||
currentAction->interrupt();
|
currentAction->interrupt();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( player.getCurrentAction() )
|
if( chara.getCurrentAction() )
|
||||||
{
|
{
|
||||||
player.sendDebug( "Skill queued: {0}", currentAction->getId() );
|
if( auto player = chara.getAsPlayer() )
|
||||||
player.setQueuedAction( currentAction );
|
{
|
||||||
|
player->sendDebug( "Skill queued: {0}", currentAction->getId() );
|
||||||
|
player->setQueuedAction( currentAction );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if we have a cast time we want to associate the action with the player so update is called
|
// if we have a cast time we want to associate the action with the player so update is called
|
||||||
if( currentAction->hasCastTime() )
|
if( currentAction->hasCastTime() )
|
||||||
{
|
{
|
||||||
player.setCurrentAction( currentAction );
|
chara.setCurrentAction( currentAction );
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: what do in cases of swiftcast/etc? script callback?
|
// todo: what do in cases of swiftcast/etc? script callback?
|
||||||
|
|
|
@ -23,9 +23,9 @@ namespace Sapphire::World::Manager
|
||||||
ActionMgr() = default;
|
ActionMgr() = default;
|
||||||
~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 );
|
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 );
|
Data::ActionPtr actionData, Common::FFXIVARR_POSITION3 pos, uint16_t sequence );
|
||||||
|
|
||||||
void handleItemAction( Entity::Player& player, uint32_t itemId, Data::ItemActionPtr itemActionData,
|
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 );
|
Data::ActionPtr actionData, uint64_t targetId, uint16_t sequence );
|
||||||
|
|
||||||
private:
|
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
|
// item action handlers
|
||||||
void handleItemActionVFX( Entity::Player& player, uint32_t itemId, uint16_t vfxId );
|
void handleItemActionVFX( Entity::Player& player, uint32_t itemId, uint16_t vfxId );
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "Script/ScriptMgr.h"
|
#include "Script/ScriptMgr.h"
|
||||||
#include "Script/NativeScriptMgr.h"
|
#include "Script/NativeScriptMgr.h"
|
||||||
|
|
||||||
|
#include "Actor/Actor.h"
|
||||||
#include "Actor/EventObject.h"
|
#include "Actor/EventObject.h"
|
||||||
#include "Actor/BNpc.h"
|
#include "Actor/BNpc.h"
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#include "Territory/PublicContent.h"
|
#include "Territory/PublicContent.h"
|
||||||
#include "Territory/InstanceObjectCache.h"
|
#include "Territory/InstanceObjectCache.h"
|
||||||
#include "Manager/TerritoryMgr.h"
|
#include "Manager/TerritoryMgr.h"
|
||||||
|
#include "Manager/ActionMgr.h"
|
||||||
#include "Event/EventDefs.h"
|
#include "Event/EventDefs.h"
|
||||||
|
|
||||||
#include "ServerMgr.h"
|
#include "ServerMgr.h"
|
||||||
|
@ -466,6 +468,28 @@ void Sapphire::World::Manager::DebugCommandMgr::set( char* data, Entity::Player&
|
||||||
}
|
}
|
||||||
player.setVisualEffect( id );
|
player.setVisualEffect( id );
|
||||||
}
|
}
|
||||||
|
else if( subCommand == "bnpccast" || subCommand == "bcast" )
|
||||||
|
{
|
||||||
|
if( auto target = player.lookupTargetById( player.getTargetId() ) )
|
||||||
|
{
|
||||||
|
if( auto bnpc = target->getAsBNpc() )
|
||||||
|
{
|
||||||
|
int32_t id;
|
||||||
|
sscanf( params.c_str(), "%d", &id );
|
||||||
|
auto actionData = Common::Service< Data::ExdDataGenerated >::ref().get< Data::Action >( id );
|
||||||
|
if ( !actionData )
|
||||||
|
return;
|
||||||
|
if( !actionData->targetArea && bnpc->getTargetId() != 0 && bnpc->getTargetId() != INVALID_GAME_OBJECT_ID64 )
|
||||||
|
{
|
||||||
|
Service< World::Manager::ActionMgr >::ref().handleTargetedAction( *bnpc, id, actionData, bnpc->getTargetId(), 0 );
|
||||||
|
}
|
||||||
|
else if ( actionData->targetArea )
|
||||||
|
{
|
||||||
|
Service< World::Manager::ActionMgr >::ref().handlePlacedAction( *bnpc, id, actionData, player.getPos(), 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
player.sendUrgent( "{0} is not a valid SET command.", subCommand );
|
player.sendUrgent( "{0} is not a valid SET command.", subCommand );
|
||||||
|
@ -696,6 +720,17 @@ void Sapphire::World::Manager::DebugCommandMgr::get( char* data, Entity::Player&
|
||||||
player.sendNotice( "x:{}, y:{}, z:{}", pPopRange->header.transform.translation.x, pPopRange->header.transform.translation.y, pPopRange->header.transform.translation.z );
|
player.sendNotice( "x:{}, y:{}, z:{}", pPopRange->header.transform.translation.x, pPopRange->header.transform.translation.y, pPopRange->header.transform.translation.z );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ( ( subCommand == "targetinfo" ) || ( subCommand == "tinfo" ) || subCommand == "ti" )
|
||||||
|
{
|
||||||
|
if( auto target = player.lookupTargetById( player.getTargetId() ) )
|
||||||
|
{
|
||||||
|
if( auto bnpc = target->getAsBNpc() )
|
||||||
|
{
|
||||||
|
player.sendNotice( "BNpcBaseId: {}, BNpcNameId, {}", bnpc->getBNpcBaseId(), bnpc->getBNpcNameId() );
|
||||||
|
}
|
||||||
|
//else if
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
player.sendUrgent( "{0} is not a valid GET command.", subCommand );
|
player.sendUrgent( "{0} is not a valid GET command.", subCommand );
|
||||||
|
|
|
@ -45,7 +45,7 @@ void Sapphire::Network::GameConnection::actionHandler( const Packets::FFXIVARR_P
|
||||||
if( !action )
|
if( !action )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
actionMgr.handleTargetedPlayerAction( player, actionId, action, targetId, sequence );
|
actionMgr.handleTargetedAction( player, actionId, action, targetId, sequence );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,5 +117,5 @@ void Sapphire::Network::GameConnection::placedActionHandler( const Packets::FFXI
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
|
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
|
||||||
actionMgr.handlePlacedPlayerAction( player, actionId, action, pos, sequence );
|
actionMgr.handlePlacedAction( player, actionId, action, pos, sequence );
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,6 +172,26 @@ namespace Sapphire::ScriptAPI
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BattleNpcScript::onInit( Entity::BNpc& bnpc )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleNpcScript::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleNpcScript::onHateListAdd( Entity::BNpc& bnpc, Entity::Chara& target )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleNpcScript::onHateListRemove( Entity::BNpc& bnpc, Entity::Chara& target )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleNpcScript::onDeath( Entity::BNpc& bnpc )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
ZoneScript::ZoneScript( uint32_t zoneId ) :
|
ZoneScript::ZoneScript( uint32_t zoneId ) :
|
||||||
|
|
|
@ -201,6 +201,16 @@ namespace Sapphire::ScriptAPI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit BattleNpcScript( uint32_t npcId );
|
explicit BattleNpcScript( uint32_t npcId );
|
||||||
|
|
||||||
|
virtual void onInit( Entity::BNpc& bnpc );
|
||||||
|
|
||||||
|
virtual void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||||
|
|
||||||
|
virtual void onHateListAdd( Entity::BNpc& bnpc, Entity::Chara& target );
|
||||||
|
|
||||||
|
virtual void onHateListRemove( Entity::BNpc& bnpc, Entity::Chara& target );
|
||||||
|
|
||||||
|
virtual void onDeath( Entity::BNpc& bnpc );
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "Territory/QuestBattle.h"
|
#include "Territory/QuestBattle.h"
|
||||||
#include "Territory/PublicContent.h"
|
#include "Territory/PublicContent.h"
|
||||||
#include "Actor/Player.h"
|
#include "Actor/Player.h"
|
||||||
|
#include "Actor/BNpc.h"
|
||||||
#include "Actor/EventObject.h"
|
#include "Actor/EventObject.h"
|
||||||
#include "ServerMgr.h"
|
#include "ServerMgr.h"
|
||||||
#include "Event/EventHandler.h"
|
#include "Event/EventHandler.h"
|
||||||
|
@ -652,3 +653,63 @@ bool Sapphire::Scripting::ScriptMgr::onPublicContentEnterTerritory( PublicConten
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Scripting::ScriptMgr::onBNpcInit( Entity::BNpc& bnpc )
|
||||||
|
{
|
||||||
|
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::BattleNpcScript >( bnpc.getBNpcBaseId() );
|
||||||
|
if( script )
|
||||||
|
{
|
||||||
|
script->onInit( bnpc );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Scripting::ScriptMgr::onBNpcUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||||
|
{
|
||||||
|
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::BattleNpcScript >( bnpc.getBNpcBaseId() );
|
||||||
|
if( script )
|
||||||
|
{
|
||||||
|
script->onUpdate( bnpc, tickCount );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Scripting::ScriptMgr::onBNpcHateListAdd( Entity::BNpc& bnpc, Entity::Chara& target )
|
||||||
|
{
|
||||||
|
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::BattleNpcScript >( bnpc.getBNpcBaseId() );
|
||||||
|
if( script )
|
||||||
|
{
|
||||||
|
script->onHateListAdd( bnpc, target );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Scripting::ScriptMgr::onBNpcHateListRemove( Entity::BNpc& bnpc, Entity::Chara& target )
|
||||||
|
{
|
||||||
|
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::BattleNpcScript >( bnpc.getBNpcBaseId() );
|
||||||
|
if( script )
|
||||||
|
{
|
||||||
|
script->onHateListRemove( bnpc, target );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Scripting::ScriptMgr::onBNpcDeath( Entity::BNpc& bnpc )
|
||||||
|
{
|
||||||
|
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::BattleNpcScript >( bnpc.getBNpcBaseId() );
|
||||||
|
if( script )
|
||||||
|
{
|
||||||
|
script->onDeath( bnpc );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -130,6 +130,16 @@ namespace Sapphire::Scripting
|
||||||
|
|
||||||
bool onPublicContentEnterTerritory( PublicContentPtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 );
|
bool onPublicContentEnterTerritory( PublicContentPtr instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 );
|
||||||
|
|
||||||
|
bool onBNpcInit( Entity::BNpc& bnpc );
|
||||||
|
|
||||||
|
bool onBNpcUpdate( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||||
|
|
||||||
|
bool onBNpcHateListAdd( Entity::BNpc& bnpc, Entity::Chara& target );
|
||||||
|
|
||||||
|
bool onBNpcHateListRemove( Entity::BNpc& bnpc, Entity::Chara& target );
|
||||||
|
|
||||||
|
bool onBNpcDeath( Entity::BNpc& bnpc );
|
||||||
|
|
||||||
bool loadDir( const std::string& dirname, std::set< std::string >& files, const std::string& ext );
|
bool loadDir( const std::string& dirname, std::set< std::string >& files, const std::string& ext );
|
||||||
|
|
||||||
NativeScriptMgr& getNativeScriptHandler();
|
NativeScriptMgr& getNativeScriptHandler();
|
||||||
|
|
Loading…
Add table
Reference in a new issue