1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-27 22:57:45 +00:00

add ref to Data::Action inside action obj, move can cast logic to action

This commit is contained in:
NotAdam 2019-03-07 20:27:45 +11:00
parent 2f9d86f962
commit 9d6622b522
15 changed files with 190 additions and 341 deletions

View file

@ -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

View file

@ -12,7 +12,7 @@ public:
{
}
void onCastFinish( Sapphire::Action::Action& currentAction ) override
void onFinish( Sapphire::Action::Action& currentAction ) override
{
if( !currentAction.getSourceChara()->isPlayer() )
return;

View file

@ -11,7 +11,7 @@ public:
{
}
void onCastFinish( Sapphire::Action::Action& currentAction ) override
void onFinish( Sapphire::Action::Action& currentAction ) override
{
auto sourceChara = currentAction.getSourceChara();

View file

@ -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?" );
}
};

View file

@ -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;
}

View file

@ -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;
};
}

View file

@ -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;

View file

@ -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;

View file

@ -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();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

View file

@ -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 )

View file

@ -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 );

View file

@ -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 )
{
}

View file

@ -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 );
};
/*!

View file

@ -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;
}

View file

@ -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 );