diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index e320cbfe..65cf285e 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -22,30 +22,39 @@ using namespace Sapphire::Network::ActorControl; Sapphire::Action::Action::Action() = default; Sapphire::Action::Action::~Action() = default; -Sapphire::Action::Action::Action( Entity::CharaPtr caster, Entity::CharaPtr target, - uint16_t actionId, FrameworkPtr fw ) : - +Sapphire::Action::Action::Action( Entity::CharaPtr caster, uint32_t actionId, + Data::ActionPtr action, FrameworkPtr fw ) : m_pSource( std::move( caster ) ), - m_pTarget( std::move( target ) ), m_pFw( std::move( fw ) ), m_id( actionId ), m_startTime( 0 ) { - auto exdData = m_pFw->get< Data::ExdDataGenerated >(); - assert( exdData ); - - auto actionData = exdData->get< Data::Action >( actionId ); - // todo: clients can crash the server here, ideally we do this check outside of the action anyway - assert( actionData ); - - m_castTime = actionData->cast100ms * 100; + m_castTime = static_cast< uint32_t >( action->cast100ms ) * 100; } -uint16_t Sapphire::Action::Action::getId() const +uint32_t Sapphire::Action::Action::getId() const { return m_id; } +Sapphire::Common::ActionType Sapphire::Action::Action::getType() const +{ + return m_type; +} + +void Sapphire::Action::Action::setType( Sapphire::Common::ActionType type ) +{ + m_type = type; +} + +void Sapphire::Action::Action::setTargetChara( Sapphire::Entity::CharaPtr chara ) +{ + assert( chara ); + + m_pTarget = chara; + m_targetId = chara->getId(); +} + Sapphire::Entity::CharaPtr Sapphire::Action::Action::getTargetChara() const { return m_pTarget; @@ -102,7 +111,7 @@ bool Sapphire::Action::Action::update() uint64_t currTime = Util::getTimeMs(); - if( ( currTime - m_startTime ) > m_castTime ) + if( !isCastedAction() || ( currTime - m_startTime ) > m_castTime ) { onFinish(); return true; @@ -117,7 +126,6 @@ void Sapphire::Action::Action::onStart() if( isCastedAction() ) { m_pSource->getAsPlayer()->sendDebug( "onStart()" ); - m_startTime = Util::getTimeMs(); auto castPacket = makeZonePacket< FFXIVIpcActorCast >( getId() ); @@ -125,7 +133,7 @@ void Sapphire::Action::Action::onStart() castPacket->data().skillType = Common::SkillType::Normal; castPacket->data().unknown_1 = m_id; // This is used for the cast bar above the target bar of the caster. - castPacket->data().cast_time = static_cast< float >( m_castTime / 1000.f ); + castPacket->data().cast_time = m_castTime / 1000.f; castPacket->data().target_id = m_pTarget->getId(); m_pSource->sendToInRangeSet( castPacket, true ); diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 9c2134e9..4448ab67 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -4,6 +4,12 @@ #include #include "ForwardsZone.h" +namespace Sapphire::Data +{ + struct Action; + using ActionPtr = std::shared_ptr< Action >; +} + namespace Sapphire::Action { @@ -12,12 +18,16 @@ namespace Sapphire::Action public: Action(); - Action( Entity::CharaPtr caster, Entity::CharaPtr target, uint16_t actionId, FrameworkPtr fw ); + Action( Entity::CharaPtr caster, uint32_t actionId, Data::ActionPtr action, FrameworkPtr fw ); virtual ~Action(); - uint16_t getId() const; + uint32_t getId() const; + Common::ActionType getType() const; + void setType( Common::ActionType type ); + + void setTargetChara( Entity::CharaPtr chara ); Entity::CharaPtr getTargetChara() const; Entity::CharaPtr getActionSource() const; @@ -43,13 +53,16 @@ namespace Sapphire::Action virtual bool update(); protected: - uint16_t m_id; + uint32_t m_id; + + Common::ActionType m_type; uint64_t m_startTime; uint32_t m_castTime; Entity::CharaPtr m_pSource; Entity::CharaPtr m_pTarget; + uint64_t m_targetId; bool m_bInterrupt; diff --git a/src/world/Manager/ActionMgr.cpp b/src/world/Manager/ActionMgr.cpp index cd066c59..45723cc9 100644 --- a/src/world/Manager/ActionMgr.cpp +++ b/src/world/Manager/ActionMgr.cpp @@ -16,13 +16,64 @@ World::Manager::ActionMgr::ActionMgr( Sapphire::FrameworkPtr pFw ) : } void World::Manager::ActionMgr::handleAoEPlayerAction( Entity::Player& player, uint8_t type, - Data::ActionPtr action, Common::FFXIVARR_POSITION3 pos ) + uint32_t actionId, Data::ActionPtr actionData, + Common::FFXIVARR_POSITION3 pos ) { - player.sendDebug( "got aoe act: {0}", action->name ); + player.sendDebug( "got aoe act: {0}", actionData->name ); } void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& player, uint8_t type, - Data::ActionPtr action, uint64_t targetId ) + uint32_t actionId, Data::ActionPtr actionData, uint64_t targetId ) { - player.sendDebug( "got act: {0}", action->name ); + player.sendDebug( "got act: {0}", actionData->name ); + + auto action = Action::make_Action( player.getAsPlayer(), nullptr, actionId, actionData, framework() ); + action->setType( static_cast< Common::ActionType >( type ) ); + + bootstrapAction( player, action, *actionData ); +} + +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; + + // todo: check class/job reqs + + // todo: min tp + // todo: min mp + + // todo: script callback for action conditionals? + + return true; } \ No newline at end of file diff --git a/src/world/Manager/ActionMgr.h b/src/world/Manager/ActionMgr.h index 0e06ce31..c40f5e8a 100644 --- a/src/world/Manager/ActionMgr.h +++ b/src/world/Manager/ActionMgr.h @@ -6,7 +6,7 @@ namespace Sapphire::Data { - class Action; + struct Action; using ActionPtr = std::shared_ptr< Action >; } @@ -18,8 +18,14 @@ namespace Sapphire::World::Manager explicit ActionMgr( FrameworkPtr pFw ); ~ActionMgr() = default; - void handleTargetedPlayerAction( Entity::Player& player, uint8_t type, Data::ActionPtr action, uint64_t targetId ); - void handleAoEPlayerAction( Entity::Player& player, uint8_t type, Data::ActionPtr action, Common::FFXIVARR_POSITION3 pos ); + void handleTargetedPlayerAction( Entity::Player& player, uint8_t type, uint32_t actionId, + Data::ActionPtr actionData, uint64_t targetId ); + void handleAoEPlayerAction( Entity::Player& player, uint8_t type, uint32_t actionId, + Data::ActionPtr actionData, Common::FFXIVARR_POSITION3 pos ); + + private: + void bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData ); + bool canPlayerUseAction( Entity::Player& player, Action::Action& currentAction, Data::Action& actionData ); }; } diff --git a/src/world/Network/Handlers/ActionHandler.cpp b/src/world/Network/Handlers/ActionHandler.cpp index 5ca1a98c..3283813c 100644 --- a/src/world/Network/Handlers/ActionHandler.cpp +++ b/src/world/Network/Handlers/ActionHandler.cpp @@ -35,7 +35,7 @@ void Sapphire::Network::GameConnection::actionHandler( FrameworkPtr pFw, return; auto actionMgr = pFw->get< World::Manager::ActionMgr >(); - actionMgr->handleTargetedPlayerAction( player, type, action, targetId ); + actionMgr->handleTargetedPlayerAction( player, type, actionId, action, targetId ); player.sendDebug( "Skill type: {0}, sequence: {1}, actionId: {2}, targetId: {3}", type, sequence, actionId, targetId ); } @@ -61,7 +61,7 @@ void Sapphire::Network::GameConnection::aoeActionHandler( FrameworkPtr pFw, return; auto actionMgr = pFw->get< World::Manager::ActionMgr >(); - actionMgr->handleAoEPlayerAction( player, type, action, pos ); + actionMgr->handleAoEPlayerAction( player, type, actionId, action, pos ); player.sendDebug( "Skill type: {0}, sequence: {1}, actionId: {2}, x:{3}, y:{4}, z:{5}", type, sequence, actionId, pos.x, pos.y, pos.z );