diff --git a/src/scripts/action/war/ActionChaoticCyclone16463.cpp b/src/scripts/action/war/ActionChaoticCyclone16463.cpp index 2cfed669..b3fa36bb 100644 --- a/src/scripts/action/war/ActionChaoticCyclone16463.cpp +++ b/src/scripts/action/war/ActionChaoticCyclone16463.cpp @@ -28,6 +28,7 @@ public: else { action.disableGenericHandler(); + action.interrupt(); } } }; diff --git a/src/scripts/action/war/ActionInnerChaos16465.cpp b/src/scripts/action/war/ActionInnerChaos16465.cpp index 08029571..18887e0c 100644 --- a/src/scripts/action/war/ActionInnerChaos16465.cpp +++ b/src/scripts/action/war/ActionInnerChaos16465.cpp @@ -28,6 +28,7 @@ public: else { action.disableGenericHandler(); + action.interrupt(); } } }; diff --git a/src/scripts/action/whm/ActionCureII135.cpp b/src/scripts/action/whm/ActionCureII135.cpp index 12b6603d..e240c505 100644 --- a/src/scripts/action/whm/ActionCureII135.cpp +++ b/src/scripts/action/whm/ActionCureII135.cpp @@ -29,7 +29,7 @@ public: } } - void onStart( Sapphire::World::Action::Action& action ) override + void onBeforePreCheck( Sapphire::World::Action::Action& action ) override { auto effectEntry = action.getSourceChara()->getStatusEffectById( STATUS_ID_FREECURE ); if( effectEntry.second ) diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 80ff6d9c..60c189b5 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -200,11 +200,6 @@ Common::ActionInterruptType Action::Action::getInterruptType() const return m_interruptType; } -void Action::Action::setInterrupted( Common::ActionInterruptType type ) -{ - m_interruptType = type; -} - uint32_t Action::Action::getCastTime() const { return m_castTimeMs; @@ -268,7 +263,6 @@ bool Action::Action::update() if( !m_pTarget->isAlive() ) { // interrupt the cast if target died - setInterrupted( Common::ActionInterruptType::RegularInterrupt ); interrupt(); return true; } @@ -319,15 +313,23 @@ void Action::Action::start() player->queuePacket( actionStartPkt ); } + auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >(); + pScriptMgr->onStart( *this ); + // instantly finish cast if there's no cast time if( !hasCastTime() ) execute(); } -void Action::Action::interrupt() +void Action::Action::interrupt( ActionInterruptType type ) { + if( isInterrupted() ) + return; + assert( m_pSource ); + m_interruptType = type; + // things that aren't players don't care about cooldowns and state flags if( m_pSource->isPlayer() ) { @@ -437,6 +439,9 @@ void Action::Action::buildEffects() pScriptMgr->onExecute( *this ); + if( isInterrupted() ) + return; + if( m_disableGenericHandler || !hasValidLutEntry() ) { // send any effect packet added by script or an empty one just to play animation for other players @@ -571,6 +576,12 @@ void Action::Action::buildEffects() bool Action::Action::preCheck() { + auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >(); + pScriptMgr->onBeforePreCheck( *this ); + + if( isInterrupted() ) + return false; + if( auto player = m_pSource->getAsPlayer() ) { if( !playerPreCheck( *player ) ) diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 716552f0..107897cb 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -41,7 +41,6 @@ namespace Sapphire::World::Action bool isInterrupted() const; Common::ActionInterruptType getInterruptType() const; - void setInterrupted( Common::ActionInterruptType type ); uint32_t getCastTime() const; void setCastTime( uint32_t castTime ); @@ -154,7 +153,7 @@ namespace Sapphire::World::Action * * m_interruptType will have the reason why the action was interrupted (eg. damage, movement, ...) */ - virtual void interrupt(); + virtual void interrupt( Common::ActionInterruptType type = Common::ActionInterruptType::RegularInterrupt ); /*! * @brief Called on each player update tick diff --git a/src/world/Action/EventAction.cpp b/src/world/Action/EventAction.cpp index 8c742ded..4b3d34c0 100644 --- a/src/world/Action/EventAction.cpp +++ b/src/world/Action/EventAction.cpp @@ -92,11 +92,13 @@ void Action::EventAction::execute() } -void Action::EventAction::interrupt() +void Action::EventAction::interrupt( Common::ActionInterruptType type ) { if( !m_pSource ) return; + m_interruptType = type; + try { diff --git a/src/world/Action/EventAction.h b/src/world/Action/EventAction.h index 4a9bb50a..6c997450 100644 --- a/src/world/Action/EventAction.h +++ b/src/world/Action/EventAction.h @@ -22,7 +22,7 @@ public: void execute() override; - void interrupt() override; + void interrupt( Common::ActionInterruptType type = Common::ActionInterruptType::None) override; private: uint32_t m_eventId; diff --git a/src/world/Action/ItemAction.cpp b/src/world/Action/ItemAction.cpp index efbef2f4..4f7e8c8d 100644 --- a/src/world/Action/ItemAction.cpp +++ b/src/world/Action/ItemAction.cpp @@ -51,7 +51,7 @@ void ItemAction::execute() } } -void ItemAction::interrupt() +void ItemAction::interrupt( Common::ActionInterruptType type ) { } diff --git a/src/world/Action/ItemAction.h b/src/world/Action/ItemAction.h index f0f7c24f..919df12f 100644 --- a/src/world/Action/ItemAction.h +++ b/src/world/Action/ItemAction.h @@ -22,7 +22,7 @@ namespace Sapphire::World::Action void execute() override; - void interrupt() override; + void interrupt( Common::ActionInterruptType type = Common::ActionInterruptType::None ) override; private: void handleVFXItem(); diff --git a/src/world/Manager/ActionMgr.cpp b/src/world/Manager/ActionMgr.cpp index 53f896e3..6b6c42dc 100644 --- a/src/world/Manager/ActionMgr.cpp +++ b/src/world/Manager/ActionMgr.cpp @@ -101,6 +101,14 @@ void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData ) { + for( const auto& statusIt : player.getStatusEffectMap() ) + { + statusIt.second->onBeforeActionStart( currentAction ); + } + + if( currentAction->isInterrupted() ) + return; + if( !currentAction->preCheck() ) { player.sendDebug( "preCheck failed" ); @@ -109,11 +117,6 @@ void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player, return; } - for( const auto& statusIt : player.getStatusEffectMap() ) - { - statusIt.second->onBeforeActionStart( currentAction ); - } - if( player.getCurrentAction() ) { player.sendDebug( "Skill queued: {0}", currentAction->getId() ); diff --git a/src/world/Network/Handlers/ClientTriggerHandler.cpp b/src/world/Network/Handlers/ClientTriggerHandler.cpp index b6decf1b..22864d58 100644 --- a/src/world/Network/Handlers/ClientTriggerHandler.cpp +++ b/src/world/Network/Handlers/ClientTriggerHandler.cpp @@ -140,7 +140,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( FrameworkPtr pFw, case ClientTriggerType::CastCancel: // Cancel cast { if( player.getCurrentAction() ) - player.getCurrentAction()->setInterrupted( Common::ActionInterruptType::RegularInterrupt ); + player.getCurrentAction()->interrupt(); break; } case ClientTriggerType::Examine: diff --git a/src/world/Network/Handlers/PacketHandlers.cpp b/src/world/Network/Handlers/PacketHandlers.cpp index 194203e1..30149bca 100644 --- a/src/world/Network/Handlers/PacketHandlers.cpp +++ b/src/world/Network/Handlers/PacketHandlers.cpp @@ -200,7 +200,7 @@ void Sapphire::Network::GameConnection::updatePositionHandler( FrameworkPtr pFw, player.setPos( updatePositionPacket.data().position ); if( ( player.getCurrentAction() != nullptr ) && bPosChanged ) - player.getCurrentAction()->setInterrupted( Common::ActionInterruptType::RegularInterrupt ); + player.getCurrentAction()->interrupt(); // if no one is in range, don't bother trying to send a position update if( !player.hasInRangeActor() ) diff --git a/src/world/Script/NativeScriptApi.cpp b/src/world/Script/NativeScriptApi.cpp index 2cada883..5e03d2c2 100644 --- a/src/world/Script/NativeScriptApi.cpp +++ b/src/world/Script/NativeScriptApi.cpp @@ -88,6 +88,10 @@ namespace Sapphire::ScriptAPI { } + void ActionScript::onBeforePreCheck( Sapphire::World::Action::Action& action ) + { + } + void ActionScript::onStart( Sapphire::World::Action::Action& action ) { } diff --git a/src/world/Script/NativeScriptApi.h b/src/world/Script/NativeScriptApi.h index 93cb0d06..bd0a3534 100644 --- a/src/world/Script/NativeScriptApi.h +++ b/src/world/Script/NativeScriptApi.h @@ -140,6 +140,8 @@ namespace Sapphire::ScriptAPI public: explicit ActionScript( uint32_t actionId ); + virtual void onBeforePreCheck( Sapphire::World::Action::Action& action ); + virtual void onStart( Sapphire::World::Action::Action& action ); virtual void onExecute( Sapphire::World::Action::Action& action ); diff --git a/src/world/Script/ScriptMgr.cpp b/src/world/Script/ScriptMgr.cpp index f899281d..4e57e42f 100644 --- a/src/world/Script/ScriptMgr.cpp +++ b/src/world/Script/ScriptMgr.cpp @@ -329,6 +329,18 @@ bool Sapphire::Scripting::ScriptMgr::onEObjHit( Sapphire::Entity::Player& player return didCallScript; } +bool Sapphire::Scripting::ScriptMgr::onBeforePreCheck( World::Action::Action& action ) +{ + auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() ); + + if( script ) + { + script->onBeforePreCheck( action ); + return true; + } + return false; +} + bool Sapphire::Scripting::ScriptMgr::onExecute( World::Action::Action& action ) { auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() ); diff --git a/src/world/Script/ScriptMgr.h b/src/world/Script/ScriptMgr.h index ca2ef45d..5782cdfc 100644 --- a/src/world/Script/ScriptMgr.h +++ b/src/world/Script/ScriptMgr.h @@ -72,6 +72,8 @@ namespace Sapphire::Scripting bool onEObjHit( Entity::Player& player, uint64_t actorId, uint32_t actionId ); + bool onBeforePreCheck( World::Action::Action& action ); + bool onStart( World::Action::Action& action ); bool onInterrupt( World::Action::Action& action );