mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 06:47: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
|
||||
};
|
||||
|
||||
enum CastType : uint8_t
|
||||
{
|
||||
SingleTarget = 1,
|
||||
CircularAOE = 2,
|
||||
RectangularAOE = 4,
|
||||
};
|
||||
|
||||
using PlayerStateFlagList = std::vector< PlayerStateFlag >;
|
||||
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ foreach(_scriptDir ${children})
|
|||
MODULE
|
||||
${SCRIPT_BUILD_FILES}
|
||||
"${SCRIPT_INCLUDE_FILES}"
|
||||
"${_scriptDir}/ScriptLoader.cpp" )
|
||||
"${_scriptDir}/ScriptLoader.cpp" action/darkknight/ActionUnleash3621.cpp action/darkknight/ActionUnleash3621.h)
|
||||
|
||||
target_link_libraries( "script_${_name}" world )
|
||||
|
||||
|
|
|
@ -14,7 +14,10 @@ public:
|
|||
|
||||
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/ActorControlPacket144.h"
|
||||
#include <Network/PacketWrappers/EffectPacket.h>
|
||||
#include <Logging/Logger.h>
|
||||
#include <Util/ActorFilter.h>
|
||||
|
||||
using namespace Sapphire::Common;
|
||||
using namespace Sapphire::Network;
|
||||
|
@ -69,8 +71,17 @@ bool Sapphire::Action::Action::init()
|
|||
m_cooldownGroup = m_actionData->cooldownGroup;
|
||||
m_range = m_actionData->range;
|
||||
m_effectRange = m_actionData->effectRange;
|
||||
m_castType = static_cast< Common::CastType >( m_actionData->castType );
|
||||
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
|
||||
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
|
||||
|
||||
addDefaultActorFilters();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -297,8 +310,14 @@ void Sapphire::Action::Action::execute()
|
|||
|
||||
if( !hasClientsideTarget() )
|
||||
{
|
||||
snapshotAffectedActors( m_hitActors );
|
||||
|
||||
if( !m_hitActors.empty() )
|
||||
{
|
||||
// only call script if actors are hit
|
||||
pScriptMgr->onExecute( *this );
|
||||
}
|
||||
}
|
||||
else if( auto player = m_pSource->getAsPlayer() )
|
||||
{
|
||||
pScriptMgr->onEObjHit( *player, m_targetId, getId() );
|
||||
|
@ -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()
|
||||
{
|
||||
if( auto player = m_pSource->getAsPlayer() )
|
||||
|
@ -491,3 +474,101 @@ bool Sapphire::Action::Action::consumeResources()
|
|||
{
|
||||
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_
|
||||
|
||||
#include <Common.h>
|
||||
#include "Util/ActorFilter.h"
|
||||
#include "ForwardsZone.h"
|
||||
|
||||
namespace Sapphire::Data
|
||||
|
@ -76,6 +77,34 @@ namespace Sapphire::Action
|
|||
*/
|
||||
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).
|
||||
*/
|
||||
|
@ -108,6 +137,8 @@ namespace Sapphire::Action
|
|||
|
||||
bool playerPrecheck( Entity::Player& player );
|
||||
|
||||
bool preFilterActor( Entity::Actor& actor ) const;
|
||||
|
||||
uint32_t m_id;
|
||||
|
||||
Common::ActionPrimaryCostType m_primaryCostType;
|
||||
|
@ -119,7 +150,9 @@ namespace Sapphire::Action
|
|||
uint8_t m_cooldownGroup;
|
||||
int8_t m_range;
|
||||
uint8_t m_effectRange;
|
||||
uint8_t m_xAxisModifier;
|
||||
Common::ActionAspect m_aspect;
|
||||
Common::CastType m_castType;
|
||||
|
||||
uint32_t m_additionalData;
|
||||
|
||||
|
@ -127,12 +160,21 @@ namespace Sapphire::Action
|
|||
Entity::CharaPtr m_pTarget;
|
||||
uint64_t m_targetId;
|
||||
|
||||
bool m_canTargetSelf;
|
||||
bool m_canTargetParty;
|
||||
bool m_canTargetFriendly;
|
||||
bool m_canTargetHostile;
|
||||
bool m_canTargetDead;
|
||||
|
||||
Common::ActionInterruptType m_interruptType;
|
||||
|
||||
FrameworkPtr m_pFw;
|
||||
Data::ActionPtr m_actionData;
|
||||
|
||||
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() );
|
||||
|
||||
action->setTargetId( targetId );
|
||||
|
||||
if( player.getId() == targetId )
|
||||
action->setPos( player.getPos() );
|
||||
|
||||
if( !action->init() )
|
||||
return;
|
||||
|
||||
|
@ -55,8 +60,6 @@ void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& play
|
|||
return;
|
||||
}
|
||||
|
||||
action->setTargetId( targetId );
|
||||
|
||||
bootstrapAction( player, action, *actionData );
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,8 @@ Sapphire::World::Session::Session( uint32_t sessionId, FrameworkPtr pFw ) :
|
|||
m_lastDataTime( Util::getTimeSeconds() ),
|
||||
m_lastSqlTime( Util::getTimeSeconds() ),
|
||||
m_isValid( false ),
|
||||
m_pFw( pFw )
|
||||
{
|
||||
}
|
||||
|
||||
Sapphire::World::Session::~Session()
|
||||
m_pFw( std::move( pFw ) ),
|
||||
m_isReplaying( false )
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Sapphire::World
|
|||
public:
|
||||
Session( uint32_t sessionId, FrameworkPtr pFw );
|
||||
|
||||
~Session();
|
||||
~Session() = default;
|
||||
|
||||
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 )
|
||||
{
|
||||
return Sapphire::Util::distance( m_startPos.x, m_startPos.y, m_startPos.z,
|
||||
actor.getPos().x, actor.getPos().y, actor.getPos().z ) <= m_range;
|
||||
return Sapphire::Util::distance( m_startPos, actor.getPos() ) <= 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
|
||||
{
|
||||
|
||||
class ActorFilter
|
||||
{
|
||||
public:
|
||||
|
@ -18,6 +17,8 @@ namespace Sapphire::World::Util
|
|||
virtual bool conditionApplies( const Entity::Actor& actor ) = 0;
|
||||
};
|
||||
|
||||
using ActorFilterPtr = std::shared_ptr< ActorFilter >;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ActorFilterInRange : public ActorFilter
|
||||
|
@ -29,18 +30,15 @@ namespace Sapphire::World::Util
|
|||
bool conditionApplies( const Entity::Actor& actor ) override;
|
||||
};
|
||||
|
||||
// usage in psudocode
|
||||
//
|
||||
// std::set< ActorPtr > filterActorList( inputSet, filter )
|
||||
// {
|
||||
// std::set< ActorPtr > resultSet;
|
||||
// for( every actor in inputSet )
|
||||
// {
|
||||
// if( filter.conditionApplies( actor ) )
|
||||
// resultSet.insert( actor.asPointer() );
|
||||
// }
|
||||
// return resultSet;
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class ActorFilterSingleTarget : public ActorFilter
|
||||
{
|
||||
uint32_t m_actorId;
|
||||
public:
|
||||
explicit ActorFilterSingleTarget( uint32_t actorId );
|
||||
bool conditionApplies( const Entity::Actor& actor ) override;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue