1
Fork 0
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:
collett 2020-01-12 03:29:52 +09:00
parent 8d7c6f5188
commit e08643f380
10 changed files with 1267 additions and 380 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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