[Spells] Implemented SPA 512 SE_Proc_Timer_Modifier, Fixed AA procs not working (#1646)

* update for SPA 511

* remove debugs, AA implemented

* update

* twinprocfix

* AA procs added

* format update

* update

* proctimer limits

* update

* rename function

renamed function
only check for buffs value > 0, don't need to check for AA's which are negative ID's

* pre merge

* variable updates

* Update spell_effects.cpp

* var rename

update var name to better represent its function.

* updated proc struct

added reuse timer

* reuse timer to spell procs

* updates

* debug remove

* Update mob.cpp

* fix

* merge
This commit is contained in:
KayenEQ
2021-11-05 14:14:11 -04:00
committed by GitHub
parent 8c95323728
commit f1bfd6bc2a
11 changed files with 469 additions and 109 deletions
+146 -35
View File
@@ -3380,17 +3380,37 @@ int32 Mob::ReduceAllDamage(int32 damage)
bool Mob::HasProcs() const
{
for (int i = 0; i < MAX_PROCS; i++)
if (PermaProcs[i].spellID != SPELL_UNKNOWN || SpellProcs[i].spellID != SPELL_UNKNOWN)
for (int i = 0; i < MAX_PROCS; i++) {
if (PermaProcs[i].spellID != SPELL_UNKNOWN || SpellProcs[i].spellID != SPELL_UNKNOWN) {
return true;
}
}
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (aabonuses.SpellProc[i]) {
return true;
}
}
}
return false;
}
bool Mob::HasDefensiveProcs() const
{
for (int i = 0; i < MAX_PROCS; i++)
if (DefensiveProcs[i].spellID != SPELL_UNKNOWN)
for (int i = 0; i < MAX_PROCS; i++) {
if (DefensiveProcs[i].spellID != SPELL_UNKNOWN) {
return true;
}
}
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (aabonuses.DefensiveProc[i]) {
return true;
}
}
}
return false;
}
@@ -3415,9 +3435,19 @@ bool Mob::HasSkillProcSuccess() const
bool Mob::HasRangedProcs() const
{
for (int i = 0; i < MAX_PROCS; i++)
if (RangedProcs[i].spellID != SPELL_UNKNOWN)
for (int i = 0; i < MAX_PROCS; i++){
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
return true;
}
}
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
if (aabonuses.RangedProc[i]) {
return true;
}
}
}
return false;
}
@@ -4051,33 +4081,61 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
return;
}
if (!HasDefensiveProcs())
if (!HasDefensiveProcs()) {
return;
}
if (!on->HasDied() && on->GetHP() > 0) {
float ProcChance, ProcBonus;
on->GetDefensiveProcChances(ProcBonus, ProcChance, hand, this);
if (hand != EQ::invslot::slotPrimary)
if (hand != EQ::invslot::slotPrimary) {
ProcChance /= 2;
}
int level_penalty = 0;
int level_diff = GetLevel() - on->GetLevel();
if (level_diff > 6)//10% penalty per level if > 6 levels over target.
if (level_diff > 6) {//10% penalty per level if > 6 levels over target.
level_penalty = (level_diff - 6) * 10;
}
ProcChance -= ProcChance*level_penalty / 100;
if (ProcChance < 0)
if (ProcChance < 0) {
return;
}
//Spell Procs and Quest added procs
for (int i = 0; i < MAX_PROCS; i++) {
if (IsValidSpell(DefensiveProcs[i].spellID)) {
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID);
if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc)) {
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID);
SetProcLimitTimer(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc);
}
}
}
}
//AA Procs
if (IsClient()){
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
int32 aa_rank_id = aabonuses.DefensiveProc[i];
int32 aa_spell_id = aabonuses.DefensiveProc[i + 1];
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + 2];
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + 3];
if (aa_rank_id) {
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc)) {
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
ExecWeaponProc(nullptr, aa_spell_id, on);
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc);
}
}
}
}
}
@@ -4122,7 +4180,9 @@ void Mob::TryWeaponProc(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand)
void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon, Mob *on, uint16 hand)
{
if (!on) {
return;
}
if (!weapon)
return;
uint16 skillinuse = 28;
@@ -4206,6 +4266,10 @@ void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon
void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon, Mob *on, uint16 hand)
{
if (!on) {
return;
}
float ProcBonus = static_cast<float>(spellbonuses.SpellProcChance +
itembonuses.SpellProcChance + aabonuses.SpellProcChance);
float ProcChance = 0.0f;
@@ -4239,7 +4303,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
// Not ranged
if (!rangedattk) {
// Perma procs (AAs)
// Perma procs (Not used for AA, they are handled below)
if (PermaProcs[i].spellID != SPELL_UNKNOWN) {
if (zone->random.Roll(PermaProcs[i].chance)) { // TODO: Do these get spell bonus?
LogCombat("Permanent proc [{}] procing spell [{}] ([{}] percent chance)", i, PermaProcs[i].spellID, PermaProcs[i].chance);
@@ -4256,32 +4320,79 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
poison_slot=i;
continue; // Process the poison proc last per @mackal
}
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
SendBeginCast(SpellProcs[i].spellID, 0);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
SpellProcs[i].base_spellID);
}
else {
LogCombat("Spell proc [{}] failed to proc [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
if (!IsProcLimitTimerActive(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc)) {
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
SendBeginCast(SpellProcs[i].spellID, 0);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
SetProcLimitTimer(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, SpellProcs[i].base_spellID);
}
else {
LogCombat("Spell proc [{}] failed to proc [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
}
}
}
}
else if (rangedattk) { // ranged only
// ranged spell procs (buffs)
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
float chance = ProcChance * (static_cast<float>(RangedProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
RangedProcs[i].base_spellID);
if (!IsProcLimitTimerActive(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc)) {
float chance = ProcChance * (static_cast<float>(RangedProcs[i].chance) / 100.0f);
if (zone->random.Roll(chance)) {
LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, RangedProcs[i].base_spellID);
SetProcLimitTimer(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc);
}
else {
LogCombat("Ranged proc [{}] failed to proc [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
}
}
else {
LogCombat("Ranged proc [{}] failed to proc [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
}
}
}
//AA Procs
if (IsClient()) {
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
int32 aa_rank_id = 0;
int32 aa_spell_id = SPELL_UNKNOWN;
int32 aa_proc_chance = 100;
uint32 aa_proc_reuse_timer = 0;
int proc_type = 0; //used to deterimne which timer array is used.
if (!rangedattk) {
aa_rank_id = aabonuses.SpellProc[i];
aa_spell_id = aabonuses.SpellProc[i + 1];
aa_proc_chance += aabonuses.SpellProc[i + 2];
aa_proc_reuse_timer = aabonuses.SpellProc[i + 3];
proc_type = SE_WeaponProc;
}
else {
aa_rank_id = aabonuses.RangedProc[i];
aa_spell_id = aabonuses.RangedProc[i + 1];
aa_proc_chance += aabonuses.RangedProc[i + 2];
aa_proc_reuse_timer = aabonuses.RangedProc[i + 3];
proc_type = SE_RangedProc;
}
if (aa_rank_id) {
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, proc_type)) {
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
LogCombat("AA proc [{}] procing spell [{}] ([{}] percent chance)", aa_rank_id, aa_spell_id, chance);
ExecWeaponProc(nullptr, aa_spell_id, on);
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, proc_type);
}
else {
LogCombat("AA proc [{}] failed to proc [{}] ([{}] percent chance)", aa_rank_id, aa_spell_id, chance);
}
}
}
}