1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-23 10:17:44 +00:00
This commit is contained in:
コレット 2025-05-07 16:54:45 +00:00 committed by GitHub
commit 71ecd9eb6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 97 additions and 37 deletions

View file

@ -350,7 +350,7 @@ void Action::Action::start()
onStart(); onStart();
// instantly finish cast if there's no cast time // instantly finish cast if there's no cast time
if( !hasCastTime() ) if( !hasCastTime() && !isInterrupted() )
execute(); execute();
} }
@ -379,6 +379,8 @@ void Action::Action::onStart()
void Action::Action::interrupt() void Action::Action::interrupt()
{ {
assert( m_pSource ); assert( m_pSource );
if( m_interruptType == ActionInterruptType::None )
m_interruptType = ActionInterruptType::RegularInterrupt;
// things that aren't players don't care about cooldowns and state flags // things that aren't players don't care about cooldowns and state flags
if( m_pSource->isPlayer() ) if( m_pSource->isPlayer() )
{ {
@ -522,6 +524,7 @@ void Action::Action::buildActionResults()
if( !m_enableGenericHandler || !hasLutEntry || m_hitActors.empty() ) if( !m_enableGenericHandler || !hasLutEntry || m_hitActors.empty() )
{ {
scriptMgr.onAfterBuildEffect( *this );
// send any effect packet added by script or an empty one just to play animation for other players // send any effect packet added by script or an empty one just to play animation for other players
m_actionResultBuilder->sendActionResults( {} ); m_actionResultBuilder->sendActionResults( {} );
return; return;
@ -592,7 +595,7 @@ void Action::Action::buildActionResults()
} }
// If we hit an enemy // If we hit an enemy
if( !m_hitActors.empty() && getHitChara()->getObjKind() != m_pSource->getObjKind() ) if( !m_hitActors.empty() && getHitChara()->isHostile( *m_pSource ) )
{ {
m_pSource->removeStatusEffectByFlag( Common::StatusEffectFlag::RemoveOnSuccessfulHit ); m_pSource->removeStatusEffectByFlag( Common::StatusEffectFlag::RemoveOnSuccessfulHit );
} }
@ -600,6 +603,8 @@ void Action::Action::buildActionResults()
handleJobAction(); handleJobAction();
handleStatusEffects(); handleStatusEffects();
scriptMgr.onAfterBuildEffect( *this );
m_actionResultBuilder->sendActionResults( m_hitActors ); m_actionResultBuilder->sendActionResults( m_hitActors );
// TODO: disabled, reset kills our queued actions // TODO: disabled, reset kills our queued actions
@ -667,7 +672,6 @@ bool Action::Action::preCheck()
bool Action::Action::playerPreCheck( Entity::Player& player ) bool Action::Action::playerPreCheck( Entity::Player& player )
{ {
// lol
if( !player.isAlive() ) if( !player.isAlive() )
return false; return false;
@ -675,27 +679,27 @@ bool Action::Action::playerPreCheck( Entity::Player& player )
//if( m_actionData->data().UseClassJob == -1 /* dunno what this is in old data && !m_actionData->data().isRoleAction*/ ) //if( m_actionData->data().UseClassJob == -1 /* dunno what this is in old data && !m_actionData->data().isRoleAction*/ )
// return false; // return false;
if( player.getLevel() < m_actionData->data().UseClassJob ) //if( player.getLevel() < m_actionData->data().UseClassJob )
return false; // return false;
auto currentClass = player.getClass(); //auto currentClass = player.getClass();
auto actionClass = static_cast< Common::ClassJob >( m_actionData->data().UseClassJob ); //auto actionClass = static_cast< Common::ClassJob >( m_actionData->data().UseClassJob );
if( actionClass != Common::ClassJob::Adventurer && currentClass != actionClass /* dunno what this is in old data && !m_actionData->data().isRoleAction*/ ) //if( actionClass != Common::ClassJob::Adventurer && currentClass != actionClass /* dunno what this is in old data && !m_actionData->data().isRoleAction*/ )
{ //{
// check if not a base class action // check if not a base class action
auto& exdData = Common::Service< Data::ExdData >::ref(); //auto& exdData = Common::Service< Data::ExdData >::ref();
auto classJob = exdData.getRow< Excel::ClassJob >( static_cast< uint8_t >( currentClass ) ); //auto classJob = exdData.getRow< Excel::ClassJob >( static_cast< uint8_t >( currentClass ) );
if( !classJob ) //if( !classJob )
return false; // return false;
if( classJob->data().MainClass != m_actionData->data().UseClassJob ) //if( classJob->data().MainClass != m_actionData->data().UseClassJob )
return false; // return false;
} //}
if( !m_actionData->data().SelectMyself && getTargetId() == m_pSource->getId() ) //if( !m_actionData->data().SelectMyself && getTargetId() == m_pSource->getId() )
return false; // return false;
// todo: does this need to check for party/alliance stuff or it's just same type? // todo: does this need to check for party/alliance stuff or it's just same type?
// todo: m_pTarget doesn't exist at this stage because we only fill it when we snapshot targets // todo: m_pTarget doesn't exist at this stage because we only fill it when we snapshot targets
@ -885,6 +889,9 @@ void Action::Action::addDefaultActorFilters()
bool Action::Action::preFilterActor( Entity::GameObject& actor ) const bool Action::Action::preFilterActor( Entity::GameObject& actor ) const
{ {
if( m_castType == Common::CastType::SingleTarget ) // client filters any single target action by itself
return true;
auto kind = actor.getObjKind(); auto kind = actor.getObjKind();
auto chara = actor.getAsChara(); auto chara = actor.getAsChara();
@ -892,20 +899,15 @@ bool Action::Action::preFilterActor( Entity::GameObject& actor ) const
if( kind != ObjKind::BattleNpc && kind != ObjKind::Player ) if( kind != ObjKind::BattleNpc && kind != ObjKind::Player )
return false; return false;
// todo: evaluate other actions that can hit condition (eg. sprint) // for any non-targeted aoe action m_canTargetSelf is always true and no other info is available
/* if( !m_canTargetSelf && chara->getId() == m_pSource->getId() )
return false;*/
if( ( m_lutEntry.potency > 0 || m_lutEntry.curePotency > 0 ) && !chara->isAlive() ) // !m_canTargetDead not working for aoe
return false;
if( m_lutEntry.potency > 0 && m_pSource->getObjKind() == chara->getObjKind() ) // !m_canTargetFriendly not working for aoe
return false;
if( ( m_lutEntry.potency == 0 && m_lutEntry.curePotency > 0 ) && m_pSource->getObjKind() != chara->getObjKind() ) // !m_canTargetHostile not working for aoe
return false;
if( chara->isAlive() && ( m_lutEntry.curePotency > 0 || m_canTargetFriendly ) && m_pSource->isFriendly( *chara ) )
return true; return true;
if( chara->isAlive() && ( m_lutEntry.potency > 0 || m_canTargetHostile ) > 0 && m_pSource->isHostile( *chara ) )
return true;
return false;
} }
std::vector< Entity::CharaPtr >& Action::Action::getHitCharas() std::vector< Entity::CharaPtr >& Action::Action::getHitCharas()

View file

@ -833,8 +833,21 @@ bool Chara::isFacingTarget( const Chara& other, float threshold )
return dot >= threshold; return dot >= threshold;
} }
bool Sapphire::Entity::Chara::isHostile( const Chara& chara )
{
return m_objKind != chara.getObjKind();
}
bool Sapphire::Entity::Chara::isFriendly( const Chara& chara )
{
return m_objKind == chara.getObjKind();
}
void Chara::onTick() void Chara::onTick()
{ {
if ( !isAlive() )
return;
uint32_t thisTickDmg = 0; uint32_t thisTickDmg = 0;
uint32_t thisTickHeal = 0; uint32_t thisTickHeal = 0;

View file

@ -229,8 +229,12 @@ namespace Sapphire::Entity
virtual void onDamageTaken( Chara& pSource ) {}; virtual void onDamageTaken( Chara& pSource ) {};
virtual bool isHostile( const Chara& chara );
virtual void onActionHostile( CharaPtr pSource ) {}; virtual void onActionHostile( CharaPtr pSource ) {};
virtual bool isFriendly( const Chara& chara );
virtual void onActionFriendly( Chara& pSource ) {}; virtual void onActionFriendly( Chara& pSource ) {};
virtual void onTick(); virtual void onTick();

View file

@ -121,15 +121,18 @@ void ActionMgr::handleMountAction( Entity::Player& player, uint16_t mountId,
void ActionMgr::bootstrapAction( Entity::Chara& src, Action::ActionPtr currentAction, void ActionMgr::bootstrapAction( Entity::Chara& src, Action::ActionPtr currentAction,
Excel::ExcelStructPtr< Excel::Action > actionData ) Excel::ExcelStructPtr< Excel::Action > actionData )
{ {
/* auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
//TODO: need to be fixed scriptMgr.onBeforeBootstrap( *currentAction );
if( currentAction->isInterrupted() )
return;
// re-enable this call but disable most of the old unfixed checks as scripts can override it with special checks.
if( !currentAction->preCheck() ) if( !currentAction->preCheck() )
{ {
// forcefully interrupt the action and reset the cooldown
currentAction->interrupt(); currentAction->interrupt();
return; return;
} }
*/
if( src.getCurrentAction() ) if( src.getCurrentAction() )
{ {

View file

@ -90,9 +90,6 @@ void Sapphire::Network::GameConnection::actionRequest( const Packets::FFXIVARR_P
break; break;
} }
} }
} }
void Sapphire::Network::GameConnection::selectGroundActionRequest( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player ) void Sapphire::Network::GameConnection::selectGroundActionRequest( const Packets::FFXIVARR_PACKET_RAW& inPacket, Entity::Player& player )

View file

@ -77,6 +77,10 @@ namespace Sapphire::ScriptAPI
{ {
} }
void ActionScript::onBeforeBootstrap( Sapphire::World::Action::Action& action )
{
}
void ActionScript::onStart( Sapphire::World::Action::Action& action ) void ActionScript::onStart( Sapphire::World::Action::Action& action )
{ {
} }
@ -89,6 +93,10 @@ namespace Sapphire::ScriptAPI
{ {
} }
void ActionScript::onAfterBuildEffect( Sapphire::World::Action::Action& action )
{
}
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
EventScript::EventScript( uint32_t eventId ) : ScriptObject( eventId, typeid( EventScript ).hash_code() ) EventScript::EventScript( uint32_t eventId ) : ScriptObject( eventId, typeid( EventScript ).hash_code() )

View file

@ -133,12 +133,16 @@ namespace Sapphire::ScriptAPI
public: public:
explicit ActionScript( uint32_t actionId ); explicit ActionScript( uint32_t actionId );
virtual void onBeforeBootstrap( Sapphire::World::Action::Action& action );
virtual void onStart( Sapphire::World::Action::Action& action ); virtual void onStart( Sapphire::World::Action::Action& action );
virtual void onExecute( Sapphire::World::Action::Action& action ); virtual void onExecute( Sapphire::World::Action::Action& action );
virtual void onInterrupt( Sapphire::World::Action::Action& action ); virtual void onInterrupt( Sapphire::World::Action::Action& action );
virtual void onAfterBuildEffect( Sapphire::World::Action::Action& action );
World::Manager::WarpMgr& warpMgr() World::Manager::WarpMgr& warpMgr()
{ {
return Common::Service< World::Manager::WarpMgr >::ref(); return Common::Service< World::Manager::WarpMgr >::ref();

View file

@ -598,6 +598,18 @@ bool Sapphire::Scripting::ScriptMgr::onExecute( World::Action::Action& action )
return false; return false;
} }
bool Sapphire::Scripting::ScriptMgr::onAfterBuildEffect( World::Action::Action& action )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() );
if( script )
{
script->onAfterBuildEffect( action );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onInterrupt( World::Action::Action& action ) bool Sapphire::Scripting::ScriptMgr::onInterrupt( World::Action::Action& action )
{ {
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() ); auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() );
@ -610,6 +622,19 @@ bool Sapphire::Scripting::ScriptMgr::onInterrupt( World::Action::Action& action
return false; return false;
} }
bool Sapphire::Scripting::ScriptMgr::onBeforeBootstrap( World::Action::Action& action )
{
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() );
if( script )
{
script->onBeforeBootstrap( action );
return true;
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onStart( World::Action::Action& action ) bool Sapphire::Scripting::ScriptMgr::onStart( World::Action::Action& action )
{ {
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() ); auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::ActionScript >( action.getId() );

View file

@ -78,12 +78,16 @@ namespace Sapphire::Scripting
bool onEObjHit( Entity::Player& player, uint64_t actorId, uint32_t actionId ); bool onEObjHit( Entity::Player& player, uint64_t actorId, uint32_t actionId );
bool onBeforeBootstrap( World::Action::Action& action );
bool onStart( World::Action::Action& action ); bool onStart( World::Action::Action& action );
bool onInterrupt( World::Action::Action& action ); bool onInterrupt( World::Action::Action& action );
bool onExecute( World::Action::Action& action ); bool onExecute( World::Action::Action& action );
bool onAfterBuildEffect( World::Action::Action& action );
bool onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId ); bool onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId );
bool onStatusTick( Entity::CharaPtr pActor, Sapphire::StatusEffect::StatusEffect& effect ); bool onStatusTick( Entity::CharaPtr pActor, Sapphire::StatusEffect::StatusEffect& effect );