mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-25 11:07:45 +00:00
implement drk blood and darkside, some war fixes as well
This commit is contained in:
parent
21fffcd353
commit
b6068046ac
7 changed files with 196 additions and 60 deletions
|
@ -583,7 +583,7 @@ namespace Sapphire::Common
|
||||||
TacticsPoints = 5,
|
TacticsPoints = 5,
|
||||||
StatusEffect = 10,
|
StatusEffect = 10,
|
||||||
WARGauge = 22,
|
WARGauge = 22,
|
||||||
// DRKGauge = 25,
|
DRKGauge = 25,
|
||||||
// AetherflowStack = 30,
|
// AetherflowStack = 30,
|
||||||
// Status = 32,
|
// Status = 32,
|
||||||
PLDGauge = 41,
|
PLDGauge = 41,
|
||||||
|
@ -1079,6 +1079,7 @@ namespace Sapphire::Common
|
||||||
GainJobResource = 8,
|
GainJobResource = 8,
|
||||||
SelfHeal = 16,
|
SelfHeal = 16,
|
||||||
DamageFallOff = 32,
|
DamageFallOff = 32,
|
||||||
|
GainJobTimer = 64,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ActionBonusEffectRequirement : uint8_t
|
enum ActionBonusEffectRequirement : uint8_t
|
||||||
|
@ -1185,9 +1186,9 @@ namespace Sapphire::Common
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint8_t blood;
|
uint8_t blood;
|
||||||
uint16_t darksideTimeRemaining;
|
uint16_t darksideTimer;
|
||||||
uint8_t darkArts;
|
uint8_t darkArts;
|
||||||
uint16_t shadowTimeRemaining;
|
uint16_t shadowTimer;
|
||||||
} drk;
|
} drk;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
#include <Script/NativeScriptApi.h>
|
|
||||||
#include <ScriptObject.h>
|
|
||||||
#include <Actor/Player.h>
|
|
||||||
#include <Action/Action.h>
|
|
||||||
#include <Math/CalcStats.h>
|
|
||||||
|
|
||||||
using namespace Sapphire;
|
|
||||||
using namespace Sapphire::StatusEffect;
|
|
||||||
|
|
||||||
const uint16_t STATUS_ID_INNER_RELEASE = 1177;
|
|
||||||
|
|
||||||
class ActionInnerRelease7389 :
|
|
||||||
public ScriptAPI::ActionScript
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ActionInnerRelease7389() :
|
|
||||||
ScriptAPI::ActionScript( 7389 )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void onExecute( Sapphire::World::Action::Action& action ) override
|
|
||||||
{
|
|
||||||
auto pSource = action.getSourceChara();
|
|
||||||
assert( pSource );
|
|
||||||
|
|
||||||
World::Action::StatusEffectEntry effectEntry;
|
|
||||||
effectEntry.effectType = static_cast< uint32_t >( Common::StatusEffectType::CritDHRateBonus );
|
|
||||||
effectEntry.effectValue1 = static_cast< int32_t >( Common::ActionTypeFilter::Physical );
|
|
||||||
effectEntry.effectValue2 = 100;
|
|
||||||
effectEntry.effectValue3 = 100;
|
|
||||||
auto pEffect = Sapphire::StatusEffect::make_StatusEffect( STATUS_ID_INNER_RELEASE, action.getSourceChara(), pSource, 10000, 3000 );
|
|
||||||
pEffect->replaceEffectEntry( effectEntry );
|
|
||||||
pEffect->setParam( 65436 );
|
|
||||||
action.getEffectbuilder()->applyStatusEffect( pSource, action.getSourceChara(), pEffect, 0 );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
EXPOSE_SCRIPT( ActionInnerRelease7389 );
|
|
|
@ -125,7 +125,30 @@ bool Action::Action::init()
|
||||||
{
|
{
|
||||||
if( entry.second->getParam() == 65436 ) // todo: decode this shit and figure out exact percentage to apply to primary cost, this magic number is 0%
|
if( entry.second->getParam() == 65436 ) // todo: decode this shit and figure out exact percentage to apply to primary cost, this magic number is 0%
|
||||||
{
|
{
|
||||||
setPrimaryCost( Common::ActionPrimaryCostType::None, 0 );
|
/*
|
||||||
|
Since the client is displaying correctly without additional data, there should be a "primary primary cost type" defined for each class.
|
||||||
|
In the case of 65436, on whm, mp cost is removed, on drk, blood cost is removed but mp cost remains.
|
||||||
|
*/
|
||||||
|
auto affectedPrimaryCost = Common::ActionPrimaryCostType::MagicPoints;
|
||||||
|
switch( m_pSource->getClass() )
|
||||||
|
{
|
||||||
|
case Common::ClassJob::Marauder:
|
||||||
|
case Common::ClassJob::Warrior:
|
||||||
|
{
|
||||||
|
affectedPrimaryCost = Common::ActionPrimaryCostType::WARGauge;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Common::ClassJob::Darkknight:
|
||||||
|
{
|
||||||
|
affectedPrimaryCost = Common::ActionPrimaryCostType::DRKGauge;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( m_primaryCostType == affectedPrimaryCost )
|
||||||
|
{
|
||||||
|
setPrimaryCost( Common::ActionPrimaryCostType::None, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -612,6 +635,26 @@ void Action::Action::buildEffects()
|
||||||
player->gaugeWarSetIb( std::min( 100, player->gaugeWarGetIb() + m_lutEntry.bonusDataByte4 ) );
|
player->gaugeWarSetIb( std::min( 100, player->gaugeWarGetIb() + m_lutEntry.bonusDataByte4 ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Common::ClassJob::Darkknight:
|
||||||
|
{
|
||||||
|
player->gaugeDrkSetBlood( std::min( 100, player->gaugeDrkGetBlood() + m_lutEntry.bonusDataByte4 ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_lutEntry.bonusEffect & Common::ActionBonusEffect::GainJobTimer )
|
||||||
|
{
|
||||||
|
if( checkActionBonusRequirement() )
|
||||||
|
{
|
||||||
|
switch( static_cast< Common::ClassJob >( m_lutEntry.bonusDataByte3 ) )
|
||||||
|
{
|
||||||
|
case Common::ClassJob::Darkknight:
|
||||||
|
{
|
||||||
|
player->gaugeDrkSetDarkSideTimer( std::min( 60000, player->gaugeDrkGetDarkSideTimer() + m_lutEntry.bonusDataUInt16L ), true );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -862,6 +905,23 @@ bool Action::Action::primaryCostCheck( bool subtractCosts )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Common::ActionPrimaryCostType::DRKGauge:
|
||||||
|
{
|
||||||
|
auto pPlayer = m_pSource->getAsPlayer();
|
||||||
|
if( pPlayer )
|
||||||
|
{
|
||||||
|
auto blood = pPlayer->gaugeDrkGetBlood();
|
||||||
|
if( blood >= m_primaryCost )
|
||||||
|
{
|
||||||
|
if( subtractCosts )
|
||||||
|
pPlayer->gaugeDrkSetBlood( blood - m_primaryCost );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// free casts, likely just pure ogcds
|
// free casts, likely just pure ogcds
|
||||||
case Common::ActionPrimaryCostType::None:
|
case Common::ActionPrimaryCostType::None:
|
||||||
{
|
{
|
||||||
|
|
|
@ -225,12 +225,12 @@ ActionLut::Lut ActionLut::m_actionLut =
|
||||||
{ 7387, { 450, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 7387, { 450, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
||||||
|
|
||||||
//Shake It Off, シェイクオフ
|
//Shake It Off, シェイクオフ
|
||||||
//applies to targets: Shake It Off, シェイクオフ, duration 0, param 0
|
//applies to targets: Shake It Off, シェイクオフ, duration 15000, param 0
|
||||||
{ 7388, { 0, 0, 0, 0, 0, 0, 0, 1457, 0, 0, 0, 0, 0 } },
|
{ 7388, { 0, 0, 0, 0, 0, 0, 0, 1457, 15000, 0, 0, 0, 0 } },
|
||||||
|
|
||||||
//Inner Release, 原初の解放
|
//Inner Release, 原初の解放
|
||||||
//comment: status removed need script
|
//applies to self: Inner Release, 原初の解放, duration 10000, param 65436
|
||||||
{ 7389, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 7389, { 0, 0, 0, 0, 1177, 10000, 65436, 0, 0, 0, 0, 0, 0 } },
|
||||||
|
|
||||||
//Chaotic Cyclone, カオティックサイクロン
|
//Chaotic Cyclone, カオティックサイクロン
|
||||||
//has damage: potency 400, combo potency 0, directional potency 0
|
//has damage: potency 400, combo potency 0, directional potency 0
|
||||||
|
@ -271,13 +271,14 @@ ActionLut::Lut ActionLut::m_actionLut =
|
||||||
|
|
||||||
//Souleater, ソウルイーター
|
//Souleater, ソウルイーター
|
||||||
//has damage: potency 100, combo potency 400, directional potency 0
|
//has damage: potency 100, combo potency 400, directional potency 0
|
||||||
//has heal: potency 300
|
//has bonus effect: 24, 169869612
|
||||||
{ 3632, { 100, 400, 0, 300, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
//bonus effect requirement: RequireCorrectCombo
|
||||||
|
{ 3632, { 100, 400, 0, 0, 0, 0, 0, 0, 0, 0, 24, 1, 169869612 } },
|
||||||
|
|
||||||
//Flood of Darkness, 暗黒の波動
|
//Flood of Darkness, 暗黒の波動
|
||||||
//has damage: potency 250, combo potency 0, directional potency 0
|
//has damage: potency 250, combo potency 0, directional potency 0
|
||||||
//applies to self: Darkside, 暗黒, duration 30000, param 0
|
//has bonus effect: GainJobTimer, 2127152
|
||||||
{ 16466, { 250, 0, 0, 0, 751, 30000, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 16466, { 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 2127152 } },
|
||||||
|
|
||||||
//Blood Weapon, ブラッドウェポン
|
//Blood Weapon, ブラッドウェポン
|
||||||
//applies to self: Blood Weapon, ブラッドウェポン, duration 10000, param 0
|
//applies to self: Blood Weapon, ブラッドウェポン, duration 10000, param 0
|
||||||
|
@ -289,8 +290,8 @@ ActionLut::Lut ActionLut::m_actionLut =
|
||||||
|
|
||||||
//Edge of Darkness, 暗黒の剣
|
//Edge of Darkness, 暗黒の剣
|
||||||
//has damage: potency 350, combo potency 0, directional potency 0
|
//has damage: potency 350, combo potency 0, directional potency 0
|
||||||
//applies to self: Darkside, 暗黒, duration 30000, param 0
|
//has bonus effect: GainJobTimer, 2127152
|
||||||
{ 16467, { 350, 0, 0, 0, 751, 30000, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 16467, { 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 2127152 } },
|
||||||
|
|
||||||
//Dark Mind, ダークマインド
|
//Dark Mind, ダークマインド
|
||||||
//applies to targets: Dark Mind, ダークマインド, duration 10000, param 0
|
//applies to targets: Dark Mind, ダークマインド, duration 10000, param 0
|
||||||
|
@ -328,8 +329,8 @@ ActionLut::Lut ActionLut::m_actionLut =
|
||||||
{ 7391, { 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 7391, { 210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
||||||
|
|
||||||
//Delirium, ブラッドデリリアム
|
//Delirium, ブラッドデリリアム
|
||||||
//applies to self: Delirium, ブラッドデリリアム, duration 10000, param 0
|
//applies to self: Delirium, ブラッドデリリアム, duration 10000, param 65436
|
||||||
{ 7390, { 0, 0, 0, 0, 1972, 10000, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 7390, { 0, 0, 0, 0, 1972, 10000, 65436, 0, 0, 0, 0, 0, 0 } },
|
||||||
|
|
||||||
//The Blackest Night, ブラックナイト
|
//The Blackest Night, ブラックナイト
|
||||||
//applies to self: Blackest Night, ブラックナイト, duration 0, param 0
|
//applies to self: Blackest Night, ブラックナイト, duration 0, param 0
|
||||||
|
@ -343,8 +344,8 @@ ActionLut::Lut ActionLut::m_actionLut =
|
||||||
|
|
||||||
//Edge of Shadow, 漆黒の剣
|
//Edge of Shadow, 漆黒の剣
|
||||||
//has damage: potency 500, combo potency 0, directional potency 0
|
//has damage: potency 500, combo potency 0, directional potency 0
|
||||||
//applies to self: Darkside, 暗黒, duration 30000, param 0
|
//has bonus effect: GainJobTimer, 2127152
|
||||||
{ 16470, { 500, 0, 0, 0, 751, 30000, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 16470, { 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 2127152 } },
|
||||||
|
|
||||||
//Dark Missionary, ダークミッショナリー
|
//Dark Missionary, ダークミッショナリー
|
||||||
//applies to targets: Dark Missionary, ダークミッショナリー, duration 15000, param 0
|
//applies to targets: Dark Missionary, ダークミッショナリー, duration 15000, param 0
|
||||||
|
@ -2834,6 +2835,11 @@ ActionLut::Lut ActionLut::m_actionLut =
|
||||||
//has damage: potency 100, combo potency 0, directional potency 0
|
//has damage: potency 100, combo potency 0, directional potency 0
|
||||||
{ 8, { 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
{ 8, { 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
|
||||||
|
|
||||||
|
//Flood of Shadow, 漆黒の波動
|
||||||
|
//has damage: potency 300, combo potency 0, directional potency 0
|
||||||
|
//has bonus effect: GainJobTimer, 2127152
|
||||||
|
{ 16469, { 300, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 2127152 } },
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ActionLut::StatusEffectTable ActionLut::m_statusEffectTable =
|
ActionLut::StatusEffectTable ActionLut::m_statusEffectTable =
|
||||||
|
|
|
@ -1192,7 +1192,25 @@ void Sapphire::Entity::Player::update( uint64_t tickCount )
|
||||||
gaugeWhmSetLilyTimer( 0 );
|
gaugeWhmSetLilyTimer( 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
break;
|
||||||
|
}
|
||||||
|
case Common::ClassJob::Darkknight:
|
||||||
|
{
|
||||||
|
auto dsTimer = gaugeDrkGetDarkSideTimer();
|
||||||
|
if( dsTimer > interval )
|
||||||
|
dsTimer -= interval;
|
||||||
|
else
|
||||||
|
dsTimer = 0;
|
||||||
|
gaugeDrkSetDarkSideTimer( dsTimer );
|
||||||
|
|
||||||
|
auto shadowTimer = gaugeDrkGetShadowTimer();
|
||||||
|
if( shadowTimer > interval )
|
||||||
|
shadowTimer -= interval;
|
||||||
|
else
|
||||||
|
shadowTimer = 0;
|
||||||
|
gaugeDrkSetShadowTimer( shadowTimer );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Chara::update( tickCount );
|
Chara::update( tickCount );
|
||||||
|
@ -2311,3 +2329,56 @@ uint16_t Sapphire::Entity::Player::gaugeWhmGetLilyTimer()
|
||||||
{
|
{
|
||||||
return m_gauge.whm.lilyTimer;
|
return m_gauge.whm.lilyTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::gaugeDrkSetBlood( uint8_t value )
|
||||||
|
{
|
||||||
|
assert( value >= 0 && value <= 100 );
|
||||||
|
auto oldValue = gaugeDrkGetBlood();
|
||||||
|
m_gauge.drk.blood = value;
|
||||||
|
if( oldValue != value )
|
||||||
|
sendActorGauge();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Sapphire::Entity::Player::gaugeDrkGetBlood()
|
||||||
|
{
|
||||||
|
return m_gauge.drk.blood;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::gaugeDrkSetDarkArts( bool value )
|
||||||
|
{
|
||||||
|
auto oldValue = gaugeDrkGetDarkArts();
|
||||||
|
m_gauge.drk.darkArts = value ? 1 : 0;
|
||||||
|
if( oldValue != value )
|
||||||
|
sendActorGauge();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::Entity::Player::gaugeDrkGetDarkArts()
|
||||||
|
{
|
||||||
|
return m_gauge.drk.darkArts > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::gaugeDrkSetDarkSideTimer( uint16_t value, bool sendPacket )
|
||||||
|
{
|
||||||
|
assert( value >= 0 && value <= 60000 );
|
||||||
|
m_gauge.drk.darksideTimer = value;
|
||||||
|
if( sendPacket )
|
||||||
|
sendActorGauge();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Sapphire::Entity::Player::gaugeDrkGetDarkSideTimer()
|
||||||
|
{
|
||||||
|
return m_gauge.drk.darksideTimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::Entity::Player::gaugeDrkSetShadowTimer( uint16_t value, bool sendPacket )
|
||||||
|
{
|
||||||
|
assert( value >= 0 && value <= 60000 );
|
||||||
|
m_gauge.drk.shadowTimer = value;
|
||||||
|
if( sendPacket )
|
||||||
|
sendActorGauge();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Sapphire::Entity::Player::gaugeDrkGetShadowTimer()
|
||||||
|
{
|
||||||
|
return m_gauge.drk.shadowTimer;
|
||||||
|
}
|
|
@ -988,6 +988,15 @@ namespace Sapphire::Entity
|
||||||
void gaugeWhmSetLilyTimer( uint16_t value, bool sendPacket = false );
|
void gaugeWhmSetLilyTimer( uint16_t value, bool sendPacket = false );
|
||||||
uint16_t gaugeWhmGetLilyTimer();
|
uint16_t gaugeWhmGetLilyTimer();
|
||||||
|
|
||||||
|
void gaugeDrkSetBlood( uint8_t value );
|
||||||
|
uint8_t gaugeDrkGetBlood();
|
||||||
|
void gaugeDrkSetDarkArts( bool value );
|
||||||
|
bool gaugeDrkGetDarkArts();
|
||||||
|
void gaugeDrkSetDarkSideTimer( uint16_t value, bool sendPacket = false );
|
||||||
|
uint16_t gaugeDrkGetDarkSideTimer();
|
||||||
|
void gaugeDrkSetShadowTimer( uint16_t value, bool sendPacket = false );
|
||||||
|
uint16_t gaugeDrkGetShadowTimer();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
|
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
|
||||||
|
|
|
@ -584,10 +584,21 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto format = "auto attack: pot: {} aa: {} ap: {} det: {} ten: {} = {}";
|
if( chara.isPlayer() )
|
||||||
|
|
||||||
if( auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer() )
|
|
||||||
{
|
{
|
||||||
|
auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer();
|
||||||
|
switch( player->getClass() )
|
||||||
|
{
|
||||||
|
case Common::ClassJob::Darkknight:
|
||||||
|
{
|
||||||
|
if( player->gaugeDrkGetDarkSideTimer() > 0 )
|
||||||
|
{
|
||||||
|
factor *= 1.1f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
constexpr auto format = "auto attack: pot: {} aa: {} ap: {} det: {} ten: {} = {}";
|
||||||
player->sendDebug( format, pot, aa, ap, det, ten, factor );
|
player->sendDebug( format, pot, aa, ap, det, ten, factor );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,6 +717,22 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( chara.isPlayer() )
|
||||||
|
{
|
||||||
|
auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer();
|
||||||
|
switch( player->getClass() )
|
||||||
|
{
|
||||||
|
case Common::ClassJob::Darkknight:
|
||||||
|
{
|
||||||
|
if( player->gaugeDrkGetDarkSideTimer() > 0 )
|
||||||
|
{
|
||||||
|
factor *= 1.1f;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return std::pair( factor, hitType );
|
return std::pair( factor, hitType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue