1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-25 19:17:45 +00:00

Implement presence of mind.

This commit is contained in:
collett 2020-01-14 21:59:05 +09:00
parent 651e8e2d3e
commit 62f25b4b77
8 changed files with 123 additions and 60 deletions

View file

@ -1038,6 +1038,7 @@ namespace Sapphire::Common
DamageDealtTrigger = 9,
Shield = 10,
MPRestore = 11,
Haste = 12,
};
enum class ActionTypeFilter : int32_t

View file

@ -79,6 +79,14 @@ bool Action::Action::init()
m_castTimeMs = static_cast< uint32_t >( m_actionData->cast100ms * 100 );
m_recastTimeMs = static_cast< uint32_t >( m_actionData->recast100ms * 100 );
auto actionCategory = static_cast< Common::ActionCategory >( m_actionData->actionCategory );
if( actionCategory == Common::ActionCategory::Spell || actionCategory == Common::ActionCategory::Weaponskill )
{
auto haste = m_pSource->getStatValue( Common::BaseParam::Haste );
m_castTimeMs = static_cast< uint32_t >( m_castTimeMs * ( m_pSource->getStatValue( Common::BaseParam::Haste ) / 100.0f ) );
m_recastTimeMs = static_cast< uint32_t >( m_recastTimeMs * ( m_pSource->getStatValue( Common::BaseParam::Haste ) / 100.0f ) );
}
m_cooldownGroup = m_actionData->cooldownGroup;
m_range = m_actionData->range;
m_effectRange = m_actionData->effectRange;

View file

@ -3508,4 +3508,7 @@ ActionLut::StatusEffectTable ActionLut::m_statusEffectTable =
//Lucid Dreaming, ルーシッドドリーム: MPRestore, value 50
{ 1204, { 11, 50, 0, 0, 0 } },
//Presence of Mind, 神速魔: Haste, 20%
{ 157, { 12, 20, 0, 0, 0 } },
};

View file

@ -735,6 +735,7 @@ void Sapphire::Entity::BNpc::calculateStats()
m_baseStats.pie = static_cast< uint32_t >( base );
m_baseStats.skillSpeed = static_cast< uint32_t >( paramGrowthInfo->baseSpeed );
m_baseStats.spellSpeed = static_cast< uint32_t >( paramGrowthInfo->baseSpeed );
m_baseStats.haste = 100;
m_baseStats.accuracy = static_cast< uint32_t >( paramGrowthInfo->baseSpeed );
m_baseStats.critHitRate = static_cast< uint32_t >( paramGrowthInfo->baseSpeed );
m_baseStats.attackPotMagic = static_cast< uint32_t >( paramGrowthInfo->baseSpeed );

View file

@ -494,8 +494,8 @@ void Sapphire::Entity::Chara::addStatusEffect( StatusEffect::StatusEffectPtr pEf
if( nextSlot == -1 )
return;
pEffect->applyStatus();
m_statusEffectMap[ nextSlot ] = pEffect;
pEffect->applyStatus();
auto statusEffectAdd = makeZonePacket< FFXIVIpcEffectResult >( getId() );
@ -594,14 +594,14 @@ void Sapphire::Entity::Chara::removeStatusEffect( uint8_t effectSlotId, bool sen
statusEffectFreeSlot( effectSlotId );
m_statusEffectMap.erase( effectSlotId );
auto pEffect = pEffectIt->second;
pEffect->removeStatus();
if( sendActorControl )
sendToInRangeSet( makeActorControl( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() );
m_statusEffectMap.erase( effectSlotId );
if( sendStatusList )
sendStatusEffectUpdate();
}
@ -941,6 +941,18 @@ uint32_t Sapphire::Entity::Chara::getStatValue( Sapphire::Common::BaseParam base
break;
}
case Common::BaseParam::Haste:
{
value = m_baseStats.haste;
for( auto const& statusIt : m_statusEffectMap )
{
auto effectEntry = statusIt.second->getEffectEntry();
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) == Common::StatusEffectType::Haste )
value -= effectEntry.effectValue1;
}
break;
}
case Common::BaseParam::CriticalHit:
{
value = m_baseStats.critHitRate;

View file

@ -47,6 +47,7 @@ namespace Sapphire::Entity
uint32_t healingPotMagic = 0;
uint32_t determination = 0;
uint32_t skillSpeed = 0;
uint32_t haste = 0;
uint32_t resistSlow = 0;
uint32_t resistSilence = 0;

View file

@ -280,6 +280,7 @@ void Sapphire::Entity::Player::calculateStats()
m_baseStats.pie = static_cast< uint32_t >( base );
m_baseStats.skillSpeed = paramGrowthInfo->baseSpeed;
m_baseStats.spellSpeed = paramGrowthInfo->baseSpeed;
m_baseStats.haste = 100;
m_baseStats.accuracy = paramGrowthInfo->baseSpeed;
m_baseStats.critHitRate = paramGrowthInfo->baseSpeed;
m_baseStats.attackPotMagic = paramGrowthInfo->baseSpeed;
@ -332,7 +333,7 @@ void Sapphire::Entity::Player::sendStats()
statPacket->data().healingMagicPotency = getStatValue( Common::BaseParam::HealingMagicPotency );
statPacket->data().skillSpeed = getStatValue( Common::BaseParam::SkillSpeed );
statPacket->data().spellSpeed = getStatValue( Common::BaseParam::SpellSpeed );
statPacket->data().haste = 100;
statPacket->data().haste = getStatValue( Common::BaseParam::Haste );
statPacket->data().criticalHit = getStatValue( Common::BaseParam::CriticalHit );
statPacket->data().defense = getStatValue( Common::BaseParam::Defense );
statPacket->data().magicDefense = getStatValue( Common::BaseParam::MagicDefense );
@ -1128,7 +1129,7 @@ void Sapphire::Entity::Player::update( uint64_t tickCount )
actor->getPos().x, actor->getPos().y, actor->getPos().z ) <= range )
{
if( ( tickCount - m_lastAttack ) > mainWeap->getDelay() )
if( ( tickCount - m_lastAttack ) > ( static_cast< float >( mainWeap->getDelay() ) * ( getStatValue( Common::BaseParam::Haste ) / 100.0f ) ) )
{
m_lastAttack = tickCount;
autoAttack( actor->getAsChara() );

View file

@ -5,6 +5,7 @@
#include <algorithm>
#include "Actor/Player.h"
#include "Actor/Chara.h"
#include "Actor/Actor.h"
@ -64,31 +65,39 @@ void Sapphire::StatusEffect::StatusEffect::registerTickEffect( uint8_t type, uin
std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect()
{
auto statusEffectType = static_cast< Common::StatusEffectType >( m_effectEntry.effectType );
if( statusEffectType == Common::StatusEffectType::Dot )
switch( static_cast< Common::StatusEffectType >( m_effectEntry.effectType ) )
{
auto value = m_value;
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
case Common::StatusEffectType::Dot:
{
value *= m_cachedSourceCritBonus;
auto value = m_value;
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
{
value *= m_cachedSourceCritBonus;
}
value *= 1.0f + ( ( Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) - 50.0f ) / 1000.0f );
m_currTickEffect = std::make_pair( 1, value );
break;
}
value *= 1.0f + ( ( Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) - 50.0f ) / 1000.0f );
m_currTickEffect = std::make_pair( 1, value );
}
else if( statusEffectType == Common::StatusEffectType::Hot )
{
auto value = m_value;
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
case Common::StatusEffectType::Hot:
{
value *= m_cachedSourceCritBonus;
auto value = m_value;
if( m_cachedSourceCrit > Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) )
{
value *= m_cachedSourceCritBonus;
}
value *= 1.0f + ( ( Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) - 50.0f ) / 1000.0f );
m_currTickEffect = std::make_pair( 2, value );
break;
}
default:
{
m_currTickEffect = std::make_pair( 0, 0 );
break;
}
value *= 1.0f + ( ( Sapphire::Math::CalcStats::range100( Sapphire::Math::CalcStats::rng ) - 50.0f ) / 1000.0f );
m_currTickEffect = std::make_pair( 2, value );
}
else
{
m_currTickEffect = std::make_pair( 0, 0 );
}
return m_currTickEffect;
}
@ -123,59 +132,86 @@ uint16_t Sapphire::StatusEffect::StatusEffect::getParam() const
void Sapphire::StatusEffect::StatusEffect::applyStatus()
{
m_startTime = Util::getTimeMs();
if( m_lastTick == 0 )
m_lastTick = m_startTime;
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
auto statusEffectType = static_cast< Common::StatusEffectType >( m_effectEntry.effectType );
if( statusEffectType == Common::StatusEffectType::Dot )
pScriptMgr->onStatusReceive( m_targetActor, m_id );
switch( static_cast< Common::StatusEffectType >( m_effectEntry.effectType ) )
{
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() )
case Common::StatusEffectType::Dot:
{
auto status = entry.second;
auto effectEntry = status->getEffectEntry();
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::DamageMultiplier )
continue;
if( effectEntry.effectValue1 & m_effectEntry.effectValue1 )
{
damage *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
}
}
auto wepDmg = Sapphire::Math::CalcStats::getWeaponDamage( m_sourceActor );
auto damage = Sapphire::Math::CalcStats::calcDamageBaseOnPotency( *m_sourceActor, m_effectEntry.effectValue2, wepDmg );
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::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( statusEffectType == Common::StatusEffectType::Hot )
{
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"
{
for( auto const& entry : m_sourceActor->getStatusEffectMap() )
{
auto status = entry.second;
auto effectEntry = status->getEffectEntry();
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::HealCastMultiplier )
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::DamageMultiplier )
continue;
heal *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
if( effectEntry.effectValue1 & m_effectEntry.effectValue1 )
{
damage *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
}
}
}
m_value = Sapphire::Math::CalcStats::applyHealingReceiveMultiplier( *m_targetActor, heal );
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Heal );
m_cachedSourceCritBonus = Sapphire::Math::CalcStats::criticalHitBonus( *m_sourceActor );
}
pScriptMgr->onStatusReceive( m_targetActor, m_id );
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::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 );
break;
}
case Common::StatusEffectType::Hot:
{
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"
{
for( auto const& entry : m_sourceActor->getStatusEffectMap() )
{
auto status = entry.second;
auto effectEntry = status->getEffectEntry();
if( static_cast< Common::StatusEffectType >( effectEntry.effectType ) != Common::StatusEffectType::HealCastMultiplier )
continue;
heal *= 1.0f + ( effectEntry.effectValue2 / 100.0f );
}
}
m_value = Sapphire::Math::CalcStats::applyHealingReceiveMultiplier( *m_targetActor, heal );
m_cachedSourceCrit = Sapphire::Math::CalcStats::criticalHitProbability( *m_sourceActor, Common::CritDHBonusFilter::Heal );
m_cachedSourceCritBonus = Sapphire::Math::CalcStats::criticalHitBonus( *m_sourceActor );
break;
}
case Common::StatusEffectType::Haste:
{
auto pPlayer = m_targetActor->getAsPlayer();
if( pPlayer )
pPlayer->sendStats();
break;
}
}
}
void Sapphire::StatusEffect::StatusEffect::removeStatus()
{
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
pScriptMgr->onStatusTimeOut( m_targetActor, m_id );
switch( static_cast< Common::StatusEffectType >( m_effectEntry.effectType ) )
{
case Common::StatusEffectType::Haste:
{
auto pPlayer = m_targetActor->getAsPlayer();
if( pPlayer )
pPlayer->sendStats();
break;
}
}
}
uint32_t Sapphire::StatusEffect::StatusEffect::getId() const