mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 05:21:29 +00:00
[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:
parent
8c95323728
commit
f1bfd6bc2a
@ -1597,3 +1597,38 @@ int32 GetViralSpreadRange(int32 spell_id)
|
||||
{
|
||||
return spells[spell_id].viral_range;
|
||||
}
|
||||
|
||||
uint32 GetProcLimitTimer(int32 spell_id, int proc_type) {
|
||||
|
||||
//This allows for support for effects that may have multiple different proc types and timers.
|
||||
if (!IsValidSpell(spell_id)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool use_next_timer = false;
|
||||
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||
|
||||
if (proc_type == SE_WeaponProc) {
|
||||
if (spells[spell_id].effect_id[i] == SE_WeaponProc || spells[spell_id].effect_id[i] == SE_AddMeleeProc) {
|
||||
use_next_timer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_RangedProc) {
|
||||
if (spells[spell_id].effect_id[i] == SE_RangedProc) {
|
||||
use_next_timer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_DefensiveProc) {
|
||||
if (spells[spell_id].effect_id[i] == SE_DefensiveProc) {
|
||||
use_next_timer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_next_timer && spells[spell_id].effect_id[i] == SE_Proc_Timer_Modifier) {
|
||||
return spells[spell_id].limit_value[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -179,8 +179,11 @@
|
||||
#define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists.
|
||||
#define MaxLimitInclude 16 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects
|
||||
#define MAX_SKILL_PROCS 4 //Number of spells to check skill procs from. (This is arbitrary) [Single spell can have multiple proc checks]
|
||||
#define MAX_AA_PROCS 16 //(Actual Proc Amount is MAX_AA_PROCS/4) Number of spells to check AA procs from. (This is arbitrary)
|
||||
#define MAX_SYMPATHETIC_PROCS 10 // Number of sympathetic procs a client can have (This is arbitrary)
|
||||
#define MAX_FOCUS_PROC_LIMIT_TIMERS 20 //Number of proc limiting timers that can be going at same time (This is arbitrary)
|
||||
#define MAX_FOCUS_PROC_LIMIT_TIMERS 20 //Number of focus recast timers that can be going at same time (This is arbitrary)
|
||||
#define MAX_PROC_LIMIT_TIMERS 8 //Number of proc delay timers that can be going at same time, different proc types get their own timer array. (This is arbitrary)
|
||||
|
||||
|
||||
|
||||
const int Z_AGGRO=10;
|
||||
@ -1209,7 +1212,7 @@ typedef enum {
|
||||
#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 // implemented, @Fc, On Target, resist modifier, base: amt
|
||||
#define SE_Ff_FocusTimerMin 511 // implemented, @Ff, sets a recast time until focus can be used again, base: 1, limit: time ms, Note: ie. limit to 1 trigger every 1.5 seconds
|
||||
#define SE_Proc_Timer_Modifier 512 // not implemented - limits procs per amount of a time based on timer value (ie limit to 1 proc every 55 seconds)
|
||||
#define SE_Proc_Timer_Modifier 512 // implemented - limits procs per amount of a time based on timer value, base: 1, limit: time ms, Note:, ie limit to 1 proc every 55 seconds)
|
||||
//#define SE_Mana_Max_Percent 513 //
|
||||
//#define SE_Endurance_Max_Percent 514 //
|
||||
#define SE_AC_Avoidance_Max_Percent 515 // implemented - stackable avoidance modifier
|
||||
@ -1514,6 +1517,7 @@ int GetViralMinSpreadTime(int32 spell_id);
|
||||
int GetViralMaxSpreadTime(int32 spell_id);
|
||||
int GetViralSpreadRange(int32 spell_id);
|
||||
bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect);
|
||||
uint32 GetProcLimitTimer(int32 spell_id, int proc_type);
|
||||
|
||||
int CalcPetHp(int levelb, int classb, int STA = 75);
|
||||
int GetSpellEffectDescNum(uint16 spell_id);
|
||||
|
||||
143
zone/attack.cpp
143
zone/attack.cpp
@ -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)) {
|
||||
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);
|
||||
@ -4257,28 +4321,32 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
continue; // Process the poison proc last per @mackal
|
||||
}
|
||||
|
||||
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);
|
||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
|
||||
SpellProcs[i].base_spellID);
|
||||
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) {
|
||||
|
||||
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);
|
||||
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);
|
||||
@ -4286,6 +4354,49 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (poison_slot > -1) {
|
||||
bool one_shot = !RuleB(Combat, UseExtendedPoisonProcs);
|
||||
|
||||
@ -1071,6 +1071,76 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_WeaponProc:
|
||||
case SE_AddMeleeProc:
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (!newbon->SpellProc[i]) {
|
||||
newbon->SpellProc[i] = rank.id; //aa rank id
|
||||
newbon->SpellProc[i + 1] = base_value; //proc spell id
|
||||
newbon->SpellProc[i + 2] = limit_value; //proc rate modifer
|
||||
newbon->SpellProc[i + 3] = 0; //Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_RangedProc:
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (!newbon->RangedProc[i]) {
|
||||
newbon->RangedProc[i] = rank.id; //aa rank id
|
||||
newbon->RangedProc[i + 1] = base_value; //proc spell id
|
||||
newbon->RangedProc[i + 2] = limit_value; //proc rate modifer
|
||||
newbon->RangedProc[i + 3] = 0; //Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_DefensiveProc:
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (!newbon->DefensiveProc[i]) {
|
||||
newbon->DefensiveProc[i] = rank.id; //aa rank id
|
||||
newbon->DefensiveProc[i + 1] = base_value; //proc spell id
|
||||
newbon->DefensiveProc[i + 2] = limit_value; //proc rate modifer
|
||||
newbon->DefensiveProc[i + 3] = 0; //Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_Proc_Timer_Modifier: {
|
||||
/*
|
||||
AA can multiples of this in a single effect, proc should use the timer
|
||||
that comes after the respective proc spell effect, thus rank.id will be already set
|
||||
when this is checked.
|
||||
*/
|
||||
|
||||
newbon->Proc_Timer_Modifier = true;
|
||||
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (newbon->SpellProc[i] == rank.id) {
|
||||
if (!newbon->SpellProc[i + 3]) {
|
||||
newbon->SpellProc[i + 3] = limit_value;//Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newbon->RangedProc[i] == rank.id) {
|
||||
if (!newbon->RangedProc[i + 3]) {
|
||||
newbon->RangedProc[i + 3] = limit_value;//Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newbon->DefensiveProc[i] == rank.id) {
|
||||
if (!newbon->DefensiveProc[i + 3]) {
|
||||
newbon->DefensiveProc[i + 3] = limit_value;//Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_CriticalHitChance: {
|
||||
// Bad data or unsupported new skill
|
||||
|
||||
@ -761,17 +761,17 @@ void Client::CompleteConnect()
|
||||
case SE_AddMeleeProc:
|
||||
case SE_WeaponProc:
|
||||
{
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel);
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel, GetProcLimitTimer(buffs[j1].spellid, SE_WeaponProc));
|
||||
break;
|
||||
}
|
||||
case SE_DefensiveProc:
|
||||
{
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid);
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_DefensiveProc));
|
||||
break;
|
||||
}
|
||||
case SE_RangedProc:
|
||||
{
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid);
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_RangedProc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,6 +535,10 @@ struct StatBonuses {
|
||||
bool LimitToSkill[EQ::skills::HIGHEST_SKILL + 2]; // Determines if we need to search for a skill proc.
|
||||
uint32 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs.
|
||||
uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success.
|
||||
int32 SpellProc[MAX_AA_PROCS]; // Max number of spells containing melee spell procs.
|
||||
int32 RangedProc[MAX_AA_PROCS]; // Max number of spells containing ranged spell procs.
|
||||
int32 DefensiveProc[MAX_AA_PROCS]; // Max number of spells containing defensive spell procs.
|
||||
bool Proc_Timer_Modifier; // Used to check if this exists, to avoid any further unnncessary checks.
|
||||
uint32 PC_Pet_Rampage[2]; // 0= % chance to rampage, 1=damage modifier
|
||||
uint32 PC_Pet_AE_Rampage[2]; // 0= % chance to AE rampage, 1=damage modifier
|
||||
uint32 PC_Pet_Flurry; // Percent chance flurry from double attack
|
||||
@ -691,6 +695,7 @@ typedef struct
|
||||
uint16 chance;
|
||||
uint16 base_spellID;
|
||||
int level_override;
|
||||
uint32 proc_reuse_time;
|
||||
} tProc;
|
||||
|
||||
|
||||
|
||||
33
zone/mob.cpp
33
zone/mob.cpp
@ -288,18 +288,22 @@ Mob::Mob(
|
||||
PermaProcs[j].chance = 0;
|
||||
PermaProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
PermaProcs[j].level_override = -1;
|
||||
PermaProcs[j].proc_reuse_time = 0;
|
||||
SpellProcs[j].spellID = SPELL_UNKNOWN;
|
||||
SpellProcs[j].chance = 0;
|
||||
SpellProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
SpellProcs[j].proc_reuse_time = 0;
|
||||
SpellProcs[j].level_override = -1;
|
||||
DefensiveProcs[j].spellID = SPELL_UNKNOWN;
|
||||
DefensiveProcs[j].chance = 0;
|
||||
DefensiveProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
DefensiveProcs[j].level_override = -1;
|
||||
DefensiveProcs[j].proc_reuse_time = 0;
|
||||
RangedProcs[j].spellID = SPELL_UNKNOWN;
|
||||
RangedProcs[j].chance = 0;
|
||||
RangedProcs[j].base_spellID = SPELL_UNKNOWN;
|
||||
RangedProcs[j].level_override = -1;
|
||||
RangedProcs[j].proc_reuse_time = 0;
|
||||
}
|
||||
|
||||
for (int i = EQ::textures::textureBegin; i < EQ::textures::materialCount; i++) {
|
||||
@ -354,6 +358,15 @@ Mob::Mob(
|
||||
focusproclimit_timer[i].Disable();
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_PROC_LIMIT_TIMERS; i++) {
|
||||
spell_proclimit_spellid[i] = 0;
|
||||
spell_proclimit_timer[i].Disable();
|
||||
ranged_proclimit_spellid[i] = 0;
|
||||
ranged_proclimit_timer[i].Disable();
|
||||
def_proclimit_spellid[i] = 0;
|
||||
def_proclimit_timer[i].Disable();
|
||||
}
|
||||
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
memset(&spellbonuses, 0, sizeof(StatBonuses));
|
||||
memset(&aabonuses, 0, sizeof(StatBonuses));
|
||||
@ -3167,6 +3180,10 @@ int32 Mob::GetActSpellCasttime(uint16 spell_id, int32 casttime)
|
||||
void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on, int level_override) {
|
||||
// Changed proc targets to look up based on the spells goodEffect flag.
|
||||
// This should work for the majority of weapons.
|
||||
if (!on) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(spell_id == SPELL_UNKNOWN || on->GetSpecialAbility(NO_HARM_FROM_CLIENT)) {
|
||||
//This is so 65535 doesn't get passed to the client message and to logs because it is not relavant information for debugging.
|
||||
return;
|
||||
@ -3202,21 +3219,25 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on,
|
||||
bool twinproc = false;
|
||||
int32 twinproc_chance = 0;
|
||||
|
||||
if(IsClient())
|
||||
if (IsClient()) {
|
||||
twinproc_chance = CastToClient()->GetFocusEffect(focusTwincast, spell_id);
|
||||
}
|
||||
|
||||
if(twinproc_chance && zone->random.Roll(twinproc_chance))
|
||||
if (twinproc_chance && zone->random.Roll(twinproc_chance)) {
|
||||
twinproc = true;
|
||||
}
|
||||
|
||||
if (IsBeneficialSpell(spell_id) && (!IsNPC() || (IsNPC() && CastToNPC()->GetInnateProcSpellID() != spell_id))) { // NPC innate procs don't take this path ever
|
||||
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
||||
if(twinproc)
|
||||
SpellOnTarget(spell_id, this, 0, false, 0, true, level_override);
|
||||
if (twinproc) {
|
||||
SpellFinished(spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
||||
}
|
||||
}
|
||||
else if(!(on->IsClient() && on->CastToClient()->dead)) { //dont proc on dead clients
|
||||
SpellFinished(spell_id, on, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
||||
if(twinproc)
|
||||
SpellOnTarget(spell_id, on, 0, false, 0, true, level_override);
|
||||
if (twinproc && (!(on->IsClient() && on->CastToClient()->dead))) {
|
||||
SpellFinished(spell_id, on, EQ::spells::CastingSlot::Item, 0, -1, spells[spell_id].resist_difficulty, true, level_override);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
15
zone/mob.h
15
zone/mob.h
@ -726,15 +726,15 @@ public:
|
||||
|
||||
//Procs
|
||||
void TriggerDefensiveProcs(Mob *on, uint16 hand = EQ::invslot::slotPrimary, bool FromSkillProc = false, int damage = 0);
|
||||
bool AddRangedProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
|
||||
bool AddRangedProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN, uint32 proc_reuse_time = 0);
|
||||
bool RemoveRangedProc(uint16 spell_id, bool bAll = false);
|
||||
bool HasRangedProcs() const;
|
||||
bool AddDefensiveProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
|
||||
bool AddDefensiveProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN, uint32 proc_reuse_time = 0);
|
||||
bool RemoveDefensiveProc(uint16 spell_id, bool bAll = false);
|
||||
bool HasDefensiveProcs() const;
|
||||
bool HasSkillProcs() const;
|
||||
bool HasSkillProcSuccess() const;
|
||||
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN, int level_override = -1);
|
||||
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN, int level_override = -1, uint32 proc_reuse_time = 0);
|
||||
bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false);
|
||||
bool HasProcs() const;
|
||||
bool IsCombatProc(uint16 spell_id);
|
||||
@ -861,6 +861,8 @@ public:
|
||||
|
||||
bool IsFocusProcLimitTimerActive(int32 focus_spell_id);
|
||||
void SetFocusProcLimitTimer(int32 focus_spell_id, uint32 focus_reuse_time);
|
||||
bool IsProcLimitTimerActive(int32 base_spell_id, uint32 proc_reuse_time, int proc_type);
|
||||
void SetProcLimitTimer(int32 base_spell_id, uint32 proc_reuse_time, int proc_type);
|
||||
|
||||
void VirusEffectProcess();
|
||||
void SpreadVirusEffect(int32 spell_id, uint32 caster_id, int32 buff_tics_remaining);
|
||||
@ -1469,6 +1471,13 @@ protected:
|
||||
Timer focusproclimit_timer[MAX_FOCUS_PROC_LIMIT_TIMERS]; //SPA 511
|
||||
int32 focusproclimit_spellid[MAX_FOCUS_PROC_LIMIT_TIMERS]; //SPA 511
|
||||
|
||||
Timer spell_proclimit_timer[MAX_PROC_LIMIT_TIMERS]; //SPA 512
|
||||
int32 spell_proclimit_spellid[MAX_PROC_LIMIT_TIMERS]; //SPA 512
|
||||
Timer ranged_proclimit_timer[MAX_PROC_LIMIT_TIMERS]; //SPA 512
|
||||
int32 ranged_proclimit_spellid[MAX_PROC_LIMIT_TIMERS]; //SPA 512
|
||||
Timer def_proclimit_timer[MAX_PROC_LIMIT_TIMERS]; //SPA 512
|
||||
int32 def_proclimit_spellid[MAX_PROC_LIMIT_TIMERS]; //SPA 512
|
||||
|
||||
Timer shield_timer;
|
||||
uint32 m_shield_target_id;
|
||||
uint32 m_shielder_id;
|
||||
|
||||
@ -576,14 +576,17 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
||||
if (buffs[j1].spellid <= (uint32)SPDAT_RECORDS) {
|
||||
for (int x1=0; x1 < EFFECT_COUNT; x1++) {
|
||||
switch (spells[buffs[j1].spellid].effect_id[x1]) {
|
||||
case SE_AddMeleeProc:
|
||||
case SE_WeaponProc:
|
||||
// We need to reapply buff based procs
|
||||
// We need to do this here so suspended pets also regain their procs.
|
||||
if (spells[buffs[j1].spellid].limit_value[x1] == 0) {
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100, buffs[j1].spellid);
|
||||
} else {
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid);
|
||||
}
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel, GetProcLimitTimer(buffs[j1].spellid, SE_WeaponProc));
|
||||
break;
|
||||
case SE_DefensiveProc:
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_DefensiveProc));
|
||||
break;
|
||||
case SE_RangedProc:
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_RangedProc));
|
||||
break;
|
||||
case SE_Charm:
|
||||
case SE_Rune:
|
||||
|
||||
@ -1897,11 +1897,27 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Weapon Proc: %s (id %d)", spells[effect_value].name, procid);
|
||||
#endif
|
||||
AddProcToWeapon(procid, false, 100 + spells[spell_id].limit_value[i], spell_id, caster_level, GetProcLimitTimer(spell_id, SE_WeaponProc));
|
||||
break;
|
||||
}
|
||||
|
||||
if(spells[spell_id].limit_value[i] == 0)
|
||||
AddProcToWeapon(procid, false, 100, spell_id, caster_level);
|
||||
else
|
||||
AddProcToWeapon(procid, false, spells[spell_id].limit_value[i]+100, spell_id, caster_level);
|
||||
case SE_RangedProc:
|
||||
{
|
||||
uint16 procid = GetProcID(spell_id, i);
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Ranged Proc: %+i", effect_value);
|
||||
#endif
|
||||
AddRangedProc(procid, 100 + spells[spell_id].limit_value[i], spell_id, GetProcLimitTimer(spell_id, SE_RangedProc));
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DefensiveProc:
|
||||
{
|
||||
uint16 procid = GetProcID(spell_id, i);
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Defensive Proc: %s (id %d)", spells[effect_value].name, procid);
|
||||
#endif
|
||||
AddDefensiveProc(procid, 100 + spells[spell_id].limit_value[i], spell_id, GetProcLimitTimer(spell_id, SE_DefensiveProc));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2273,20 +2289,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_RangedProc:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Ranged Proc: %+i", effect_value);
|
||||
#endif
|
||||
uint16 procid = GetProcID(spell_id, i);
|
||||
|
||||
if(spells[spell_id].limit_value[i] == 0)
|
||||
AddRangedProc(procid, 100, spell_id);
|
||||
else
|
||||
AddRangedProc(procid, spells[spell_id].limit_value[i]+100, spell_id);
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Rampage:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
@ -2383,21 +2385,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DefensiveProc:
|
||||
{
|
||||
uint16 procid = GetProcID(spell_id, i);
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Defensive Proc: %s (id %d)", spells[effect_value].name, procid);
|
||||
#endif
|
||||
if(spells[spell_id].limit_value[i] == 0)
|
||||
AddDefensiveProc(procid, 100,spell_id);
|
||||
else
|
||||
AddDefensiveProc(procid, spells[spell_id].limit_value[i]+100,spell_id);
|
||||
break;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_BardAEDot:
|
||||
{
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
@ -3278,6 +3265,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
case SE_Worn_Endurance_Regen_Cap:
|
||||
case SE_Buy_AA_Rank:
|
||||
case SE_Ff_FocusTimerMin:
|
||||
case SE_Proc_Timer_Modifier:
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -8634,7 +8622,7 @@ void Mob::SpreadVirusEffect(int32 spell_id, uint32 caster_id, int32 buff_tics_re
|
||||
|
||||
bool Mob::IsFocusProcLimitTimerActive(int32 focus_spell_id) {
|
||||
/*
|
||||
Used with SPA SE_Ff_FocusTimerMin to limit how often a focus effect can be applied.
|
||||
Used with SPA 511 SE_Ff_FocusTimerMin to limit how often a focus effect can be applied.
|
||||
Ie. Can only have a spell trigger once every 15 seconds, or to be more creative can only
|
||||
have the fire spells received a very high special focused once every 30 seconds.
|
||||
Note, this stores timers for both spell, item and AA related focuses For AA the focus_spell_id
|
||||
@ -8673,3 +8661,110 @@ void Mob::SetFocusProcLimitTimer(int32 focus_spell_id, uint32 focus_reuse_time)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::IsProcLimitTimerActive(int32 base_spell_id, uint32 proc_reuse_time, int proc_type) {
|
||||
/*
|
||||
Used with SPA 512 SE_Proc_Timer_Modifier to limit how often a proc can be cast.
|
||||
If this effect exists it will prevent the next proc from firing until the timer
|
||||
defined in SPA 512 is finished. Ie. 1 proc every 55 seconds.
|
||||
Spell, Ranged, and Defensive procs all have their own timer array, therefore
|
||||
you can stack multiple different types of effects in the same spell. Make sure
|
||||
SPA 512 goes directly after each proc you want to have the timer.
|
||||
*/
|
||||
if (!proc_reuse_time) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_PROC_LIMIT_TIMERS; i++) {
|
||||
|
||||
if (proc_type == SE_WeaponProc) {
|
||||
if (spell_proclimit_spellid[i] == base_spell_id) {
|
||||
if (spell_proclimit_timer[i].Enabled()) {
|
||||
if (spell_proclimit_timer[i].GetRemainingTime() > 0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
spell_proclimit_timer[i].Disable();
|
||||
spell_proclimit_spellid[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (proc_type == SE_RangedProc) {
|
||||
if (ranged_proclimit_spellid[i] == base_spell_id) {
|
||||
if (ranged_proclimit_timer[i].Enabled()) {
|
||||
if (ranged_proclimit_timer[i].GetRemainingTime() > 0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
ranged_proclimit_timer[i].Disable();
|
||||
ranged_proclimit_spellid[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (proc_type == SE_DefensiveProc) {
|
||||
if (def_proclimit_spellid[i] == base_spell_id) {
|
||||
if (def_proclimit_timer[i].Enabled()) {
|
||||
if (def_proclimit_timer[i].GetRemainingTime() > 0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
def_proclimit_timer[i].Disable();
|
||||
def_proclimit_spellid[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mob::SetProcLimitTimer(int32 base_spell_id, uint32 proc_reuse_time, int proc_type) {
|
||||
|
||||
if (!proc_reuse_time) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_set = false;
|
||||
|
||||
for (int i = 0; i < MAX_PROC_LIMIT_TIMERS; i++) {
|
||||
|
||||
if (proc_type == SE_WeaponProc) {
|
||||
if (!spell_proclimit_spellid[i] && !is_set) {
|
||||
spell_proclimit_spellid[i] = base_spell_id;
|
||||
spell_proclimit_timer[i].SetTimer(proc_reuse_time);
|
||||
is_set = true;
|
||||
}
|
||||
else if (spell_proclimit_spellid[i] > 0 && !FindBuff(base_spell_id)) {
|
||||
spell_proclimit_spellid[i] = 0;
|
||||
spell_proclimit_timer[i].Disable();
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_RangedProc) {
|
||||
if (!ranged_proclimit_spellid[i] && !is_set) {
|
||||
ranged_proclimit_spellid[i] = base_spell_id;
|
||||
ranged_proclimit_timer[i].SetTimer(proc_reuse_time);
|
||||
is_set = true;
|
||||
}
|
||||
else if (ranged_proclimit_spellid[i] > 0 && !FindBuff(base_spell_id)) {
|
||||
ranged_proclimit_spellid[i] = 0;
|
||||
ranged_proclimit_timer[i].Disable();
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_DefensiveProc) {
|
||||
if (!def_proclimit_spellid[i] && !is_set) {
|
||||
def_proclimit_spellid[i] = base_spell_id;
|
||||
def_proclimit_timer[i].SetTimer(proc_reuse_time);
|
||||
is_set = true;
|
||||
}
|
||||
else if (def_proclimit_spellid[i] > 0 && !FindBuff(base_spell_id)) {
|
||||
def_proclimit_spellid[i] = 0;
|
||||
def_proclimit_timer[i].Disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5665,7 +5665,7 @@ bool Mob::IsCombatProc(uint16 spell_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id, int level_override) {
|
||||
bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 base_spell_id, int level_override, uint32 proc_reuse_time) {
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
return(false);
|
||||
|
||||
@ -5677,8 +5677,8 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
|
||||
PermaProcs[i].chance = iChance;
|
||||
PermaProcs[i].base_spellID = base_spell_id;
|
||||
PermaProcs[i].level_override = level_override;
|
||||
PermaProcs[i].proc_reuse_time = proc_reuse_time;
|
||||
LogSpells("Added permanent proc spell [{}] with chance [{}] to slot [{}]", spell_id, iChance, i);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -5692,6 +5692,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
|
||||
SpellProcs[i].spellID = spell_id;
|
||||
SpellProcs[i].chance = iChance;
|
||||
SpellProcs[i].level_override = level_override;
|
||||
SpellProcs[i].proc_reuse_time = proc_reuse_time;
|
||||
Log(Logs::Detail, Logs::Spells, "Replaced poison-granted proc spell %d with chance %d to slot %d", spell_id, iChance, i);
|
||||
return true;
|
||||
}
|
||||
@ -5708,6 +5709,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b
|
||||
SpellProcs[i].chance = iChance;
|
||||
SpellProcs[i].base_spellID = base_spell_id;;
|
||||
SpellProcs[i].level_override = level_override;
|
||||
SpellProcs[i].proc_reuse_time = proc_reuse_time;
|
||||
LogSpells("Added [{}]-granted proc spell [{}] with chance [{}] to slot [{}]", (base_spell_id == POISON_PROC) ? "poison" : "spell", spell_id, iChance, i);
|
||||
return true;
|
||||
}
|
||||
@ -5724,13 +5726,14 @@ bool Mob::RemoveProcFromWeapon(uint16 spell_id, bool bAll) {
|
||||
SpellProcs[i].chance = 0;
|
||||
SpellProcs[i].base_spellID = SPELL_UNKNOWN;
|
||||
SpellProcs[i].level_override = -1;
|
||||
SpellProcs[i].proc_reuse_time = 0;
|
||||
LogSpells("Removed proc [{}] from slot [{}]", spell_id, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id)
|
||||
bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, uint32 proc_reuse_time)
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
return(false);
|
||||
@ -5741,6 +5744,7 @@ bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id
|
||||
DefensiveProcs[i].spellID = spell_id;
|
||||
DefensiveProcs[i].chance = iChance;
|
||||
DefensiveProcs[i].base_spellID = base_spell_id;
|
||||
DefensiveProcs[i].proc_reuse_time = proc_reuse_time;
|
||||
LogSpells("Added spell-granted defensive proc spell [{}] with chance [{}] to slot [{}]", spell_id, iChance, i);
|
||||
return true;
|
||||
}
|
||||
@ -5756,13 +5760,14 @@ bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll)
|
||||
DefensiveProcs[i].spellID = SPELL_UNKNOWN;
|
||||
DefensiveProcs[i].chance = 0;
|
||||
DefensiveProcs[i].base_spellID = SPELL_UNKNOWN;
|
||||
DefensiveProcs[i].proc_reuse_time = 0;
|
||||
LogSpells("Removed defensive proc [{}] from slot [{}]", spell_id, i);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id)
|
||||
bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, uint32 proc_reuse_time)
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
return(false);
|
||||
@ -5773,6 +5778,7 @@ bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id)
|
||||
RangedProcs[i].spellID = spell_id;
|
||||
RangedProcs[i].chance = iChance;
|
||||
RangedProcs[i].base_spellID = base_spell_id;
|
||||
RangedProcs[i].proc_reuse_time = proc_reuse_time;
|
||||
LogSpells("Added spell-granted ranged proc spell [{}] with chance [{}] to slot [{}]", spell_id, iChance, i);
|
||||
return true;
|
||||
}
|
||||
@ -5787,7 +5793,8 @@ bool Mob::RemoveRangedProc(uint16 spell_id, bool bAll)
|
||||
if (bAll || RangedProcs[i].spellID == spell_id) {
|
||||
RangedProcs[i].spellID = SPELL_UNKNOWN;
|
||||
RangedProcs[i].chance = 0;
|
||||
RangedProcs[i].base_spellID = SPELL_UNKNOWN;;
|
||||
RangedProcs[i].base_spellID = SPELL_UNKNOWN;
|
||||
RangedProcs[i].proc_reuse_time = 0;
|
||||
LogSpells("Removed ranged proc [{}] from slot [{}]", spell_id, i);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user