diff --git a/common/ruletypes.h b/common/ruletypes.h index be7f03b2c..05e4ffbd6 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -531,6 +531,7 @@ RULE_BOOL(Combat, BackstabIgnoresBane, false, "Enable or disable Bane weapon dam RULE_BOOL(Combat, SummonMeleeRange, true, "Enable or disable summoning of a player when already in melee range of the summoner.") RULE_BOOL(Combat, WaterMatchRequiredForAutoFireLoS, true, "Enable/Disable the requirement of both the attacker/victim being both in or out of water for AutoFire LoS to pass.") RULE_INT(Combat, ExtraAllowedKickClassesBitmask, 0, "Bitmask for allowing extra classes beyond Warrior, Ranger, Beastlord, and Berserker to kick, No Extra Classes (0) by default") +RULE_INT(Combat, MaxProcs, 4, "Adjustable maximum number of procs per round, the hard cap is MAX_PROCS (11). Requires mob repop or client zone when changed") RULE_CATEGORY_END() RULE_CATEGORY(NPC) diff --git a/zone/attack.cpp b/zone/attack.cpp index 8371d00fc..667c361a5 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3628,7 +3628,7 @@ int64 Mob::ReduceAllDamage(int64 damage) bool Mob::HasProcs() const { - for (int i = 0; i < MAX_PROCS; i++) { + for (int i = 0; i < m_max_procs; i++) { if (IsValidSpell(PermaProcs[i].spellID) || IsValidSpell(SpellProcs[i].spellID)) { return true; } @@ -3646,7 +3646,7 @@ bool Mob::HasProcs() const bool Mob::HasDefensiveProcs() const { - for (int i = 0; i < MAX_PROCS; i++) { + for (int i = 0; i < m_max_procs; i++) { if (IsValidSpell(DefensiveProcs[i].spellID)) { return true; } @@ -3682,7 +3682,7 @@ bool Mob::HasSkillProcSuccess() const bool Mob::HasRangedProcs() const { - for (int i = 0; i < MAX_PROCS; i++){ + for (int i = 0; i < m_max_procs; i++){ if (IsValidSpell(RangedProcs[i].spellID)) { return true; } @@ -4580,7 +4580,7 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) } //Spell Procs and Quest added procs - for (int i = 0; i < MAX_PROCS; i++) { + for (int i = 0; i < m_max_procs; i++) { if (IsValidSpell(DefensiveProcs[i].spellID)) { if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, ProcType::DEFENSIVE_PROC)) { float chance = proc_chance * (static_cast(DefensiveProcs[i].chance) / 100.0f); @@ -4783,7 +4783,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon, int16 poison_slot=-1; - for (uint32 i = 0; i < MAX_PROCS; i++) { + for (uint32 i = 0; i < m_max_procs; i++) { if (IsPet() && hand != EQ::invslot::slotPrimary) //Pets can only proc spell procs from their primay hand (ie; beastlord pets) continue; // If pets ever can proc from off hand, this will need to change diff --git a/zone/mob.cpp b/zone/mob.cpp index 9eb0f0f68..c85354e8b 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -288,8 +288,11 @@ Mob::Mob( feigned = false; + int max_procs = MAX_PROCS; + m_max_procs = std::min(RuleI(Combat, MaxProcs), max_procs); + // clear the proc arrays - for (int j = 0; j < MAX_PROCS; j++) { + for (int j = 0; j < m_max_procs; j++) { PermaProcs[j].spellID = SPELL_UNKNOWN; PermaProcs[j].chance = 0; PermaProcs[j].base_spellID = SPELL_UNKNOWN; @@ -511,6 +514,7 @@ Mob::Mob( SetCanOpenDoors(true); is_boat = IsBoat(); + } Mob::~Mob() diff --git a/zone/mob.h b/zone/mob.h index 68779cc53..388553876 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1459,6 +1459,9 @@ protected: Timer m_z_clip_check_timer; + // dynamically set via memory on constructor + int8 m_max_procs = 0; + virtual bool AI_EngagedCastCheck() { return(false); } virtual bool AI_PursueCastCheck() { return(false); } virtual bool AI_IdleCastCheck() { return(false); } @@ -1600,7 +1603,7 @@ protected: int16 GetSympatheticSpellProcRate(uint16 spell_id); uint16 GetSympatheticSpellProcID(uint16 spell_id); - enum {MAX_PROCS = 4}; + enum {MAX_PROCS = 10}; tProc PermaProcs[MAX_PROCS]; tProc SpellProcs[MAX_PROCS]; tProc DefensiveProcs[MAX_PROCS]; diff --git a/zone/spells.cpp b/zone/spells.cpp index 714312413..3951a352d 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -6017,7 +6017,7 @@ bool Mob::IsCombatProc(uint16 spell_id) { /* Procs that originate from casted spells are still limited by SPA 311 (~Kayen confirmed on live 2/4/22) */ - for (int i = 0; i < MAX_PROCS; i++) { + for (int i = 0; i < m_max_procs; i++) { if (PermaProcs[i].spellID == spell_id || SpellProcs[i].spellID == spell_id || RangedProcs[i].spellID == spell_id || @@ -6044,7 +6044,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b int i; if (bPerma) { - for (i = 0; i < MAX_PROCS; i++) { + for (i = 0; i < m_max_procs; i++) { if (!IsValidSpell(PermaProcs[i].spellID)) { PermaProcs[i].spellID = spell_id; PermaProcs[i].chance = iChance; @@ -6059,7 +6059,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b } else { // If its a poison proc, replace any existing one if present. if (base_spell_id == POISON_PROC) { - for (i = 0; i < MAX_PROCS; i++) { + for (i = 0; i < m_max_procs; i++) { // If we already have a poison proc active replace it and return if (SpellProcs[i].base_spellID == POISON_PROC) { SpellProcs[i].spellID = spell_id; @@ -6076,7 +6076,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b // or it is poison and no poison procs are currently present. // Find a slot and use it as normal. - for (i = 0; i < MAX_PROCS; i++) { + for (i = 0; i < m_max_procs; i++) { if (!IsValidSpell(SpellProcs[i].spellID)) { SpellProcs[i].spellID = spell_id; SpellProcs[i].chance = iChance; @@ -6093,7 +6093,7 @@ bool Mob::AddProcToWeapon(uint16 spell_id, bool bPerma, uint16 iChance, uint16 b } bool Mob::RemoveProcFromWeapon(uint16 spell_id, bool bAll) { - for (int i = 0; i < MAX_PROCS; i++) { + for (int i = 0; i < m_max_procs; i++) { if (bAll || SpellProcs[i].spellID == spell_id) { SpellProcs[i].spellID = SPELL_UNKNOWN; SpellProcs[i].chance = 0; @@ -6112,7 +6112,7 @@ bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id return(false); int i; - for (i = 0; i < MAX_PROCS; i++) { + for (i = 0; i < m_max_procs; i++) { if (!IsValidSpell(DefensiveProcs[i].spellID)) { DefensiveProcs[i].spellID = spell_id; DefensiveProcs[i].chance = iChance; @@ -6128,7 +6128,7 @@ bool Mob::AddDefensiveProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll) { - for (int i = 0; i < MAX_PROCS; i++) { + for (int i = 0; i < m_max_procs; i++) { if (bAll || DefensiveProcs[i].spellID == spell_id) { DefensiveProcs[i].spellID = SPELL_UNKNOWN; DefensiveProcs[i].chance = 0; @@ -6146,7 +6146,7 @@ bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, u return(false); int i; - for (i = 0; i < MAX_PROCS; i++) { + for (i = 0; i < m_max_procs; i++) { if (!IsValidSpell(RangedProcs[i].spellID)) { RangedProcs[i].spellID = spell_id; RangedProcs[i].chance = iChance; @@ -6162,7 +6162,7 @@ bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id, u bool Mob::RemoveRangedProc(uint16 spell_id, bool bAll) { - for (int i = 0; i < MAX_PROCS; i++) { + for (int i = 0; i < m_max_procs; i++) { if (bAll || RangedProcs[i].spellID == spell_id) { RangedProcs[i].spellID = SPELL_UNKNOWN; RangedProcs[i].chance = 0;