diff --git a/src/common/Common.h b/src/common/Common.h index d86e57a0..a5d60a91 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -537,19 +537,19 @@ namespace Sapphire::Common Unaspected = 7 // Doesn't imply magical unaspected damage - could be unaspected physical }; - enum class ActionCostType : uint8_t + enum class ActionPrimaryCostType : uint8_t { - None = 0, // ? +// None = 0, // ? MagicPoints = 3, TacticsPoints = 5, - WARGauge = 22, - DRKGauge = 25, - AetherflowStack = 30, - Status = 32, - PLDGauge = 41, - RDMGaugeBoth = 74, -// RDMGaugeBlack = 75, // not right? - DRGGauge3Eyes = 76, +// WARGauge = 22, +// DRKGauge = 25, +// AetherflowStack = 30, +// Status = 32, +// PLDGauge = 41, +// RDMGaugeBoth = 74, +//// RDMGaugeBlack = 75, // not right? +// DRGGauge3Eyes = 76, }; enum class ActionType : int8_t diff --git a/src/scripts/action/common/ActionReturn6.cpp b/src/scripts/action/common/ActionReturn6.cpp index f74c5d0d..19737104 100644 --- a/src/scripts/action/common/ActionReturn6.cpp +++ b/src/scripts/action/common/ActionReturn6.cpp @@ -12,7 +12,7 @@ public: { } - void onCastFinish( Sapphire::Action::Action& currentAction ) override + void onFinish( Sapphire::Action::Action& currentAction ) override { if( !currentAction.getSourceChara()->isPlayer() ) return; diff --git a/src/scripts/action/common/ActionSprint3.cpp b/src/scripts/action/common/ActionSprint3.cpp index f0655f29..1ccce78e 100644 --- a/src/scripts/action/common/ActionSprint3.cpp +++ b/src/scripts/action/common/ActionSprint3.cpp @@ -11,7 +11,7 @@ public: { } - void onCastFinish( Sapphire::Action::Action& currentAction ) override + void onFinish( Sapphire::Action::Action& currentAction ) override { auto sourceChara = currentAction.getSourceChara(); diff --git a/src/scripts/action/playeractions/archer/ActionHeavyShot97.cpp b/src/scripts/action/playeractions/archer/ActionHeavyShot97.cpp index c762c523..8e59f470 100644 --- a/src/scripts/action/playeractions/archer/ActionHeavyShot97.cpp +++ b/src/scripts/action/playeractions/archer/ActionHeavyShot97.cpp @@ -12,9 +12,10 @@ public: { } - void onCharaHit( Sapphire::Action::Action& currentAction, Sapphire::Entity::Chara& hitActor ) override + void onFinish( Sapphire::Action::Action& currentAction ) override { - currentAction.damageTarget( 150, hitActor ); + if( auto player = currentAction.getSourceChara()->getAsPlayer() ) + player->sendDebug( "Imagine you just hit an enemy for 150 potency. Incredible, right?" ); } }; diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 2f8c472d..3a6806b3 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -27,7 +27,7 @@ Sapphire::Action::Action::Action() = default; Sapphire::Action::Action::~Action() = default; Sapphire::Action::Action::Action( Entity::CharaPtr caster, uint32_t actionId, - Data::ActionPtr action, FrameworkPtr fw ) : + Data::ActionPtr actionData, FrameworkPtr fw ) : m_pSource( std::move( caster ) ), m_pFw( std::move( fw ) ), m_id( actionId ), @@ -35,17 +35,19 @@ Sapphire::Action::Action::Action( Entity::CharaPtr caster, uint32_t actionId, m_interruptType( Common::ActionInterruptType::None ), m_hasResidentTarget( false ) { - m_castTime = static_cast< uint32_t >( action->cast100ms * 100 ); - m_recastTime = static_cast< uint16_t >( action->recast100ms * 100 ); - m_cooldownGroup = action->cooldownGroup; - m_range = action->range; - m_effectRange = action->effectRange; - m_aspect = static_cast< Common::ActionAspect >( action->aspect ); + m_actionData = actionData; + + m_castTime = static_cast< uint32_t >( actionData->cast100ms * 100 ); + m_recastTime = static_cast< uint16_t >( actionData->recast100ms * 100 ); + m_cooldownGroup = actionData->cooldownGroup; + m_range = actionData->range; + m_effectRange = actionData->effectRange; + m_aspect = static_cast< Common::ActionAspect >( actionData->aspect ); // a default range is set by the game for the class/job if( m_range == -1 ) { - switch( static_cast< Common::ClassJob >( action->classJob ) ) + switch( static_cast< Common::ClassJob >( actionData->classJob ) ) { case Common::ClassJob::Bard: case Common::ClassJob::Archer: @@ -57,12 +59,10 @@ Sapphire::Action::Action::Action( Entity::CharaPtr caster, uint32_t actionId, } } - m_actionCost.fill( { Common::ActionCostType::None, 0 } ); + m_primaryCostType = static_cast< Common::ActionPrimaryCostType >( actionData->costType ); + m_primaryCost = actionData->cost; - m_actionCost[ 0 ] = { - static_cast< Common::ActionCostType >( action->costType ), - action->cost - }; + // todo: add missing rows for secondaryCostType/secondaryCostType and rename the current rows to primaryCostX calculateActionCost(); } @@ -145,7 +145,7 @@ bool Sapphire::Action::Action::update() if( isInterrupted() ) { - castInterrupt(); + onInterrupt(); return true; } @@ -158,14 +158,14 @@ bool Sapphire::Action::Action::update() if( !hasCastTime() || std::difftime( currTime, m_startTime ) > m_castTime ) { - castFinish(); + onExecute(); return true; } return false; } -void Sapphire::Action::Action::castStart() +void Sapphire::Action::Action::onStart() { assert( m_pSource ); @@ -193,14 +193,14 @@ void Sapphire::Action::Action::castStart() } auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >(); - if( !pScriptMgr->onCastStart( *this ) ) + if( !pScriptMgr->onStart( *this ) ) { // script not implemented - castInterrupt(); + onInterrupt(); if( player ) { - player->sendUrgent( "Action not implemented, missing script for actionId#{0}", getId() ); + player->sendUrgent( "Action not implemented, missing script for action#{0}", getId() ); player->setCurrentAction( nullptr ); } @@ -209,10 +209,10 @@ void Sapphire::Action::Action::castStart() // instantly finish cast if there's no cast time if( !hasCastTime() ) - castFinish(); + onExecute(); } -void Sapphire::Action::Action::castInterrupt() +void Sapphire::Action::Action::onInterrupt() { assert( m_pSource ); @@ -246,10 +246,10 @@ void Sapphire::Action::Action::castInterrupt() } auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >(); - pScriptMgr->onCastInterrupt( *this ); + pScriptMgr->onInterrupt( *this ); } -void Sapphire::Action::Action::castFinish() +void Sapphire::Action::Action::onExecute() { assert( m_pSource ); @@ -257,170 +257,60 @@ void Sapphire::Action::Action::castFinish() if( hasCastTime() ) { + // todo: what's this? /*auto control = ActorControlPacket143( m_pTarget->getId(), ActorControlType::Unk7, 0x219, m_id, m_id, m_id, m_id ); m_pSource->sendToInRangeSet( control, true );*/ } - pScriptMgr->onCastFinish( *this ); - if( !hasResidentTarget() ) { assert( m_pTarget ); - // todo: calculate final hit targets and call onCharaHit in action script - pScriptMgr->onCharaHit( *this, *m_pTarget ); + pScriptMgr->onExecute( *this ); } else if( auto player = m_pSource->getAsPlayer() ) { pScriptMgr->onEObjHit( *player, m_targetId ); return; } - - buildEffectPackets(); -} - -void Sapphire::Action::Action::buildEffectPackets() -{ - for( int i = 0; i < EffectPacketIdentity::MAX_ACTION_EFFECT_PACKET_IDENT; ++i ) - { - auto& packetData = m_effects[ static_cast< EffectPacketIdentity >( i ) ]; - - auto actorsHit = packetData.m_hitActors.size(); - if( actorsHit == 0 ) - continue; - - // get effect sequence - auto zone = m_pSource->getCurrentZone(); - assert( zone ); - - auto sequence = zone->getNextEffectSequence(); - - if( actorsHit == 1 ) - { - // send normal effect - auto effectPacket = std::make_shared< Network::Packets::Server::EffectPacket >( m_pSource->getId(), m_pTarget->getId(), getId() ); - effectPacket->setTargetActor( packetData.m_hitActors[ 0 ] ); - effectPacket->setSequence( sequence ); - effectPacket->setDisplayType( Common::ActionEffectDisplayType::ShowActionName ); - - for( auto& effect : packetData.m_entries ) - { - effectPacket->addEffect( effect ); - } - - m_pSource->sendToInRangeSet( effectPacket, true ); - } - else - { - // todo: aoe effects - } - } -} - -void Sapphire::Action::Action::damageTarget( uint16_t potency, Entity::Chara& chara ) -{ - // todo: scale potency into damage from stats - - Common::EffectEntry entry{}; - - // todo: handle cases where the action misses/is blocked? - entry.effectType = Common::ActionEffectType::Damage; - - // todo: handle crits - entry.hitSeverity = Common::ActionHitSeverityType::NormalDamage; - - // todo: handle > 65535 damage values, not sure if this is right? - if( potency > 65535 ) - { - entry.value = static_cast< int16_t >( potency / 10 ); - // todo: rename this? need to confirm how it works again - entry.valueMultiplier = 1; - } - else - entry.value = static_cast< int16_t >( potency ); - - // add to aggro table - // todo: probably move this into takeDamage? this is pretty garbage - if( chara.isBattleNpc() ) - { - auto bNpc = chara.getAsBNpc(); - if( bNpc ) - { - if( bNpc->getStance() != Common::Stance::Active ) - { - bNpc->aggro( getSourceChara() ); - bNpc->hateListUpdate( getSourceChara(), potency ); - } - else - { - bNpc->hateListUpdate( getSourceChara(), potency ); - } - } - } - - // todo: aspected damage? - chara.takeDamage( potency ); - - if( auto player = m_pSource->getAsPlayer() ) - player->sendDebug( "hit actorId#{0} for potency: {1}", chara.getId(), potency ); - - m_effects[ EffectPacketIdentity::DamageEffect ].m_entries.emplace_back( entry ); - - // todo: make sure that we don't add the same actor more than once - m_effects[ EffectPacketIdentity::DamageEffect ].m_hitActors.emplace_back( chara.getId() ); -} - -void Sapphire::Action::Action::healTarget( uint16_t potency, Entity::Chara& chara ) -{ - // todo: scale potency into healing from stats - - Common::EffectEntry entry{}; - - entry.effectType = Common::ActionEffectType::Heal; - - // todo: handle crits - entry.hitSeverity = Common::ActionHitSeverityType::NormalHeal; - - // todo: handle > 65535 healing values, not sure if this is right? - if( potency > 65535 ) - { - entry.value = static_cast< int16_t >( potency / 10 ); - // todo: rename this? need to confirm how it works again - entry.valueMultiplier = 1; - } - else - entry.value = static_cast< int16_t >( potency ); - - chara.heal( potency ); - - if( auto player = m_pSource->getAsPlayer() ) - player->sendDebug( "hit actorId#{0} for heal: {1}", chara.getId(), potency ); - - m_effects[ EffectPacketIdentity::HealingEffect ].m_entries.emplace_back( entry ); - - // todo: make sure that we don't add the same actor more than once - m_effects[ EffectPacketIdentity::HealingEffect ].m_hitActors.emplace_back( chara.getId() ); -} - -const Sapphire::Action::Action::ActionCostArray& Sapphire::Action::Action::getCostArray() const -{ - return m_actionCost; } void Sapphire::Action::Action::calculateActionCost() { - for( uint8_t i = 0; i < m_actionCost.size(); ++i ) + // 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 ) { - auto& entry = m_actionCost[ i ]; + case ActionPrimaryCostType::MagicPoints: + { + calculateMPCost( m_primaryCost ); + break; + } - if( entry.m_costType == ActionCostType::MagicPoints ) - calculateMPCost( i ); + 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 } // todo: this shouldn't be in action and instead be in some general stat calc util -void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) +void Sapphire::Action::Action::calculateMPCost( uint16_t baseCost ) { auto level = m_pSource->getLevel(); @@ -429,9 +319,7 @@ void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) // dividing by 10 on the border will break this unless we subtract 1 auto levelGroup = std::max< uint8_t >( level - 1, 1 ) / 10; - auto& costEntry = m_actionCost[ costArrayIndex ]; - - float cost = costEntry.m_cost; + float cost = baseCost; // thanks to andrew for helping me figure this shit out, should be pretty accurate switch( levelGroup ) @@ -444,7 +332,7 @@ void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) break; } - // level 11-20 + // level 11-20 case 1: { // r^2 = 1 @@ -452,7 +340,7 @@ void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) break; } - // level 21-30 + // level 21-30 case 2: { // r^2 = 1 @@ -460,7 +348,7 @@ void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) break; } - // level 31-40 + // level 31-40 case 3: { // r^2 = 1 @@ -476,7 +364,7 @@ void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) break; } - // level 51-60 + // level 51-60 case 5: { // r^2 = 1 @@ -484,7 +372,7 @@ void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) break; } - // level 61-70 + // level 61-70 case 6: { // r^2 = 0.9998 @@ -496,9 +384,70 @@ void Sapphire::Action::Action::calculateMPCost( uint8_t costArrayIndex ) return; } - // m_cost is the base cost, cost is the multiplier for the current player level - costEntry.m_cost = static_cast< uint16_t >( std::round( cost * costEntry.m_cost ) ); + // m_primaryCost is the base cost, cost is the multiplier for the current player level + m_primaryCost = static_cast< uint16_t >( std::round( cost * baseCost ) ); if( auto player = m_pSource->getAsPlayer() ) - player->sendDebug( "calculated mp cost: {0}", costEntry.m_cost ); + player->sendDebug( "calculated mp cost: {0}", m_primaryCost ); +} + +bool Sapphire::Action::Action::precheck() +{ + if( auto player = m_pSource->getAsPlayer() ) + { + if( !playerPrecheck( *player ) ) + return false; + } + + return true; +} + +bool Sapphire::Action::Action::playerPrecheck( Entity::Player& player ) +{ + // lol + if( !player.isAlive() ) + return false; + + // npc actions/non player actions + if( m_actionData->classJob == -1 ) + return false; + + if( player.getLevel() < m_actionData->classJobLevel ) + return false; + + auto currentClass = player.getClass(); + auto actionClass = static_cast< Common::ClassJob >( m_actionData->classJob ); + + if( actionClass != Common::ClassJob::Adventurer && currentClass != actionClass ) + { + // check if not a base class action + auto exdData = m_pFw->get< Data::ExdDataGenerated >(); + assert( exdData ); + + auto classJob = exdData->get< Data::ClassJob >( static_cast< uint8_t >( currentClass ) ); + if( !classJob ) + return false; + + if( classJob->classJobParent != m_actionData->classJob ) + return false; + } + + // reset target on actions that can only be casted on yourself while having a target set + // todo: check what actions send when targeting an enemy + if( m_actionData->canTargetSelf && + !m_actionData->canTargetFriendly && + !m_actionData->canTargetHostile && + !m_actionData->canTargetParty ) + { + setTargetChara( getSourceChara() ); + } + + // todo: party/enemy validation + + // validate range + + + // todo: validate costs/conditionals here + + return true; } \ No newline at end of file diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 66b2bd93..af0928fc 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -18,16 +18,9 @@ namespace Sapphire::Action { public: - struct ActionCostEntry - { - Common::ActionCostType m_costType; - uint16_t m_cost; - }; - - using ActionCostArray = std::array< ActionCostEntry, 2 >; Action(); - Action( Entity::CharaPtr caster, uint32_t actionId, Data::ActionPtr action, FrameworkPtr fw ); + Action( Entity::CharaPtr caster, uint32_t actionId, Data::ActionPtr actionData, FrameworkPtr fw ); virtual ~Action(); @@ -53,36 +46,34 @@ namespace Sapphire::Action */ bool hasResidentTarget() const; - const ActionCostArray& getCostArray() const; - /*! * @brief Tests whether the action is instantly usable or has a cast assoc'd with it * @return true if action has a cast time */ bool hasCastTime() const; - void buildEffectPackets(); - /*! - * @brief Damages a target and adds the effect entry - * @param potency The amount of damage the target takes - * @param chara The chara to inflict damage upon + * @brief Tests if an action is castable by the current source chara + * @return true if castable, false if the caster doesn't meet the requirements */ - void damageTarget( uint16_t potency, Entity::Chara& chara ); - - /*! - * @brief Heals a target and adds the effect entry - * @param potency Amount of healing to apply - * @param chara Chara to receive healing - */ - void healTarget( uint16_t potency, Entity::Chara& chara ); + bool precheck(); /*! * @brief Starts the cast. Finishes it immediately if there is no cast time (weaponskills). */ - virtual void castStart(); - virtual void castFinish(); - virtual void castInterrupt(); + virtual void onStart(); + + /*! + * @brief Finishes the cast, effected targets are calculated here. + */ + virtual void onExecute(); + + /*! + * @brief Called when a cast is interrupted for any reason + * + * m_interruptType will have the reason why the action was interrupted (eg. damage, movement, ...) + */ + virtual void onInterrupt(); // update action, if returns true, action is done and has to be removed from the actor virtual bool update(); @@ -90,31 +81,14 @@ namespace Sapphire::Action protected: void calculateActionCost(); - void calculateMPCost( uint8_t costArrayIndex ); + void calculateMPCost( uint16_t baseCost ); - /*! - * @brief Some actions are capable of both healing and dealing damage. This identifies them. - */ - enum EffectPacketIdentity : uint8_t - { - DamageEffect, - HealingEffect, - - MAX_ACTION_EFFECT_PACKET_IDENT - }; - - struct EffectPacketData - { - std::vector< Common::EffectEntry > m_entries; - std::vector< uint32_t > m_hitActors; - }; + bool playerPrecheck( Entity::Player& player ); uint32_t m_id; - Common::ActionCostType m_costType; - uint16_t m_cost; - - ActionCostArray m_actionCost; + Common::ActionPrimaryCostType m_primaryCostType; + uint16_t m_primaryCost; uint64_t m_startTime; uint32_t m_castTime; @@ -124,6 +98,7 @@ namespace Sapphire::Action uint8_t m_effectRange; Common::ActionAspect m_aspect; + Entity::CharaPtr m_pSource; Entity::CharaPtr m_pTarget; uint64_t m_targetId; @@ -132,10 +107,9 @@ namespace Sapphire::Action Common::ActionInterruptType m_interruptType; FrameworkPtr m_pFw; + Data::ActionPtr m_actionData; Common::FFXIVARR_POSITION3 m_pos; - - std::array< EffectPacketData, MAX_ACTION_EFFECT_PACKET_IDENT > m_effects; }; } diff --git a/src/world/Action/EventAction.cpp b/src/world/Action/EventAction.cpp index 84be1368..6773785d 100644 --- a/src/world/Action/EventAction.cpp +++ b/src/world/Action/EventAction.cpp @@ -35,7 +35,7 @@ Sapphire::Action::EventAction::EventAction( Entity::CharaPtr pActor, uint32_t ev Sapphire::Action::EventAction::~EventAction() = default; -void Sapphire::Action::EventAction::castStart() +void Sapphire::Action::EventAction::onStart() { if( !m_pSource ) return; @@ -54,7 +54,7 @@ void Sapphire::Action::EventAction::castStart() m_pSource->sendToInRangeSet( control ); } -void Sapphire::Action::EventAction::castFinish() +void Sapphire::Action::EventAction::onExecute() { if( !m_pSource ) return; @@ -90,7 +90,7 @@ void Sapphire::Action::EventAction::castFinish() } -void Sapphire::Action::EventAction::castInterrupt() +void Sapphire::Action::EventAction::onInterrupt() { if( !m_pSource ) return; diff --git a/src/world/Action/EventAction.h b/src/world/Action/EventAction.h index 2db43c37..898bf4b4 100644 --- a/src/world/Action/EventAction.h +++ b/src/world/Action/EventAction.h @@ -18,11 +18,11 @@ public: EventAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action, ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional, FrameworkPtr pFw ); - void castStart() override; + void onStart() override; - void castFinish() override; + void onExecute() override; - void castInterrupt() override; + void onInterrupt() override; private: uint32_t m_eventId; diff --git a/src/world/Actor/PlayerEvent.cpp b/src/world/Actor/PlayerEvent.cpp index e4c27afc..52c4d82e 100644 --- a/src/world/Actor/PlayerEvent.cpp +++ b/src/world/Actor/PlayerEvent.cpp @@ -303,7 +303,7 @@ void Sapphire::Entity::Player::eventActionStart( uint32_t eventId, pEvent->setPlayedScene( true ); setCurrentAction( pEventAction ); - pEventAction->castStart(); + pEventAction->onStart(); } @@ -318,7 +318,7 @@ void Sapphire::Entity::Player::eventItemActionStart( uint32_t eventId, // // setCurrentAction( pEventItemAction ); // -// pEventItemAction->onCastStart(); +// pEventItemAction->onStart(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/world/Manager/ActionMgr.cpp b/src/world/Manager/ActionMgr.cpp index 3e26105b..0dbc4931 100644 --- a/src/world/Manager/ActionMgr.cpp +++ b/src/world/Manager/ActionMgr.cpp @@ -29,7 +29,7 @@ void World::Manager::ActionMgr::handleAoEPlayerAction( Entity::Player& player, u if( !actionData->targetArea ) { // not an action that has an aoe, cancel it - action->castInterrupt(); + action->onInterrupt(); return; } @@ -44,7 +44,7 @@ void World::Manager::ActionMgr::handleTargetedPlayerAction( Entity::Player& play // cancel any aoe actions casted with this packet if( actionData->targetArea ) { - action->castInterrupt(); + action->onInterrupt(); return; } @@ -99,10 +99,10 @@ void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData ) { - if( !canPlayerUseAction( player, *currentAction, actionData ) ) + if( !currentAction->precheck() ) { // forcefully interrupt the action and reset the cooldown - currentAction->castInterrupt(); + currentAction->onInterrupt(); return; } @@ -113,63 +113,7 @@ void World::Manager::ActionMgr::bootstrapAction( Entity::Player& player, } // todo: what do in cases of swiftcast/etc? script callback? - currentAction->castStart(); -} - -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; - - if( player.getLevel() < actionData.classJobLevel ) - return false; - - auto currentClass = player.getClass(); - auto actionClass = static_cast< Common::ClassJob >( actionData.classJob ); - - if( actionClass != Common::ClassJob::Adventurer && currentClass != actionClass ) - { - // 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 >( currentClass ) ); - if( !classJob ) - return false; - - if( classJob->classJobParent != actionData.classJob ) - return false; - } - - // reset target on actions that can only be casted on yourself while having a target set - // todo: check what actions send when targeting an enemy - if( actionData.canTargetSelf && - !actionData.canTargetFriendly && - !actionData.canTargetHostile && - !actionData.canTargetParty ) - { - currentAction.setTargetChara( currentAction.getSourceChara() ); - } - - // todo: party/enemy validation - - // validate range - - - auto& actionCost = currentAction.getCostArray(); - for( uint8_t i = 0; i < actionCost.size(); ++i ) - { - // todo: validate costs/conditionals here - } - - return true; + currentAction->onStart(); } void World::Manager::ActionMgr::handleItemActionVFX( Sapphire::Entity::Player& player, uint32_t itemId, uint16_t vfxId ) diff --git a/src/world/Manager/ActionMgr.h b/src/world/Manager/ActionMgr.h index 2e77ad44..67d2ea5f 100644 --- a/src/world/Manager/ActionMgr.h +++ b/src/world/Manager/ActionMgr.h @@ -31,7 +31,6 @@ namespace Sapphire::World::Manager private: void bootstrapAction( Entity::Player& player, Action::ActionPtr currentAction, Data::Action& actionData ); - bool canPlayerUseAction( Entity::Player& player, Action::Action& currentAction, Data::Action& actionData ); // item action handlers void handleItemActionVFX( Entity::Player& player, uint32_t itemId, uint16_t vfxId ); diff --git a/src/world/Script/NativeScriptApi.cpp b/src/world/Script/NativeScriptApi.cpp index 5c98b2e3..d966d207 100644 --- a/src/world/Script/NativeScriptApi.cpp +++ b/src/world/Script/NativeScriptApi.cpp @@ -88,19 +88,15 @@ namespace Sapphire::ScriptAPI { } - void ActionScript::onCastStart( Sapphire::Action::Action& currentAction ) + void ActionScript::onStart( Sapphire::Action::Action& currentAction ) { } - void ActionScript::onCastFinish( Sapphire::Action::Action& currentAction ) + void ActionScript::onFinish( Sapphire::Action::Action& currentAction ) { } - void ActionScript::onCastInterrupt( Sapphire::Action::Action& currentAction ) - { - } - - void ActionScript::onCharaHit( Sapphire::Action::Action& currentAction, Sapphire::Entity::Chara& hitActor ) + void ActionScript::onInterrupt( Sapphire::Action::Action& currentAction ) { } diff --git a/src/world/Script/NativeScriptApi.h b/src/world/Script/NativeScriptApi.h index 82de8d9f..a4040536 100644 --- a/src/world/Script/NativeScriptApi.h +++ b/src/world/Script/NativeScriptApi.h @@ -140,13 +140,11 @@ namespace Sapphire::ScriptAPI public: explicit ActionScript( uint32_t abilityId ); - virtual void onCastStart( Sapphire::Action::Action& currentAction ); + virtual void onStart( Sapphire::Action::Action& currentAction ); - virtual void onCastFinish( Sapphire::Action::Action& currentAction ); + virtual void onFinish( Sapphire::Action::Action& currentAction ); - virtual void onCastInterrupt( Sapphire::Action::Action& currentAction ); - - virtual void onCharaHit( Sapphire::Action::Action& currentAction, Sapphire::Entity::Chara& hitActor ); + virtual void onInterrupt( Sapphire::Action::Action& currentAction ); }; /*! diff --git a/src/world/Script/ScriptMgr.cpp b/src/world/Script/ScriptMgr.cpp index c002cfe2..064cba39 100644 --- a/src/world/Script/ScriptMgr.cpp +++ b/src/world/Script/ScriptMgr.cpp @@ -328,50 +328,37 @@ bool Sapphire::Scripting::ScriptMgr::onEObjHit( Sapphire::Entity::Player& player return didCallScript; } -bool Sapphire::Scripting::ScriptMgr::onCastFinish( Action::Action& currentAction ) +bool Sapphire::Scripting::ScriptMgr::onExecute( Action::Action& currentAction ) { auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( currentAction.getId() ); if( script ) { - script->onCastFinish( currentAction ); + script->onFinish( currentAction ); return true; } return false; } -bool Sapphire::Scripting::ScriptMgr::onCastInterrupt( Action::Action& currentAction ) +bool Sapphire::Scripting::ScriptMgr::onInterrupt( Action::Action& currentAction ) { auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( currentAction.getId() ); if( script ) { - script->onCastInterrupt( currentAction ); + script->onInterrupt( currentAction ); return true; } return false; } -bool Sapphire::Scripting::ScriptMgr::onCastStart( Action::Action& currentAction ) +bool Sapphire::Scripting::ScriptMgr::onStart( Action::Action& currentAction ) { auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( currentAction.getId() ); if( script ) { - script->onCastStart( currentAction ); - return true; - } - - return false; -} - -bool Sapphire::Scripting::ScriptMgr::onCharaHit( Action::Action& currentAction, Entity::Chara& hitActor ) -{ - auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( currentAction.getId() ); - - if( script ) - { - script->onCharaHit( currentAction, hitActor ); + script->onStart( currentAction ); return true; } diff --git a/src/world/Script/ScriptMgr.h b/src/world/Script/ScriptMgr.h index 74fbc26e..03893e91 100644 --- a/src/world/Script/ScriptMgr.h +++ b/src/world/Script/ScriptMgr.h @@ -72,10 +72,11 @@ namespace Sapphire::Scripting bool onEObjHit( Entity::Player& player, uint64_t actorId ); - bool onCastStart( Action::Action& currentAction ); - bool onCastInterrupt( Action::Action& currentAction ); - bool onCastFinish( Action::Action& currentAction ); - bool onCharaHit( Action::Action& currentAction, Entity::Chara& hitActor ); + bool onStart( Action::Action& currentAction ); + + bool onInterrupt( Action::Action& currentAction ); + + bool onExecute( Action::Action& currentAction ); bool onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId );