mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 17:51:28 +00:00
[Spells] Implemented SPA 511 SE_Ff_FocusTimerMin (#1645)
* update for SPA 511 * remove debugs, AA implemented * update * format update * rename function renamed function only check for buffs value > 0, don't need to check for AA's which are negative ID's * var rename update var name to better represent its function.
This commit is contained in:
parent
ef5124d756
commit
fb66afd565
@ -1255,6 +1255,7 @@ bool IsEffectIgnoredInStacking(int spa)
|
||||
case SE_Ff_ReuseTimeMax:
|
||||
case SE_Ff_Value_Min:
|
||||
case SE_Ff_Value_Max:
|
||||
case SE_Ff_FocusTimerMin:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -1296,6 +1297,7 @@ bool IsFocusLimit(int spa)
|
||||
case SE_Ff_ReuseTimeMax:
|
||||
case SE_Ff_Value_Min:
|
||||
case SE_Ff_Value_Max:
|
||||
case SE_Ff_FocusTimerMin:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
@ -180,7 +180,7 @@
|
||||
#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_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)
|
||||
|
||||
|
||||
const int Z_AGGRO=10;
|
||||
@ -1208,8 +1208,8 @@ typedef enum {
|
||||
#define SE_Fc_Amplify_Amt 508 // implemented, @Fc, On Caster, damage-heal-dot mod flat amt, base: amt
|
||||
#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 //
|
||||
#define SE_Proc_Timer_Modifier 512 // implemented - spell trigger limiter used currently with SPA 481, ie. limit to 1 proc every 1.5 seconds (base=1 base2=1500).
|
||||
#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_Mana_Max_Percent 513 //
|
||||
//#define SE_Endurance_Max_Percent 514 //
|
||||
#define SE_AC_Avoidance_Max_Percent 515 // implemented - stackable avoidance modifier
|
||||
|
||||
@ -509,9 +509,6 @@ bool Client::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
if (focus_proc_limit_timer.Check() && !dead)
|
||||
FocusProcLimitProcess();
|
||||
|
||||
if (client_state == CLIENT_KICKED) {
|
||||
Save();
|
||||
OnDisconnect(true);
|
||||
|
||||
@ -328,8 +328,6 @@ struct Buffs_Struct {
|
||||
int32 ExtraDIChance;
|
||||
int16 RootBreakChance; //Not saved to dbase
|
||||
uint32 instrument_mod;
|
||||
int16 focusproclimit_time; //timer to limit number of procs from focus effects
|
||||
int16 focusproclimit_procamt; //amount of procs that can be cast before timer limiter is set
|
||||
int32 virus_spread_time; //time till next attempted viral spread
|
||||
bool persistant_buff;
|
||||
bool client; //True if the caster is a client
|
||||
|
||||
@ -103,7 +103,6 @@ Mob::Mob(
|
||||
ranged_timer(2000),
|
||||
tic_timer(6000),
|
||||
mana_timer(2000),
|
||||
focus_proc_limit_timer(250),
|
||||
spellend_timer(0),
|
||||
rewind_timer(30000),
|
||||
bindwound_timer(10000),
|
||||
@ -350,6 +349,11 @@ Mob::Mob(
|
||||
ProjectileAtk[i].speed_mod = 0.0f;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_FOCUS_PROC_LIMIT_TIMERS; i++) {
|
||||
focusproclimit_spellid[i] = 0;
|
||||
focusproclimit_timer[i].Disable();
|
||||
}
|
||||
|
||||
memset(&itembonuses, 0, sizeof(StatBonuses));
|
||||
memset(&spellbonuses, 0, sizeof(StatBonuses));
|
||||
memset(&aabonuses, 0, sizeof(StatBonuses));
|
||||
|
||||
10
zone/mob.h
10
zone/mob.h
@ -857,8 +857,9 @@ public:
|
||||
inline void SetUseDoubleMeleeRoundDmgBonus(bool val) { use_double_melee_round_dmg_bonus = val; }
|
||||
|
||||
void CastSpellOnLand(Mob* caster, int32 spell_id);
|
||||
void FocusProcLimitProcess();
|
||||
bool ApplyFocusProcLimiter(int32 spell_id, int buffslot = -1);
|
||||
|
||||
bool IsFocusProcLimitTimerActive(int32 focus_spell_id);
|
||||
void SetFocusProcLimitTimer(int32 focus_spell_id, uint32 focus_reuse_time);
|
||||
|
||||
void VirusEffectProcess();
|
||||
void SpreadVirusEffect(int32 spell_id, uint32 caster_id, int32 buff_tics_remaining);
|
||||
@ -1463,7 +1464,9 @@ protected:
|
||||
int16 slow_mitigation; // Allows for a slow mitigation (100 = 100%, 50% = 50%)
|
||||
Timer tic_timer;
|
||||
Timer mana_timer;
|
||||
Timer focus_proc_limit_timer;
|
||||
|
||||
Timer focusproclimit_timer[MAX_FOCUS_PROC_LIMIT_TIMERS]; //SPA 511
|
||||
int32 focusproclimit_spellid[MAX_FOCUS_PROC_LIMIT_TIMERS]; //SPA 511
|
||||
|
||||
Timer shield_timer;
|
||||
uint32 m_shield_target_id;
|
||||
@ -1560,7 +1563,6 @@ protected:
|
||||
Timer bardsong_timer;
|
||||
Timer gravity_timer;
|
||||
Timer viral_timer;
|
||||
uint8 viral_timer_counter;
|
||||
|
||||
// MobAI stuff
|
||||
eStandingPetOrder pStandingPetOrder;
|
||||
|
||||
@ -1125,9 +1125,6 @@ void Mob::AI_Process() {
|
||||
|
||||
ProjectileAttack();
|
||||
|
||||
if (focus_proc_limit_timer.Check())
|
||||
FocusProcLimitProcess();
|
||||
|
||||
if (shield_timer.Check()) {
|
||||
ShieldAbilityFinish();
|
||||
}
|
||||
|
||||
@ -2992,11 +2992,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Proc_Timer_Modifier:{
|
||||
buffs[buffslot].focusproclimit_procamt = spells[spell_id].base[i]; //Set max amount of procs before lockout timer
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_PetShield: {
|
||||
if (IsPet()) {
|
||||
Mob* petowner = GetOwner();
|
||||
@ -3300,6 +3295,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
case SE_Skill_Base_Damage_Mod:
|
||||
case SE_Worn_Endurance_Regen_Cap:
|
||||
case SE_Buy_AA_Rank:
|
||||
case SE_Ff_FocusTimerMin:
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -4568,8 +4564,9 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
||||
int32 base1 = 0;
|
||||
int32 base2 = 0;
|
||||
uint32 slot = 0;
|
||||
|
||||
|
||||
int index_id = -1;
|
||||
uint32 focus_reuse_time = 0;
|
||||
|
||||
bool LimitFailure = false;
|
||||
bool LimitInclude[MaxLimitInclude] = {false};
|
||||
@ -4917,6 +4914,15 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_Ff_FocusTimerMin:
|
||||
if (IsFocusProcLimitTimerActive(-rank.id)) {
|
||||
LimitFailure = true;
|
||||
}
|
||||
else {
|
||||
focus_reuse_time = base2;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/* These are not applicable to AA's because there is never a 'caster' of the 'buff' with the focus effect.
|
||||
case SE_Ff_Same_Caster:
|
||||
@ -5217,6 +5223,10 @@ int32 Client::CalcAAFocus(focusType type, const AA::Rank &rank, uint16 spell_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (focus_reuse_time) {
|
||||
SetFocusProcLimitTimer(-rank.id, focus_reuse_time);
|
||||
}
|
||||
|
||||
return (value * lvlModifier / 100);
|
||||
}
|
||||
|
||||
@ -5247,6 +5257,7 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
int lvldiff = 0;
|
||||
uint32 Caston_spell_id = 0;
|
||||
int index_id = -1;
|
||||
uint32 focus_reuse_time = 0; //If this is set and all limits pass, start timer at end of script.
|
||||
|
||||
bool LimitInclude[MaxLimitInclude] = {false};
|
||||
/* Certain limits require only one of several Include conditions to be true. Determined by limits being negative or positive
|
||||
@ -5579,7 +5590,16 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
}
|
||||
break;
|
||||
|
||||
// handle effects
|
||||
case SE_Ff_FocusTimerMin:
|
||||
if (IsFocusProcLimitTimerActive(focus_spell.id)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
focus_reuse_time = focus_spell.base2[i];
|
||||
}
|
||||
break;
|
||||
|
||||
// handle effects
|
||||
case SE_ImprovedDamage:
|
||||
if (type == focusImprovedDamage) {
|
||||
value = GetFocusRandomEffectivenessValue(focus_spell.base[i], focus_spell.base2[i], best_focus);
|
||||
@ -5882,6 +5902,10 @@ int32 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
}
|
||||
}
|
||||
|
||||
if (focus_reuse_time) {
|
||||
SetFocusProcLimitTimer(focus_spell.id, focus_reuse_time);
|
||||
}
|
||||
|
||||
return (value * lvlModifier / 100);
|
||||
}
|
||||
|
||||
@ -8293,102 +8317,22 @@ void Mob::CastSpellOnLand(Mob* caster, int32 spell_id)
|
||||
|
||||
if (IsValidSpell(trigger_spell_id) && (trigger_spell_id != spell_id)) {
|
||||
|
||||
//Step 3: Check if SE_Proc_Time_Modifier is present and if so apply it.
|
||||
if (ApplyFocusProcLimiter(buffs[i].spellid, i)) {
|
||||
//Step 4: Cast spells
|
||||
if (IsBeneficialSpell(trigger_spell_id)) {
|
||||
SpellFinished(trigger_spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[trigger_spell_id].ResistDiff);
|
||||
}
|
||||
else {
|
||||
Mob* current_target = GetTarget();
|
||||
//For now don't let players cast detrimental effects on themselves if they are targeting themselves. Need to confirm behavior.
|
||||
if (current_target && current_target->GetID() != GetID())
|
||||
SpellFinished(trigger_spell_id, current_target, EQ::spells::CastingSlot::Item, 0, -1, spells[trigger_spell_id].ResistDiff);
|
||||
}
|
||||
//Step 3: Cast spells
|
||||
if (IsBeneficialSpell(trigger_spell_id)) {
|
||||
SpellFinished(trigger_spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[trigger_spell_id].ResistDiff);
|
||||
}
|
||||
|
||||
if (i >= 0)
|
||||
CheckNumHitsRemaining(NumHit::MatchingSpells, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::ApplyFocusProcLimiter(int32 spell_id, int buffslot)
|
||||
{
|
||||
if (buffslot < 0)
|
||||
return false;
|
||||
|
||||
//Do not allow spell cast if timer is active.
|
||||
if (buffs[buffslot].focusproclimit_time > 0)
|
||||
return false;
|
||||
|
||||
/*
|
||||
SE_Proc_Timer_Modifier
|
||||
base1= amount of total procs allowed until lock out timer is triggered, should be set to at least 1 in any spell for the effect to function.
|
||||
base2= lock out timer, which prevents any more procs set in ms 1500 = 1.5 seconds
|
||||
This system allows easy scaling for multiple different buffs with same effects each having seperate active individual timer checks. Ie.
|
||||
*/
|
||||
|
||||
if (IsValidSpell(spell_id)) {
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
|
||||
//Step 1: Find which slot the spell effect is in.
|
||||
if (spells[spell_id].effectid[i] == SE_Proc_Timer_Modifier) {
|
||||
|
||||
//Step 2: Check if you still have procs left to trigger, and if so reduce available procs
|
||||
if (buffs[buffslot].focusproclimit_procamt > 0) {
|
||||
--buffs[buffslot].focusproclimit_procamt; //Reduce total amount of triggers possible.
|
||||
}
|
||||
|
||||
//Step 3: If you used all the procs in the time frame then set proc amount back to max
|
||||
if (buffs[buffslot].focusproclimit_procamt == 0 && spells[spell_id].base[i] > 0) {
|
||||
buffs[buffslot].focusproclimit_procamt = spells[spell_id].base[i];//reset to max
|
||||
|
||||
//Step 4: Check if timer exists on this spell, and then set it, and activiate global timer if not active
|
||||
if (buffs[buffslot].focusproclimit_time ==0 && spells[spell_id].base2[i] > 0) {
|
||||
buffs[buffslot].focusproclimit_time = spells[spell_id].base2[i];//set time
|
||||
|
||||
//Step 5: If timer is not already running, then start it.
|
||||
if (!focus_proc_limit_timer.Enabled()) {
|
||||
focus_proc_limit_timer.Start(250);
|
||||
}
|
||||
|
||||
return true;
|
||||
else {
|
||||
Mob* current_target = GetTarget();
|
||||
//For now don't let players cast detrimental effects on themselves if they are targeting themselves. Need to confirm behavior.
|
||||
if (current_target && current_target->GetID() != GetID())
|
||||
SpellFinished(trigger_spell_id, current_target, EQ::spells::CastingSlot::Item, 0, -1, spells[trigger_spell_id].ResistDiff);
|
||||
}
|
||||
}
|
||||
if (i >= 0)
|
||||
CheckNumHitsRemaining(NumHit::MatchingSpells, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mob::FocusProcLimitProcess()
|
||||
{
|
||||
/*
|
||||
Fast 250 ms uinversal timer for checking Focus effects that have a proc rate limiter set in actual time.
|
||||
*/
|
||||
bool stop_timer = true;
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for (int buffs_i = 0; buffs_i < buff_count; ++buffs_i)
|
||||
{
|
||||
if (IsValidSpell(buffs[buffs_i].spellid))
|
||||
{
|
||||
if (buffs[buffs_i].focusproclimit_time > 0) {
|
||||
buffs[buffs_i].focusproclimit_time -= 250;
|
||||
stop_timer = false;
|
||||
}
|
||||
|
||||
if (buffs[buffs_i].focusproclimit_time < 0)
|
||||
buffs[buffs_i].focusproclimit_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (stop_timer) {
|
||||
focus_proc_limit_timer.Disable();
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster)
|
||||
@ -8668,3 +8612,45 @@ 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.
|
||||
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
|
||||
is saved as the the negative value of the rank.id (to avoid conflicting with spell_ids)
|
||||
*/
|
||||
for (int i = 0; i < MAX_FOCUS_PROC_LIMIT_TIMERS; i++) {
|
||||
if (focusproclimit_spellid[i] == focus_spell_id) {
|
||||
if (focusproclimit_timer[i].Enabled()) {
|
||||
if (focusproclimit_timer[i].GetRemainingTime() > 0) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
focusproclimit_timer[i].Disable();
|
||||
focusproclimit_spellid[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mob::SetFocusProcLimitTimer(int32 focus_spell_id, uint32 focus_reuse_time) {
|
||||
|
||||
bool is_set = false;
|
||||
|
||||
for (int i = 0; i < MAX_FOCUS_PROC_LIMIT_TIMERS; i++) {
|
||||
if (!focusproclimit_spellid[i] && !is_set) {
|
||||
focusproclimit_spellid[i] = focus_spell_id;
|
||||
focusproclimit_timer[i].SetTimer(focus_reuse_time);
|
||||
is_set = true;
|
||||
}
|
||||
//Remove old temporary focus if was from a buff you no longer have.
|
||||
else if (focusproclimit_spellid[i] > 0 && !FindBuff(focus_spell_id)) {
|
||||
focusproclimit_spellid[i] = 0;
|
||||
focusproclimit_timer[i].Disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3421,8 +3421,6 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
buffs[emptyslot].dot_rune = 0;
|
||||
buffs[emptyslot].ExtraDIChance = 0;
|
||||
buffs[emptyslot].RootBreakChance = 0;
|
||||
buffs[emptyslot].focusproclimit_time = 0;
|
||||
buffs[emptyslot].focusproclimit_procamt = 0;
|
||||
buffs[emptyslot].virus_spread_time = 0;
|
||||
buffs[emptyslot].instrument_mod = caster ? caster->GetInstrumentMod(spell_id) : 10;
|
||||
|
||||
|
||||
@ -3670,8 +3670,6 @@ void ZoneDatabase::LoadBuffs(Client *client)
|
||||
buffs[slot_id].caston_z = caston_z;
|
||||
buffs[slot_id].ExtraDIChance = ExtraDIChance;
|
||||
buffs[slot_id].RootBreakChance = 0;
|
||||
buffs[slot_id].focusproclimit_time = 0;
|
||||
buffs[slot_id].focusproclimit_procamt = 0;
|
||||
buffs[slot_id].virus_spread_time = 0;
|
||||
buffs[slot_id].UpdateClient = false;
|
||||
buffs[slot_id].instrument_mod = instrument_mod;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user