2019-02-03 19:38:04 +11:00
|
|
|
#include "ActionMgr.h"
|
|
|
|
|
2019-02-09 14:45:22 +11:00
|
|
|
#include "Action/Action.h"
|
|
|
|
#include "Script/ScriptMgr.h"
|
|
|
|
#include "Actor/Player.h"
|
|
|
|
|
|
|
|
#include <Exd/ExdDataGenerated.h>
|
2019-02-09 18:02:11 +11:00
|
|
|
#include "Framework.h"
|
2019-02-09 14:45:22 +11:00
|
|
|
|
2019-02-09 21:48:42 +11:00
|
|
|
#include <Network/PacketWrappers/EffectPacket.h>
|
|
|
|
|
2019-02-03 19:38:04 +11:00
|
|
|
using namespace Sapphire;
|
|
|
|
|
|
|
|
World::Manager::ActionMgr::ActionMgr( Sapphire::FrameworkPtr pFw ) :
|
|
|
|
BaseManager( pFw )
|
|
|
|
{
|
|
|
|
|
2019-02-03 19:57:04 +11:00
|
|
|
}
|
|
|
|
|
2019-02-09 19:26:31 +11:00
|
|
|
void World::Manager::ActionMgr::handleAoEPlayerAction( Entity::Player& player, uint32_t actionId,
|
|
|
|
Data::ActionPtr actionData, Common::FFXIVARR_POSITION3 pos )
|
2019-02-03 19:57:04 +11:00
|
|
|
{
|
2019-02-09 15:39:05 +11:00
|
|
|
player.sendDebug( "got aoe act: {0}", actionData->name );
|
2019-02-09 18:02:11 +11:00
|
|
|
|
|
|
|
auto action = Action::make_Action( player.getAsPlayer(), actionId, actionData, framework() );
|
2019-02-09 18:32:10 +11:00
|
|
|
action->setPos( pos );
|
|
|
|
|
|
|
|
bootstrapAction( player, action, *actionData );
|
2019-02-03 19:57:04 +11:00
|
|
|
}
|
|
|
|
|
2019-02-09 19:26:31 +11:00
|
|
|
void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& player, uint32_t actionId,
|
|
|
|
Data::ActionPtr actionData, uint64_t targetId )
|
2019-02-03 19:57:04 +11:00
|
|
|
{
|
2019-02-09 15:39:05 +11:00
|
|
|
player.sendDebug( "got act: {0}", actionData->name );
|
|
|
|
|
2019-02-09 15:45:02 +11:00
|
|
|
auto action = Action::make_Action( player.getAsPlayer(), actionId, actionData, framework() );
|
2019-02-09 15:39:05 +11:00
|
|
|
|
2019-02-09 23:54:49 +11:00
|
|
|
if( targetId != player.getId() )
|
|
|
|
{
|
|
|
|
auto target = player.lookupTargetById( targetId );
|
2019-02-10 22:13:47 +11:00
|
|
|
if( !target )
|
|
|
|
{
|
|
|
|
// an eobj?
|
|
|
|
player.sendDebug( "Unable to find actor for targetId#{0}, passing through to event scripts...", targetId );
|
|
|
|
action->setResidentTargetId( targetId );
|
|
|
|
}
|
|
|
|
else if( auto chara = target->getAsChara() )
|
|
|
|
{
|
2019-02-09 23:54:49 +11:00
|
|
|
action->setTargetChara( chara );
|
2019-02-10 22:13:47 +11:00
|
|
|
}
|
2019-02-09 23:54:49 +11:00
|
|
|
}
|
|
|
|
|
2019-02-09 15:39:05 +11:00
|
|
|
bootstrapAction( player, action, *actionData );
|
|
|
|
}
|
|
|
|
|
2019-02-10 19:50:28 +11:00
|
|
|
void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& player, uint32_t itemId,
|
|
|
|
Data::ItemActionPtr itemActionData,
|
|
|
|
uint16_t itemSourceSlot, uint16_t itemSourceContainer )
|
2019-02-09 19:26:31 +11:00
|
|
|
{
|
2019-02-10 19:50:28 +11:00
|
|
|
player.sendDebug( "got item act: {0}, slot: {1}, container: {2}", itemId, itemSourceSlot, itemSourceContainer );
|
|
|
|
|
|
|
|
// todo: check we have item & remove item from inventory
|
2019-02-09 21:48:42 +11:00
|
|
|
|
|
|
|
switch( itemActionData->type )
|
|
|
|
{
|
|
|
|
default:
|
2019-02-09 22:45:29 +11:00
|
|
|
{
|
|
|
|
player.sendDebug( "ItemAction type {0} not supported.", itemActionData->type );
|
|
|
|
break;
|
|
|
|
}
|
2019-02-09 21:48:42 +11:00
|
|
|
|
|
|
|
case Common::ItemActionType::ItemActionVFX:
|
|
|
|
{
|
|
|
|
handleItemActionVFX( player, itemId, itemActionData->data[ 0 ] );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-02-09 19:26:31 +11:00
|
|
|
}
|
|
|
|
|
2019-02-09 15:39:05 +11:00
|
|
|
void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player,
|
|
|
|
Action::ActionPtr currentAction,
|
|
|
|
Data::Action& actionData )
|
|
|
|
{
|
|
|
|
if( !canPlayerUseAction( player, *currentAction, actionData ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// instantly cast and finish actions that have no cast time
|
|
|
|
// not worth adding it to the player
|
|
|
|
// todo: what do in cases of swiftcast/etc? script callback?
|
|
|
|
if( !currentAction->isCastedAction() )
|
|
|
|
{
|
|
|
|
currentAction->start();
|
|
|
|
currentAction->onFinish();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// otherwise, set the action on the player and start it
|
|
|
|
player.setCurrentAction( currentAction );
|
|
|
|
currentAction->start();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool World::Manager::ActionMgr::canPlayerUseAction( Entity::Player& player,
|
|
|
|
Action::Action& currentAction,
|
|
|
|
Data::Action& actionData )
|
|
|
|
{
|
|
|
|
// lol
|
|
|
|
if( !player.isAlive() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// npc actions/non player actions
|
|
|
|
if( actionData.classJob == -1 )
|
|
|
|
return false;
|
|
|
|
|
2019-02-09 18:02:11 +11:00
|
|
|
if( player.getLevel() < actionData.classJobLevel )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if( player.getClass() != static_cast< Common::ClassJob >( actionData.classJob ) )
|
|
|
|
{
|
|
|
|
// check if not a base class action
|
|
|
|
auto exdData = framework()->get< Data::ExdDataGenerated >();
|
|
|
|
assert( exdData );
|
|
|
|
|
|
|
|
auto classJob = exdData->get< Data::ClassJob >( static_cast< uint8_t >( player.getClass() ) );
|
|
|
|
if( !classJob )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if( classJob->classJobParent != actionData.classJob )
|
|
|
|
return false;
|
|
|
|
}
|
2019-02-09 15:39:05 +11:00
|
|
|
|
2019-02-09 23:54:49 +11:00
|
|
|
auto& actionCost = currentAction.getCostArray();
|
|
|
|
for( uint8_t i = 0; i < actionCost.size(); ++i )
|
|
|
|
{
|
|
|
|
// todo: validate costs/conditionals here
|
|
|
|
}
|
2019-02-09 15:39:05 +11:00
|
|
|
|
|
|
|
return true;
|
2019-02-09 21:48:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
void World::Manager::ActionMgr::handleItemActionVFX( Sapphire::Entity::Player& player, uint32_t itemId, uint16_t vfxId )
|
|
|
|
{
|
|
|
|
Common::EffectEntry effect{};
|
|
|
|
effect.effectType = Common::ActionEffectType::VFX;
|
|
|
|
effect.value = vfxId;
|
|
|
|
|
|
|
|
auto effectPacket = std::make_shared< Network::Packets::Server::EffectPacket >( player.getId(), player.getId(), itemId );
|
|
|
|
effectPacket->setTargetActor( player.getId() );
|
|
|
|
effectPacket->setAnimationId( Common::ItemActionType::ItemActionVFX );
|
|
|
|
effectPacket->setDisplayType( Common::ActionEffectDisplayType::ShowItemName );
|
|
|
|
effectPacket->addEffect( effect );
|
|
|
|
|
|
|
|
player.sendToInRangeSet( effectPacket, true );
|
2019-02-03 19:38:04 +11:00
|
|
|
}
|