mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-25 19:17:45 +00:00
Implement shield buff, and script for adloquium as a demo.
This commit is contained in:
parent
659786590c
commit
0573138e1b
16 changed files with 337 additions and 69 deletions
|
@ -624,6 +624,7 @@ namespace Sapphire::Common
|
||||||
TpGain = 13,
|
TpGain = 13,
|
||||||
GpGain = 14,
|
GpGain = 14,
|
||||||
ApplyStatusEffect = 15,
|
ApplyStatusEffect = 15,
|
||||||
|
StatusNoEffect = 21,
|
||||||
/*!
|
/*!
|
||||||
* @brief Tells the client that it should show combo indicators on actions.
|
* @brief Tells the client that it should show combo indicators on actions.
|
||||||
*
|
*
|
||||||
|
@ -650,6 +651,7 @@ namespace Sapphire::Common
|
||||||
enum class ActionEffectResultFlag : uint8_t
|
enum class ActionEffectResultFlag : uint8_t
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0,
|
||||||
|
Absorbed = 4,
|
||||||
EffectOnSource = 0x80,
|
EffectOnSource = 0x80,
|
||||||
Reflected = 0xA0,
|
Reflected = 0xA0,
|
||||||
};
|
};
|
||||||
|
@ -1034,6 +1036,7 @@ namespace Sapphire::Common
|
||||||
CritDHRateBonus = 7,
|
CritDHRateBonus = 7,
|
||||||
DamageReceiveTrigger = 8,
|
DamageReceiveTrigger = 8,
|
||||||
DamageDealtTrigger = 9,
|
DamageDealtTrigger = 9,
|
||||||
|
Shield = 10,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ActionTypeFilter : int32_t
|
enum class ActionTypeFilter : int32_t
|
||||||
|
|
|
@ -422,7 +422,8 @@ namespace Sapphire::Network::Packets::Server
|
||||||
uint16_t current_mp;
|
uint16_t current_mp;
|
||||||
uint16_t max_mp;
|
uint16_t max_mp;
|
||||||
uint16_t currentTp;
|
uint16_t currentTp;
|
||||||
uint16_t unknown1;
|
uint8_t shieldPercentage;
|
||||||
|
uint8_t unknown1;
|
||||||
Common::StatusEffect effect[30];
|
Common::StatusEffect effect[30];
|
||||||
uint32_t padding;
|
uint32_t padding;
|
||||||
};
|
};
|
||||||
|
@ -441,25 +442,16 @@ namespace Sapphire::Network::Packets::Server
|
||||||
{
|
{
|
||||||
uint32_t unknown;
|
uint32_t unknown;
|
||||||
uint32_t actor_id;
|
uint32_t actor_id;
|
||||||
//uint8_t unknown1;
|
|
||||||
//uint8_t unknown2;
|
|
||||||
//uint16_t padding1;
|
|
||||||
//uint32_t current_hp;
|
|
||||||
//uint16_t current_mp;
|
|
||||||
//uint16_t current_tp;
|
|
||||||
//uint32_t max_hp;
|
|
||||||
//uint16_t max_mp;
|
|
||||||
//uint16_t max_something;
|
|
||||||
uint32_t current_hp;
|
uint32_t current_hp;
|
||||||
uint32_t max_hp;
|
uint32_t max_hp;
|
||||||
uint16_t current_mp;
|
uint16_t current_mp;
|
||||||
uint16_t unknown1;
|
uint16_t current_tp;
|
||||||
uint16_t max_mp;
|
uint16_t max_mp;
|
||||||
uint8_t unknown2;
|
uint8_t unknown1;
|
||||||
uint8_t classId;
|
uint8_t classId;
|
||||||
uint8_t unknown4;
|
uint8_t shieldPercentage;
|
||||||
uint8_t unkFlag;
|
uint8_t entryCount;
|
||||||
uint16_t unknown6;
|
uint16_t unknown2;
|
||||||
|
|
||||||
struct StatusEntry
|
struct StatusEntry
|
||||||
{
|
{
|
||||||
|
@ -467,12 +459,12 @@ namespace Sapphire::Network::Packets::Server
|
||||||
uint8_t unknown3;
|
uint8_t unknown3;
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
uint16_t param;
|
uint16_t param;
|
||||||
uint16_t unknown5; // Sort this out (old right half of power/param property)
|
uint16_t unknown4; // Sort this out (old right half of power/param property)
|
||||||
float duration;
|
float duration;
|
||||||
uint32_t sourceActorId;
|
uint32_t sourceActorId;
|
||||||
} statusEntries[4];
|
} statusEntries[4];
|
||||||
|
|
||||||
uint32_t unknown7;
|
uint32_t unknown5;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
83
src/scripts/action/common/ActionAdloquium185.cpp
Normal file
83
src/scripts/action/common/ActionAdloquium185.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
#include <Script/NativeScriptApi.h>
|
||||||
|
#include <ScriptObject.h>
|
||||||
|
#include <Actor/Player.h>
|
||||||
|
#include <Action/Action.h>
|
||||||
|
#include <Math/CalcStats.h>
|
||||||
|
|
||||||
|
#include "StatusEffect/StatusEffect.h"
|
||||||
|
|
||||||
|
using namespace Sapphire;
|
||||||
|
using namespace Sapphire::StatusEffect;
|
||||||
|
|
||||||
|
const uint16_t STATUS_ID_GALVANIZE = 297;
|
||||||
|
const uint16_t STATUS_ID_CATALYZE = 1918;
|
||||||
|
|
||||||
|
class ActionAdloquium185 :
|
||||||
|
public ScriptAPI::ActionScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActionAdloquium185() :
|
||||||
|
ScriptAPI::ActionScript( 185 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onExecute( Sapphire::World::Action::Action& action ) override
|
||||||
|
{
|
||||||
|
auto pTarget = action.getHitChara();
|
||||||
|
if( pTarget )
|
||||||
|
{
|
||||||
|
// still pull out the lut entry to get potency values etc.
|
||||||
|
auto lutEntry = action.getActionEntry();
|
||||||
|
|
||||||
|
// do healing part
|
||||||
|
auto heal = action.calcHealing( lutEntry.healPotency );
|
||||||
|
heal.first = Math::CalcStats::applyHealingReceiveMultiplier( *pTarget, heal.first );
|
||||||
|
action.getEffectbuilder()->heal( pTarget, pTarget, heal.first, heal.second );
|
||||||
|
|
||||||
|
float shieldValue = heal.first * 1.25f;
|
||||||
|
// apply new galvanize when not existing or larger than existing one
|
||||||
|
auto oldEffect = pTarget->getStatusEffectById( STATUS_ID_GALVANIZE );
|
||||||
|
if( !oldEffect.second || oldEffect.second->getEffectEntry().effectValue1 <= shieldValue )
|
||||||
|
{
|
||||||
|
World::Action::StatusEffectEntry effectEntry;
|
||||||
|
effectEntry.effectType = static_cast< uint32_t >( Common::StatusEffectType::Shield );
|
||||||
|
effectEntry.effectValue1 = static_cast< int32_t >( shieldValue );
|
||||||
|
auto pNewEffect = action.createStatusEffect( STATUS_ID_GALVANIZE, action.getSourceChara(), pTarget, 30000, 3000 );
|
||||||
|
pNewEffect->replaceEffectEntry( effectEntry );
|
||||||
|
action.getEffectbuilder()->applyStatusEffect( pTarget, action.getSourceChara(), pNewEffect );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action.getEffectbuilder()->statusNoEffect( pTarget, STATUS_ID_GALVANIZE );
|
||||||
|
|
||||||
|
if( heal.second == Common::ActionHitSeverityType::CritHeal )
|
||||||
|
{
|
||||||
|
// apply catalyze when crit, same rule as galvanize
|
||||||
|
oldEffect = pTarget->getStatusEffectById( STATUS_ID_CATALYZE );
|
||||||
|
if( !oldEffect.second || oldEffect.second->getEffectEntry().effectValue1 <= shieldValue )
|
||||||
|
{
|
||||||
|
World::Action::StatusEffectEntry effectEntry;
|
||||||
|
effectEntry.effectType = static_cast< uint32_t >( Common::StatusEffectType::Shield );
|
||||||
|
effectEntry.effectValue1 = static_cast< int32_t >( shieldValue ); // same shield value
|
||||||
|
auto pNewEffect = action.createStatusEffect( STATUS_ID_CATALYZE, action.getSourceChara(), pTarget, 30000, 3000 );
|
||||||
|
pNewEffect->replaceEffectEntry( effectEntry );
|
||||||
|
action.getEffectbuilder()->applyStatusEffect( pTarget, action.getSourceChara(), pNewEffect );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action.getEffectbuilder()->statusNoEffect( pTarget, STATUS_ID_CATALYZE );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onStart( Sapphire::World::Action::Action& action ) override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
don't run generic action handler for this action.
|
||||||
|
for simpler actions like cure 1 we only want to apply the freecure proc in script,
|
||||||
|
and let the generic handler do the heal so we don't have to copy heal code into scripts,
|
||||||
|
unless in cases like adlo, the healing result matters so we have to.
|
||||||
|
*/
|
||||||
|
action.disableGenericHandler();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPOSE_SCRIPT( ActionAdloquium185 );
|
|
@ -51,7 +51,8 @@ Action::Action::Action( Entity::CharaPtr caster, uint32_t actionId, uint16_t seq
|
||||||
m_startTime( 0 ),
|
m_startTime( 0 ),
|
||||||
m_interruptType( Common::ActionInterruptType::None ),
|
m_interruptType( Common::ActionInterruptType::None ),
|
||||||
m_sequence( sequence ),
|
m_sequence( sequence ),
|
||||||
m_isAutoAttack( false )
|
m_isAutoAttack( false ),
|
||||||
|
m_disableGenericHandler( false )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +296,7 @@ void Action::Action::start()
|
||||||
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
||||||
|
|
||||||
// check the lut too and see if we have something usable, otherwise cancel the cast
|
// check the lut too and see if we have something usable, otherwise cancel the cast
|
||||||
if( !pScriptMgr->onStart( *this ) && !ActionLut::validEntryExists( static_cast< uint16_t >( getId() ) ) )
|
if( !pScriptMgr->onStart( *this ) && !hasValidLutEntry() )
|
||||||
{
|
{
|
||||||
// script not implemented and insufficient lut data (no potencies)
|
// script not implemented and insufficient lut data (no potencies)
|
||||||
interrupt();
|
interrupt();
|
||||||
|
@ -424,9 +425,8 @@ void Action::Action::buildEffects()
|
||||||
snapshotAffectedActors( m_hitActors );
|
snapshotAffectedActors( m_hitActors );
|
||||||
|
|
||||||
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
||||||
auto hasLutEntry = hasValidLutEntry();
|
|
||||||
|
|
||||||
if( !pScriptMgr->onExecute( *this ) && !hasLutEntry )
|
if( !pScriptMgr->onExecute( *this ) && !hasValidLutEntry() )
|
||||||
{
|
{
|
||||||
if( auto player = m_pSource->getAsPlayer() )
|
if( auto player = m_pSource->getAsPlayer() )
|
||||||
{
|
{
|
||||||
|
@ -436,7 +436,7 @@ void Action::Action::buildEffects()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !hasLutEntry ) // this is just "if ( weCanNotUseGenericActionHandler )" in case we start to expand it.
|
if( m_disableGenericHandler || !hasValidLutEntry() )
|
||||||
{
|
{
|
||||||
// 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_effectBuilder->buildAndSendPackets();
|
m_effectBuilder->buildAndSendPackets();
|
||||||
|
@ -469,7 +469,8 @@ void Action::Action::buildEffects()
|
||||||
if( dmg.first > 0 )
|
if( dmg.first > 0 )
|
||||||
{
|
{
|
||||||
actor->onActionHostile( m_pSource );
|
actor->onActionHostile( m_pSource );
|
||||||
m_effectBuilder->damage( actor, actor, dmg.first, dmg.second );
|
dmg.first = Math::CalcStats::applyShieldProtection( actor, dmg.first );
|
||||||
|
m_effectBuilder->damage( actor, actor, dmg.first, dmg.second, dmg.first == 0 ? Common::ActionEffectResultFlag::Absorbed : Common::ActionEffectResultFlag::None );
|
||||||
}
|
}
|
||||||
|
|
||||||
auto reflectDmg = Math::CalcStats::calcDamageReflect( m_pSource, actor, dmg.first,
|
auto reflectDmg = Math::CalcStats::calcDamageReflect( m_pSource, actor, dmg.first,
|
||||||
|
@ -824,11 +825,21 @@ Data::ActionPtr Action::Action::getActionData() const
|
||||||
return m_actionData;
|
return m_actionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action::ActionEntry Action::Action::getActionEntry() const
|
||||||
|
{
|
||||||
|
return m_lutEntry;
|
||||||
|
}
|
||||||
|
|
||||||
void Action::Action::setAutoAttack()
|
void Action::Action::setAutoAttack()
|
||||||
{
|
{
|
||||||
m_isAutoAttack = true;
|
m_isAutoAttack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Action::Action::disableGenericHandler()
|
||||||
|
{
|
||||||
|
m_disableGenericHandler = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Action::Action::isPhysical() const
|
bool Action::Action::isPhysical() const
|
||||||
{
|
{
|
||||||
return isAttackTypePhysical( static_cast< Common::AttackType >( m_actionData->attackType ) );
|
return isAttackTypePhysical( static_cast< Common::AttackType >( m_actionData->attackType ) );
|
||||||
|
@ -848,3 +859,9 @@ bool Action::Action::isAttackTypeMagical( Common::AttackType attackType )
|
||||||
{
|
{
|
||||||
return attackType == Common::AttackType::Magical;
|
return attackType == Common::AttackType::Magical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sapphire::StatusEffect::StatusEffectPtr Action::Action::createStatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor, uint32_t duration, uint32_t tickRate )
|
||||||
|
{
|
||||||
|
// workaround to framework access issue in action script
|
||||||
|
return StatusEffect::make_StatusEffect( id, sourceActor, targetActor, duration, tickRate, m_pFw );
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
#include "Util/ActorFilter.h"
|
#include "Util/ActorFilter.h"
|
||||||
#include "ForwardsZone.h"
|
#include "ForwardsZone.h"
|
||||||
#include "EffectBuilder.h"
|
#include "EffectBuilder.h"
|
||||||
|
#include "StatusEffect/StatusEffect.h"
|
||||||
|
|
||||||
namespace Sapphire::Data
|
namespace Sapphire::Data
|
||||||
{
|
{
|
||||||
|
@ -54,6 +55,10 @@ namespace Sapphire::World::Action
|
||||||
|
|
||||||
void setAutoAttack();
|
void setAutoAttack();
|
||||||
|
|
||||||
|
void disableGenericHandler();
|
||||||
|
|
||||||
|
StatusEffect::StatusEffectPtr createStatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor, uint32_t duration, uint32_t tickRate );
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Checks if a chara has enough resources available to cast the action (tp/mp/etc)
|
* @brief Checks if a chara has enough resources available to cast the action (tp/mp/etc)
|
||||||
* @return true if they have the required resources
|
* @return true if they have the required resources
|
||||||
|
@ -122,6 +127,8 @@ namespace Sapphire::World::Action
|
||||||
|
|
||||||
Data::ActionPtr getActionData() const;
|
Data::ActionPtr getActionData() const;
|
||||||
|
|
||||||
|
ActionEntry getActionEntry() const;
|
||||||
|
|
||||||
bool isPhysical() const;
|
bool isPhysical() const;
|
||||||
bool isMagical() const;
|
bool isMagical() const;
|
||||||
|
|
||||||
|
@ -191,6 +198,7 @@ namespace Sapphire::World::Action
|
||||||
bool m_canTargetHostile;
|
bool m_canTargetHostile;
|
||||||
bool m_canTargetDead;
|
bool m_canTargetDead;
|
||||||
bool m_isAutoAttack;
|
bool m_isAutoAttack;
|
||||||
|
bool m_disableGenericHandler;
|
||||||
|
|
||||||
Common::ActionInterruptType m_interruptType;
|
Common::ActionInterruptType m_interruptType;
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,20 @@ void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, Entity::CharaPt
|
||||||
moveToResultList( target, nextResult );
|
moveToResultList( target, nextResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectBuilder::applyStatusEffect( Entity::CharaPtr& target, Entity::CharaPtr& source, StatusEffect::StatusEffectPtr pStatusEffect )
|
||||||
|
{
|
||||||
|
EffectResultPtr nextResult = make_EffectResult( target, source, getResultDelayMs() );
|
||||||
|
nextResult->applyStatusEffect( pStatusEffect );
|
||||||
|
moveToResultList( target, nextResult );
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectBuilder::statusNoEffect( Entity::CharaPtr& target, uint16_t statusId )
|
||||||
|
{
|
||||||
|
EffectResultPtr nextResult = make_EffectResult( target, nullptr, 0 );
|
||||||
|
nextResult->statusNoEffect( statusId );
|
||||||
|
moveToResultList( target, nextResult );
|
||||||
|
}
|
||||||
|
|
||||||
void EffectBuilder::buildAndSendPackets()
|
void EffectBuilder::buildAndSendPackets()
|
||||||
{
|
{
|
||||||
auto targetCount = m_resolvedEffects.size();
|
auto targetCount = m_resolvedEffects.size();
|
||||||
|
|
|
@ -27,10 +27,12 @@ namespace Sapphire::World::Action
|
||||||
void comboSucceed( Entity::CharaPtr& target );
|
void comboSucceed( Entity::CharaPtr& target );
|
||||||
|
|
||||||
void applyStatusEffect( Entity::CharaPtr& target, Entity::CharaPtr& source, uint16_t statusId, uint32_t duration, uint8_t param );
|
void applyStatusEffect( Entity::CharaPtr& target, Entity::CharaPtr& source, uint16_t statusId, uint32_t duration, uint8_t param );
|
||||||
|
void applyStatusEffect( Entity::CharaPtr& target, Entity::CharaPtr& source, StatusEffect::StatusEffectPtr pStatusEffect );
|
||||||
|
|
||||||
|
void statusNoEffect( Entity::CharaPtr& target, uint16_t statusId );
|
||||||
|
|
||||||
void buildAndSendPackets();
|
void buildAndSendPackets();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void moveToResultList( Entity::CharaPtr& chara, EffectResultPtr result );
|
void moveToResultList( Entity::CharaPtr& chara, EffectResultPtr result );
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,8 @@ EffectResult::EffectResult( Entity::CharaPtr target, Entity::CharaPtr source, ui
|
||||||
m_param0( 0 ),
|
m_param0( 0 ),
|
||||||
m_param1( 0 ),
|
m_param1( 0 ),
|
||||||
m_param2( 0 ),
|
m_param2( 0 ),
|
||||||
m_flag( Common::ActionEffectResultFlag::None )
|
m_flag( Common::ActionEffectResultFlag::None ),
|
||||||
|
m_pPreBuiltStatusEffect( nullptr )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,6 +93,22 @@ void EffectResult::applyStatusEffect( uint16_t statusId, uint32_t duration, uint
|
||||||
m_type = Common::ActionEffectType::ApplyStatusEffect;
|
m_type = Common::ActionEffectType::ApplyStatusEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EffectResult::applyStatusEffect( StatusEffect::StatusEffectPtr pStatusEffect )
|
||||||
|
{
|
||||||
|
m_value = pStatusEffect->getId();
|
||||||
|
m_param2 = pStatusEffect->getParam();
|
||||||
|
m_pPreBuiltStatusEffect = std::move( pStatusEffect );
|
||||||
|
|
||||||
|
m_type = Common::ActionEffectType::ApplyStatusEffect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EffectResult::statusNoEffect( uint16_t statusId )
|
||||||
|
{
|
||||||
|
m_value = statusId;
|
||||||
|
|
||||||
|
m_type = Common::ActionEffectType::StatusNoEffect;
|
||||||
|
}
|
||||||
|
|
||||||
Common::EffectEntry EffectResult::buildEffectEntry() const
|
Common::EffectEntry EffectResult::buildEffectEntry() const
|
||||||
{
|
{
|
||||||
Common::EffectEntry entry{};
|
Common::EffectEntry entry{};
|
||||||
|
@ -131,6 +148,21 @@ void EffectResult::execute()
|
||||||
|
|
||||||
case Common::ActionEffectType::ApplyStatusEffect:
|
case Common::ActionEffectType::ApplyStatusEffect:
|
||||||
{
|
{
|
||||||
|
//remove same effect from the same source (refreshing old buff)
|
||||||
|
for( auto const& entry : m_target->getStatusEffectMap() )
|
||||||
|
{
|
||||||
|
auto statusEffect = entry.second;
|
||||||
|
if( statusEffect->getId() == m_value && statusEffect->getSrcActorId() == m_source->getId() )
|
||||||
|
{
|
||||||
|
// refreshing does not show "-status" flying text, and we don't send status list now because we are adding a new one
|
||||||
|
m_target->removeStatusEffect( entry.first, false, false );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_pPreBuiltStatusEffect )
|
||||||
|
m_target->addStatusEffect( m_pPreBuiltStatusEffect );
|
||||||
|
else
|
||||||
m_target->addStatusEffectById( m_value, m_value2, *m_source, m_param2 );
|
m_target->addStatusEffectById( m_value, m_value2, *m_source, m_param2 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <ForwardsZone.h>
|
#include <ForwardsZone.h>
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
|
|
||||||
|
#include "StatusEffect/StatusEffect.h"
|
||||||
|
|
||||||
namespace Sapphire::World::Action
|
namespace Sapphire::World::Action
|
||||||
{
|
{
|
||||||
/*!
|
/*!
|
||||||
|
@ -21,6 +23,8 @@ namespace Sapphire::World::Action
|
||||||
void startCombo( uint16_t actionId );
|
void startCombo( uint16_t actionId );
|
||||||
void comboSucceed();
|
void comboSucceed();
|
||||||
void applyStatusEffect( uint16_t statusId, uint32_t duration, uint8_t param );
|
void applyStatusEffect( uint16_t statusId, uint32_t duration, uint8_t param );
|
||||||
|
void applyStatusEffect( StatusEffect::StatusEffectPtr pStatusEffect );
|
||||||
|
void statusNoEffect( uint16_t statusId );
|
||||||
|
|
||||||
Entity::CharaPtr getSource() const;
|
Entity::CharaPtr getSource() const;
|
||||||
Entity::CharaPtr getTarget() const;
|
Entity::CharaPtr getTarget() const;
|
||||||
|
@ -48,6 +52,8 @@ namespace Sapphire::World::Action
|
||||||
uint32_t m_value;
|
uint32_t m_value;
|
||||||
uint32_t m_value2;
|
uint32_t m_value2;
|
||||||
Common::ActionEffectResultFlag m_flag;
|
Common::ActionEffectResultFlag m_flag;
|
||||||
|
|
||||||
|
StatusEffect::StatusEffectPtr m_pPreBuiltStatusEffect;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -501,13 +501,11 @@ void Sapphire::Entity::Chara::addStatusEffect( StatusEffect::StatusEffectPtr pEf
|
||||||
statusEffectAdd->data().actor_id = pEffect->getTargetActorId();
|
statusEffectAdd->data().actor_id = pEffect->getTargetActorId();
|
||||||
statusEffectAdd->data().current_hp = getHp();
|
statusEffectAdd->data().current_hp = getHp();
|
||||||
statusEffectAdd->data().current_mp = static_cast< uint16_t >( getMp() );
|
statusEffectAdd->data().current_mp = static_cast< uint16_t >( getMp() );
|
||||||
//statusEffectAdd->data().current_tp = getTp();
|
statusEffectAdd->data().current_tp = getTp();
|
||||||
statusEffectAdd->data().max_hp = getMaxHp();
|
statusEffectAdd->data().max_hp = getMaxHp();
|
||||||
statusEffectAdd->data().max_mp = static_cast< uint16_t >( getMaxMp() );
|
statusEffectAdd->data().max_mp = static_cast< uint16_t >( getMaxMp() );
|
||||||
//statusEffectAdd->data().max_something = 1;
|
|
||||||
//statusEffectAdd->data().unknown2 = 28;
|
|
||||||
statusEffectAdd->data().classId = static_cast< uint8_t >( getClass() );
|
statusEffectAdd->data().classId = static_cast< uint8_t >( getClass() );
|
||||||
statusEffectAdd->data().unkFlag = 1;
|
statusEffectAdd->data().entryCount = 1; // todo: add multiple status but send only one result
|
||||||
|
|
||||||
auto& status = statusEffectAdd->data().statusEntries[0];
|
auto& status = statusEffectAdd->data().statusEntries[0];
|
||||||
|
|
||||||
|
@ -517,31 +515,47 @@ void Sapphire::Entity::Chara::addStatusEffect( StatusEffect::StatusEffectPtr pEf
|
||||||
status.index = static_cast< uint8_t >( nextSlot );
|
status.index = static_cast< uint8_t >( nextSlot );
|
||||||
status.param = pEffect->getParam();
|
status.param = pEffect->getParam();
|
||||||
|
|
||||||
sendToInRangeSet( statusEffectAdd, isPlayer() );
|
float totalShieldValue = 0;
|
||||||
|
for( auto effectIt : m_statusEffectMap )
|
||||||
|
{
|
||||||
|
auto statusEffect = effectIt.second;
|
||||||
|
if( static_cast< Common::StatusEffectType >( statusEffect->getEffectEntry().effectType ) == Common::StatusEffectType::Shield )
|
||||||
|
{
|
||||||
|
totalShieldValue += statusEffect->getEffectEntry().effectValue1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( totalShieldValue > 0 )
|
||||||
|
{
|
||||||
|
totalShieldValue /= getMaxHp();
|
||||||
|
totalShieldValue *= 100;
|
||||||
|
statusEffectAdd->data().shieldPercentage = totalShieldValue >= 255 ? 255 : static_cast< uint8_t >( totalShieldValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToInRangeSet( statusEffectAdd, true );
|
||||||
|
sendStatusEffectUpdate(); // although client buff displays correctly without this but retail sends it so we do it as well
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \param StatusEffectPtr to be applied to the actor */
|
|
||||||
void Sapphire::Entity::Chara::addStatusEffectById( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param )
|
void Sapphire::Entity::Chara::addStatusEffectById( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param )
|
||||||
{
|
{
|
||||||
if( hasStatusEffect( id ) ) // todo: check if we want to refresh it or discard and keep the old one
|
auto oldEffect = getStatusEffectById( id );
|
||||||
removeSingleStatusEffectById( id, false );
|
if( oldEffect.second )
|
||||||
|
removeStatusEffect( oldEffect.first, false, false );
|
||||||
|
|
||||||
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000, m_pFw );
|
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000, m_pFw );
|
||||||
effect->setParam( param );
|
effect->setParam( param );
|
||||||
addStatusEffect( effect );
|
addStatusEffect( effect );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \param StatusEffectPtr to be applied to the actor */
|
|
||||||
void Sapphire::Entity::Chara::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source,
|
void Sapphire::Entity::Chara::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source,
|
||||||
uint16_t param )
|
uint16_t param )
|
||||||
{
|
{
|
||||||
if( hasStatusEffect( id ) )
|
if( getStatusEffectById( id ).second )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000, m_pFw );
|
auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000, m_pFw );
|
||||||
effect->setParam( param );
|
effect->setParam( param );
|
||||||
addStatusEffect( effect );
|
addStatusEffect( effect );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t Sapphire::Entity::Chara::getStatusEffectFreeSlot()
|
int8_t Sapphire::Entity::Chara::getStatusEffectFreeSlot()
|
||||||
|
@ -562,19 +576,19 @@ void Sapphire::Entity::Chara::statusEffectFreeSlot( uint8_t slotId )
|
||||||
m_statusEffectFreeSlotQueue.push( slotId );
|
m_statusEffectFreeSlotQueue.push( slotId );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Chara::removeSingleStatusEffectById( uint32_t id, bool sendPacket )
|
void Sapphire::Entity::Chara::removeSingleStatusEffectById( uint32_t id, bool sendActorControl, bool sendStatusList )
|
||||||
{
|
{
|
||||||
for( auto effectIt : m_statusEffectMap )
|
for( auto effectIt : m_statusEffectMap )
|
||||||
{
|
{
|
||||||
if( effectIt.second->getId() == id )
|
if( effectIt.second->getId() == id )
|
||||||
{
|
{
|
||||||
removeStatusEffect( effectIt.first, sendPacket );
|
removeStatusEffect( effectIt.first, sendActorControl, sendStatusList );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Chara::removeStatusEffect( uint8_t effectSlotId, bool sendPacket )
|
void Sapphire::Entity::Chara::removeStatusEffect( uint8_t effectSlotId, bool sendActorControl, bool sendStatusList )
|
||||||
{
|
{
|
||||||
auto pEffectIt = m_statusEffectMap.find( effectSlotId );
|
auto pEffectIt = m_statusEffectMap.find( effectSlotId );
|
||||||
if( pEffectIt == m_statusEffectMap.end() )
|
if( pEffectIt == m_statusEffectMap.end() )
|
||||||
|
@ -585,11 +599,12 @@ void Sapphire::Entity::Chara::removeStatusEffect( uint8_t effectSlotId, bool sen
|
||||||
auto pEffect = pEffectIt->second;
|
auto pEffect = pEffectIt->second;
|
||||||
pEffect->removeStatus();
|
pEffect->removeStatus();
|
||||||
|
|
||||||
if( sendPacket )
|
if( sendActorControl )
|
||||||
sendToInRangeSet( makeActorControl( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() );
|
sendToInRangeSet( makeActorControl( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() );
|
||||||
|
|
||||||
m_statusEffectMap.erase( effectSlotId );
|
m_statusEffectMap.erase( effectSlotId );
|
||||||
|
|
||||||
|
if( sendStatusList )
|
||||||
sendStatusEffectUpdate();
|
sendStatusEffectUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,7 +637,6 @@ void Sapphire::Entity::Chara::sendStatusEffectUpdate()
|
||||||
{
|
{
|
||||||
uint64_t currentTimeMs = Util::getTimeMs();
|
uint64_t currentTimeMs = Util::getTimeMs();
|
||||||
|
|
||||||
|
|
||||||
auto statusEffectList = makeZonePacket< FFXIVIpcStatusEffectList >( getId() );
|
auto statusEffectList = makeZonePacket< FFXIVIpcStatusEffectList >( getId() );
|
||||||
statusEffectList->data().classId = static_cast< uint8_t >( getClass() );
|
statusEffectList->data().classId = static_cast< uint8_t >( getClass() );
|
||||||
statusEffectList->data().level = getLevel();
|
statusEffectList->data().level = getLevel();
|
||||||
|
@ -633,18 +647,63 @@ void Sapphire::Entity::Chara::sendStatusEffectUpdate()
|
||||||
statusEffectList->data().max_hp = getMaxHp();
|
statusEffectList->data().max_hp = getMaxHp();
|
||||||
statusEffectList->data().max_mp = getMaxMp();
|
statusEffectList->data().max_mp = getMaxMp();
|
||||||
uint8_t slot = 0;
|
uint8_t slot = 0;
|
||||||
|
float totalShieldValue = 0;
|
||||||
for( auto effectIt : m_statusEffectMap )
|
for( auto effectIt : m_statusEffectMap )
|
||||||
{
|
{
|
||||||
float timeLeft = static_cast< float >( effectIt.second->getDuration() -
|
auto statusEffect = effectIt.second;
|
||||||
( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000;
|
if( static_cast< Common::StatusEffectType >( statusEffect->getEffectEntry().effectType ) == Common::StatusEffectType::Shield )
|
||||||
|
{
|
||||||
|
totalShieldValue += statusEffect->getEffectEntry().effectValue1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float timeLeft = static_cast< float >( statusEffect->getDuration() -
|
||||||
|
( currentTimeMs - statusEffect->getStartTimeMs() ) ) / 1000;
|
||||||
statusEffectList->data().effect[ slot ].duration = timeLeft;
|
statusEffectList->data().effect[ slot ].duration = timeLeft;
|
||||||
statusEffectList->data().effect[ slot ].effect_id = effectIt.second->getId();
|
statusEffectList->data().effect[ slot ].effect_id = statusEffect->getId();
|
||||||
statusEffectList->data().effect[ slot ].sourceActorId = effectIt.second->getSrcActorId();
|
statusEffectList->data().effect[ slot ].sourceActorId = statusEffect->getSrcActorId();
|
||||||
slot++;
|
slot++;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendToInRangeSet( statusEffectList, isPlayer() );
|
if( totalShieldValue > 0 )
|
||||||
|
{
|
||||||
|
totalShieldValue /= getMaxHp();
|
||||||
|
totalShieldValue *= 100;
|
||||||
|
statusEffectList->data().shieldPercentage = totalShieldValue >= 255 ? 255 : static_cast< uint8_t >( totalShieldValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToInRangeSet( statusEffectList, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Chara::sendEffectResultToUpdateShieldValue()
|
||||||
|
{
|
||||||
|
auto pPacket = makeZonePacket< FFXIVIpcEffectResult >( getId() );
|
||||||
|
|
||||||
|
pPacket->data().actor_id = getId();
|
||||||
|
pPacket->data().current_hp = getHp();
|
||||||
|
pPacket->data().current_mp = static_cast< uint16_t >( getMp() );
|
||||||
|
pPacket->data().current_tp = getTp();
|
||||||
|
pPacket->data().max_hp = getMaxHp();
|
||||||
|
pPacket->data().max_mp = static_cast< uint16_t >( getMaxMp() );
|
||||||
|
pPacket->data().classId = static_cast< uint8_t >( getClass() );
|
||||||
|
|
||||||
|
float totalShieldValue = 0;
|
||||||
|
for( auto effectIt : m_statusEffectMap )
|
||||||
|
{
|
||||||
|
auto statusEffect = effectIt.second;
|
||||||
|
if( static_cast< Common::StatusEffectType >( statusEffect->getEffectEntry().effectType ) == Common::StatusEffectType::Shield )
|
||||||
|
{
|
||||||
|
totalShieldValue += statusEffect->getEffectEntry().effectValue1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( totalShieldValue > 0 )
|
||||||
|
{
|
||||||
|
totalShieldValue /= getMaxHp();
|
||||||
|
totalShieldValue *= 100;
|
||||||
|
pPacket->data().shieldPercentage = totalShieldValue >= 255 ? 255 : static_cast< uint8_t >( totalShieldValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
sendToInRangeSet( pPacket, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::Entity::Chara::updateStatusEffects()
|
void Sapphire::Entity::Chara::updateStatusEffects()
|
||||||
|
@ -667,7 +726,7 @@ void Sapphire::Entity::Chara::updateStatusEffects()
|
||||||
if( duration > 0 && ( currentTimeMs - startTime ) > duration )
|
if( duration > 0 && ( currentTimeMs - startTime ) > duration )
|
||||||
{
|
{
|
||||||
// remove status effect
|
// remove status effect
|
||||||
removeStatusEffect( effectIndex, true );
|
removeStatusEffect( effectIndex, true, true );
|
||||||
// break because removing invalidates iterators
|
// break because removing invalidates iterators
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -714,17 +773,16 @@ void Sapphire::Entity::Chara::updateStatusEffects()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Sapphire::Entity::Chara::hasStatusEffect( uint32_t id )
|
std::pair< uint8_t, Sapphire::StatusEffect::StatusEffectPtr > Sapphire::Entity::Chara::getStatusEffectById( uint32_t id )
|
||||||
{
|
{
|
||||||
//return m_statusEffectMap.find( id ) != m_statusEffectMap.end();
|
|
||||||
for( auto effectIt : m_statusEffectMap )
|
for( auto effectIt : m_statusEffectMap )
|
||||||
{
|
{
|
||||||
if( effectIt.second->getId() == id )
|
if( effectIt.second->getId() == id )
|
||||||
{
|
{
|
||||||
return true;
|
return std::make_pair( effectIt.first, effectIt.second );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return std::make_pair( 0, nullptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Sapphire::Entity::Chara::getLastUpdateTime() const
|
int64_t Sapphire::Entity::Chara::getLastUpdateTime() const
|
||||||
|
|
|
@ -146,13 +146,13 @@ namespace Sapphire::Entity
|
||||||
/// Status effect functions
|
/// Status effect functions
|
||||||
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
||||||
|
|
||||||
void removeStatusEffect( uint8_t effectSlotId, bool sendPacket );
|
void removeStatusEffect( uint8_t effectSlotId, bool sendActorControl, bool sendStatusList );
|
||||||
|
|
||||||
void removeSingleStatusEffectById( uint32_t id, bool sendPacket );
|
void removeSingleStatusEffectById( uint32_t id, bool sendActorControl, bool sendStatusList );
|
||||||
|
|
||||||
void updateStatusEffects();
|
void updateStatusEffects();
|
||||||
|
|
||||||
bool hasStatusEffect( uint32_t id );
|
std::pair< uint8_t, StatusEffect::StatusEffectPtr > getStatusEffectById( uint32_t id );
|
||||||
|
|
||||||
int8_t getStatusEffectFreeSlot();
|
int8_t getStatusEffectFreeSlot();
|
||||||
|
|
||||||
|
@ -166,6 +166,8 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
void sendStatusEffectUpdate();
|
void sendStatusEffectUpdate();
|
||||||
|
|
||||||
|
void sendEffectResultToUpdateShieldValue();
|
||||||
|
|
||||||
/*! return a const pointer to the look array */
|
/*! return a const pointer to the look array */
|
||||||
const uint8_t* getLookArray() const;
|
const uint8_t* getLookArray() const;
|
||||||
|
|
||||||
|
@ -177,8 +179,6 @@ namespace Sapphire::Entity
|
||||||
// add a status effect by id if it doesn't exist
|
// add a status effect by id if it doesn't exist
|
||||||
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 );
|
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 );
|
||||||
|
|
||||||
// remove a status effect by id
|
|
||||||
void removeSingleStatusEffectFromId( uint32_t id );
|
|
||||||
/// End Status Effect Functions
|
/// End Status Effect Functions
|
||||||
|
|
||||||
std::string getName() const;
|
std::string getName() const;
|
||||||
|
|
|
@ -716,7 +716,7 @@ uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara )
|
||||||
|
|
||||||
std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcDamageReflect( Sapphire::Entity::CharaPtr pCharaAttacker, Sapphire::Entity::CharaPtr pCharaVictim, float damage, Sapphire::Common::ActionTypeFilter filter )
|
std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcDamageReflect( Sapphire::Entity::CharaPtr pCharaAttacker, Sapphire::Entity::CharaPtr pCharaVictim, float damage, Sapphire::Common::ActionTypeFilter filter )
|
||||||
{
|
{
|
||||||
for( auto entry : pCharaVictim->getStatusEffectMap() )
|
for( auto const& entry : pCharaVictim->getStatusEffectMap() )
|
||||||
{
|
{
|
||||||
auto status = entry.second;
|
auto status = entry.second;
|
||||||
auto effectEntry = status->getEffectEntry();
|
auto effectEntry = status->getEffectEntry();
|
||||||
|
@ -740,7 +740,7 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcDamag
|
||||||
float CalcStats::calcAbsorbHP( Sapphire::Entity::CharaPtr pChara, float damage, Sapphire::Common::ActionTypeFilter filter )
|
float CalcStats::calcAbsorbHP( Sapphire::Entity::CharaPtr pChara, float damage, Sapphire::Common::ActionTypeFilter filter )
|
||||||
{
|
{
|
||||||
float result = 0;
|
float result = 0;
|
||||||
for( auto entry : pChara->getStatusEffectMap() )
|
for( auto const& entry : pChara->getStatusEffectMap() )
|
||||||
{
|
{
|
||||||
auto status = entry.second;
|
auto status = entry.second;
|
||||||
auto effectEntry = status->getEffectEntry();
|
auto effectEntry = status->getEffectEntry();
|
||||||
|
@ -755,3 +755,48 @@ float CalcStats::calcAbsorbHP( Sapphire::Entity::CharaPtr pChara, float damage,
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float CalcStats::applyShieldProtection( Sapphire::Entity::CharaPtr pChara, float damage )
|
||||||
|
{
|
||||||
|
float remainingDamage = damage;
|
||||||
|
bool shieldChanged = false;
|
||||||
|
std::vector< uint8_t > destroyedShieldSlotList;
|
||||||
|
|
||||||
|
for( auto const& entry : pChara->getStatusEffectMap() )
|
||||||
|
{
|
||||||
|
auto status = entry.second;
|
||||||
|
auto effectEntry = status->getEffectEntry();
|
||||||
|
|
||||||
|
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) == Common::StatusEffectType::Shield )
|
||||||
|
{
|
||||||
|
shieldChanged = true;
|
||||||
|
if( remainingDamage < effectEntry.effectValue1 )
|
||||||
|
{
|
||||||
|
effectEntry.effectValue1 -= static_cast< int32_t >( remainingDamage );
|
||||||
|
status->replaceEffectEntry( effectEntry );
|
||||||
|
remainingDamage = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remainingDamage -= effectEntry.effectValue1;
|
||||||
|
destroyedShieldSlotList.push_back( entry.first );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( shieldChanged )
|
||||||
|
{
|
||||||
|
if( !destroyedShieldSlotList.empty() )
|
||||||
|
{
|
||||||
|
for( auto const& slotId : destroyedShieldSlotList )
|
||||||
|
{
|
||||||
|
pChara->removeStatusEffect( slotId, true, false );
|
||||||
|
}
|
||||||
|
pChara->sendStatusEffectUpdate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pChara->sendEffectResultToUpdateShieldValue(); // yes this is the packet to update shield value
|
||||||
|
}
|
||||||
|
return remainingDamage;
|
||||||
|
}
|
|
@ -148,6 +148,8 @@ namespace Sapphire::Math
|
||||||
|
|
||||||
static float calcAbsorbHP( Sapphire::Entity::CharaPtr pChara, float damage, Sapphire::Common::ActionTypeFilter filter );
|
static float calcAbsorbHP( Sapphire::Entity::CharaPtr pChara, float damage, Sapphire::Common::ActionTypeFilter filter );
|
||||||
|
|
||||||
|
static float applyShieldProtection( Sapphire::Entity::CharaPtr pChara, float damage );
|
||||||
|
|
||||||
static std::random_device dev;
|
static std::random_device dev;
|
||||||
static std::mt19937 rng;
|
static std::mt19937 rng;
|
||||||
static std::uniform_int_distribution< std::mt19937::result_type > range100;
|
static std::uniform_int_distribution< std::mt19937::result_type > range100;
|
||||||
|
|
|
@ -134,7 +134,7 @@ void Sapphire::Network::GameConnection::clientTriggerHandler( FrameworkPtr pFw,
|
||||||
case ClientTriggerType::RemoveStatusEffect: // Remove status (clicking it off)
|
case ClientTriggerType::RemoveStatusEffect: // Remove status (clicking it off)
|
||||||
{
|
{
|
||||||
// todo: check if status can be removed by client from exd
|
// todo: check if status can be removed by client from exd
|
||||||
player.removeSingleStatusEffectById( static_cast< uint32_t >( param1 ), true );
|
player.removeSingleStatusEffectById( static_cast< uint32_t >( param1 ), true, true );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ClientTriggerType::CastCancel: // Cancel cast
|
case ClientTriggerType::CastCancel: // Cancel cast
|
||||||
|
|
|
@ -29,7 +29,7 @@ Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPt
|
||||||
m_tickRate( tickRate ),
|
m_tickRate( tickRate ),
|
||||||
m_lastTick( 0 ),
|
m_lastTick( 0 ),
|
||||||
m_pFw( pFw ),
|
m_pFw( pFw ),
|
||||||
m_cachedHotOrDotValue( 0 ),
|
m_value( 0 ),
|
||||||
m_cachedSourceCrit( 0 ),
|
m_cachedSourceCrit( 0 ),
|
||||||
m_cachedSourceCritBonus( 0 )
|
m_cachedSourceCritBonus( 0 )
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,6 @@ Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPt
|
||||||
m_effectEntry.effectType = static_cast< uint32_t >( Common::StatusEffectType::Invalid );
|
m_effectEntry.effectType = static_cast< uint32_t >( Common::StatusEffectType::Invalid );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Sapphire::StatusEffect::StatusEffect::~StatusEffect()
|
Sapphire::StatusEffect::StatusEffect::~StatusEffect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -69,7 +68,7 @@ std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffe
|
||||||
auto statusEffectType = static_cast< Common::StatusEffectType >( m_effectEntry.effectType );
|
auto statusEffectType = static_cast< Common::StatusEffectType >( m_effectEntry.effectType );
|
||||||
if( statusEffectType == Common::StatusEffectType::Dot )
|
if( statusEffectType == Common::StatusEffectType::Dot )
|
||||||
{
|
{
|
||||||
auto value = m_cachedHotOrDotValue;
|
auto value = m_value;
|
||||||
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
|
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
|
||||||
{
|
{
|
||||||
value *= m_cachedSourceCritBonus;
|
value *= m_cachedSourceCritBonus;
|
||||||
|
@ -79,7 +78,7 @@ std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffe
|
||||||
}
|
}
|
||||||
else if( statusEffectType == Common::StatusEffectType::Hot )
|
else if( statusEffectType == Common::StatusEffectType::Hot )
|
||||||
{
|
{
|
||||||
auto value = m_cachedHotOrDotValue;
|
auto value = m_value;
|
||||||
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
|
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
|
||||||
{
|
{
|
||||||
value *= m_cachedSourceCritBonus;
|
value *= m_cachedSourceCritBonus;
|
||||||
|
@ -138,7 +137,7 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cachedHotOrDotValue = Sapphire::Math::CalcStats::applyDamageReceiveMultiplier( *m_targetActor, damage,
|
m_value = Sapphire::Math::CalcStats::applyDamageReceiveMultiplier( *m_targetActor, damage,
|
||||||
m_effectEntry.effectValue1 == static_cast< int32_t >( Common::ActionTypeFilter::Physical ) ? Common::AttackType::Physical :
|
m_effectEntry.effectValue1 == static_cast< int32_t >( Common::ActionTypeFilter::Physical ) ? Common::AttackType::Physical :
|
||||||
( m_effectEntry.effectValue1 == static_cast< int32_t >( Common::ActionTypeFilter::Magical ) ? Common::AttackType::Magical : Common::AttackType::Unknown_0 ) );
|
( m_effectEntry.effectValue1 == static_cast< int32_t >( Common::ActionTypeFilter::Magical ) ? Common::AttackType::Magical : Common::AttackType::Unknown_0 ) );
|
||||||
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Damage );
|
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Damage );
|
||||||
|
@ -160,7 +159,7 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
||||||
heal *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
|
heal *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_cachedHotOrDotValue = Sapphire::Math::CalcStats::applyHealingReceiveMultiplier( *m_targetActor, heal );
|
m_value = Sapphire::Math::CalcStats::applyHealingReceiveMultiplier( *m_targetActor, heal );
|
||||||
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Heal );
|
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Heal );
|
||||||
m_cachedSourceCritBonus = Sapphire::Math::CalcStats::criticalHitBonus( *m_sourceActor );
|
m_cachedSourceCritBonus = Sapphire::Math::CalcStats::criticalHitBonus( *m_sourceActor );
|
||||||
}
|
}
|
||||||
|
@ -218,3 +217,8 @@ const Sapphire::World::Action::StatusEffectEntry& Sapphire::StatusEffect::Status
|
||||||
{
|
{
|
||||||
return m_effectEntry;
|
return m_effectEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::StatusEffect::StatusEffect::replaceEffectEntry( Sapphire::World::Action::StatusEffectEntry entryOverride )
|
||||||
|
{
|
||||||
|
m_effectEntry = entryOverride;
|
||||||
|
}
|
|
@ -51,6 +51,8 @@ public:
|
||||||
|
|
||||||
const Sapphire::World::Action::StatusEffectEntry& getEffectEntry() const;
|
const Sapphire::World::Action::StatusEffectEntry& getEffectEntry() const;
|
||||||
|
|
||||||
|
void replaceEffectEntry( Sapphire::World::Action::StatusEffectEntry entryOverride );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_id;
|
uint32_t m_id;
|
||||||
Entity::CharaPtr m_sourceActor;
|
Entity::CharaPtr m_sourceActor;
|
||||||
|
@ -64,7 +66,7 @@ private:
|
||||||
std::pair< uint8_t, uint32_t > m_currTickEffect;
|
std::pair< uint8_t, uint32_t > m_currTickEffect;
|
||||||
FrameworkPtr m_pFw;
|
FrameworkPtr m_pFw;
|
||||||
Sapphire::World::Action::StatusEffectEntry m_effectEntry;
|
Sapphire::World::Action::StatusEffectEntry m_effectEntry;
|
||||||
uint32_t m_cachedHotOrDotValue;
|
uint32_t m_value;
|
||||||
float m_cachedSourceCrit;
|
float m_cachedSourceCrit;
|
||||||
float m_cachedSourceCritBonus;
|
float m_cachedSourceCritBonus;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue