mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 22:57:45 +00:00
Start of action target selection implementation
This commit is contained in:
parent
4e4ab53381
commit
1b49f2502d
12 changed files with 229 additions and 63 deletions
|
@ -972,6 +972,13 @@ namespace Sapphire::Common
|
||||||
THREAT
|
THREAT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CastType : uint8_t
|
||||||
|
{
|
||||||
|
SingleTarget = 1,
|
||||||
|
CircularAOE = 2,
|
||||||
|
RectangularAOE = 4,
|
||||||
|
};
|
||||||
|
|
||||||
using PlayerStateFlagList = std::vector< PlayerStateFlag >;
|
using PlayerStateFlagList = std::vector< PlayerStateFlag >;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ foreach(_scriptDir ${children})
|
||||||
MODULE
|
MODULE
|
||||||
${SCRIPT_BUILD_FILES}
|
${SCRIPT_BUILD_FILES}
|
||||||
"${SCRIPT_INCLUDE_FILES}"
|
"${SCRIPT_INCLUDE_FILES}"
|
||||||
"${_scriptDir}/ScriptLoader.cpp" )
|
"${_scriptDir}/ScriptLoader.cpp" action/darkknight/ActionUnleash3621.cpp action/darkknight/ActionUnleash3621.h)
|
||||||
|
|
||||||
target_link_libraries( "script_${_name}" world )
|
target_link_libraries( "script_${_name}" world )
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,10 @@ public:
|
||||||
|
|
||||||
void onExecute( Sapphire::Action::Action& action ) override
|
void onExecute( Sapphire::Action::Action& action ) override
|
||||||
{
|
{
|
||||||
|
for( auto& chara : action.getHitActors() )
|
||||||
|
{
|
||||||
|
chara->setHp( chara->getHp() - chara->getMaxHp() * 0.34f );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
24
src/scripts/action/darkknight/ActionUnleash3621.cpp
Normal file
24
src/scripts/action/darkknight/ActionUnleash3621.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <Script/NativeScriptApi.h>
|
||||||
|
#include <ScriptObject.h>
|
||||||
|
#include <Actor/Player.h>
|
||||||
|
#include <Action/Action.h>
|
||||||
|
|
||||||
|
class ActionUnleash3621 :
|
||||||
|
public Sapphire::ScriptAPI::ActionScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActionUnleash3621() :
|
||||||
|
Sapphire::ScriptAPI::ActionScript( 3621 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onExecute( Sapphire::Action::Action& action ) override
|
||||||
|
{
|
||||||
|
for( auto& chara : action.getHitActors() )
|
||||||
|
{
|
||||||
|
chara->setHp( chara->getHp() - chara->getMaxHp() * 0.34f );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPOSE_SCRIPT( ActionUnleash3621 );
|
|
@ -17,6 +17,8 @@
|
||||||
#include "Network/PacketWrappers/ActorControlPacket143.h"
|
#include "Network/PacketWrappers/ActorControlPacket143.h"
|
||||||
#include "Network/PacketWrappers/ActorControlPacket144.h"
|
#include "Network/PacketWrappers/ActorControlPacket144.h"
|
||||||
#include <Network/PacketWrappers/EffectPacket.h>
|
#include <Network/PacketWrappers/EffectPacket.h>
|
||||||
|
#include <Logging/Logger.h>
|
||||||
|
#include <Util/ActorFilter.h>
|
||||||
|
|
||||||
using namespace Sapphire::Common;
|
using namespace Sapphire::Common;
|
||||||
using namespace Sapphire::Network;
|
using namespace Sapphire::Network;
|
||||||
|
@ -69,8 +71,17 @@ bool Sapphire::Action::Action::init()
|
||||||
m_cooldownGroup = m_actionData->cooldownGroup;
|
m_cooldownGroup = m_actionData->cooldownGroup;
|
||||||
m_range = m_actionData->range;
|
m_range = m_actionData->range;
|
||||||
m_effectRange = m_actionData->effectRange;
|
m_effectRange = m_actionData->effectRange;
|
||||||
|
m_castType = static_cast< Common::CastType >( m_actionData->castType );
|
||||||
m_aspect = static_cast< Common::ActionAspect >( m_actionData->aspect );
|
m_aspect = static_cast< Common::ActionAspect >( m_actionData->aspect );
|
||||||
|
|
||||||
|
// todo: move this to bitset
|
||||||
|
m_canTargetSelf = m_actionData->canTargetSelf;
|
||||||
|
m_canTargetParty = m_actionData->canTargetParty;
|
||||||
|
m_canTargetFriendly = m_actionData->canTargetFriendly;
|
||||||
|
m_canTargetHostile = m_actionData->canTargetHostile;
|
||||||
|
// todo: this one doesn't look right based on whats in that col, probably has shifted
|
||||||
|
m_canTargetDead = m_actionData->canTargetDead;
|
||||||
|
|
||||||
// a default range is set by the game for the class/job
|
// a default range is set by the game for the class/job
|
||||||
if( m_range == -1 )
|
if( m_range == -1 )
|
||||||
{
|
{
|
||||||
|
@ -91,6 +102,8 @@ bool Sapphire::Action::Action::init()
|
||||||
|
|
||||||
// todo: add missing rows for secondaryCostType/secondaryCostType and rename the current rows to primaryCostX
|
// todo: add missing rows for secondaryCostType/secondaryCostType and rename the current rows to primaryCostX
|
||||||
|
|
||||||
|
addDefaultActorFilters();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +310,13 @@ void Sapphire::Action::Action::execute()
|
||||||
|
|
||||||
if( !hasClientsideTarget() )
|
if( !hasClientsideTarget() )
|
||||||
{
|
{
|
||||||
pScriptMgr->onExecute( *this );
|
snapshotAffectedActors( m_hitActors );
|
||||||
|
|
||||||
|
if( !m_hitActors.empty() )
|
||||||
|
{
|
||||||
|
// only call script if actors are hit
|
||||||
|
pScriptMgr->onExecute( *this );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if( auto player = m_pSource->getAsPlayer() )
|
else if( auto player = m_pSource->getAsPlayer() )
|
||||||
{
|
{
|
||||||
|
@ -313,42 +332,6 @@ void Sapphire::Action::Action::execute()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Action::Action::calculateActionCost()
|
|
||||||
{
|
|
||||||
// todo: just a test handler for now to get MP output for each cast, not sure where we should put this
|
|
||||||
// check primary cost
|
|
||||||
switch( m_primaryCostType )
|
|
||||||
{
|
|
||||||
case ActionPrimaryCostType::None:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ActionPrimaryCostType::MagicPoints:
|
|
||||||
{
|
|
||||||
// todo: not sure if we should store the final value like this?
|
|
||||||
m_primaryCost = Math::CalcStats::calculateMpCost( *m_pSource, m_primaryCost );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ActionPrimaryCostType::TacticsPoints:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if( auto player = m_pSource->getAsPlayer() )
|
|
||||||
{
|
|
||||||
player->sendDebug( "action#{0} is missing a handler for cost type: {1}",
|
|
||||||
m_id, static_cast< uint8_t >( m_primaryCostType ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: secondary cost type needs to be handled
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Sapphire::Action::Action::precheck()
|
bool Sapphire::Action::Action::precheck()
|
||||||
{
|
{
|
||||||
if( auto player = m_pSource->getAsPlayer() )
|
if( auto player = m_pSource->getAsPlayer() )
|
||||||
|
@ -491,3 +474,101 @@ bool Sapphire::Action::Action::consumeResources()
|
||||||
{
|
{
|
||||||
return primaryCostCheck( true ) && secondaryCostCheck( true );
|
return primaryCostCheck( true ) && secondaryCostCheck( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Action::Action::snapshotAffectedActors( std::vector< Entity::CharaPtr >& actors )
|
||||||
|
{
|
||||||
|
for( const auto& actor : m_pSource->getInRangeActors() )
|
||||||
|
{
|
||||||
|
// check for initial target validity based on flags in action exd (pc/enemy/etc.)
|
||||||
|
if( !preFilterActor( *actor ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for( const auto& filter : m_actorFilters )
|
||||||
|
{
|
||||||
|
if( filter->conditionApplies( *actor ) )
|
||||||
|
{
|
||||||
|
actors.push_back( actor->getAsChara() );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( auto player = m_pSource->getAsPlayer() )
|
||||||
|
{
|
||||||
|
player->sendDebug( "Hit {} actors with {} filters", actors.size(), m_actorFilters.size() );
|
||||||
|
for( const auto& actor : actors )
|
||||||
|
{
|
||||||
|
player->sendDebug( "hit actor#{}", actor->getId() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Action::Action::addActorFilter( World::Util::ActorFilterPtr filter )
|
||||||
|
{
|
||||||
|
m_actorFilters.push_back( std::move( filter ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Action::Action::addDefaultActorFilters()
|
||||||
|
{
|
||||||
|
switch( m_castType )
|
||||||
|
{
|
||||||
|
case Common::CastType::SingleTarget:
|
||||||
|
{
|
||||||
|
auto filter = std::make_shared< World::Util::ActorFilterSingleTarget >( static_cast< uint32_t >( m_targetId ) );
|
||||||
|
|
||||||
|
addActorFilter( filter );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Common::CastType::CircularAOE:
|
||||||
|
{
|
||||||
|
auto filter = std::make_shared< World::Util::ActorFilterInRange >( m_pos, m_effectRange );
|
||||||
|
|
||||||
|
addActorFilter( filter );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case Common::CastType::RectangularAOE:
|
||||||
|
// {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
Logger::error( "[{}] Action#{} has CastType#{} but that cast type is unhandled. Cancelling cast.",
|
||||||
|
m_pSource->getId(), getId(), m_castType );
|
||||||
|
|
||||||
|
interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Action::Action::preFilterActor( Sapphire::Entity::Actor& actor ) const
|
||||||
|
{
|
||||||
|
auto kind = actor.getObjKind();
|
||||||
|
|
||||||
|
// todo: are there any server side eobjs that players can hit?
|
||||||
|
if( kind != ObjKind::BattleNpc && kind != ObjKind::Player )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// todo: handle things such based on canTargetX
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< Sapphire::Entity::CharaPtr >& Sapphire::Action::Action::getHitActors()
|
||||||
|
{
|
||||||
|
return m_hitActors;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sapphire::Entity::CharaPtr Sapphire::Action::Action::getHitActor()
|
||||||
|
{
|
||||||
|
if( !m_hitActors.empty() )
|
||||||
|
{
|
||||||
|
return m_hitActors.at( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#define _ACTION_H_
|
#define _ACTION_H_
|
||||||
|
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
|
#include "Util/ActorFilter.h"
|
||||||
#include "ForwardsZone.h"
|
#include "ForwardsZone.h"
|
||||||
|
|
||||||
namespace Sapphire::Data
|
namespace Sapphire::Data
|
||||||
|
@ -76,6 +77,34 @@ namespace Sapphire::Action
|
||||||
*/
|
*/
|
||||||
bool precheck();
|
bool precheck();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Snapshots characters affected by a cast.
|
||||||
|
* @param filters A vector of filters to be applied to the in range set of the caster
|
||||||
|
* @param actors Actors that match the filters are copied here
|
||||||
|
* @return true if actors are hit
|
||||||
|
*/
|
||||||
|
bool snapshotAffectedActors( std::vector< Entity::CharaPtr >& actors );
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Adds an actor filter to this action.
|
||||||
|
* @param filter The ptr to the ActorFilter to add
|
||||||
|
*/
|
||||||
|
void addActorFilter( World::Util::ActorFilterPtr filter );
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Adds the default actor filters based on the CastType entry in the Action exd.
|
||||||
|
*/
|
||||||
|
void addDefaultActorFilters();
|
||||||
|
|
||||||
|
|
||||||
|
std::vector< Entity::CharaPtr >& getHitActors();
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief Returns the first hit actor inside the m_hitActors vector.
|
||||||
|
* @return The CharaPtr otherwise nullptr
|
||||||
|
*/
|
||||||
|
Entity::CharaPtr getHitActor();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Starts the cast. Finishes it immediately if there is no cast time (weaponskills).
|
* @brief Starts the cast. Finishes it immediately if there is no cast time (weaponskills).
|
||||||
*/
|
*/
|
||||||
|
@ -108,6 +137,8 @@ namespace Sapphire::Action
|
||||||
|
|
||||||
bool playerPrecheck( Entity::Player& player );
|
bool playerPrecheck( Entity::Player& player );
|
||||||
|
|
||||||
|
bool preFilterActor( Entity::Actor& actor ) const;
|
||||||
|
|
||||||
uint32_t m_id;
|
uint32_t m_id;
|
||||||
|
|
||||||
Common::ActionPrimaryCostType m_primaryCostType;
|
Common::ActionPrimaryCostType m_primaryCostType;
|
||||||
|
@ -119,7 +150,9 @@ namespace Sapphire::Action
|
||||||
uint8_t m_cooldownGroup;
|
uint8_t m_cooldownGroup;
|
||||||
int8_t m_range;
|
int8_t m_range;
|
||||||
uint8_t m_effectRange;
|
uint8_t m_effectRange;
|
||||||
|
uint8_t m_xAxisModifier;
|
||||||
Common::ActionAspect m_aspect;
|
Common::ActionAspect m_aspect;
|
||||||
|
Common::CastType m_castType;
|
||||||
|
|
||||||
uint32_t m_additionalData;
|
uint32_t m_additionalData;
|
||||||
|
|
||||||
|
@ -127,12 +160,21 @@ namespace Sapphire::Action
|
||||||
Entity::CharaPtr m_pTarget;
|
Entity::CharaPtr m_pTarget;
|
||||||
uint64_t m_targetId;
|
uint64_t m_targetId;
|
||||||
|
|
||||||
|
bool m_canTargetSelf;
|
||||||
|
bool m_canTargetParty;
|
||||||
|
bool m_canTargetFriendly;
|
||||||
|
bool m_canTargetHostile;
|
||||||
|
bool m_canTargetDead;
|
||||||
|
|
||||||
Common::ActionInterruptType m_interruptType;
|
Common::ActionInterruptType m_interruptType;
|
||||||
|
|
||||||
FrameworkPtr m_pFw;
|
FrameworkPtr m_pFw;
|
||||||
Data::ActionPtr m_actionData;
|
Data::ActionPtr m_actionData;
|
||||||
|
|
||||||
Common::FFXIVARR_POSITION3 m_pos;
|
Common::FFXIVARR_POSITION3 m_pos;
|
||||||
|
|
||||||
|
std::vector< World::Util::ActorFilterPtr > m_actorFilters;
|
||||||
|
std::vector< Entity::CharaPtr > m_hitActors;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,11 @@ void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& play
|
||||||
{
|
{
|
||||||
auto action = Action::make_Action( player.getAsPlayer(), actionId, actionData, framework() );
|
auto action = Action::make_Action( player.getAsPlayer(), actionId, actionData, framework() );
|
||||||
|
|
||||||
|
action->setTargetId( targetId );
|
||||||
|
|
||||||
|
if( player.getId() == targetId )
|
||||||
|
action->setPos( player.getPos() );
|
||||||
|
|
||||||
if( !action->init() )
|
if( !action->init() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -55,8 +60,6 @@ void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& play
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
action->setTargetId( targetId );
|
|
||||||
|
|
||||||
bootstrapAction( player, action, *actionData );
|
bootstrapAction( player, action, *actionData );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,8 @@ Sapphire::World::Session::Session( uint32_t sessionId, FrameworkPtr pFw ) :
|
||||||
m_lastDataTime( Util::getTimeSeconds() ),
|
m_lastDataTime( Util::getTimeSeconds() ),
|
||||||
m_lastSqlTime( Util::getTimeSeconds() ),
|
m_lastSqlTime( Util::getTimeSeconds() ),
|
||||||
m_isValid( false ),
|
m_isValid( false ),
|
||||||
m_pFw( pFw )
|
m_pFw( std::move( pFw ) ),
|
||||||
{
|
m_isReplaying( false )
|
||||||
}
|
|
||||||
|
|
||||||
Sapphire::World::Session::~Session()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Sapphire::World
|
||||||
public:
|
public:
|
||||||
Session( uint32_t sessionId, FrameworkPtr pFw );
|
Session( uint32_t sessionId, FrameworkPtr pFw );
|
||||||
|
|
||||||
~Session();
|
~Session() = default;
|
||||||
|
|
||||||
void setZoneConnection( Network::GameConnectionPtr zoneCon );
|
void setZoneConnection( Network::GameConnectionPtr zoneCon );
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,19 @@ Sapphire::World::Util::ActorFilterInRange::ActorFilterInRange( Common::FFXIVARR_
|
||||||
|
|
||||||
bool Sapphire::World::Util::ActorFilterInRange::conditionApplies( const Entity::Actor& actor )
|
bool Sapphire::World::Util::ActorFilterInRange::conditionApplies( const Entity::Actor& actor )
|
||||||
{
|
{
|
||||||
return Sapphire::Util::distance( m_startPos.x, m_startPos.y, m_startPos.z,
|
return Sapphire::Util::distance( m_startPos, actor.getPos() ) <= m_range;
|
||||||
actor.getPos().x, actor.getPos().y, actor.getPos().z ) <= m_range;
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Sapphire::World::Util::ActorFilterSingleTarget::ActorFilterSingleTarget( uint32_t actorId ) :
|
||||||
|
m_actorId( actorId )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::World::Util::ActorFilterSingleTarget::conditionApplies( const Sapphire::Entity::Actor& actor )
|
||||||
|
{
|
||||||
|
return actor.getId() == m_actorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
namespace Sapphire::World::Util
|
namespace Sapphire::World::Util
|
||||||
{
|
{
|
||||||
|
|
||||||
class ActorFilter
|
class ActorFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -18,6 +17,8 @@ namespace Sapphire::World::Util
|
||||||
virtual bool conditionApplies( const Entity::Actor& actor ) = 0;
|
virtual bool conditionApplies( const Entity::Actor& actor ) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ActorFilterPtr = std::shared_ptr< ActorFilter >;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class ActorFilterInRange : public ActorFilter
|
class ActorFilterInRange : public ActorFilter
|
||||||
|
@ -29,18 +30,15 @@ namespace Sapphire::World::Util
|
||||||
bool conditionApplies( const Entity::Actor& actor ) override;
|
bool conditionApplies( const Entity::Actor& actor ) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// usage in psudocode
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
|
||||||
// std::set< ActorPtr > filterActorList( inputSet, filter )
|
class ActorFilterSingleTarget : public ActorFilter
|
||||||
// {
|
{
|
||||||
// std::set< ActorPtr > resultSet;
|
uint32_t m_actorId;
|
||||||
// for( every actor in inputSet )
|
public:
|
||||||
// {
|
explicit ActorFilterSingleTarget( uint32_t actorId );
|
||||||
// if( filter.conditionApplies( actor ) )
|
bool conditionApplies( const Entity::Actor& actor ) override;
|
||||||
// resultSet.insert( actor.asPointer() );
|
};
|
||||||
// }
|
|
||||||
// return resultSet;
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue