mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-25 19:17:45 +00:00
Implement damage reflect trigger.
Replace consts with enums in Common.h Use effect builder for autoattacks. Dumb mistake fixed.
This commit is contained in:
parent
8d7c6f5188
commit
e08643f380
10 changed files with 1267 additions and 380 deletions
|
@ -591,14 +591,15 @@ namespace Sapphire::Common
|
|||
// DRGGauge3Eyes = 76,
|
||||
};
|
||||
|
||||
enum class ActionType : int8_t
|
||||
enum class AttackType : int8_t
|
||||
{
|
||||
WeaponOverride = -1, // Needs more investigation (takes the damage type of the equipped weapon)?
|
||||
//WeaponOverride = -1, // Needs more investigation (takes the damage type of the equipped weapon)?
|
||||
Physical = -1, // seems to be the case
|
||||
Unknown_0 = 0,
|
||||
Slashing = 1,
|
||||
Piercing = 2,
|
||||
Blunt = 3,
|
||||
Unknown_4 = 4,
|
||||
Slashing = 1, // likely not used post 5.0
|
||||
Piercing = 2, // likely not used post 5.0
|
||||
Blunt = 3, // likely not used post 5.0
|
||||
Unknown_4 = 4, // likely not used post 5.0
|
||||
Magical = 5,
|
||||
Darkness = 6,
|
||||
Unknown_7 = 7,
|
||||
|
@ -650,6 +651,7 @@ namespace Sapphire::Common
|
|||
{
|
||||
None = 0,
|
||||
EffectOnSource = 0x80,
|
||||
Reflected = 0xA0,
|
||||
};
|
||||
|
||||
enum ItemActionType : uint16_t
|
||||
|
@ -1020,12 +1022,38 @@ namespace Sapphire::Common
|
|||
Gatherer
|
||||
};
|
||||
|
||||
enum class AttackType : int8_t
|
||||
enum class StatusEffectType : uint32_t
|
||||
{
|
||||
Invalid = 0,
|
||||
DamageMultiplier = 1,
|
||||
DamageReceiveMultiplier = 2,
|
||||
Hot = 3,
|
||||
Dot = 4,
|
||||
HealReceiveMultiplier = 5,
|
||||
HealCastMultiplier = 6,
|
||||
CritDHRateBonus = 7,
|
||||
DamageReceiveTrigger = 8,
|
||||
};
|
||||
|
||||
enum class ActionTypeFilter : int32_t
|
||||
{
|
||||
Unknown = 0,
|
||||
Physical = 1,
|
||||
Magical = 2,
|
||||
All = 255,
|
||||
};
|
||||
|
||||
enum class CritDHBonusFilter : int32_t
|
||||
{
|
||||
Physical = -1,
|
||||
None = 0,
|
||||
Magic = 5,
|
||||
LimitBreak = 8,
|
||||
Damage = 1,
|
||||
Heal = 2,
|
||||
All = 255,
|
||||
};
|
||||
|
||||
enum class StatusEffectTriggerResult : int32_t
|
||||
{
|
||||
ReflectDamage = 1,
|
||||
};
|
||||
|
||||
using PlayerStateFlagList = std::vector< PlayerStateFlag >;
|
||||
|
|
|
@ -406,12 +406,12 @@ void Action::Action::execute()
|
|||
|
||||
std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage( uint32_t potency )
|
||||
{
|
||||
return Math::CalcStats::calcActionDamage( *m_pSource, *this, potency, Math::CalcStats::getWeaponDamage( *m_pSource ) );
|
||||
return Math::CalcStats::calcActionDamage( *m_pSource, static_cast< Common::AttackType >( m_actionData->attackType ), potency, Math::CalcStats::getWeaponDamage( m_pSource ) );
|
||||
}
|
||||
|
||||
std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcHealing( uint32_t potency )
|
||||
{
|
||||
return Math::CalcStats::calcActionHealing( *m_pSource, *this, potency, Math::CalcStats::getWeaponDamage( *m_pSource ) );
|
||||
return Math::CalcStats::calcActionHealing( *m_pSource, static_cast< Common::ActionCategory >( m_actionData->actionCategory ), potency, Math::CalcStats::getWeaponDamage( m_pSource ) );
|
||||
}
|
||||
|
||||
void Action::Action::buildEffects()
|
||||
|
@ -457,12 +457,23 @@ void Action::Action::buildEffects()
|
|||
{
|
||||
if( m_lutEntry.damagePotency > 0 )
|
||||
{
|
||||
Common::AttackType attackType = static_cast< Common::AttackType >( m_actionData->attackType );
|
||||
auto dmg = calcDamage( isCorrectCombo() ? m_lutEntry.damageComboPotency : m_lutEntry.damagePotency );
|
||||
dmg.first = Math::CalcStats::applyDamageReceiveMultiplier( *actor, dmg.first, static_cast< Common::AttackType >( m_actionData->attackType ) );
|
||||
m_effectBuilder->damage( actor, actor, dmg.first, dmg.second );
|
||||
dmg.first = Math::CalcStats::applyDamageReceiveMultiplier( *actor, dmg.first, attackType );
|
||||
auto reflectDmg = Math::CalcStats::calcDamageReflect( m_pSource, actor, dmg.first,
|
||||
attackType == Common::AttackType::Physical ? Common::ActionTypeFilter::Physical :
|
||||
( attackType == Common::AttackType::Magical ? Common::ActionTypeFilter::Magical : Common::ActionTypeFilter::Unknown ) );
|
||||
|
||||
if( dmg.first > 0 )
|
||||
{
|
||||
actor->onActionHostile( m_pSource );
|
||||
m_effectBuilder->damage( actor, actor, dmg.first, dmg.second );
|
||||
}
|
||||
|
||||
if( reflectDmg.first > 0 )
|
||||
{
|
||||
m_effectBuilder->damage( actor, m_pSource, dmg.first, dmg.second, Common::ActionEffectResultFlag::Reflected );
|
||||
}
|
||||
|
||||
if( isCorrectCombo() && shouldApplyComboSucceedEffect )
|
||||
{
|
||||
|
@ -819,5 +830,5 @@ bool Action::Action::isAttackTypePhysical( Common::AttackType attackType )
|
|||
|
||||
bool Action::Action::isAttackTypeMagical( Common::AttackType attackType )
|
||||
{
|
||||
return attackType == Common::AttackType::Magic;
|
||||
return attackType == Common::AttackType::Magical;
|
||||
}
|
|
@ -21,23 +21,6 @@ namespace Sapphire::World::Action
|
|||
uint16_t gainMPPercentage;
|
||||
};
|
||||
|
||||
const uint32_t EffectTypeInvalid = 0;
|
||||
const uint32_t EffectTypeDamageMultiplier = 1;
|
||||
const uint32_t EffectTypeDamageReceiveMultiplier = 2;
|
||||
const uint32_t EffectTypeHot = 3;
|
||||
const uint32_t EffectTypeDot = 4;
|
||||
const uint32_t EffectTypeHealReceiveMultiplier = 5;
|
||||
const uint32_t EffectTypeHealCastMultiplier = 6;
|
||||
const uint32_t EffectTypeCritDHRateBonus = 7;
|
||||
|
||||
const uint8_t EffectActionTypeFilterPhysical = 1;
|
||||
const uint8_t EffectActionTypeFilterMagical = 2;
|
||||
const uint8_t EffectActionTypeFilterAll = 255;
|
||||
|
||||
const uint8_t EffectCritDHBonusFilterDamage = 1;
|
||||
const uint8_t EffectCritDHBonusFilterHeal = 2;
|
||||
const uint8_t EffectCritDHBonusFilterAll = 255;
|
||||
|
||||
struct StatusEffectEntry
|
||||
{
|
||||
uint32_t effectType;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -679,9 +679,17 @@ void Sapphire::Entity::BNpc::setFlag( uint32_t flag )
|
|||
m_flags |= flag;
|
||||
}
|
||||
|
||||
/*!
|
||||
Autoattack prototype implementation
|
||||
TODO: move the check if the autoAttack can be performed to the callee
|
||||
also rename autoAttack to autoAttack as that is more elaborate
|
||||
On top of that, this only solves attacks from melee classes.
|
||||
Will have to be extended for ranged attacks.
|
||||
|
||||
\param ActorPtr the autoAttack is performed on
|
||||
*/
|
||||
void Sapphire::Entity::BNpc::autoAttack( CharaPtr pTarget )
|
||||
{
|
||||
|
||||
uint64_t tick = Util::getTimeMs();
|
||||
|
||||
// todo: this needs to use the auto attack delay for the equipped weapon
|
||||
|
@ -689,24 +697,19 @@ void Sapphire::Entity::BNpc::autoAttack( CharaPtr pTarget )
|
|||
{
|
||||
pTarget->onActionHostile( getAsChara() );
|
||||
m_lastAttack = tick;
|
||||
srand( static_cast< uint32_t >( tick ) );
|
||||
|
||||
auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >();
|
||||
auto pSource = getAsChara();
|
||||
auto damage = Math::CalcStats::calcAutoAttackDamage( *this );
|
||||
damage.first = Math::CalcStats::applyDamageReceiveMultiplier( *pTarget, damage.first, Common::AttackType::Physical );
|
||||
auto effectPacket = std::make_shared< Server::EffectPacket >( getId(), pTarget->getId(), 7 );
|
||||
effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) );
|
||||
Common::EffectEntry effectEntry{};
|
||||
effectEntry.value = static_cast< int16_t >( damage.first );
|
||||
effectEntry.effectType = ActionEffectType::Damage;
|
||||
effectEntry.param0 = static_cast< uint8_t >( damage.second );
|
||||
effectEntry.param2 = 0x71;
|
||||
effectPacket->addEffect( effectEntry );
|
||||
|
||||
sendToInRangeSet( effectPacket );
|
||||
|
||||
pTarget->takeDamage( static_cast< uint16_t >( damage.first ) );
|
||||
auto reflectDmg = Math::CalcStats::calcDamageReflect( pSource, pTarget, damage.first, Common::ActionTypeFilter::Physical );
|
||||
|
||||
World::Action::EffectBuilder effectBuilder( pSource, 7, 0 );
|
||||
effectBuilder.damage( pTarget, pTarget, damage.first, damage.second );
|
||||
if( reflectDmg.first > 0 )
|
||||
{
|
||||
effectBuilder.damage( pTarget, pSource, reflectDmg.first, reflectDmg.second, Common::ActionEffectResultFlag::Reflected );
|
||||
}
|
||||
effectBuilder.buildAndSendPackets();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -480,44 +480,9 @@ uint32_t Sapphire::Entity::Chara::getBonusStat( Common::BaseParam bonus ) const
|
|||
return m_bonusStats[ static_cast< uint8_t >( bonus ) ];
|
||||
}
|
||||
|
||||
/*!
|
||||
Autoattack prototype implementation
|
||||
TODO: move the check if the autoAttack can be performed to the callee
|
||||
also rename autoAttack to autoAttack as that is more elaborate
|
||||
On top of that, this only solves attacks from melee classes.
|
||||
Will have to be extended for ranged attacks.
|
||||
|
||||
\param ActorPtr the autoAttack is performed on
|
||||
*/
|
||||
void Sapphire::Entity::Chara::autoAttack( CharaPtr pTarget )
|
||||
{
|
||||
|
||||
uint64_t tick = Util::getTimeMs();
|
||||
|
||||
// todo: this needs to use the auto attack delay for the equipped weapon
|
||||
if( ( tick - m_lastAttack ) > 2500 )
|
||||
{
|
||||
pTarget->onActionHostile( getAsChara() );
|
||||
m_lastAttack = tick;
|
||||
srand( static_cast< uint32_t >( tick ) );
|
||||
|
||||
auto damage = static_cast< uint16_t >( 10 + rand() % 12 );
|
||||
damage = Math::CalcStats::applyDamageReceiveMultiplier( *pTarget, damage, Common::AttackType::Physical );
|
||||
|
||||
auto effectPacket = std::make_shared< Server::EffectPacket >( getId(), pTarget->getId(), 7 );
|
||||
effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) );
|
||||
Common::EffectEntry effectEntry{};
|
||||
effectEntry.value = static_cast< int16_t >( damage );
|
||||
effectEntry.effectType = ActionEffectType::Damage;
|
||||
effectEntry.param0 = static_cast< uint8_t >( ActionHitSeverityType::NormalDamage );
|
||||
effectEntry.param2 = 0x71;
|
||||
effectPacket->addEffect( effectEntry );
|
||||
|
||||
sendToInRangeSet( effectPacket );
|
||||
|
||||
pTarget->takeDamage( damage );
|
||||
|
||||
}
|
||||
// moved to BNpc
|
||||
}
|
||||
|
||||
/*! \param StatusEffectPtr to be applied to the actor */
|
||||
|
|
|
@ -1569,49 +1569,28 @@ void Sapphire::Entity::Player::autoAttack( CharaPtr pTarget )
|
|||
auto mainWeap = getItemAt( Common::GearSet0, Common::GearSetSlot::MainHand );
|
||||
|
||||
pTarget->onActionHostile( getAsChara() );
|
||||
//uint64_t tick = Util::getTimeMs();
|
||||
//srand(static_cast< uint32_t >(tick));
|
||||
|
||||
auto pRNGMgr = m_pFw->get< World::Manager::RNGMgr >();
|
||||
auto variation = static_cast< uint32_t >( pRNGMgr->getRandGenerator< float >( 0, 3 ).next() );
|
||||
|
||||
auto pSource = getAsChara();
|
||||
auto damage = Math::CalcStats::calcAutoAttackDamage( *this );
|
||||
damage.first = Math::CalcStats::applyDamageReceiveMultiplier( *pTarget, damage.first, Common::AttackType::Physical );
|
||||
auto reflectDmg = Math::CalcStats::calcDamageReflect( pSource, pTarget, damage.first, Common::ActionTypeFilter::Physical );
|
||||
|
||||
World::Action::EffectBuilderPtr effectBuilder = nullptr;
|
||||
if( getClass() == ClassJob::Machinist || getClass() == ClassJob::Bard || getClass() == ClassJob::Archer )
|
||||
{
|
||||
auto effectPacket = std::make_shared< Server::EffectPacket >( getId(), pTarget->getId(), 8 );
|
||||
effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) );
|
||||
|
||||
Common::EffectEntry entry{};
|
||||
entry.value = damage.first;
|
||||
entry.effectType = Common::ActionEffectType::Damage;
|
||||
entry.param0 = static_cast< uint8_t >( damage.second );
|
||||
entry.param2 = 0x72;
|
||||
|
||||
effectPacket->addEffect( entry );
|
||||
|
||||
sendToInRangeSet( effectPacket, true );
|
||||
effectBuilder = World::Action::make_EffectBuilder( pSource, 8, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto effectPacket = std::make_shared< Server::EffectPacket >( getId(), pTarget->getId(), 7 );
|
||||
effectPacket->setRotation( Util::floatToUInt16Rot( getRot() ) );
|
||||
|
||||
Common::EffectEntry entry{};
|
||||
entry.value = damage.first;
|
||||
entry.effectType = Common::ActionEffectType::Damage;
|
||||
entry.param0 = static_cast< uint8_t >( damage.second );
|
||||
entry.param2 = 0x73;
|
||||
|
||||
effectPacket->addEffect( entry );
|
||||
|
||||
sendToInRangeSet( effectPacket, true );
|
||||
|
||||
effectBuilder = World::Action::make_EffectBuilder( pSource, 7, 0 );
|
||||
}
|
||||
|
||||
pTarget->takeDamage( damage.first );
|
||||
|
||||
effectBuilder->damage( pTarget, pTarget, damage.first, damage.second );
|
||||
if( reflectDmg.first > 0 )
|
||||
{
|
||||
effectBuilder->damage( pTarget, pSource, reflectDmg.first, reflectDmg.second, Common::ActionEffectResultFlag::Reflected );
|
||||
}
|
||||
effectBuilder->buildAndSendPackets();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -194,7 +194,7 @@ float CalcStats::blockProbability( const Chara& chara )
|
|||
return std::floor( ( 30 * blockRate ) / levelVal + 10 );
|
||||
}
|
||||
|
||||
float CalcStats::directHitProbability( const Chara& chara, uint8_t filterType )
|
||||
float CalcStats::directHitProbability( const Chara& chara, Sapphire::Common::CritDHBonusFilter filter )
|
||||
{
|
||||
const auto& baseStats = chara.getStats();
|
||||
auto level = chara.getLevel();
|
||||
|
@ -210,9 +210,9 @@ float CalcStats::directHitProbability( const Chara& chara, uint8_t filterType )
|
|||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeCritDHRateBonus )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::CritDHRateBonus )
|
||||
continue;
|
||||
if( effectEntry.effectValue1 & filterType )
|
||||
if( effectEntry.effectValue1 & static_cast< int32_t >( filter ) )
|
||||
{
|
||||
result += effectEntry.effectValue3;
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ float CalcStats::directHitProbability( const Chara& chara, uint8_t filterType )
|
|||
return result;
|
||||
}
|
||||
|
||||
float CalcStats::criticalHitProbability( const Chara& chara, uint8_t filterType )
|
||||
float CalcStats::criticalHitProbability( const Chara& chara, Sapphire::Common::CritDHBonusFilter filter )
|
||||
{
|
||||
const auto& baseStats = chara.getStats();
|
||||
auto level = chara.getLevel();
|
||||
|
@ -236,9 +236,9 @@ float CalcStats::criticalHitProbability( const Chara& chara, uint8_t filterType
|
|||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeCritDHRateBonus )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::CritDHRateBonus )
|
||||
continue;
|
||||
if( effectEntry.effectValue1 & filterType )
|
||||
if( effectEntry.effectValue1 & static_cast< int32_t >( filter ) )
|
||||
{
|
||||
result += effectEntry.effectValue2;
|
||||
}
|
||||
|
@ -358,11 +358,11 @@ float CalcStats::healingMagicPower( const Sapphire::Entity::Chara& chara )
|
|||
return calcAttackPower( chara, chara.getStatValue( Common::BaseParam::HealingMagicPotency ) );
|
||||
}
|
||||
|
||||
float CalcStats::getWeaponDamage( Sapphire::Entity::Chara& chara )
|
||||
float CalcStats::getWeaponDamage( CharaPtr chara )
|
||||
{
|
||||
auto wepDmg = chara.getLevel();
|
||||
auto wepDmg = chara->getLevel();
|
||||
|
||||
if( auto player = chara.getAsPlayer() )
|
||||
if( auto player = chara->getAsPlayer() )
|
||||
{
|
||||
auto item = player->getEquippedWeapon();
|
||||
assert( item );
|
||||
|
@ -517,13 +517,13 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA
|
|||
|
||||
factor = std::floor( factor * speed( chara ) );
|
||||
|
||||
if( criticalHitProbability( chara, Sapphire::World::Action::EffectCritDHBonusFilterDamage ) > range100( rng ) )
|
||||
if( criticalHitProbability( chara, Common::CritDHBonusFilter::Damage ) > range100( rng ) )
|
||||
{
|
||||
factor *= criticalHitBonus( chara );
|
||||
hitType = Sapphire::Common::ActionHitSeverityType::CritDamage;
|
||||
}
|
||||
|
||||
if( directHitProbability( chara, Sapphire::World::Action::EffectCritDHBonusFilterDamage ) > range100( rng ) )
|
||||
if( directHitProbability( chara, Common::CritDHBonusFilter::Damage ) > range100( rng ) )
|
||||
{
|
||||
factor *= 1.25f;
|
||||
hitType = hitType == Sapphire::Common::ActionHitSeverityType::CritDamage ?
|
||||
|
@ -537,9 +537,9 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA
|
|||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeDamageMultiplier )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::DamageMultiplier )
|
||||
continue;
|
||||
if( effectEntry.effectValue1 & Sapphire::World::Action::EffectActionTypeFilterPhysical )
|
||||
if( effectEntry.effectValue1 & static_cast< int32_t >( Common::ActionTypeFilter::Physical ) )
|
||||
{
|
||||
factor *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
|
||||
}
|
||||
|
@ -605,18 +605,18 @@ float CalcStats::calcHealBaseOnPotency( const Sapphire::Entity::Chara& chara, ui
|
|||
return factor;
|
||||
}
|
||||
|
||||
std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, const Sapphire::World::Action::Action& action, uint32_t ptc, float wepDmg )
|
||||
std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, Sapphire::Common::AttackType attackType, uint32_t ptc, float wepDmg )
|
||||
{
|
||||
auto factor = calcDamageBaseOnPotency( chara, ptc, wepDmg );
|
||||
Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalDamage;
|
||||
|
||||
if( criticalHitProbability( chara, Sapphire::World::Action::EffectCritDHBonusFilterDamage ) > range100( rng ) )
|
||||
if( criticalHitProbability( chara, Common::CritDHBonusFilter::Damage ) > range100( rng ) )
|
||||
{
|
||||
factor *= criticalHitBonus( chara );
|
||||
hitType = Sapphire::Common::ActionHitSeverityType::CritDamage;
|
||||
}
|
||||
|
||||
if( directHitProbability( chara, Sapphire::World::Action::EffectCritDHBonusFilterDamage ) > range100( rng ) )
|
||||
if( directHitProbability( chara, Common::CritDHBonusFilter::Damage ) > range100( rng ) )
|
||||
{
|
||||
factor *= 1.25f;
|
||||
hitType = hitType == Sapphire::Common::ActionHitSeverityType::CritDamage ?
|
||||
|
@ -626,20 +626,20 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio
|
|||
|
||||
factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f );
|
||||
|
||||
uint8_t actionType = 0;
|
||||
if( action.isPhysical() )
|
||||
actionType = Sapphire::World::Action::EffectActionTypeFilterPhysical;
|
||||
else if( action.isMagical() )
|
||||
actionType = Sapphire::World::Action::EffectActionTypeFilterMagical;
|
||||
Common::ActionTypeFilter actionTypeFilter = Common::ActionTypeFilter::Unknown;
|
||||
if( World::Action::Action::isAttackTypePhysical( attackType ) )
|
||||
actionTypeFilter = Common::ActionTypeFilter::Physical;
|
||||
else if( World::Action::Action::isAttackTypeMagical( attackType ) )
|
||||
actionTypeFilter = Common::ActionTypeFilter::Magical;
|
||||
|
||||
for( auto const& entry : chara.getStatusEffectMap() )
|
||||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeDamageMultiplier )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::DamageMultiplier )
|
||||
continue;
|
||||
|
||||
if( effectEntry.effectValue1 & actionType )
|
||||
if( effectEntry.effectValue1 & static_cast< int32_t >( actionTypeFilter ) )
|
||||
{
|
||||
factor *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
|
||||
}
|
||||
|
@ -652,20 +652,20 @@ float CalcStats::applyDamageReceiveMultiplier( const Sapphire::Entity::Chara& ch
|
|||
{
|
||||
float damage = originalDamage;
|
||||
|
||||
uint8_t actionType = 0;
|
||||
Common::ActionTypeFilter actionTypeFilter = Common::ActionTypeFilter::Unknown;
|
||||
if( World::Action::Action::isAttackTypePhysical( attackType ) )
|
||||
actionType = Sapphire::World::Action::EffectActionTypeFilterPhysical;
|
||||
actionTypeFilter = Common::ActionTypeFilter::Physical;
|
||||
else if( World::Action::Action::isAttackTypeMagical( attackType ) )
|
||||
actionType = Sapphire::World::Action::EffectActionTypeFilterMagical;
|
||||
actionTypeFilter = Common::ActionTypeFilter::Magical;
|
||||
|
||||
for( auto const& entry : chara.getStatusEffectMap() )
|
||||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeDamageReceiveMultiplier )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::DamageReceiveMultiplier )
|
||||
continue;
|
||||
|
||||
if( effectEntry.effectValue1 & actionType )
|
||||
if( effectEntry.effectValue1 & static_cast< int32_t >( actionTypeFilter ) )
|
||||
{
|
||||
damage *= ( 1.0f + ( effectEntry.effectValue2 / 100.0f ) );
|
||||
}
|
||||
|
@ -680,19 +680,19 @@ float CalcStats::applyHealingReceiveMultiplier( const Sapphire::Entity::Chara& c
|
|||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeHealReceiveMultiplier )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::HealReceiveMultiplier )
|
||||
continue;
|
||||
heal *= ( 1.0f + ( effectEntry.effectValue2 / 100.0f ) );
|
||||
}
|
||||
return heal;
|
||||
}
|
||||
|
||||
std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, const Sapphire::World::Action::Action& action, uint32_t ptc, float wepDmg )
|
||||
std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, Sapphire::Common::ActionCategory actionCategory, uint32_t ptc, float wepDmg )
|
||||
{
|
||||
auto factor = calcHealBaseOnPotency( chara, ptc, wepDmg );
|
||||
Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalHeal;
|
||||
|
||||
if( criticalHitProbability( chara, Sapphire::World::Action::EffectCritDHBonusFilterHeal ) > range100( rng ) )
|
||||
if( criticalHitProbability( chara, Common::CritDHBonusFilter::Heal ) > range100( rng ) )
|
||||
{
|
||||
factor *= criticalHitBonus( chara );
|
||||
hitType = Sapphire::Common::ActionHitSeverityType::CritHeal;
|
||||
|
@ -704,10 +704,10 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio
|
|||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeHealCastMultiplier )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::HealCastMultiplier )
|
||||
continue;
|
||||
|
||||
if( static_cast< Common::ActionCategory >( action.getActionData()->actionCategory ) == Common::ActionCategory::Spell ) // must be a "cast"
|
||||
if( actionCategory == Common::ActionCategory::Spell ) // must be a "cast"
|
||||
{
|
||||
factor *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
|
||||
}
|
||||
|
@ -719,4 +719,27 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio
|
|||
uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara )
|
||||
{
|
||||
return chara.getStatValue( chara.getPrimaryStat() );
|
||||
}
|
||||
|
||||
std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcDamageReflect( Sapphire::Entity::CharaPtr charaAttacker, Sapphire::Entity::CharaPtr charaVictim, float damage, Sapphire::Common::ActionTypeFilter filter )
|
||||
{
|
||||
for( auto entry : charaVictim->getStatusEffectMap() )
|
||||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) == Common::StatusEffectType::DamageReceiveTrigger && ( effectEntry.effectValue1 & static_cast< int32_t >( filter ) ) )
|
||||
{
|
||||
if( static_cast< Common::StatusEffectTriggerResult >( effectEntry.effectValue3 ) == Common::StatusEffectTriggerResult::ReflectDamage )
|
||||
{
|
||||
auto wepDmg = Sapphire::Math::CalcStats::getWeaponDamage( charaVictim );
|
||||
// any magical reflect damage exists?
|
||||
auto damage = Sapphire::Math::CalcStats::calcActionDamage( *charaVictim, Common::AttackType::Physical, effectEntry.effectValue2, wepDmg );
|
||||
damage.first = Math::CalcStats::applyDamageReceiveMultiplier( *charaAttacker, damage.first, Common::AttackType::Physical );
|
||||
|
||||
return damage;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::pair< float, Sapphire::Common::ActionHitSeverityType >( 0, Sapphire::Common::ActionHitSeverityType::NormalDamage );
|
||||
}
|
|
@ -26,12 +26,12 @@ namespace Sapphire::Math
|
|||
/*!
|
||||
* @brief Calculates the probability of a direct hit happening
|
||||
*/
|
||||
static float directHitProbability( const Sapphire::Entity::Chara& chara, uint8_t filterType );
|
||||
static float directHitProbability( const Sapphire::Entity::Chara& chara, Sapphire::Common::CritDHBonusFilter filter );
|
||||
|
||||
/*!
|
||||
* @brief Calculates the probability of a critical hit happening
|
||||
*/
|
||||
static float criticalHitProbability( const Sapphire::Entity::Chara& chara, uint8_t filterType );
|
||||
static float criticalHitProbability( const Sapphire::Entity::Chara& chara, Sapphire::Common::CritDHBonusFilter filter );
|
||||
|
||||
/*!
|
||||
* @brief Calculates the contribution of potency to damage output.
|
||||
|
@ -64,7 +64,7 @@ namespace Sapphire::Math
|
|||
|
||||
static float healingMagicPower( const Sapphire::Entity::Chara& chara );
|
||||
|
||||
static float getWeaponDamage( Sapphire::Entity::Chara& chara );
|
||||
static float getWeaponDamage( Sapphire::Entity::CharaPtr chara );
|
||||
|
||||
/*!
|
||||
* @brief Calculates determinations contribution to damage and healing output.
|
||||
|
@ -137,16 +137,18 @@ namespace Sapphire::Math
|
|||
|
||||
static std::pair< float, Common::ActionHitSeverityType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara );
|
||||
|
||||
static std::pair< float, Common::ActionHitSeverityType > calcActionDamage( const Sapphire::Entity::Chara& chara, const Sapphire::World::Action::Action& action, uint32_t ptc, float wepDmg );
|
||||
static std::pair< float, Common::ActionHitSeverityType > calcActionDamage( const Sapphire::Entity::Chara& chara, Common::AttackType attackType, uint32_t ptc, float wepDmg );
|
||||
|
||||
static float applyDamageReceiveMultiplier( const Sapphire::Entity::Chara& chara, float originalDamage, Common::AttackType attackType );
|
||||
|
||||
static float applyHealingReceiveMultiplier( const Sapphire::Entity::Chara& chara, float originalHeal );
|
||||
|
||||
static std::pair< float, Common::ActionHitSeverityType > calcActionHealing( const Sapphire::Entity::Chara& chara, const Sapphire::World::Action::Action& action, uint32_t ptc, float wepDmg );
|
||||
static std::pair< float, Common::ActionHitSeverityType > calcActionHealing( const Sapphire::Entity::Chara& chara, Sapphire::Common::ActionCategory actionCategory, uint32_t ptc, float wepDmg );
|
||||
|
||||
static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara );
|
||||
|
||||
static std::pair< float, Sapphire::Common::ActionHitSeverityType > calcDamageReflect( Sapphire::Entity::CharaPtr charaAttacker, Sapphire::Entity::CharaPtr charaVictim, float damage, Sapphire::Common::ActionTypeFilter filter );
|
||||
|
||||
static std::random_device dev;
|
||||
static std::mt19937 rng;
|
||||
static std::uniform_int_distribution< std::mt19937::result_type > range100;
|
||||
|
|
|
@ -50,7 +50,7 @@ Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPt
|
|||
if( Sapphire::World::Action::ActionLut::validStatusEffectExists( id ) )
|
||||
m_effectEntry = Sapphire::World::Action::ActionLut::getStatusEffectEntry( id );
|
||||
else
|
||||
m_effectEntry.effectType = Sapphire::World::Action::EffectTypeInvalid;
|
||||
m_effectEntry.effectType = static_cast< uint32_t >( Common::StatusEffectType::Invalid );
|
||||
}
|
||||
|
||||
|
||||
|
@ -66,7 +66,8 @@ void Sapphire::StatusEffect::StatusEffect::registerTickEffect( uint8_t type, uin
|
|||
std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect()
|
||||
{
|
||||
auto thisTick = m_currTickEffect;
|
||||
if( m_effectEntry.effectType == Sapphire::World::Action::EffectTypeDot )
|
||||
auto statusEffectType = static_cast< Common::StatusEffectType >( m_effectEntry.effectType );
|
||||
if( statusEffectType == Common::StatusEffectType::Dot )
|
||||
{
|
||||
auto value = m_cachedHotOrDotValue;
|
||||
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
|
||||
|
@ -76,7 +77,7 @@ std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffe
|
|||
value *= 1.0f + ( ( Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) - 50.0f ) / 1000.0f );
|
||||
m_currTickEffect = std::make_pair( 1, value );
|
||||
}
|
||||
else if( m_effectEntry.effectType == Sapphire::World::Action::EffectTypeHot )
|
||||
else if( statusEffectType == Common::StatusEffectType::Hot )
|
||||
{
|
||||
auto value = m_cachedHotOrDotValue;
|
||||
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
|
||||
|
@ -119,17 +120,17 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
|||
{
|
||||
m_startTime = Util::getTimeMs();
|
||||
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
||||
|
||||
if( m_effectEntry.effectType == Sapphire::World::Action::EffectTypeDot )
|
||||
auto statusEffectType = static_cast< Common::StatusEffectType >( m_effectEntry.effectType );
|
||||
if( statusEffectType == Common::StatusEffectType::Dot )
|
||||
{
|
||||
auto wepDmg = Sapphire::Math::CalcStats::getWeaponDamage( *m_sourceActor );
|
||||
auto wepDmg = Sapphire::Math::CalcStats::getWeaponDamage( m_sourceActor );
|
||||
auto damage = Sapphire::Math::CalcStats::calcDamageBaseOnPotency( *m_sourceActor, m_effectEntry.effectValue2, wepDmg );
|
||||
|
||||
for( auto const& entry : m_sourceActor->getStatusEffectMap() )
|
||||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeDamageMultiplier )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::DamageMultiplier )
|
||||
continue;
|
||||
if( effectEntry.effectValue1 & m_effectEntry.effectValue1 )
|
||||
{
|
||||
|
@ -138,14 +139,14 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
|||
}
|
||||
|
||||
m_cachedHotOrDotValue = Sapphire::Math::CalcStats::applyDamageReceiveMultiplier( *m_targetActor, damage,
|
||||
m_effectEntry.effectValue1 == Sapphire::World::Action::EffectActionTypeFilterPhysical ? Common::AttackType::Physical :
|
||||
( m_effectEntry.effectValue1 == Sapphire::World::Action::EffectActionTypeFilterMagical ? Common::AttackType::Magic : Common::AttackType::None ) );
|
||||
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Sapphire::World::Action::EffectCritDHBonusFilterDamage );
|
||||
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_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Damage );
|
||||
m_cachedSourceCritBonus = Sapphire::Math::CalcStats::criticalHitBonus( *m_sourceActor );
|
||||
}
|
||||
else if( m_effectEntry.effectType == Sapphire::World::Action::EffectTypeHot )
|
||||
else if( statusEffectType == Common::StatusEffectType::Hot )
|
||||
{
|
||||
auto wepDmg = Sapphire::Math::CalcStats::getWeaponDamage( *m_sourceActor );
|
||||
auto wepDmg = Sapphire::Math::CalcStats::getWeaponDamage( m_sourceActor );
|
||||
auto heal = Sapphire::Math::CalcStats::calcHealBaseOnPotency( *m_sourceActor, m_effectEntry.effectValue2, wepDmg );
|
||||
|
||||
if( m_effectEntry.effectValue1 == 0 ) // this value is always 0 atm, if statement here just in case there is a hot that isn't a "cast"
|
||||
|
@ -154,13 +155,13 @@ void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
|||
{
|
||||
auto status = entry.second;
|
||||
auto effectEntry = status->getEffectEntry();
|
||||
if( effectEntry.effectType != Sapphire::World::Action::EffectTypeHealCastMultiplier )
|
||||
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::HealCastMultiplier )
|
||||
continue;
|
||||
heal *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
|
||||
}
|
||||
}
|
||||
m_cachedHotOrDotValue = Sapphire::Math::CalcStats::applyHealingReceiveMultiplier( *m_targetActor, heal );
|
||||
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Sapphire::World::Action::EffectCritDHBonusFilterHeal );
|
||||
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Heal );
|
||||
m_cachedSourceCritBonus = Sapphire::Math::CalcStats::criticalHitBonus( *m_sourceActor );
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue