From 93a4153a4bce0e1883f254f89c428a12ee12daa8 Mon Sep 17 00:00:00 2001 From: nytmyr <53322305+nytmyr@users.noreply.github.com> Date: Mon, 8 May 2023 08:32:21 -0500 Subject: [PATCH] [Rules] ResurrectionEffectBlock to prevent/allow/move buffs. (#3288) * [Rules] ResurrectionEffectsBlock to prevent/allow/move buffs. This removes the rule ResurrectionEffectsBlock (Bool) and creates ResurrectionEffectsBlock (Int) Default = 2 Setting to 0 = Functions as it did before any blocking changes, Focus of Spirit and Strength buffs can overwrite Resurrection Effects. Setting to 1 = Blocks all buffs that could overwrite Resurrection Effects. Setting to 2 = Allows all buffs that would overwrite Resurrection Effects to land, however they will be moved to a new buff slot if one is available to allow both the beneficial buff to land and detrimental effects of Resurrection Effects to stay in effect until the duration is expired. * Update logging --------- Co-authored-by: Akkadius --- common/ruletypes.h | 2 +- common/spdat.cpp | 29 +++++++++++++++++++++++------ common/spdat.h | 6 ++++++ zone/spells.cpp | 34 ++++++++++++++++++++++++++++++---- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index d8972c94a..c22b04d14 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -444,7 +444,7 @@ RULE_BOOL(Spells, IllusionsAlwaysPersist, false, "Allows Illusions to persist be RULE_BOOL(Spells, UseItemCastMessage, false, "Enable to use the \"item begins to glow\" messages when casting from an item.") RULE_BOOL(Spells, TargetsTargetRequiresCombatRange, true, "Disable to remove combat range requirement from Target's Target Spell Target Type") RULE_BOOL(Spells, NPCBuffLevelRestrictions, false, "Impose BuffLevelRestrictions on NPCs if true") -RULE_BOOL(Spells, ResurrectionEffectsBlock, true, "If enabled, resurrection effects cannot be overwritten.") +RULE_INT(Spells, ResurrectionEffectBlock, 2, "0 = allow overwrites/rule disabled. If set to 1 = Block all buffs that would overwrite Resurrection Effects. If set to 2 = Will not overwrite Resurrection Effects, instead moves new buff to an empty slot if available. Default is 2.") RULE_CATEGORY_END() RULE_CATEGORY(Combat) diff --git a/common/spdat.cpp b/common/spdat.cpp index 43cc191e2..ba93e9f46 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -776,6 +776,23 @@ bool IsResurrectionEffects(uint16 spell_id) return false; } +int8 GetResurrectionSicknessCheck(uint16 spell_id1, uint16 spell_id2) +{ + if (RuleI(Spells, ResurrectionEffectBlock) == RES_EFFECTS_BLOCK) { + LogSpells("[{}] is blocked by [{}]", spells[spell_id2].name, spells[spell_id1].name); + return -1; // can't stack + } + else if (RuleI(Spells, ResurrectionEffectBlock) == RES_EFFECTS_BLOCK_WITH_BUFFS) { + LogSpells( + "[{}] is blocked by [{}], moving to empty slot if available", + spells[spell_id2].name, + spells[spell_id1].name + ); + return MOVE_NEW_SLOT; // move to empty slot if available + } + return NO_RES_EFFECTS_BLOCK; +} + bool IsRuneSpell(uint16 spell_id) { if (IsValidSpell(spell_id)) @@ -1003,7 +1020,7 @@ bool IsFastHealSpell(uint16 spell_id) ( spells[spell_id].effect_id[i] == SE_CurrentHP || spells[spell_id].effect_id[i] == SE_CurrentHPOnce - ) && + ) && spells[spell_id].base_value[i] > 0 ) { return true; @@ -1029,7 +1046,7 @@ bool IsVeryFastHealSpell(uint16 spell_id) ( spells[spell_id].effect_id[i] == SE_CurrentHP || spells[spell_id].effect_id[i] == SE_CurrentHPOnce - ) && + ) && spells[spell_id].base_value[i] > 0 ) { return true; @@ -1054,8 +1071,8 @@ bool IsRegularSingleTargetHealSpell(uint16 spell_id) ( spells[spell_id].effect_id[i] == SE_CurrentHP || spells[spell_id].effect_id[i] == SE_CurrentHPOnce - ) && - spells[spell_id].base_value[i] > 0 && + ) && + spells[spell_id].base_value[i] > 0 && spells[spell_id].buff_duration == 0 ) { return true; @@ -1080,8 +1097,8 @@ bool IsRegularGroupHealSpell(uint16 spell_id) ( spells[spell_id].effect_id[i] == SE_CurrentHP || spells[spell_id].effect_id[i] == SE_CurrentHPOnce - ) && - spells[spell_id].base_value[i] > 0 && + ) && + spells[spell_id].base_value[i] > 0 && spells[spell_id].buff_duration == 0 ) { return true; diff --git a/common/spdat.h b/common/spdat.h index 882077c73..0219f8a41 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -201,6 +201,11 @@ #define INSTRUMENT_LUTE 13011 #define INSTRUMENT_HORN 13012 +//option types for the rule Spells:ResurrectionEffectBlock +#define NO_RES_EFFECTS_BLOCK 0 +#define RES_EFFECTS_BLOCK 1 +#define RES_EFFECTS_BLOCK_WITH_BUFFS 2 +#define MOVE_NEW_SLOT 2 const int Z_AGGRO=10; @@ -1505,6 +1510,7 @@ bool IsDisciplineBuff(uint16 spell_id); bool IsDiscipline(uint16 spell_id); bool IsCombatSkill(uint16 spell_id); bool IsResurrectionEffects(uint16 spell_id); +int8 GetResurrectionSicknessCheck(uint16 spell_id1, uint16 spell_id2); bool IsRuneSpell(uint16 spell_id); bool IsMagicRuneSpell(uint16 spell_id); bool IsManaTapSpell(uint16 spell_id); diff --git a/zone/spells.cpp b/zone/spells.cpp index 002280153..408a2c6a8 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -3037,6 +3037,12 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, if(sp1_value < overwrite_below_value) { + if (IsResurrectionEffects(spellid1)) { + int8 res_effect_check = GetResurrectionSicknessCheck(spellid1, spellid2); + if (res_effect_check != 0) { + return res_effect_check; + } + } LogSpells("Overwrite spell because sp1_value < overwrite_below_value"); return 1; // overwrite spell if its value is less } @@ -3162,6 +3168,13 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, if(sp2_value < 0) sp2_value = 0 - sp2_value; + if (IsResurrectionEffects(spellid1)) { + int8 res_effect_check = GetResurrectionSicknessCheck(spellid1, spellid2); + if (res_effect_check != 0) { + return res_effect_check; + } + } + if(sp2_value < sp1_value) { LogSpells("Spell [{}] (value [{}]) is not as good as [{}] (value [{}]). Rejecting [{}]", sp2.name, sp2_value, sp1.name, sp1_value, sp2.name); @@ -3170,10 +3183,6 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, if (sp2_value != sp1_value) values_equal = false; - if (RuleB(Spells, ResurrectionEffectsBlock) && IsResurrectionEffects(spellid1)) { - LogSpells("ResurrectionEffectsBlock triggered -- [{}] is blocked by [{}]", sp2.name, sp1.name); - return -1; // can't stack - } //we dont return here... a better value on this one effect dosent mean they are //all better... @@ -3364,6 +3373,10 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid will_overwrite = true; overwrite_slots.push_back(buffslot); } + if (ret == 2) { //ResurrectionEffectBlock handling to move potential overwrites to a new buff slock while keeping Res Sickness + LogSpells("Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}], but ResurrectionEffectBlock is set to 2. Attempting to move [{}] to an empty buff slot.", + spell_id, curbuf.spellid, buffslot, curbuf.casterlevel, spell_id); + } } else { if (emptyslot == -1) { if (buffslot >= start_slot && buffslot < end_slot) { @@ -3521,6 +3534,19 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) LogAIDetail("Buff [{}] would conflict with [{}] in slot [{}], reporting stack failure", spellid, curbuf.spellid, i); return -1; // stop the spell, can't stack it } + if (ret == 2) { //ResurrectionEffectBlock handling to move potential overwrites to a new buff slock while keeping Res Sickness + LogAIDetail("Adding buff [{}] will overwrite spell [{}] in slot [{}] with caster level [{}], but ResurrectionEffectBlock is set to 2. Attempting to move [{}] to an empty buff slot.", + spellid, curbuf.spellid, i, curbuf.casterlevel, spellid); + for (int x = 0; x < buff_count; x++) { + const Buffs_Struct& curbuf = buffs[x]; + if (IsValidSpell(curbuf.spellid)) { + continue; + } + else { + firstfree = x; + } + } + } } LogAIDetail("Reporting that buff [{}] could successfully be placed into slot [{}]", spellid, firstfree);