[Feature] New SPAs pass 1 (#1454)

* Implemented SPA Duration Pct

Implemented new spell effects
SE_Duration_HP_Pct 			524
SE_Duration_Mana_Pct			525
SE_Duration_Endurance_Pct		526

Consumes 'base1' % of your maximum health/mana/endurance every 6 seconds. 'max' is maximum amount that can be consumed per tic.

Additional Functionality
Can be used as a heal/gain % by setting the base1 value to a positive.

* Implemented SPA Instant Mana/End pct

Fixes for SPA 524-526
Implemented
SE_Instant_Mana_Pct			522
SE_Instant_Endurance_Pct		523

Extracts 'base1' percent of your maximum mana/endurance, or 'max', whichever is lower.

* Implemented: SPA 521 EndAbsorbPctDmg

Implemented
SE_Endurance_Absorb_Pct_Damage 521

Absorb Damage using Endurance: base1 % (base2 End per 1 HP)
Note: Both base1 and base2 need to be divided by 100 for actually value

* Implemented SE_HealthTransfer 509

Implemented
SE_Health_Transfer			509
'life burn'
Consume base2 % of Hit Points to Damage for base % of Hit Points

Can be used for heal
Act of Valor

* Implemented SPA 515,516,518,496

Implemented
SE_AC_Avoidance_Max_Percent 515
SE_AC_Mitigation_Max_Percent	516
SE_Attack_Accuracy_Max_Percent	518
Above are stackable defense and offensive mods

SE_Critical_Melee_Damage_Mod_Max	496 - This is a non stackable melee critical modifier

* Implemented SPA 503 , 505

SE_Melee_Damage_Position_Mod	503
define SE_Damage_Taken_Position_Mod	505

SPA 503 increase/decreases melee damage by percent base1 based on your position base2 0=back 1=front

SPA 504 increase/decreases melee damage taken by percent base1 based on your position base2 0=back 1=front

* Implemented 467,468

Implemented
SE_DS_Mitigation_Amount		467
SE_DS_Mitigation_Percentage	468

Reduce incoming DS by amt or percentage. base1 is value, if a reduction is desired it should be set to negative for both.

* Fixes

Formula fixes

* Update spdat.h

Added spa descriptions.

* Fixes for PR

removed debug shouts
fixed description issue
This commit is contained in:
KayenEQ 2021-07-14 23:15:04 -04:00 committed by GitHub
parent a8e12c82a7
commit 8a2a1b152e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 498 additions and 35 deletions

View File

@ -62,6 +62,8 @@
#define SPELL_SHAPECHANGE60 1924
#define SPELL_COMMAND_OF_DRUZZIL 3355
#define SPELL_SHAPECHANGE70 6503
#define SPELL_MANA_BURN 2751
#define SPELL_LIFE_BURN 2755
// these have known hardcoded behavior but we don't do anything yet, move them above this comment when fixed
#define SPELL_THE_DAINS_JUSTICE 1476
#define SPELL_MODULATION 1502
@ -152,7 +154,7 @@
#define SPELL_RESURRECTION_SICKNESS 756
#define SPELL_RESURRECTION_SICKNESS2 5249
#define SPELL_REVIVAL_SICKNESS 13087
#define SPELL_MANA_BURN 2751
#define EFFECT_COUNT 12
@ -807,13 +809,13 @@ typedef enum {
#define SE_PC_Pet_Rampage 464 // implemented - Base1 % chance to do rampage for base2 % of damage each melee round
//#define SE_PC_Pet_AE_Rampage 465 // Would assume as above but need to confirm.
#define SE_PC_Pet_Flurry_Chance 466 // implemented - Base1 % chance to do flurry from double attack hit.
//#define SE_DS_Mitigation_Amount 467 //
//#define SE_DS_Mitigation_Percentage 468 //
#define SE_DS_Mitigation_Amount 467 // implemented - Modify incoming damage shield damage by a flat amount
#define SE_DS_Mitigation_Percentage 468 // implemented - Modify incoming damage shield damage by percentage
//#define SE_Chance_Best_in_Spell_Grp 469 //
//#define SE_Trigger_Best_in_Spell Grp 470 //
//#define SE_Double_Melee_Round 471 //
//#define SE_Buy_AA_Rank 472 //
//#define SE_Double_Backstab_Front 473 //
#define SE_Double_Backstab_Front 473 // implemented - Chance to double backstab from front
//#define SE_Pet_Crit_Melee_Damage_Pct_Owner 474 //
//#define SE_Trigger_Spell_Non_Item 475 //
//#define SE_Weapon_Stance 476 //
@ -836,37 +838,37 @@ typedef enum {
//#define SE_Ff_Endurance_Max 493 //
//#define SE_Pet_Add_Atk 494 //
//#define SE_Ff_DurationMax 495 //
//#define SE_Critical_Melee_Damage_Mod_Max 496 //
#define SE_Critical_Melee_Damage_Mod_Max 496 // implemented - increase or decrease by percent critical damage (not stackable)
//#define SE_Ff_FocusCastProcNoBypass 497 //
//#define SE_AddExtraAttackPct_1h_Primary 498 //
//#define SE_AddExtraAttackPct_1h_Secondary 499 //
//#define SE_Fc_CastTimeMod2 500 //
//#define SE_Fc_CastTimeAmt 501 //
//#define SE_Fearstun 502 //
//#define SE_Melee_Damage_Position_Mod 503 //
#define SE_Melee_Damage_Position_Mod 503 // implemented - modify melee damage by pct if done from Front or Behind
//#define SE_Melee_Damage_Position_Amt 504 //
//#define SE_Damage_Taken_Position_Mod 505 //
#define SE_Damage_Taken_Position_Mod 505 // implemented - mitigate melee damage by pct if dmg taken from Front or Behind
//#define SE_Damage_Taken_Position_Amt 506 //
//#define SE_Fc_Amplify_Mod 507 //
//#define SE_Fc_Amplify_Amt 508 //
//#define SE_Health_Transfer 509 //
#define SE_Health_Transfer 509 // implemented - exchange health for damage or healing on a target. ie Lifeburn/Act of Valor
//#define SE_Fc_ResistIncoming 510 //
//#define SE_Ff_FocusTimerMin 511 //
//#define SE_Proc_Timer_Modifier 512 //
//#define SE_Mana_Max_Percent 513 //
//#define SE_Endurance_Max_Percent 514 //
//#define SE_AC_Avoidance_Max_Percent 515 //
//#define SE_AC_Mitigation_Max_Percent 516 //
//#define SE_Attack_Offense_Max_Percent 517 //
//#define SE_Attack_Accuracy_Max_Percent 518 //
#define SE_AC_Avoidance_Max_Percent 515 // implemented - stackable avoidance modifier
#define SE_AC_Mitigation_Max_Percent 516 // implemented - stackable defense modifier
//#define SE_Attack_Offense_Max_Percent 517 //
#define SE_Attack_Accuracy_Max_Percent 518 // implemented - stackable accurary modifer
//#define SE_Luck_Amount 519 //
//#define SE_Luck_Percent 520 //
//#define SE_Endurance_Absorb_Pct_Damage 521 //
//#define SE_Instant_Mana_Pct 522 //
//#define SE_Instant_Endurance_Pct 523 //
//#define SE_Duration_HP_Pct 524 //
//#define SE_Duration_Mana_Pct 525 //
//#define SE_Duration_Endurance_Pct 526 //
#define SE_Endurance_Absorb_Pct_Damage 521 // implemented - Reduces % of Damage using Endurance, drains endurance at a ratio (ie. 0.05 Endurance per Hit Point)
#define SE_Instant_Mana_Pct 522 // implemented - Increase/Decrease mana by percent of max mana
#define SE_Instant_Endurance_Pct 523 // implemented - Increase/Decrease mana by percent of max endurance
#define SE_Duration_HP_Pct 524 // implemented - Decrease Current Hit Points by % of Total Hit Points per Tick, up to a MAX per tick
#define SE_Duration_Mana_Pct 525 // implemented - Decrease Current Mana by % of Total Mana per Tick, up to a MAX per tick
#define SE_Duration_Endurance_Pct 526 // implemented - Decrease Current Endurance by % of Total Hit Points per Tick, up to a MAX per tick
// LAST

View File

@ -188,6 +188,11 @@ int Mob::GetTotalToHit(EQ::skills::SkillType skill, int chance_mod)
if (skill != EQ::skills::SkillArchery && skill != EQ::skills::SkillThrowing)
accuracy += itembonuses.HitChance;
//518 Increase ATK accuracy by percentage, stackable
auto atkhit_bonus = itembonuses.Attack_Accuracy_Max_Percent + aabonuses.Attack_Accuracy_Max_Percent + spellbonuses.Attack_Accuracy_Max_Percent;
if (atkhit_bonus)
accuracy += round(static_cast<double>(accuracy) * static_cast<double>(atkhit_bonus) * 0.0001);
// 216 Melee Accuracy Amt aka SE_Accuracy -- flat bonus
accuracy += itembonuses.Accuracy[EQ::skills::HIGHEST_SKILL + 1] +
aabonuses.Accuracy[EQ::skills::HIGHEST_SKILL + 1] +
@ -233,6 +238,11 @@ int Mob::compute_defense()
if (IsClient())
defense += CastToClient()->GetHeroicAGI() / 10;
//516 SE_AC_Mitigation_Max_Percent
auto ac_bonus = itembonuses.AC_Mitigation_Max_Percent + aabonuses.AC_Mitigation_Max_Percent + spellbonuses.AC_Mitigation_Max_Percent;
if (ac_bonus)
defense += round(static_cast<double>(defense) * static_cast<double>(ac_bonus) * 0.0001);
defense += itembonuses.AvoidMeleeChance; // item mod2
if (IsNPC())
defense += CastToNPC()->GetAvoidanceRating();
@ -255,7 +265,12 @@ int Mob::GetTotalDefense()
auto evasion_bonus = spellbonuses.AvoidMeleeChanceEffect; // we check this first since it has a special case
if (evasion_bonus >= 10000)
return -1;
//
// 515 SE_AC_Avoidance_Max_Percent
auto ac_aviodance_bonus = itembonuses.AC_Avoidance_Max_Percent + aabonuses.AC_Avoidance_Max_Percent + spellbonuses.AC_Avoidance_Max_Percent;
if (ac_aviodance_bonus)
avoidance += round(static_cast<double>(avoidance) * static_cast<double>(ac_aviodance_bonus) * 0.0001);
// 172 Evasion aka SE_AvoidMeleeChance
evasion_bonus += itembonuses.AvoidMeleeChanceEffect + aabonuses.AvoidMeleeChanceEffect; // item bonus here isn't mod2 avoidance
@ -2887,6 +2902,10 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
DS += aabonuses.DamageShield; //Live AA - coat of thistles. (negative value)
DS -= itembonuses.DamageShield; //+Damage Shield should only work when you already have a DS spell
DS -= attacker->aabonuses.DS_Mitigation_Amount + attacker->itembonuses.DS_Mitigation_Amount + attacker->spellbonuses.DS_Mitigation_Amount; //Negative value to reduce
//Do not allow flat amount reductions to reduce past 0.
if (DS >= 0)
return;
//Spell data for damage shield mitigation shows a negative value for spells for clients and positive
//value for spells that effect pets. Unclear as to why. For now will convert all positive to be consistent.
@ -2896,7 +2915,12 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
attacker->aabonuses.DSMitigationOffHand;
DS -= DS*mitigation / 100;
}
DS -= DS * attacker->itembonuses.DSMitigation / 100;
int ds_mitigation = attacker->itembonuses.DSMitigation;
// Subtract mitigations because DS_Mitigation_Percentage is a negative value when reducing total, thus final value will be positive
ds_mitigation -= attacker->aabonuses.DS_Mitigation_Percentage + attacker->itembonuses.DS_Mitigation_Percentage + attacker->spellbonuses.DS_Mitigation_Percentage; //Negative value to reduce
DS -= DS * ds_mitigation / 100;
}
attacker->Damage(this, -DS, spellid, EQ::skills::SkillAbjuration/*hackish*/, false);
//we can assume there is a spell now
@ -3323,8 +3347,8 @@ int32 Mob::ReduceAllDamage(int32 damage)
if (damage <= 0)
return damage;
if (spellbonuses.ManaAbsorbPercentDamage[0]) {
int32 mana_reduced = damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100;
if (spellbonuses.ManaAbsorbPercentDamage) {
int32 mana_reduced = damage * spellbonuses.ManaAbsorbPercentDamage / 100;
if (GetMana() >= mana_reduced) {
damage -= mana_reduced;
SetMana(GetMana() - mana_reduced);
@ -3332,6 +3356,19 @@ int32 Mob::ReduceAllDamage(int32 damage)
}
}
if (spellbonuses.EnduranceAbsorbPercentDamage[0]) {
int32 damage_reduced = damage * spellbonuses.EnduranceAbsorbPercentDamage[0] / 10000; //If hit for 1000, at 10% then lower damage by 100;
int32 endurance_drain = damage_reduced * spellbonuses.EnduranceAbsorbPercentDamage[1] / 10000; //Reduce endurance by 0.05% per HP loss
if (endurance_drain < 1)
endurance_drain = 1;
if (IsClient() && CastToClient()->GetEndurance() >= endurance_drain) {
damage -= damage_reduced;
CastToClient()->SetEndurance(CastToClient()->GetEndurance() - endurance_drain);
TryTriggerOnValueAmount(false, false, true);
}
}
CheckNumHitsRemaining(NumHit::IncomingDamage);
return(damage);
@ -4628,6 +4665,7 @@ void Mob::ApplyMeleeDamageMods(uint16 skill, int &damage, Mob *defender, ExtraAt
int dmgbonusmod = 0;
dmgbonusmod += GetMeleeDamageMod_SE(skill);
dmgbonusmod += GetMeleeDmgPositionMod(defender);
if (opts)
dmgbonusmod += opts->melee_damage_bonus_flat;
@ -5241,7 +5279,9 @@ void Mob::CommonOutgoingHitSuccess(Mob* defender, DamageHitInfo &hit, ExtraAttac
if (spec_mod > 0)
hit.damage_done = (hit.damage_done * spec_mod) / 100;
hit.damage_done += (hit.damage_done * defender->GetSkillDmgTaken(hit.skill, opts) / 100) + (defender->GetFcDamageAmtIncoming(this, 0, true, hit.skill));
int pct_damage_reduction = defender->GetSkillDmgTaken(hit.skill, opts) + defender->GetPositionalDmgTaken(this);
hit.damage_done += (hit.damage_done * pct_damage_reduction / 100) + (defender->GetFcDamageAmtIncoming(this, 0, true, hit.skill));
CheckNumHitsRemaining(NumHit::OutgoingHitSuccess);
}

View File

@ -978,6 +978,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
case SE_FrontalBackstabChance:
newbon->FrontalBackstabChance += base1;
break;
case SE_Double_Backstab_Front:
newbon->Double_Backstab_Front += base1;
break;
case SE_BlockBehind:
newbon->BlockBehind += base1;
break;
@ -1102,6 +1105,19 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
break;
}
case SE_Critical_Melee_Damage_Mod_Max:
{
// Bad data or unsupported new skill
if (base2 > EQ::skills::HIGHEST_SKILL)
break;
int skill = base2 == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : base2;
if (base1 < 0 && newbon->CritDmgModNoStack[skill] > base1)
newbon->CritDmgModNoStack[skill] = base1;
else if (base1 > 0 && newbon->CritDmgModNoStack[skill] < base1)
newbon->CritDmgModNoStack[skill] = base1;
break;
}
case SE_CriticalSpellChance: {
newbon->CriticalSpellChance += base1;
@ -1487,6 +1503,50 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
}
break;
case SE_Attack_Accuracy_Max_Percent:
newbon->Attack_Accuracy_Max_Percent += base1;
break;
case SE_AC_Mitigation_Max_Percent:
newbon->AC_Mitigation_Max_Percent += base1;
break;
case SE_AC_Avoidance_Max_Percent:
newbon->AC_Avoidance_Max_Percent += base1;
break;
case SE_Damage_Taken_Position_Mod:
{
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
if (base2 < 0 || base2 > 2)
break;
else if (base1 < 0 && newbon->Damage_Taken_Position_Mod[base2] > base1)
newbon->Damage_Taken_Position_Mod[base2] = base1;
else if (base1 > 0 && newbon->Damage_Taken_Position_Mod[base2] < base1)
newbon->Damage_Taken_Position_Mod[base2] = base1;
break;
}
case SE_Melee_Damage_Position_Mod:
{
if (base2 < 0 || base2 > 2)
break;
else if (base1 < 0 && newbon->Melee_Damage_Position_Mod[base2] > base1)
newbon->Melee_Damage_Position_Mod[base2] = base1;
else if (base1 > 0 && newbon->Melee_Damage_Position_Mod[base2] < base1)
newbon->Melee_Damage_Position_Mod[base2] = base1;
break;
}
case SE_DS_Mitigation_Amount:
newbon->DS_Mitigation_Amount += base1;
break;
case SE_DS_Mitigation_Percentage:
newbon->DS_Mitigation_Percentage += base1;
break;
// to do
case SE_PetDiscipline:
break;
@ -2485,6 +2545,20 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
break;
}
case SE_Critical_Melee_Damage_Mod_Max:
{
// Bad data or unsupported new skill
if (base2 > EQ::skills::HIGHEST_SKILL)
break;
int skill = base2 == ALL_SKILLS ? EQ::skills::HIGHEST_SKILL + 1 : base2;
if (effect_value < 0 && new_bonus->CritDmgModNoStack[skill] > effect_value)
new_bonus->CritDmgModNoStack[skill] = effect_value;
else if (effect_value > 0 && new_bonus->CritDmgModNoStack[skill] < effect_value) {
new_bonus->CritDmgModNoStack[skill] = effect_value;
}
break;
}
case SE_ReduceSkillTimer:
{
if(new_bonus->SkillReuseTime[base2] < effect_value)
@ -2690,9 +2764,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
case SE_ManaAbsorbPercentDamage:
{
if (new_bonus->ManaAbsorbPercentDamage[0] < effect_value){
new_bonus->ManaAbsorbPercentDamage[0] = effect_value;
new_bonus->ManaAbsorbPercentDamage[1] = buffslot;
if (new_bonus->ManaAbsorbPercentDamage < effect_value){
new_bonus->ManaAbsorbPercentDamage = effect_value;
}
break;
}
case SE_Endurance_Absorb_Pct_Damage:
{
if (new_bonus->EnduranceAbsorbPercentDamage[0] < effect_value) {
new_bonus->EnduranceAbsorbPercentDamage[0] = effect_value;
new_bonus->EnduranceAbsorbPercentDamage[1] = base2;
}
break;
}
@ -2762,6 +2844,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
new_bonus->FrontalBackstabChance += effect_value;
break;
case SE_Double_Backstab_Front:
new_bonus->Double_Backstab_Front += effect_value;
break;
case SE_ConsumeProjectile:
new_bonus->ConsumeProjectile += effect_value;
break;
@ -3250,6 +3336,57 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
if (new_bonus->trap_slots < effect_value)
new_bonus->trap_slots = effect_value;
break;
case SE_Attack_Accuracy_Max_Percent:
new_bonus->Attack_Accuracy_Max_Percent += effect_value;
break;
case SE_AC_Mitigation_Max_Percent:
new_bonus->AC_Mitigation_Max_Percent += effect_value;
break;
case SE_AC_Avoidance_Max_Percent:
new_bonus->AC_Avoidance_Max_Percent += effect_value;
break;
case SE_Damage_Taken_Position_Mod:
{
//Mitigate if damage taken from behind base2 = 0, from front base2 = 1
if (base2 < 0 || base2 > 2)
break;
if (AdditiveWornBonus)
new_bonus->Damage_Taken_Position_Mod[base2] += effect_value;
else if (effect_value < 0 && new_bonus->Damage_Taken_Position_Mod[base2] > effect_value)
new_bonus->Damage_Taken_Position_Mod[base2] = effect_value;
else if (effect_value > 0 && new_bonus->Damage_Taken_Position_Mod[base2] < effect_value)
new_bonus->Damage_Taken_Position_Mod[base2] = effect_value;
break;
}
case SE_Melee_Damage_Position_Mod:
{
//Increase damage by percent from behind base2 = 0, from front base2 = 1
if (base2 < 0 || base2 > 2)
break;
if (AdditiveWornBonus)
new_bonus->Melee_Damage_Position_Mod[base2] += effect_value;
else if (effect_value < 0 && new_bonus->Melee_Damage_Position_Mod[base2] > effect_value)
new_bonus->Melee_Damage_Position_Mod[base2] = effect_value;
else if (effect_value > 0 && new_bonus->Melee_Damage_Position_Mod[base2] < effect_value)
new_bonus->Melee_Damage_Position_Mod[base2] = effect_value;
break;
}
case SE_DS_Mitigation_Amount:
new_bonus->DS_Mitigation_Amount += effect_value;
break;
case SE_DS_Mitigation_Percentage:
new_bonus->DS_Mitigation_Percentage += effect_value;
break;
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) {
@ -4258,6 +4395,17 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
break;
}
case SE_Critical_Melee_Damage_Mod_Max:
{
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
{
spellbonuses.CritDmgModNoStack[e] = effect_value;
aabonuses.CritDmgModNoStack[e] = effect_value;
itembonuses.CritDmgModNoStack[e] = effect_value;
}
break;
}
case SE_SkillDamageAmount:
{
for (int e = 0; e < EQ::skills::HIGHEST_SKILL + 1; e++)
@ -4353,8 +4501,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
break;
case SE_ManaAbsorbPercentDamage:
spellbonuses.ManaAbsorbPercentDamage[0] = effect_value;
spellbonuses.ManaAbsorbPercentDamage[1] = -1;
spellbonuses.ManaAbsorbPercentDamage = effect_value;
break;
case SE_Endurance_Absorb_Pct_Damage:
spellbonuses.EnduranceAbsorbPercentDamage[0] = effect_value;
spellbonuses.EnduranceAbsorbPercentDamage[1] = effect_value;
break;
case SE_ShieldBlock:
@ -4428,6 +4580,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
itembonuses.FrontalBackstabChance = effect_value;
break;
case SE_Double_Backstab_Front:
spellbonuses.Double_Backstab_Front = effect_value;
aabonuses.Double_Backstab_Front = effect_value;
itembonuses.Double_Backstab_Front = effect_value;
break;
case SE_ConsumeProjectile:
spellbonuses.ConsumeProjectile = effect_value;
aabonuses.ConsumeProjectile = effect_value;
@ -4770,6 +4928,56 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
aabonuses.IllusionPersistence = false;
break;
case SE_Attack_Accuracy_Max_Percent:
spellbonuses.Attack_Accuracy_Max_Percent = effect_value;
itembonuses.Attack_Accuracy_Max_Percent = effect_value;
aabonuses.Attack_Accuracy_Max_Percent = effect_value;
break;
case SE_AC_Mitigation_Max_Percent:
spellbonuses.AC_Mitigation_Max_Percent = effect_value;
itembonuses.AC_Mitigation_Max_Percent = effect_value;
aabonuses.AC_Mitigation_Max_Percent = effect_value;
break;
case SE_AC_Avoidance_Max_Percent:
spellbonuses.AC_Avoidance_Max_Percent = effect_value;
itembonuses.AC_Avoidance_Max_Percent = effect_value;
aabonuses.AC_Avoidance_Max_Percent = effect_value;
break;
case SE_Melee_Damage_Position_Mod:
spellbonuses.Melee_Damage_Position_Mod[0] = effect_value;
aabonuses.Melee_Damage_Position_Mod[0] = effect_value;
itembonuses.Melee_Damage_Position_Mod[0] = effect_value;
spellbonuses.Melee_Damage_Position_Mod[1] = effect_value;
aabonuses.Melee_Damage_Position_Mod[1] = effect_value;
itembonuses.Melee_Damage_Position_Mod[1] = effect_value;
break;
case SE_Damage_Taken_Position_Mod:
spellbonuses.Damage_Taken_Position_Mod[0] = effect_value;
aabonuses.Damage_Taken_Position_Mod[0] = effect_value;
itembonuses.Damage_Taken_Position_Mod[0] = effect_value;
spellbonuses.Damage_Taken_Position_Mod[1] = effect_value;
aabonuses.Damage_Taken_Position_Mod[1] = effect_value;
itembonuses.Damage_Taken_Position_Mod[1] = effect_value;
break;
case SE_DS_Mitigation_Amount:
spellbonuses.DS_Mitigation_Amount = effect_value;
itembonuses.DS_Mitigation_Amount = effect_value;
aabonuses.DS_Mitigation_Amount = effect_value;
break;
case SE_DS_Mitigation_Percentage:
spellbonuses.DS_Mitigation_Percentage = effect_value;
itembonuses.DS_Mitigation_Percentage = effect_value;
aabonuses.DS_Mitigation_Percentage = effect_value;
break;
case SE_SkillProcSuccess:{
for(int e = 0; e < MAX_SKILL_PROCS; e++)
{

View File

@ -461,6 +461,7 @@ struct StatBonuses {
uint32 SpellOnKill[MAX_SPELL_TRIGGER*3]; // Chance to proc after killing a mob
uint32 SpellOnDeath[MAX_SPELL_TRIGGER*2]; // Chance to have effect cast when you die
int32 CritDmgMod[EQ::skills::HIGHEST_SKILL + 2]; // All Skills + -1
int32 CritDmgModNoStack[EQ::skills::HIGHEST_SKILL + 2];// Critical melee damage modifier by percent, does not stack.
int32 SkillReuseTime[EQ::skills::HIGHEST_SKILL + 1]; // Reduces skill timers
int32 SkillDamageAmount[EQ::skills::HIGHEST_SKILL + 2]; // All Skills + -1
int32 TwoHandBluntBlock; // chance to block when wielding two hand blunt weapon
@ -494,7 +495,8 @@ struct StatBonuses {
uint32 MitigateDotRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per tick 3 = Rune Amt
bool TriggerMeleeThreshold; // Has Melee Threshhold
bool TriggerSpellThreshold; // Has Spell Threshhold
uint32 ManaAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Buff Slot
uint32 ManaAbsorbPercentDamage; // 0 = Mitigation value
int32 EnduranceAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Percent Endurance drain per HP lost
int32 ShieldBlock; // Chance to Shield Block
int32 BlockBehind; // Chance to Block Behind (with our without shield)
bool CriticalRegenDecay; // increase critical regen chance, decays based on spell level cast
@ -523,6 +525,14 @@ struct StatBonuses {
uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success.
uint32 PC_Pet_Rampage[2]; // 0= % chance to rampage, 1=damage modifier
uint32 PC_Pet_Flurry; // Percent chance flurry from double attack
int32 Attack_Accuracy_Max_Percent; // Increase ATK accuracy by percent.
int32 AC_Mitigation_Max_Percent; // Increase AC mitigation by percent
int32 AC_Avoidance_Max_Percent; // Increase AC avoidance by percent
int32 Damage_Taken_Position_Mod[2]; // base = percent melee damage reduction base2 0=back 1=front. [0]Back[1]Front
int32 Melee_Damage_Position_Mod[2]; // base = percent melee damage increase base2 0=back 1=front. [0]Back[1]Front
int32 Double_Backstab_Front; // base = percent chance to double back stab front
int32 DS_Mitigation_Amount; // base = flat amt DS mitigation. Negative value to reduce
int32 DS_Mitigation_Percentage; // base = percent amt of DS mitigation. Negative value to reduce
// AAs
int8 Packrat; //weight reduction for items, 1 point = 10%

View File

@ -1162,7 +1162,7 @@ uint32 Lua_StatBonuses::GetMitigateDotRune(int idx) const {
uint32 Lua_StatBonuses::GetManaAbsorbPercentDamage(int idx) const {
Lua_Safe_Call_Int();
return self->ManaAbsorbPercentDamage[idx];
return self->ManaAbsorbPercentDamage;
}
int32 Lua_StatBonuses::GetImprovedTaunt(int idx) const {

View File

@ -3711,6 +3711,32 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id)
}
}
//Used for effects that should occur after the completion of the spell
void Mob::TryOnSpellFinished(Mob *caster, Mob *target, uint16 spell_id)
{
if (!IsValidSpell(spell_id))
return;
/*Apply damage from Lifeburn type effects on caster at end of spell cast.
This allows for the AE spells to function without repeatedly killing caster
Damage or heal portion can be found as regular single use spell effect
*/
if (IsEffectInSpell(spell_id, SE_Health_Transfer)){
for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[spell_id].effectid[i] == SE_Health_Transfer) {
int new_hp = GetMaxHP();
new_hp -= GetMaxHP() * spells[spell_id].base[i] / 1000;
if (new_hp > 0)
SetHP(new_hp);
else
Kill();
}
}
}
}
int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining)
{
if (!IsValidSpell(spell_id))
@ -3771,7 +3797,7 @@ int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining)
return value;
}
int16 Mob::GetSkillDmgTaken(const EQ::skills::SkillType skill_used, ExtraAttackOptions *opts)
int32 Mob::GetSkillDmgTaken(const EQ::skills::SkillType skill_used, ExtraAttackOptions *opts)
{
int skilldmg_mod = 0;
@ -3790,6 +3816,33 @@ int16 Mob::GetSkillDmgTaken(const EQ::skills::SkillType skill_used, ExtraAttackO
return skilldmg_mod;
}
int32 Mob::GetPositionalDmgTaken(Mob *attacker)
{
if (!attacker)
return 0;
int front_arc = 0;
int back_arc = 0;
int total_mod = 0;
back_arc += itembonuses.Damage_Taken_Position_Mod[0] + aabonuses.Damage_Taken_Position_Mod[0] + spellbonuses.Damage_Taken_Position_Mod[0];
front_arc += itembonuses.Damage_Taken_Position_Mod[1] + aabonuses.Damage_Taken_Position_Mod[1] + spellbonuses.Damage_Taken_Position_Mod[1];
if (back_arc || front_arc) { //Do they have this bonus?
if (attacker->BehindMob(this, attacker->GetX(), attacker->GetY()))//Check if attacker is striking from behind
total_mod = back_arc; //If so, apply the back arc modifier only
else
total_mod = front_arc;//If not, apply the front arc modifer only
}
total_mod = round(static_cast<double>(total_mod) * 0.1);
if (total_mod < -100)
total_mod = -100;
return total_mod;
}
int16 Mob::GetHealRate(uint16 spell_id, Mob* caster) {
int16 heal_rate = 0;
@ -4598,10 +4651,13 @@ int16 Mob::GetCritDmgMod(uint16 skill)
{
int critDmg_mod = 0;
// All skill dmg mod + Skill specific
// All skill dmg mod + Skill specific [SPA 330 and 496]
critDmg_mod += itembonuses.CritDmgMod[EQ::skills::HIGHEST_SKILL + 1] + spellbonuses.CritDmgMod[EQ::skills::HIGHEST_SKILL + 1] + aabonuses.CritDmgMod[EQ::skills::HIGHEST_SKILL + 1] +
itembonuses.CritDmgMod[skill] + spellbonuses.CritDmgMod[skill] + aabonuses.CritDmgMod[skill];
critDmg_mod += itembonuses.CritDmgModNoStack[EQ::skills::HIGHEST_SKILL + 1] + spellbonuses.CritDmgModNoStack[EQ::skills::HIGHEST_SKILL + 1] + aabonuses.CritDmgModNoStack[EQ::skills::HIGHEST_SKILL + 1] +
itembonuses.CritDmgModNoStack[skill] + spellbonuses.CritDmgModNoStack[skill] + aabonuses.CritDmgModNoStack[skill];
return critDmg_mod;
}
@ -4692,6 +4748,35 @@ int16 Mob::GetCrippBlowChance()
return crip_chance;
}
int16 Mob::GetMeleeDmgPositionMod(Mob* defender)
{
if (!defender)
return 0;
int front_arc = 0;
int back_arc = 0;
int total_mod = 0;
back_arc += itembonuses.Melee_Damage_Position_Mod[0] + aabonuses.Melee_Damage_Position_Mod[0] + spellbonuses.Melee_Damage_Position_Mod[0];
front_arc += itembonuses.Melee_Damage_Position_Mod[1] + aabonuses.Melee_Damage_Position_Mod[1] + spellbonuses.Melee_Damage_Position_Mod[1];
if (back_arc || front_arc) { //Do they have this bonus?
if (BehindMob(defender, GetX(), GetY()))//Check if attacker is striking from behind
total_mod = back_arc; //If so, apply the back arc modifier only
else
total_mod = front_arc;//If not, apply the front arc modifer only
}
total_mod = round(static_cast<double>(total_mod) * 0.1);
if (total_mod < -100)
total_mod = -100;
return total_mod;
}
int16 Mob::GetSkillReuseTime(uint16 skill)
{
int skill_reduction = this->itembonuses.SkillReuseTime[skill] + this->spellbonuses.SkillReuseTime[skill] + this->aabonuses.SkillReuseTime[skill];

View File

@ -353,6 +353,7 @@ public:
void CalcDestFromHeading(float heading, float distance, float MaxZDiff, float StartX, float StartY, float &dX, float &dY, float &dZ);
void BeamDirectional(uint16 spell_id, int16 resist_adjust);
void ConeDirectional(uint16 spell_id, int16 resist_adjust);
void TryOnSpellFinished(Mob *caster, Mob *target, uint16 spell_id);
//Buff
void BuffProcess();
@ -802,7 +803,8 @@ public:
int32 GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining);
int32 GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill = false, uint16 skill=0);
int32 GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spell_id);
int16 GetSkillDmgTaken(const EQ::skills::SkillType skill_used, ExtraAttackOptions *opts = nullptr);
int32 GetSkillDmgTaken(const EQ::skills::SkillType skill_used, ExtraAttackOptions *opts = nullptr);
int32 GetPositionalDmgTaken(Mob *attacker);
void DoKnockback(Mob *caster, uint32 pushback, uint32 pushup);
int16 CalcResistChanceBonus();
int16 CalcFearResistChance();
@ -816,6 +818,7 @@ public:
int16 GetMeleeDamageMod_SE(uint16 skill);
int16 GetMeleeMinDamageMod_SE(uint16 skill);
int16 GetCrippBlowChance();
int16 GetMeleeDmgPositionMod(Mob* defender);
int16 GetSkillReuseTime(uint16 skill);
int GetCriticalChanceBonus(uint16 skill);
int16 GetSkillDmgAmt(uint16 skill);

View File

@ -585,6 +585,10 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
if(IsClient())
CastToClient()->CheckIncreaseSkill(EQ::skills::SkillBackstab, other, 10);
m_specialattacks = eSpecialAttacks::None;
int double_bs_front = aabonuses.Double_Backstab_Front + itembonuses.Double_Backstab_Front + spellbonuses.Double_Backstab_Front;
if (double_bs_front && other->GetHP() > 0 && zone->random.Roll(double_bs_front))
RogueBackstab(other, false, ReuseTime);
}
else { //We do a single regular attack if we attack from the front without chaotic stab
Attack(other, EQ::invslot::slotPrimary);

View File

@ -275,11 +275,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#endif
int32 dmg = effect_value;
if (spell_id == 2751 && caster) //Manaburn
if (spell_id == SPELL_MANA_BURN && caster) //Manaburn
{
dmg = caster->GetMana()*-3;
caster->SetMana(0);
} else if (spell_id == 2755 && caster) //Lifeburn
} else if (spell_id == SPELL_LIFE_BURN && caster) //Lifeburn
{
dmg = caster->GetHP(); // just your current HP
caster->SetHP(dmg / 4); // 2003 patch notes say ~ 1/4 HP. Should this be 1/4 your current HP or do 3/4 max HP dmg? Can it kill you?
@ -303,6 +303,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
break;
}
case SE_PercentalHeal:
{
#ifdef SPELL_EFFECT_SPAM
@ -2828,6 +2829,52 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
break;
}
case SE_Instant_Mana_Pct: {
effect_value = spells[spell_id].base[i];
int32 amt = abs(GetMaxMana() * effect_value / 10000);
if (spells[spell_id].max[i] && amt > spells[spell_id].max[i])
amt = spells[spell_id].max[i];
if (effect_value < 0) {
SetMana(GetMana() - amt);
}
else {
SetMana(GetMana() + amt);
}
break;
}
case SE_Instant_Endurance_Pct: {
effect_value = spells[spell_id].base[i];
if (IsClient()) {
int32 amt = abs(CastToClient()->GetMaxEndurance() * effect_value / 10000);
if (spells[spell_id].max[i] && amt > spells[spell_id].max[i])
amt = spells[spell_id].max[i];
if (effect_value < 0) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() - amt);
}
else {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + amt);
}
}
break;
}
/*Calc for base1 is found in TryOnSpellFinished() due to needing to account for AOE functionality
since effect can potentially kill caster*/
case SE_Health_Transfer: {
effect_value = spells[spell_id].base2[i];
int32 amt = abs(caster->GetMaxHP() * effect_value / 1000);
if (effect_value < 0)
Damage(caster, amt, spell_id, spell.skill, false, buffslot, false);
else
HealDamage(amt, caster);
break;
}
case SE_PersistentEffect:
MakeAura(spell_id);
break;
@ -3071,6 +3118,19 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
case SE_SkillProc:
case SE_SkillProcSuccess:
case SE_SpellResistReduction:
case SE_Duration_HP_Pct:
case SE_Duration_Mana_Pct:
case SE_Duration_Endurance_Pct:
case SE_Endurance_Absorb_Pct_Damage:
case SE_AC_Mitigation_Max_Percent:
case SE_AC_Avoidance_Max_Percent:
case SE_Attack_Accuracy_Max_Percent:
case SE_Critical_Melee_Damage_Mod_Max:
case SE_Melee_Damage_Position_Mod:
case SE_Damage_Taken_Position_Mod:
case SE_DS_Mitigation_Amount:
case SE_DS_Mitigation_Percentage:
case SE_Double_Backstab_Front:
{
break;
}
@ -3777,6 +3837,55 @@ void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
break;
}
case SE_Duration_HP_Pct: {
effect_value = spells[buff.spellid].base[i];
int32 amt = abs(GetMaxHP() * effect_value / 100);
if (spells[buff.spellid].max[i] && amt > spells[buff.spellid].max[i])
amt = spells[buff.spellid].max[i];
if (effect_value < 0) {
Damage(this, amt, 0, EQ::skills::SkillEvocation, false);
}
else {
HealDamage(amt);
}
break;
}
case SE_Duration_Mana_Pct: {
effect_value = spells[buff.spellid].base[i];
int32 amt = abs(GetMaxMana() * effect_value / 100);
if (spells[buff.spellid].max[i] && amt > spells[buff.spellid].max[i])
amt = spells[buff.spellid].max[i];
if (effect_value < 0) {
SetMana(GetMana() - amt);
}
else {
SetMana(GetMana() + amt);
}
break;
}
case SE_Duration_Endurance_Pct: {
effect_value = spells[buff.spellid].base[i];
if (IsClient()) {
int32 amt = abs(CastToClient()->GetMaxEndurance() * effect_value / 100);
if (spells[buff.spellid].max[i] && amt > spells[buff.spellid].max[i])
amt = spells[buff.spellid].max[i];
if (effect_value < 0) {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() - amt);
}
else {
CastToClient()->SetEndurance(CastToClient()->GetEndurance() + amt);
}
}
break;
}
default: {
// do we need to do anyting here?
}

View File

@ -1393,6 +1393,8 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
TrySympatheticProc(target, spell_id);
}
TryOnSpellFinished(this, target, spell_id);
TryTwincast(this, target, spell_id);
TryTriggerOnCast(spell_id, 0);