diff --git a/src/common/Common.h b/src/common/Common.h index 183ae15d..277e5bd1 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -586,6 +586,7 @@ namespace Sapphire::Common DRKGauge = 25, // AetherflowStack = 30, // Status = 32, + SAMKenki = 39, PLDGauge = 41, GNBAmmo = 55, WHMBloodLily = 56, @@ -1049,6 +1050,7 @@ namespace Sapphire::Common InstantCast = 13, BlockParryRateBonus = 14, MPRestorePerGCD = 15, + AlwaysCombo = 16, }; enum class ActionTypeFilter : int32_t diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 6b5cdd01..21827508 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -54,7 +54,8 @@ Action::Action::Action( Entity::CharaPtr caster, uint32_t actionId, uint16_t seq m_sequence( sequence ), m_isAutoAttack( false ), m_disableGenericHandler( false ), - m_started( false ) + m_started( false ), + m_shouldAlwaysCombo( false ) { } @@ -799,6 +800,9 @@ void Action::Action::setAdditionalData( uint32_t data ) bool Action::Action::isCorrectCombo() const { + if( m_shouldAlwaysCombo ) + return true; + auto lastActionId = m_pSource->getLastComboActionId(); if( lastActionId == 0 ) @@ -814,6 +818,11 @@ bool Action::Action::isComboAction() const return m_actionData->actionCombo != 0; } +void Sapphire::World::Action::Action::setAlwaysCombo() +{ + m_shouldAlwaysCombo = true; +} + bool Action::Action::primaryCostCheck( bool subtractCosts ) { switch( m_primaryCostType ) @@ -969,6 +978,23 @@ bool Action::Action::primaryCostCheck( bool subtractCosts ) return false; } + case Common::ActionPrimaryCostType::SAMKenki: + { + auto pPlayer = m_pSource->getAsPlayer(); + if( pPlayer ) + { + auto kenki = pPlayer->gaugeSamGetKenki(); + if( kenki >= m_primaryCost ) + { + if( subtractCosts ) + pPlayer->gaugeSamSetKenki( kenki - m_primaryCost ); + + return true; + } + } + return false; + } + // free casts, likely just pure ogcds case Common::ActionPrimaryCostType::None: { diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 95eaff8b..c77c730f 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -52,6 +52,8 @@ namespace Sapphire::World::Action bool isComboAction() const; + void setAlwaysCombo(); + void setAutoAttack(); void disableGenericHandler(); @@ -202,6 +204,7 @@ namespace Sapphire::World::Action bool m_isAutoAttack; bool m_disableGenericHandler; bool m_started; + bool m_shouldAlwaysCombo; Common::ActionInterruptType m_interruptType; diff --git a/src/world/Action/ActionLutData.cpp b/src/world/Action/ActionLutData.cpp index 88dafa3d..05b2bf81 100644 --- a/src/world/Action/ActionLutData.cpp +++ b/src/world/Action/ActionLutData.cpp @@ -878,8 +878,8 @@ ActionLut::Lut ActionLut::m_actionLut = { 7480, { 100, 360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }, //Meikyo Shisui, 明鏡止水 - //applies to self: Meikyo Shisui, 明鏡止水, duration 15000, param 0 - { 7499, { 0, 0, 0, 0, 1233, 15000, 0, 0, 0, 0, 0, 0, 0 } }, + //applies to self: Meikyo Shisui, 明鏡止水, duration 15000, param 3 + { 7499, { 0, 0, 0, 0, 1233, 15000, 3, 0, 0, 0, 0, 0, 0 } }, //Hissatsu: Kaiten, 必殺剣・回天 //applies to self: Kaiten, 必殺剣・回天, duration 10000, param 0 @@ -3538,4 +3538,6 @@ ActionLut::StatusEffectTable ActionLut::m_statusEffectTable = { 1972, { 15, 2, 7392, 7391, 0 } }, + { 1233, { 16, 3, 0, 0, 0 } }, + }; diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index e5fb90a7..848f748d 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -2448,3 +2448,17 @@ uint8_t Sapphire::Entity::Player::gaugeGnbGetComboStep() { return m_gauge.gnb.ammoComboStep; } + +void Sapphire::Entity::Player::gaugeSamSetKenki( uint8_t value ) +{ + assert( value >= 0 && value <= 100 ); + auto oldValue = gaugeSamGetKenki(); + m_gauge.sam.kenki = value; + if( oldValue != value ) + sendActorGauge(); +} + +uint8_t Sapphire::Entity::Player::gaugeSamGetKenki() +{ + return m_gauge.sam.kenki; +} diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 71e31ca9..8afe1bc8 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -1006,6 +1006,9 @@ namespace Sapphire::Entity void gaugeGnbSetComboStep( uint8_t value ); uint8_t gaugeGnbGetComboStep(); + void gaugeSamSetKenki( uint8_t value ); + uint8_t gaugeSamGetKenki(); + ////////////////////////////////////////////////////////////////////////////////////////////////////// Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index ); diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index 37faa0b1..5d00683e 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -525,7 +525,7 @@ float CalcStats::autoAttack( const Sapphire::Entity::Chara& chara ) } else { - weaponDamage = chara.getLevel() * 10; + weaponDamage = chara.getLevel() * 3; } auto level = chara.getLevel(); diff --git a/src/world/StatusEffect/StatusEffect.cpp b/src/world/StatusEffect/StatusEffect.cpp index 5739859c..c1e4b74e 100644 --- a/src/world/StatusEffect/StatusEffect.cpp +++ b/src/world/StatusEffect/StatusEffect.cpp @@ -299,6 +299,12 @@ void Sapphire::StatusEffect::StatusEffect::onBeforeActionStart( Sapphire::World: } if( m_effectEntry.effectValue1 > 0 ) { + // if stacks equal to remaining uses, assume it is synced + if( m_effectEntry.effectValue1 == m_param ) + { + m_param--; + m_targetActor->sendStatusEffectUpdate(); + } m_effectEntry.effectValue1--; if( m_effectEntry.effectValue1 == 0 ) { @@ -308,6 +314,37 @@ void Sapphire::StatusEffect::StatusEffect::onBeforeActionStart( Sapphire::World: } break; } + case Common::StatusEffectType::AlwaysCombo: + { + if( action->isGCD() ) + { + // value1: remaining uses + // value2-4: affected action ids, or all actions if value2 is 0 + if( m_effectEntry.effectValue2 != 0 ) + { + if( action->getId() != m_effectEntry.effectValue2 && + action->getId() != m_effectEntry.effectValue3 && + action->getId() != m_effectEntry.effectValue4 ) + break; + } + if( m_effectEntry.effectValue1 > 0 ) + { + // if stacks equal to remaining uses, assume it is synced + if( m_effectEntry.effectValue1 == m_param ) + { + m_param--; + m_targetActor->sendStatusEffectUpdate(); + } + m_effectEntry.effectValue1--; + if( m_effectEntry.effectValue1 == 0 ) + { + markToRemove(); + } + action->setAlwaysCombo(); + } + break; + } + } } }