From b23af6d436ca98d57fd7f7068dbff0b545f2316b Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 25 Jun 2014 14:14:55 -0400 Subject: [PATCH 01/19] Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. --- changelog.txt | 4 ++++ common/spdat.h | 2 +- zone/spell_effects.cpp | 27 +++++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index c4fa6cecf..97a68ad24 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- + +== 06/25/2014 == +Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. + == 06/17/2014 == Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. These effects when present in buffs prevent each other from stacking, diff --git a/common/spdat.h b/common/spdat.h index b302e8314..fd9ba923f 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -339,7 +339,7 @@ typedef enum { #define SE_CurrentEndurance 189 // implemented #define SE_EndurancePool 190 // implemented #define SE_Amnesia 191 // implemented - Silence vs Melee Effect -#define SE_Hate2 192 // implemented +#define SE_Hate 192 // implemented - Instant and hate over time. #define SE_SkillAttack 193 // implemented #define SE_FadingMemories 194 // implemented #define SE_StunResist 195 // implemented diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 6f71a56eb..e32170e67 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2676,6 +2676,30 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } + case SE_Hate:{ + + if (buffslot >= 0) + break; + + if(caster){ + if(effect_value > 0){ + if(caster){ + if(caster->IsClient() && !caster->CastToClient()->GetFeigned()) + AddToHateList(caster, effect_value); + else if(!caster->IsClient()) + AddToHateList(caster, effect_value); + } + }else{ + int32 newhate = GetHateAmount(caster) + effect_value; + if (newhate < 1) + SetHate(caster,1); + else + SetHate(caster,newhate); + } + } + break; + } + // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: @@ -2746,7 +2770,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_ChangeFrenzyRad: case SE_Harmony: case SE_ChangeAggro: - case SE_Hate2: case SE_Identify: case SE_InstantHate: case SE_ReduceHate: @@ -3340,7 +3363,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste break; } - case SE_Hate2:{ + case SE_Hate:{ effect_value = CalcSpellEffectValue(spell_id, i, caster_level); if(caster){ if(effect_value > 0){ From 677ba36d5586bf7e9fd62d7715398153023ca5bb Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 25 Jun 2014 14:31:35 -0400 Subject: [PATCH 02/19] Updated SE_FadingMemories - Base value will be properly utilized to set % chance for fade effect to work. --- changelog.txt | 1 + zone/spell_effects.cpp | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 97a68ad24..9b890da6a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. +Kayen: Updated SE_FadingMemories - Base value will be properly utilized to set % chance for fade effect to work. == 06/17/2014 == Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index e32170e67..5861d31e6 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2183,12 +2183,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Fading Memories"); #endif - if(caster && caster->IsClient()) - caster->CastToClient()->Escape(); - else - { - entity_list.RemoveFromTargets(caster); - SetInvisible(1); + if(MakeRandomInt(0, 99) < spells[spell_id].base[i] ) { + + if(caster && caster->IsClient()) + caster->CastToClient()->Escape(); + else + { + entity_list.RemoveFromTargets(caster); + SetInvisible(1); + } } break; } From 02e780025db4eefae0b3b4c0eedd641ed1f6517d Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 25 Jun 2014 14:41:15 -0400 Subject: [PATCH 03/19] Implemented SE_StrikeThough (Was incorrectly defined as implemented previously) - Works same as item bonus. --- common/spdat.h | 2 +- zone/bonuses.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/common/spdat.h b/common/spdat.h index fd9ba923f..f4883552b 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -343,7 +343,7 @@ typedef enum { #define SE_SkillAttack 193 // implemented #define SE_FadingMemories 194 // implemented #define SE_StunResist 195 // implemented -#define SE_Strikethrough 196 // implemented +#define SE_StrikeThrough 196 // implemented #define SE_SkillDamageTaken 197 // implemented #define SE_CurrentEnduranceOnce 198 // implemented #define SE_Taunt 199 // implemented - % chance to taunt the target diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 3ce6becca..f46328ea6 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -953,6 +953,8 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) case SE_BlockBehind: newbon->BlockBehind += base1; break; + + case SE_StrikeThrough: case SE_StrikeThrough2: newbon->StrikeThrough += base1; break; @@ -2469,6 +2471,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->SecondaryDmgInc = true; break; + case SE_StrikeThrough: case SE_StrikeThrough2: newbon->StrikeThrough += effect_value; break; @@ -3909,6 +3912,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.SecondaryDmgInc = false; break; + case SE_StrikeThrough: + spellbonuses.StrikeThrough = effect_value; + aabonuses.StrikeThrough = effect_value; + itembonuses.StrikeThrough = effect_value; + break; + case SE_StrikeThrough2: spellbonuses.StrikeThrough = effect_value; aabonuses.StrikeThrough = effect_value; From 2a48b199d2901aacf68dbaed4441609432e8c37b Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 25 Jun 2014 15:25:22 -0400 Subject: [PATCH 04/19] Update SE_Taunt - Limit value if present will now add instant hate. --- changelog.txt | 2 ++ zone/spell_effects.cpp | 25 ++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9b890da6a..5a77ec900 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. Kayen: Updated SE_FadingMemories - Base value will be properly utilized to set % chance for fade effect to work. +Kayen: Implemented SE_StrikeThough (Was incorrectly defined as implemented previously) - Works same as item bonus. +Kayen: Update SE_Taunt - Limit value if present will now add instant hate. == 06/17/2014 == Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 5861d31e6..b073b65e2 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2646,9 +2646,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_Taunt: { - if (IsNPC()) + if (IsNPC()){ caster->Taunt(this->CastToNPC(), false, spell.base[i]); - + + if (spell.base2[i] > 0) + CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i])); + } break; } @@ -2673,9 +2676,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_AddHatePct: { - if (IsNPC()) - CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100)); + if (IsNPC()){ + int32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100; + if (new_hate <= 0) + new_hate = 1; + CastToNPC()->SetHate(caster, new_hate); + } break; } @@ -3562,9 +3569,13 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste case SE_AddHateOverTimePct: { - if (IsNPC()) - CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100)); - + if (IsNPC()){ + int32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100; + if (new_hate <= 0) + new_hate = 1; + + CastToNPC()->SetHate(caster, new_hate); + } break; } From ec35c0d93328d6006bcb2a54726bc6746bf31138 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 26 Jun 2014 05:40:09 -0400 Subject: [PATCH 05/19] Implemented SE_MassGroupBuff as spell effect (no longer hard coded for AA only). Run required SQL to update AA tables. Updated spells_new field175 -> numhits_type --- changelog.txt | 4 ++++ common/spdat.h | 2 +- zone/AA.cpp | 5 ----- zone/AA.h | 2 +- zone/mob.cpp | 1 + zone/mob.h | 3 +++ zone/spell_effects.cpp | 10 +++++++++- zone/spells.cpp | 6 +++--- 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/changelog.txt b/changelog.txt index 5a77ec900..991ffbba5 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,10 @@ Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant Kayen: Updated SE_FadingMemories - Base value will be properly utilized to set % chance for fade effect to work. Kayen: Implemented SE_StrikeThough (Was incorrectly defined as implemented previously) - Works same as item bonus. Kayen: Update SE_Taunt - Limit value if present will now add instant hate. +Kayen: Implemented SE_MassGroupBuff - Allows next group buff cast to be a MGB (AA now uses this) + +Required SQL: utils/sql/git/required/2014_06_25_MGB_AA.sql + == 06/17/2014 == Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. diff --git a/common/spdat.h b/common/spdat.h index f4883552b..956d40b31 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -350,7 +350,7 @@ typedef enum { #define SE_ProcChance 200 // implemented #define SE_RangedProc 201 // implemented //#define SE_IllusionOther 202 // *not implemented as bonus(Project Illusion) -//#define SE_MassGroupBuff 203 // *not implemented as bonus +#define SE_MassGroupBuff 203 // implemented #define SE_GroupFearImmunity 204 // *not implemented as bonus #define SE_Rampage 205 // implemented #define SE_AETaunt 206 // implemented diff --git a/zone/AA.cpp b/zone/AA.cpp index 8566c09b5..bd1e568b3 100644 --- a/zone/AA.cpp +++ b/zone/AA.cpp @@ -352,11 +352,6 @@ void Client::HandleAAAction(aaID activate) { entity_list.AETaunt(this); break; - case aaActionMassBuff: - EnableAAEffect(aaEffectMassGroupBuff, 3600); - Message_StringID(MT_Disciplines, MGB_STRING); //The next group buff you cast will hit all targets in range. - break; - case aaActionFlamingArrows: //toggle it if(CheckAAEffect(aaEffectFlamingArrows)) diff --git a/zone/AA.h b/zone/AA.h index ccdddf317..36cc886af 100644 --- a/zone/AA.h +++ b/zone/AA.h @@ -43,7 +43,7 @@ typedef enum { //use these for AAs which dont cast spells, yet need effects //if this list grows beyond 32, more work is needed in *AAEffect typedef enum { //AA Effect IDs - aaEffectMassGroupBuff = 1, + aaEffectMassGroupBuff = 1, //unused - Handled via spell effect. aaEffectRampage, aaEffectSharedHealth, aaEffectFlamingArrows, diff --git a/zone/mob.cpp b/zone/mob.cpp index 138c159cd..e10a1aeb1 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -180,6 +180,7 @@ Mob::Mob(const char* in_name, trackable = true; has_shieldequiped = false; has_numhits = false; + has_MGB = false; if(in_aa_title>0) aa_title = in_aa_title; diff --git a/zone/mob.h b/zone/mob.h index 4ab9d8a84..599fa3b69 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -268,6 +268,8 @@ public: void CheckNumHitsRemaining(uint8 type, uint32 buff_slot=0, uint16 spell_id=SPELL_UNKNOWN); bool HasNumhits() const { return has_numhits; } inline void Numhits(bool val) { has_numhits = val; } + bool HasMGB() const { return has_MGB; } + inline void SetMGB(bool val) { has_MGB = val; } void SpreadVirus(uint16 spell_id, uint16 casterID); bool IsNimbusEffectActive(uint32 nimbus_effect); void SetNimbusEffect(uint32 nimbus_effect); @@ -1097,6 +1099,7 @@ protected: bool offhand; bool has_shieldequiped; bool has_numhits; + bool has_MGB; // Bind wound Timer bindwound_timer; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index b073b65e2..35e8ecf66 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2710,6 +2710,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } + case SE_MassGroupBuff:{ + + SetMGB(true); + Message_StringID(MT_Disciplines, MGB_STRING); + break; + } + // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: @@ -2864,7 +2871,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_ACv2: case SE_ManaRegen_v2: case SE_FcDamagePctCrit: - case SE_FcHealAmt: + case SE_FcHealAmt: case SE_FcHealPctIncoming: case SE_CriticalHealDecay: case SE_CriticalRegenDecay: @@ -2878,6 +2885,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_PetCriticalHit: case SE_SlayUndead: case SE_GiveDoubleAttack: + case SE_StrikeThrough: case SE_StrikeThrough2: case SE_SecondaryDmgInc: case SE_ArcheryDamageModifier: diff --git a/zone/spells.cpp b/zone/spells.cpp index 32140849b..041f13fce 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -399,7 +399,7 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot, mana_cost = GetActSpellCost(spell_id, mana_cost); } - if(IsClient() && CastToClient()->CheckAAEffect(aaEffectMassGroupBuff) && spells[spell_id].can_mgb) + if(HasMGB() && spells[spell_id].can_mgb) mana_cost *= 2; // mana is checked for clients on the frontend. we need to recheck it for NPCs though @@ -1969,11 +1969,11 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 } #endif //BOTS - if(spells[spell_id].can_mgb && IsClient() && CastToClient()->CheckAAEffect(aaEffectMassGroupBuff)) + if(spells[spell_id].can_mgb && HasMGB()) { SpellOnTarget(spell_id, this); entity_list.MassGroupBuff(this, this, spell_id, true); - CastToClient()->DisableAAEffect(aaEffectMassGroupBuff); + SetMGB(false); } else { From 87e7b9c3f0ee8418494c7f44c9e3a9378cbf42f5 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 26 Jun 2014 06:23:27 -0400 Subject: [PATCH 06/19] Implemented SE_IllusionOther - Allows next Illusion buff (self only) cast to be cast on target. (AA ProjectIllusion now uses this) Run required SLQ to update AA. --- changelog.txt | 1 + common/spdat.h | 2 +- utils/sql/git/required/2014_06_25_AA_Updates..sql | 10 ++++++++++ zone/AA.cpp | 6 ------ zone/AA.h | 2 +- zone/mob.cpp | 1 + zone/mob.h | 3 +++ zone/spell_effects.cpp | 6 ++++++ zone/spells.cpp | 8 ++++---- 9 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 utils/sql/git/required/2014_06_25_AA_Updates..sql diff --git a/changelog.txt b/changelog.txt index 991ffbba5..d54a8d52d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,7 @@ Kayen: Updated SE_FadingMemories - Base value will be properly utilized to set % Kayen: Implemented SE_StrikeThough (Was incorrectly defined as implemented previously) - Works same as item bonus. Kayen: Update SE_Taunt - Limit value if present will now add instant hate. Kayen: Implemented SE_MassGroupBuff - Allows next group buff cast to be a MGB (AA now uses this) +Kayen: Implemented SE_IllusionOther - Allows next Illusion buff (self only) cast to be cast on target. (AA now uses this) Required SQL: utils/sql/git/required/2014_06_25_MGB_AA.sql diff --git a/common/spdat.h b/common/spdat.h index 956d40b31..ea4218ff1 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -349,7 +349,7 @@ typedef enum { #define SE_Taunt 199 // implemented - % chance to taunt the target #define SE_ProcChance 200 // implemented #define SE_RangedProc 201 // implemented -//#define SE_IllusionOther 202 // *not implemented as bonus(Project Illusion) +#define SE_IllusionOther 202 // implemented - Project Illusion #define SE_MassGroupBuff 203 // implemented #define SE_GroupFearImmunity 204 // *not implemented as bonus #define SE_Rampage 205 // implemented diff --git a/utils/sql/git/required/2014_06_25_AA_Updates..sql b/utils/sql/git/required/2014_06_25_AA_Updates..sql new file mode 100644 index 000000000..2e2b7579f --- /dev/null +++ b/utils/sql/git/required/2014_06_25_AA_Updates..sql @@ -0,0 +1,10 @@ +-- AA MGB update +UPDATE altadv_vars SET spellid = 5228 WHERE skill_id = 128; +UPDATE aa_actions SET spell_id = 5228, nonspell_action = 0 WHERE aaid = 128; + +-- AA Project Illusion update +UPDATE altadv_vars SET spellid = 5227 WHERE skill_id = 643; +UPDATE aa_actions SET spell_id = 5227, nonspell_action = 0 WHERE aaid = 643; + +-- spells_new update +ALTER TABLE `spells_new` CHANGE `field175` `numhits_type` INT(11) NOT NULL DEFAULT '0'; \ No newline at end of file diff --git a/zone/AA.cpp b/zone/AA.cpp index bd1e568b3..6e5569c3c 100644 --- a/zone/AA.cpp +++ b/zone/AA.cpp @@ -454,12 +454,6 @@ void Client::HandleAAAction(aaID activate) { } break; - case aaActionProjectIllusion: - EnableAAEffect(aaEffectProjectIllusion, 3600); - Message(10, "The power of your next illusion spell will flow to your grouped target in your place."); - break; - - case aaActionEscape: Escape(); break; diff --git a/zone/AA.h b/zone/AA.h index 36cc886af..3adc887e3 100644 --- a/zone/AA.h +++ b/zone/AA.h @@ -50,7 +50,7 @@ typedef enum { //AA Effect IDs aaEffectFrostArrows, aaEffectWarcry, aaEffectLeechTouch, - aaEffectProjectIllusion // seveian 2008-09-23 + aaEffectProjectIllusion // unused - Handled via spell effect } aaEffectType; diff --git a/zone/mob.cpp b/zone/mob.cpp index e10a1aeb1..ed2072e21 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -181,6 +181,7 @@ Mob::Mob(const char* in_name, has_shieldequiped = false; has_numhits = false; has_MGB = false; + has_ProjectIllusion = false; if(in_aa_title>0) aa_title = in_aa_title; diff --git a/zone/mob.h b/zone/mob.h index 599fa3b69..61a2220d6 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -270,6 +270,8 @@ public: inline void Numhits(bool val) { has_numhits = val; } bool HasMGB() const { return has_MGB; } inline void SetMGB(bool val) { has_MGB = val; } + bool HasProjectIllusion() const { return has_ProjectIllusion ; } + inline void SetProjectIllusion(bool val) { has_ProjectIllusion = val; } void SpreadVirus(uint16 spell_id, uint16 casterID); bool IsNimbusEffectActive(uint32 nimbus_effect); void SetNimbusEffect(uint32 nimbus_effect); @@ -1100,6 +1102,7 @@ protected: bool has_shieldequiped; bool has_numhits; bool has_MGB; + bool has_ProjectIllusion; // Bind wound Timer bindwound_timer; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 35e8ecf66..635fc9270 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2717,6 +2717,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } + case SE_IllusionOther: { + SetProjectIllusion(true); + Message(10, "The power of your next illusion spell will flow to your grouped target in your place."); + break; + } + // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: diff --git a/zone/spells.cpp b/zone/spells.cpp index 041f13fce..78dce3379 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1371,7 +1371,7 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce && IsClient() && (IsGrouped() // still self only if not grouped || IsRaidGrouped()) - && CastToClient()->CheckAAEffect(aaEffectProjectIllusion)){ + && (HasProjectIllusion())){ mlog(AA__MESSAGE, "Project Illusion overwrote target caster: %s spell id: %d was ON", GetName(), spell_id); targetType = ST_GroupClientAndPet; } @@ -1853,7 +1853,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 range = GetActSpellRange(spell_id, range); if(IsPlayerIllusionSpell(spell_id) && IsClient() - && CastToClient()->CheckAAEffect(aaEffectProjectIllusion)){ + && (HasProjectIllusion())){ range = 100; } if(spell_target != nullptr && spell_target != this) { @@ -1912,9 +1912,9 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 if(IsPlayerIllusionSpell(spell_id) && IsClient() - && CastToClient()->CheckAAEffect(aaEffectProjectIllusion)){ + && (HasProjectIllusion())){ mlog(AA__MESSAGE, "Effect Project Illusion for %s on spell id: %d was ON", GetName(), spell_id); - CastToClient()->DisableAAEffect(aaEffectProjectIllusion); + SetProjectIllusion(false); } else{ mlog(AA__MESSAGE, "Effect Project Illusion for %s on spell id: %d was OFF", GetName(), spell_id); From a573e840dbed1b53248b6fd8f2236a7625af5ce4 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 26 Jun 2014 06:45:18 -0400 Subject: [PATCH 07/19] changelog fix --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index d54a8d52d..a2d099bab 100644 --- a/changelog.txt +++ b/changelog.txt @@ -9,7 +9,7 @@ Kayen: Update SE_Taunt - Limit value if present will now add instant hate. Kayen: Implemented SE_MassGroupBuff - Allows next group buff cast to be a MGB (AA now uses this) Kayen: Implemented SE_IllusionOther - Allows next Illusion buff (self only) cast to be cast on target. (AA now uses this) -Required SQL: utils/sql/git/required/2014_06_25_MGB_AA.sql +Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql == 06/17/2014 == From 1867088e1a023ff24aa7bc349377485c16f60243 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 26 Jun 2014 10:04:21 -0400 Subject: [PATCH 08/19] Update SE_AETaunt - Base value will now determine AE taunt range (This will not result in any change to currently used spells). --- changelog.txt | 1 + common/spdat.h | 4 ++-- zone/spell_effects.cpp | 9 +++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index a2d099bab..a177460ee 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,7 @@ Kayen: Implemented SE_StrikeThough (Was incorrectly defined as implemented previ Kayen: Update SE_Taunt - Limit value if present will now add instant hate. Kayen: Implemented SE_MassGroupBuff - Allows next group buff cast to be a MGB (AA now uses this) Kayen: Implemented SE_IllusionOther - Allows next Illusion buff (self only) cast to be cast on target. (AA now uses this) +Kayen: Update SE_AETaunt - Base value will now determine AE taunt range (This will not result in any change to currently used spells). Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql diff --git a/common/spdat.h b/common/spdat.h index ea4218ff1..7773a95c4 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -237,7 +237,7 @@ typedef enum { #define SE_MagnifyVision 87 // implemented - Telescope #define SE_Succor 88 // implemented - Evacuate/Succor lines #define SE_ModelSize 89 // implemented - Shrink, Growth -#define SE_Cloak 90 // *not implemented - Used in only 2 spells +//#define SE_Cloak 90 // *not implemented - Used in only 2 spells #define SE_SummonCorpse 91 // implemented #define SE_InstantHate 92 // implemented - add hate #define SE_StopRain 93 // implemented - Wake of Karana @@ -351,7 +351,7 @@ typedef enum { #define SE_RangedProc 201 // implemented #define SE_IllusionOther 202 // implemented - Project Illusion #define SE_MassGroupBuff 203 // implemented -#define SE_GroupFearImmunity 204 // *not implemented as bonus +#define SE_GroupFearImmunity 204 // implemented - (Does not use bonus) #define SE_Rampage 205 // implemented #define SE_AETaunt 206 // implemented #define SE_FleshToBone 207 // implemented diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 635fc9270..f2587a0d3 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2237,8 +2237,13 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "AE Taunt"); #endif - if(caster && caster->IsClient()) - entity_list.AETaunt(caster->CastToClient()); + if(caster && caster->IsClient()){ + float range = 0.0f; + if (spells[spell_id].base2[i]) + range = (float)spells[spell_id].base[i]; + + entity_list.AETaunt(caster->CastToClient(), range); + } break; } From 2fb95b00a5895101835f4597afb95ee66913d8f9 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 26 Jun 2014 10:54:18 -0400 Subject: [PATCH 09/19] Slight change to TryDispel formula for better accuracy. Live PATCH 5-20-14 Note: "Updated all spells which use Remove Detrimental and Cancel Beneficial spell effects to use a new method. The chances for those spells to affect their targets have not changed unless otherwise noted" Support added for new base values to give a nearly equivelent result. (Ie. Will work for values pre and post change) --- zone/spell_effects.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f2587a0d3..e3fb89d6f 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -5798,16 +5798,25 @@ uint16 Mob::GetSpellEffectResistChance(uint16 spell_id) bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ + /*Live 5-20-14 Patch Note: Updated all spells which use Remove Detrimental and + Cancel Beneficial spell effects to use a new method. The chances for those spells to + affect their targets have not changed unless otherwise noted.*/ + + /*This should provide a somewhat accurate conversion between pre 5/14 base values and post. + until more information is avialble - Kayen*/ + if (level_modifier > 100) + level_modifier = level_modifier/100; + //Dispels - Check level of caster agianst buffs level (level of the caster who cast the buff) //Effect value of dispels are treated as a level modifier. //Values for scaling were obtain from live parses, best estimates. caster_level += level_modifier - 1; - int dispel_chance = 36; //Baseline chance if no level difference and no modifier + int dispel_chance = 32; //Baseline chance if no level difference and no modifier int level_diff = caster_level - buff_level; if (level_diff > 0) - dispel_chance += level_diff * 8; + dispel_chance += level_diff * 7; else if (level_diff < 0) dispel_chance += level_diff * 2; From ce2a79b63ed4b5714ba959f6dc3d392274076122 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Fri, 27 Jun 2014 20:55:17 -0400 Subject: [PATCH 10/19] Udpated SE_ReclaimPet - Correct forumla for mana returned to properly return 75% of actual pet spell mana cost. Implemented SE_ImprovedReclaimEnergy - Modifies % mana returned from SE_ReclaimPet. Required SQL update. --- changelog.txt | 2 ++ common/spdat.h | 6 +++--- .../git/required/2014_06_25_AA_Updates..sql | 3 +++ zone/bonuses.cpp | 19 +++++++++++++++++ zone/client_mods.cpp | 2 +- zone/common.h | 1 + zone/spell_effects.cpp | 21 ++++++++++++------- 7 files changed, 43 insertions(+), 11 deletions(-) diff --git a/changelog.txt b/changelog.txt index a177460ee..e02571f44 100644 --- a/changelog.txt +++ b/changelog.txt @@ -9,6 +9,8 @@ Kayen: Update SE_Taunt - Limit value if present will now add instant hate. Kayen: Implemented SE_MassGroupBuff - Allows next group buff cast to be a MGB (AA now uses this) Kayen: Implemented SE_IllusionOther - Allows next Illusion buff (self only) cast to be cast on target. (AA now uses this) Kayen: Update SE_AETaunt - Base value will now determine AE taunt range (This will not result in any change to currently used spells). +Kayen: Udpated SE_ReclaimPet - Correct forumla for mana returned to properly return 75% of actual pet spell mana cost. +Kayen: Implemented SE_ImprovedReclaimEnergy - Modifies % mana returned from SE_ReclaimPet. Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql diff --git a/common/spdat.h b/common/spdat.h index 7773a95c4..bb3951019 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -358,7 +358,7 @@ typedef enum { //#define SE_PurgePoison 208 // not used #define SE_DispelBeneficial 209 // implemented //#define SE_PetShield 210 // *not implemented -#define SE_AEMelee 211 // implemented +#define SE_AEMelee 211 // implemented TO DO: Implement to allow NPC use (client only atm). #define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana. #define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet #define SE_MaxHPChange 214 // implemented @@ -375,7 +375,7 @@ typedef enum { #define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance. #define SE_TwoHandBash 226 // *not implemented as bonus #define SE_ReduceSkillTimer 227 // implemented -#define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling +//#define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling #define SE_PersistantCasting 229 // implemented //#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability #define SE_StunBashChance 231 // implemented - increase chance to stun from bash. @@ -388,7 +388,7 @@ typedef enum { //#define SE_IllusionPersistence 238 // *not implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed. //#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. //#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.] -#define SE_ImprovedReclaimEnergy 241 // not implemented as bonus - increase the amount of mana returned to you when reclaiming your pet. +#define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet. #define SE_IncreaseChanceMemwipe 242 // implemented - increases the chance to wipe hate with memory blurr #define SE_CharmBreakChance 243 // implemented - Total Domination #define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break. diff --git a/utils/sql/git/required/2014_06_25_AA_Updates..sql b/utils/sql/git/required/2014_06_25_AA_Updates..sql index 2e2b7579f..13522e93c 100644 --- a/utils/sql/git/required/2014_06_25_AA_Updates..sql +++ b/utils/sql/git/required/2014_06_25_AA_Updates..sql @@ -6,5 +6,8 @@ UPDATE aa_actions SET spell_id = 5228, nonspell_action = 0 WHERE aaid = 128; UPDATE altadv_vars SET spellid = 5227 WHERE skill_id = 643; UPDATE aa_actions SET spell_id = 5227, nonspell_action = 0 WHERE aaid = 643; +-- AA Improved Reclaim Energy +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('180', '1', '241', '95', '0'); + -- spells_new update ALTER TABLE `spells_new` CHANGE `field175` `numhits_type` INT(11) NOT NULL DEFAULT '0'; \ No newline at end of file diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index f46328ea6..be847b280 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1270,6 +1270,15 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->Metabolism += base1; break; + case SE_ImprovedReclaimEnergy: + { + if((base1 < 0) && (newbon->ImprovedReclaimEnergy > base1)) + newbon->ImprovedReclaimEnergy = base1; + + else if(newbon->ImprovedReclaimEnergy < base1) + newbon->ImprovedReclaimEnergy = base1; + break; + } } } } @@ -2741,6 +2750,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->Metabolism += effect_value; break; + case SE_ImprovedReclaimEnergy: + { + if((effect_value < 0) && (newbon->ImprovedReclaimEnergy > effect_value)) + newbon->ImprovedReclaimEnergy = effect_value; + + else if(newbon->ImprovedReclaimEnergy < effect_value) + newbon->ImprovedReclaimEnergy = effect_value; + break; + } + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 955a29d38..7ffc1e797 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -1177,7 +1177,7 @@ uint32 Client::CalcCurrentWeight() { Total += (m_pp.platinum + m_pp.gold + m_pp.silver + m_pp.copper) / 4; } - float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat; + float Packrat = (float)spellbonuses.Packrat + (float)aabonuses.Packrat + (float)itembonuses.Packrat; if (Packrat > 0) Total = (uint32)((float)Total * (1.0f - ((Packrat * 1.0f) / 100.0f))); //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same % //without casting to float & back to uint32, this didn't work right diff --git a/zone/common.h b/zone/common.h index a8e8a17c9..421474eec 100644 --- a/zone/common.h +++ b/zone/common.h @@ -422,6 +422,7 @@ struct StatBonuses { int8 StunBashChance; // chance to stun with bash. int8 IncreaseChanceMemwipe; // increases chance to memory wipe int8 CriticalMend; // chance critical monk mend + int16 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy }; typedef struct diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index e3fb89d6f..8eab0b329 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1551,15 +1551,22 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) GetPetType() != petCharmed ) { - int lvlmod = 4; - if(caster->IsClient() && caster->CastToClient()->GetAA(aaImprovedReclaimEnergy)) - lvlmod = 8; //this is an unconfirmed number, I made it up - if(caster->IsClient() && caster->CastToClient()->GetAA(aaImprovedReclaimEnergy2)) - lvlmod = 8; //this is an unconfirmed number, I made it up - caster->SetMana(caster->GetMana()+(GetLevel()*lvlmod)); + uint16 pet_spellid = CastToNPC()->GetPetSpellID(); + uint16 pet_ActSpellCost = caster->GetActSpellCost(pet_spellid, spells[pet_spellid].mana); + int16 ImprovedReclaimMod = caster->spellbonuses.ImprovedReclaimEnergy + + caster->itembonuses.ImprovedReclaimEnergy + + caster->aabonuses.ImprovedReclaimEnergy; + + if (!ImprovedReclaimMod) + ImprovedReclaimMod = 75; //Reclaim Energy default is 75% of actual mana cost + + pet_ActSpellCost = pet_ActSpellCost*ImprovedReclaimMod/100; + + caster->SetMana(caster->GetMana() + pet_ActSpellCost); if(caster->IsClient()) caster->CastToClient()->SetPet(0); + SetOwnerID(0); // this will kill the pet } break; @@ -5804,7 +5811,7 @@ bool Mob::TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier){ /*This should provide a somewhat accurate conversion between pre 5/14 base values and post. until more information is avialble - Kayen*/ - if (level_modifier > 100) + if (level_modifier >= 100) level_modifier = level_modifier/100; //Dispels - Check level of caster agianst buffs level (level of the caster who cast the buff) From 8a92fada5af82afdfcf2f3c72907bf86dc923fd3 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 29 Jun 2014 01:10:19 -0400 Subject: [PATCH 11/19] Implemented SE_HeadShot, SE_HeadShotLevel - Defines headshot damage and level requirements. Revised HeadShot mechanic so damage now recieves all archery bonuses, proc chance can be set to either (lives new Proc Per minute system, or flat chance based on dex (formula updated). Required SQL for AA data Optional SQL for rules --- changelog.txt | 4 + common/ruletypes.h | 2 + common/spdat.h | 8 +- .../git/optional/2014_06_29_HeadShotRules.sql | 2 + .../git/required/2014_06_25_AA_Updates..sql | 4 + zone/bonuses.cpp | 73 ++++++++++++- zone/client_mods.cpp | 2 +- zone/common.h | 7 +- zone/mob.h | 3 +- zone/special_attacks.cpp | 101 ++++++++++++++---- zone/spell_effects.cpp | 2 + 11 files changed, 176 insertions(+), 32 deletions(-) create mode 100644 utils/sql/git/optional/2014_06_29_HeadShotRules.sql diff --git a/changelog.txt b/changelog.txt index e02571f44..43c045ce8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -11,8 +11,12 @@ Kayen: Implemented SE_IllusionOther - Allows next Illusion buff (self only) cast Kayen: Update SE_AETaunt - Base value will now determine AE taunt range (This will not result in any change to currently used spells). Kayen: Udpated SE_ReclaimPet - Correct forumla for mana returned to properly return 75% of actual pet spell mana cost. Kayen: Implemented SE_ImprovedReclaimEnergy - Modifies % mana returned from SE_ReclaimPet. +Kayen: Implemented SE_HeadShot, SE_HeadShotLevel - Defines headshot damage and level requirements. +Revised HeadShot mechanic so damage now recieves all archery bonuses, proc chance can be set to either (lives new Proc Per minute +system, or flat chance based on dex (formula updated). Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql +Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql == 06/17/2014 == diff --git a/common/ruletypes.h b/common/ruletypes.h index 70e4ba0d2..6f5fe0769 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -333,6 +333,8 @@ RULE_REAL ( Combat, AvgProcsPerMinute, 2.0) RULE_REAL ( Combat, ProcPerMinDexContrib, 0.075) RULE_REAL ( Combat, BaseProcChance, 0.035) RULE_REAL ( Combat, ProcDexDivideBy, 11000) +RULE_BOOL ( Combat, AdjustSpecialProcPerMinute, true) //Set PPM for special abilities like HeadShot (Live does this as of 4-14) +RULE_REAL ( Combat, AvgSpecialProcsPerMinute, 2.0) //Unclear what best value is atm. RULE_REAL ( Combat, BaseHitChance, 69.0) RULE_REAL ( Combat, NPCBonusHitChance, 26.0) RULE_REAL ( Combat, HitFalloffMinor, 5.0) //hit will fall off up to 5% over the initial level range diff --git a/common/spdat.h b/common/spdat.h index bb3951019..65bb9f692 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -364,7 +364,7 @@ typedef enum { #define SE_MaxHPChange 214 // implemented #define SE_PetAvoidance 215 // implemented[AA] - increases pet ability to avoid melee damage #define SE_Accuracy 216 // implemented -//#define SE_HeadShot 217 // not implemented as bonus - ability to head shot (base2 = damage) +#define SE_HeadShot 217 // implemented - ability to head shot (base2 = damage) #define SE_PetCriticalHit 218 // implemented[AA] - gives pets a baseline critical hit chance #define SE_SlayUndead 219 // implemented - Allow extra damage against undead (base1 = rate, base2 = damage mod). #define SE_SkillDamageAmount 220 // implemented @@ -492,8 +492,8 @@ typedef enum { #define SE_ImmuneFleeing 342 // implemented - stop mob from fleeing #define SE_InterruptCasting 343 // implemented - % chance to interrupt spells being cast every tic. Cacophony (8272) #define SE_ChannelChanceItems 344 // implemented[AA] - chance to not have ITEM effects interrupted when you take damage. -//#define SE_AssassinationLevel 345 // not implemented as bonus - AA Assisination max level to kill -//#define SE_HeadShotLevel 346 // not implemented as bonus - AA HeadShot max level to kill +#define SE_AssassinateLevel 345 // implemented as bonus - AA Assisination max level to kill +#define SE_HeadShotLevel 346 // implemented[AA] - HeadShot max level to kill #define SE_DoubleRangedAttack 347 // implemented - chance at an additional archery attack (consumes arrow) #define SE_LimitManaMin 348 // implemented #define SE_ShieldEquipHateMod 349 // implemented[AA] Increase melee hate when wearing a shield. @@ -586,7 +586,7 @@ typedef enum { //#define SE_BeneficialCountDownHold 436 // not used ( 23491 | ABTest Buff Hold) //#define SE_TeleporttoAnchor 437 // *not implemented - Teleport Guild Hall Anchor(33099) //#define SE_TranslocatetoAnchor 438 // *not implemented - Translocate Primary Anchor (27750) -//#define SE_IncreaseAssassinationLvl 439 // *not implemented[AA] - increases the maximum level of humanoid that can be affected by assassination +#define SE_Assassinate 439 // implemented[AA] - Assassinate damage #define SE_FinishingBlowLvl 440 // implemented[AA] - Sets the level Finishing blow can be triggered on an NPC #define SE_DistanceRemoval 441 // implemented - Buff is removed from target when target moves X amount of distance away from where initially hit. #define SE_TriggerOnReqTarget 442 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) diff --git a/utils/sql/git/optional/2014_06_29_HeadShotRules.sql b/utils/sql/git/optional/2014_06_29_HeadShotRules.sql new file mode 100644 index 000000000..ad3de19b6 --- /dev/null +++ b/utils/sql/git/optional/2014_06_29_HeadShotRules.sql @@ -0,0 +1,2 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:AdjustSpecialProcPerMinute', 'false', 'Allow PPM for special abilities HeadShot, Assassinate, Decap ect.'); +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Combat:AvgSpecialProcsPerMinute', '2.0', 'Set PPM for special abilities HeadShot, Assassinate, Decap ect. (Unknown what value live uses) .'); \ No newline at end of file diff --git a/utils/sql/git/required/2014_06_25_AA_Updates..sql b/utils/sql/git/required/2014_06_25_AA_Updates..sql index 13522e93c..c9ae42237 100644 --- a/utils/sql/git/required/2014_06_25_AA_Updates..sql +++ b/utils/sql/git/required/2014_06_25_AA_Updates..sql @@ -9,5 +9,9 @@ UPDATE aa_actions SET spell_id = 5227, nonspell_action = 0 WHERE aaid = 643; -- AA Improved Reclaim Energy INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('180', '1', '241', '95', '0'); +-- AA Headshot +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '1', '217', '0', '32000'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '2', '346', '46', '0'); + -- spells_new update ALTER TABLE `spells_new` CHANGE `field175` `numhits_type` INT(11) NOT NULL DEFAULT '0'; \ No newline at end of file diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index be847b280..345f602f8 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -637,7 +637,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) continue; _log(AA__BONUSES, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName()); - + uint8 focus = IsFocusEffect(0, 0, true,effect); if (focus) { @@ -1279,6 +1279,23 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->ImprovedReclaimEnergy = base1; break; } + + case SE_HeadShot: + { + if(newbon->HeadShot[1] < base2){ + newbon->HeadShot[0] = base1; + newbon->HeadShot[1] = base2; + } + break; + } + + case SE_HeadShotLevel: + { + if(newbon->HSLevel < base1) + newbon->HSLevel = base1; + break; + } + } } } @@ -2760,6 +2777,38 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_HeadShot: + { + if(newbon->HeadShot[1] < base2){ + newbon->HeadShot[0] = effect_value; + newbon->HeadShot[1] = base2; + } + break; + } + + case SE_HeadShotLevel: + { + if(newbon->HSLevel < effect_value) + newbon->HSLevel = effect_value; + break; + } + + case SE_Assassinate: + { + if(newbon->Assassinate[1] < base2){ + newbon->Assassinate[0] = effect_value; + newbon->Assassinate[1] = base2; + } + break; + } + + case SE_AssassinateLevel: + { + if(newbon->AssassinateLevel < effect_value) + newbon->AssassinateLevel = effect_value; + break; + } + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4173,7 +4222,27 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.Metabolism = effect_value; itembonuses.Metabolism = effect_value; break; - + + case SE_ImprovedReclaimEnergy: + spellbonuses.ImprovedReclaimEnergy = effect_value; + aabonuses.ImprovedReclaimEnergy = effect_value; + itembonuses.ImprovedReclaimEnergy = effect_value; + break; + + case SE_HeadShot: + spellbonuses.HeadShot[0] = effect_value; + aabonuses.HeadShot[0] = effect_value; + itembonuses.HeadShot[0] = effect_value; + spellbonuses.HeadShot[1] = effect_value; + aabonuses.HeadShot[1] = effect_value; + itembonuses.HeadShot[1] = effect_value; + break; + + case SE_HeadShotLevel: + spellbonuses.HSLevel = effect_value; + aabonuses.HSLevel = effect_value; + itembonuses.HSLevel = effect_value; + } } } diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 7ffc1e797..3bf2217cb 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -1864,7 +1864,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const break; } - effectmodcap += aabonuses.songModCap + spellbonuses.songModCap; + effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap; if (effectmod < 10) effectmod = 10; diff --git a/zone/common.h b/zone/common.h index 421474eec..95f1df783 100644 --- a/zone/common.h +++ b/zone/common.h @@ -422,7 +422,12 @@ struct StatBonuses { int8 StunBashChance; // chance to stun with bash. int8 IncreaseChanceMemwipe; // increases chance to memory wipe int8 CriticalMend; // chance critical monk mend - int16 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy + int16 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy + int32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg + uint8 HSLevel; // Max Level Headshot will be effective at. + int32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg + uint8 AssassinateLevel; // Max Level Assassinate will be effective at. + }; typedef struct diff --git a/zone/mob.h b/zone/mob.h index 61a2220d6..b5e21c932 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -141,7 +141,7 @@ public: virtual void TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts = nullptr); void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage); virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse); - virtual bool TryHeadShot(Mob* defender, SkillUseTypes skillInUse); + uint32 TryHeadShot(Mob* defender, SkillUseTypes skillInUse); virtual void DoRiposte(Mob* defender); void ApplyMeleeDamageBonus(uint16 skill, int32 &damage); virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr); @@ -991,6 +991,7 @@ protected: void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on); virtual float GetProcChances(float ProcBonus, uint16 weapon_speed = 30, uint16 hand = 13); virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13); + virtual float GetSpecialProcChances(uint16 hand = 13); int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item); int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr); int GetKickDamage(); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index f9f324b6d..55e919bc3 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -861,8 +861,12 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item } else { mlog(COMBAT__RANGED, "Ranged attack hit %s.", other->GetName()); - if(!TryHeadShot(other, SkillArchery)) - { + + bool HeadShot = false; + uint32 HeadShot_Dmg = TryHeadShot(other, SkillArchery); + if (HeadShot_Dmg) + HeadShot = true; + int32 TotalDmg = 0; int16 WDmg = 0; int16 ADmg = 0; @@ -882,6 +886,9 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item uint32 MaxDmg = (RuleR(Combat, ArcheryBaseDamageBonus)*(WDmg+ADmg)*GetDamageTable(SkillArchery)) / 100; int32 hate = ((WDmg+ADmg)); + if (HeadShot) + MaxDmg = HeadShot_Dmg; + uint16 bonusArcheryDamageModifier = aabonuses.ArcheryDamageModifier + itembonuses.ArcheryDamageModifier + spellbonuses.ArcheryDamageModifier; MaxDmg += MaxDmg*bonusArcheryDamageModifier / 100; @@ -938,7 +945,9 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item hate += (2*((GetLevel()-25)/3)); } - other->AvoidDamage(this, TotalDmg, false); + if (!HeadShot) + other->AvoidDamage(this, TotalDmg, false); + other->MeleeMitigation(this, TotalDmg, minDmg); if(TotalDmg > 0) { @@ -957,8 +966,11 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item else TotalDmg = -5; + if (HeadShot) + entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FATAL_BOW_SHOT, GetName()); + other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery); - } + } //try proc on hits and misses @@ -2074,30 +2086,73 @@ void Mob::InstillDoubt(Mob *who) { } } -bool Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { - bool Result = false; +uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { - if(defender && skillInUse == SkillArchery) { - if(GetAA(aaHeadshot) && defender->GetBodyType() == BT_Humanoid) { - if((GetLevelCon(GetLevel(), defender->GetLevel()) == CON_LIGHTBLUE || GetLevelCon(GetLevel(), defender->GetLevel()) == CON_GREEN) && defender->GetLevel() <= 60 && !defender->IsClient()) { - // WildcardX: These chance formula's below are arbitrary. If someone has a better formula that is more - // consistent with live, feel free to update these. - int AttackerChance = 20 + ((GetLevel() - 51) / 2) + (itembonuses.HeroicDEX / 10); - int DefenderChance = MakeRandomInt(0, 100); - if(AttackerChance > DefenderChance) { - mlog(COMBAT__ATTACKS, "Landed a headshot: Attacker chance was %f and Defender chance was %f.", AttackerChance, DefenderChance); - entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FATAL_BOW_SHOT, GetName()); - defender->Damage(this, 32000, SPELL_UNKNOWN, skillInUse); - Result = true; - } - else { - mlog(COMBAT__ATTACKS, "FAILED a headshot: Attacker chance was %f and Defender chance was %f.", AttackerChance, DefenderChance); - } + //Only works on YOUR target. + if(defender && (skillInUse == SkillArchery) && (GetTarget() == defender)) { + + int32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; + + uint8 HeadShot_Level = 0; //Get Highest Headshot Level + HeadShot_Level = aabonuses.HSLevel; + if (HeadShot_Level < spellbonuses.HSLevel) + HeadShot_Level = spellbonuses.HSLevel; + else if (HeadShot_Level < itembonuses.HSLevel) + HeadShot_Level = itembonuses.HSLevel; + + if(HeadShot_Dmg && defender->GetBodyType() == BT_Humanoid) { + if(HeadShot_Level && (defender->GetLevel() <= HeadShot_Level) && !defender->IsClient()){ + + float ProcChance = GetSpecialProcChances(11); + if(ProcChance > MakeRandomFloat(0,1)) + return HeadShot_Dmg; + } } } - return Result; + return 0; +} + +float Mob::GetSpecialProcChances(uint16 hand) +{ + int mydex = GetDEX(); + + if (mydex > 255) + mydex = 255; + + uint16 weapon_speed; + float ProcChance = 0.0f; + float ProcBonus = 0.0f; + + switch (hand) { + case 13: + weapon_speed = attack_timer.GetDuration(); + break; + case 14: + weapon_speed = attack_dw_timer.GetDuration(); + break; + case 11: + weapon_speed = ranged_timer.GetDuration(); + break; + } + + if (weapon_speed < RuleI(Combat, MinHastedDelay)) + weapon_speed = RuleI(Combat, MinHastedDelay); + + if (RuleB(Combat, AdjustSpecialProcPerMinute)) { + ProcChance = (static_cast(weapon_speed) * + RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); + ProcBonus += static_cast(mydex/35) + static_cast(itembonuses.HeroicDEX / 25); + ProcChance += ProcChance * ProcBonus / 100.0f; + } else { + /*PRE 2014 CHANGE Dev Quote - "Elidroth SOE:Proc chance is a function of your base hardcapped Dexterity / 35 + Heroic Dexterity / 25.” + Kayen: Most reports suggest a ~ 6% chance to Headshot which consistent with above.*/ + + ProcChance = (static_cast(mydex/35) + static_cast(itembonuses.HeroicDEX / 25))/100.0f; + } + + return ProcChance; } void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 8eab0b329..51979eddc 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2922,6 +2922,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_CombatStability: case SE_AddSingingMod: case SE_SongModCap: + case SE_HeadShot: + case SE_HeadShotLevel: case SE_PetAvoidance: case SE_GiveDoubleRiposte: case SE_Ambidexterity: From 70f10782b048fe3a7362c453307ba091ae0c281b Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 29 Jun 2014 23:26:22 -0400 Subject: [PATCH 12/19] Implemented SE_Assassinate, SE_AssassinateLevel - Defines assassinate damage and level requirements. Revised Assassinate mechanic so damage now receives all backstab bonuses, proc chance can be set to either (lives new Proc Per minute system, or flat chance based on dex (formula updated). Assassinate can now proc from THROW if behind target, various other adjustments. Required SQL for AA updates --- changelog.txt | 5 +- .../git/required/2014_06_25_AA_Updates..sql | 10 +- zone/bonuses.cpp | 16 ++ zone/common.h | 4 +- zone/mob.h | 6 +- zone/special_attacks.cpp | 263 ++++++++---------- 6 files changed, 157 insertions(+), 147 deletions(-) diff --git a/changelog.txt b/changelog.txt index 43c045ce8..53585d982 100644 --- a/changelog.txt +++ b/changelog.txt @@ -12,8 +12,11 @@ Kayen: Update SE_AETaunt - Base value will now determine AE taunt range (This wi Kayen: Udpated SE_ReclaimPet - Correct forumla for mana returned to properly return 75% of actual pet spell mana cost. Kayen: Implemented SE_ImprovedReclaimEnergy - Modifies % mana returned from SE_ReclaimPet. Kayen: Implemented SE_HeadShot, SE_HeadShotLevel - Defines headshot damage and level requirements. -Revised HeadShot mechanic so damage now recieves all archery bonuses, proc chance can be set to either (lives new Proc Per minute +Revised HeadShot mechanic so damage now receives all archery bonuses, proc chance can be set to either (lives new Proc Per minute system, or flat chance based on dex (formula updated). +Kayen: Implemented SE_Assassinate, SE_AssassinateLevel - Defines assassinate damage and level requirements. +Revised Assassinate mechanic so damage now receives all backstab bonuses, proc chance can be set to either (lives new Proc Per minute +system, or flat chance based on dex (formula updated). Assassinate can now proc from THROW if behind target, various other adjustments. Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql diff --git a/utils/sql/git/required/2014_06_25_AA_Updates..sql b/utils/sql/git/required/2014_06_25_AA_Updates..sql index c9ae42237..d51948af9 100644 --- a/utils/sql/git/required/2014_06_25_AA_Updates..sql +++ b/utils/sql/git/required/2014_06_25_AA_Updates..sql @@ -13,5 +13,11 @@ INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ( INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '1', '217', '0', '32000'); INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '2', '346', '46', '0'); --- spells_new update -ALTER TABLE `spells_new` CHANGE `field175` `numhits_type` INT(11) NOT NULL DEFAULT '0'; \ No newline at end of file +-- AA Anatomy (Rogue Assassinate) +INSERT INTO `altadv_vars` (`skill_id`, `name`, `cost`, `max_level`, `hotkey_sid`, `hotkey_sid2`, `title_sid`, `desc_sid`, `type`, `spellid`, `prereq_skill`, `prereq_minpoints`, `spell_type`, `spell_refresh`, `classes`, `berserker`, `class_type`, `cost_inc`, `aa_expansion`, `special_category`, `sof_type`, `sof_cost_inc`, `sof_max_level`, `sof_next_skill`, `clientver`, `account_time_required`, `sof_current_level`,`sof_next_id`,`level_inc`) VALUES ('1604', 'Anatomy', '5', '3', '4294967295', '4294967295', '1604', '1604', '1', '4294967295', '0', '0', '0', '0', '512', '0', '60', '1', '10', '4294967295', '3', '0', '3', '1604', '1', '0', '0', '0', '0'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '1', '439', '0', '32000'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '2', '345', '48', '0'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '1', '439', '0', '32000'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '2', '345', '51', '0'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '1', '439', '0', '32000'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '2', '345', '53', '0'); \ No newline at end of file diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 345f602f8..0871e3679 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1296,6 +1296,22 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_Assassinate: + { + if(newbon->Assassinate[1] < base2){ + newbon->Assassinate[0] = base1; + newbon->Assassinate[1] = base2; + } + break; + } + + case SE_AssassinateLevel: + { + if(newbon->AssassinateLevel < base1) + newbon->AssassinateLevel = base1; + break; + } + } } } diff --git a/zone/common.h b/zone/common.h index 95f1df783..6d6ae581f 100644 --- a/zone/common.h +++ b/zone/common.h @@ -423,9 +423,9 @@ struct StatBonuses { int8 IncreaseChanceMemwipe; // increases chance to memory wipe int8 CriticalMend; // chance critical monk mend int16 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy - int32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg + uint32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg uint8 HSLevel; // Max Level Headshot will be effective at. - int32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg + uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg uint8 AssassinateLevel; // Max Level Assassinate will be effective at. }; diff --git a/zone/mob.h b/zone/mob.h index b5e21c932..5c1240e83 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -142,6 +142,7 @@ public: void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage); virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse); uint32 TryHeadShot(Mob* defender, SkillUseTypes skillInUse); + uint32 TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime); virtual void DoRiposte(Mob* defender); void ApplyMeleeDamageBonus(uint16 skill, int32 &damage); virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr); @@ -694,7 +695,7 @@ public: int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker); int32 ReduceAllDamage(int32 damage); - virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false); + virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false, bool CanAvoid=true); virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0); virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false); virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0); @@ -991,7 +992,8 @@ protected: void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on); virtual float GetProcChances(float ProcBonus, uint16 weapon_speed = 30, uint16 hand = 13); virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13); - virtual float GetSpecialProcChances(uint16 hand = 13); + virtual float GetSpecialProcChances(uint16 hand); + virtual float GetAssassinateProcChances(uint16 ReuseTime); int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item); int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr); int GetKickDamage(); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 55e919bc3..4ffa21ab4 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -100,7 +100,8 @@ void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) } } -void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, bool HitChance) { +void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, + bool HitChance, bool CanAvoid) { //this really should go through the same code as normal melee damage to //pick up all the special behavior there @@ -135,7 +136,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&' CanRiposte = false; - who->AvoidDamage(this, max_damage, CanRiposte); + if (CanAvoid) + who->AvoidDamage(this, max_damage, CanRiposte); + who->MeleeMitigation(this, max_damage, min_damage); if(max_damage > 0) { @@ -373,8 +376,8 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) { if (ca_atk->m_atk != 100 || ca_atk->m_skill != SkillBackstab) { break; } - TryBackstab(GetTarget(), ReuseTime); ReuseTime = BackstabReuseTime-1 - skill_reduction; + TryBackstab(GetTarget(), ReuseTime); break; } default: @@ -527,64 +530,47 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { if (FrontalBSChance && (FrontalBSChance > MakeRandomInt(0, 100))) bCanFrontalBS = true; } - + if (bIsBehind || bCanFrontalBS){ // Player is behind other OR can do Frontal Backstab - if (bCanFrontalBS) { + if (bCanFrontalBS) CastToClient()->Message(0,"Your fierce attack is executed with such grace, your target did not see it coming!"); - } + + RogueBackstab(other,false,ReuseTime); + if (level > 54) { - // solar - chance to assassinate - int chance = 10 + (GetDEX()/10) + (itembonuses.HeroicDEX/10); //18.5% chance at 85 dex 40% chance at 300 dex - if( - level >= 60 && // player is 60 or higher - other->GetLevel() <= 45 && // mob 45 or under - !other->CastToNPC()->IsEngaged() && // not aggro - other->GetHP()<=32000 - && other->IsNPC() - && MakeRandomFloat(0, 99) < chance // chance - ) { - entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName()); - if(IsClient()) - CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); - RogueAssassinate(other); - } - else { - RogueBackstab(other); - if (level > 54) { - float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max - // Check for double attack with main hand assuming maxed DA Skill (MS) + if(IsClient() && CastToClient()->CheckDoubleAttack(false)) + { + if(other->GetHP() > 0) + RogueBackstab(other,false,ReuseTime); - if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA - { - if(other->GetHP() > 0) - RogueBackstab(other,false,ReuseTime); - - if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) - RogueBackstab(other,false,ReuseTime); - } + if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) + RogueBackstab(other,false,ReuseTime); } - if(IsClient()) - CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); } + + if(IsClient()) + CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); + } //Live AA - Chaotic Backstab else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) { //we can stab from any angle, we do min damage though. - RogueBackstab(other, true); + RogueBackstab(other, true, ReuseTime); if (level > 54) { - float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max - if(IsClient()) - CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); + // Check for double attack with main hand assuming maxed DA Skill (MS) - if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA + if(IsClient() && CastToClient()->CheckDoubleAttack(false)) if(other->GetHP() > 0) RogueBackstab(other,true, ReuseTime); if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) RogueBackstab(other,false,ReuseTime); } + + if(IsClient()) + CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10); } else { //We do a single regular attack if we attack from the front without chaotic stab Attack(other, 13); @@ -594,6 +580,9 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) { //heko: backstab void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) { + if (!other) + return; + int32 ndamage = 0; int32 max_hit = 0; int32 min_hit = 0; @@ -668,12 +657,20 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) } ndamage = mod_backstab_damage(ndamage); + + uint32 Assassinate_Dmg = 0; + Assassinate_Dmg = TryAssassinate(other, SkillBackstab, ReuseTime); + + if (Assassinate_Dmg) { + ndamage = Assassinate_Dmg; + entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName()); + } - DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime); + DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime, false, false); DoAnim(animPiercing); } -// solar - assassinate +// solar - assassinate [Kayen: No longer used for regular assassinate 6-29-14] void Mob::RogueAssassinate(Mob* other) { //can you dodge, parry, etc.. an assassinate?? @@ -1276,13 +1273,24 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite int32 TotalDmg = 0; + uint32 Assassinate_Dmg = 0; + if (GetClass() == ROGUE && (BehindMob(other, GetX(), GetY()))) + Assassinate_Dmg = TryAssassinate(other, SkillThrowing, ranged_timer.GetDuration()); + if(WDmg > 0) { int minDmg = 1; uint16 MaxDmg = GetThrownDamage(WDmg, TotalDmg, minDmg); + if (Assassinate_Dmg) { + TotalDmg = Assassinate_Dmg; + entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName()); + } + mlog(COMBAT__RANGED, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg); - other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks. + if (!Assassinate_Dmg) + other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks. + other->MeleeMitigation(this, TotalDmg, minDmg); if(TotalDmg > 0) { @@ -1866,92 +1874,6 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte) } } -/* -void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { - - if (who == nullptr) - return; - - if(DivineAura()) - return; - - if(!CombatRange(who)) - return; - - if(!always_succeed && IsClient()) - CastToClient()->CheckIncreaseSkill(TAUNT, who, 10); - - int level = GetLevel(); - Mob *hate_top = who->GetHateMost(); - - // Check to see if we're already at the top of the target's hate list - // a mob will not be taunted if its target's health is below 20% - if ((hate_top != this) - && (who->GetLevel() < level) - && (hate_top == nullptr || hate_top->GetHPRatio() >= 20) ) { - int32 newhate, tauntvalue; - - float tauntchance; - if(always_succeed) { - tauntchance = 101; - } else { - - // no idea how taunt success is actually calculated - // TODO: chance for level 50+ mobs should be lower - int level_difference = level - who->GetLevel(); - if (level_difference <= 5) { - tauntchance = 25.0; // minimum - tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier - if (tauntchance > 65.0) - tauntchance = 65.0; - } - else if (level_difference <= 10) { - tauntchance = 30.0; // minimum - tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier - if (tauntchance > 85.0) - tauntchance = 85.0; - } - else if (level_difference <= 15) { - tauntchance = 40.0; // minimum - tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier - if (tauntchance > 90.0) - tauntchance = 90.0; - } - else { - tauntchance = 50.0; // minimum - tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier - if (tauntchance > 95.0) - tauntchance = 95.0; - } - } - - if (chance_bonus) - tauntchance = tauntchance + (tauntchance*chance_bonus/100.0f); - - if (tauntchance > MakeRandomFloat(0, 100)) { - // this is the max additional hate added per succesfull taunt - tauntvalue = (MakeRandomInt(2, 4) * level); - //tauntvalue = (int32) ((float)level * 10.0 * (float)rand()/(float)RAND_MAX + 1); - // new hate: find diff of player's hate and whoever's at top of list, add that plus tauntvalue to players hate - newhate = who->GetNPCHate(hate_top) - who->GetNPCHate(this) + tauntvalue; - // add the hate - who->CastToNPC()->AddToHateList(this, newhate); - } - else{ - //generate at least some hate reguardless of the outcome. - who->CastToNPC()->AddToHateList(this, (MakeRandomInt(2, 4)*level)); - } - } - - //generate at least some hate reguardless of the outcome. - who->CastToNPC()->AddToHateList(this, (MakeRandomInt(2, 4)*level)); - if (HasSkillProcs()){ - float chance = (float)TauntReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f; - TrySkillProc(who, TAUNT, chance); - } -} -*/ - void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { if (who == nullptr) @@ -2089,9 +2011,10 @@ void Mob::InstillDoubt(Mob *who) { uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { //Only works on YOUR target. - if(defender && (skillInUse == SkillArchery) && (GetTarget() == defender)) { + if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() + && (skillInUse == SkillArchery) && (GetTarget() == defender)) { - int32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; + uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; uint8 HeadShot_Level = 0; //Get Highest Headshot Level HeadShot_Level = aabonuses.HSLevel; @@ -2100,14 +2023,11 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { else if (HeadShot_Level < itembonuses.HSLevel) HeadShot_Level = itembonuses.HSLevel; - if(HeadShot_Dmg && defender->GetBodyType() == BT_Humanoid) { - if(HeadShot_Level && (defender->GetLevel() <= HeadShot_Level) && !defender->IsClient()){ + if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){ - float ProcChance = GetSpecialProcChances(11); - if(ProcChance > MakeRandomFloat(0,1)) - return HeadShot_Dmg; - - } + float ProcChance = GetSpecialProcChances(11); + if(ProcChance > MakeRandomFloat(0,1)) + return HeadShot_Dmg; } } @@ -2119,7 +2039,7 @@ float Mob::GetSpecialProcChances(uint16 hand) int mydex = GetDEX(); if (mydex > 255) - mydex = 255; + mydex = 255; uint16 weapon_speed; float ProcChance = 0.0f; @@ -2155,6 +2075,69 @@ float Mob::GetSpecialProcChances(uint16 hand) return ProcChance; } +uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime) { + + if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() && + (skillInUse == SkillBackstab || skillInUse == SkillThrowing)) { + + uint32 Assassinate_Dmg = aabonuses.Assassinate[1] + spellbonuses.Assassinate[1] + itembonuses.Assassinate[1]; + + uint8 Assassinate_Level = 0; //Get Highest Headshot Level + Assassinate_Level = aabonuses.AssassinateLevel; + if (Assassinate_Level < spellbonuses.AssassinateLevel) + Assassinate_Level = spellbonuses.AssassinateLevel; + else if (Assassinate_Level < itembonuses.AssassinateLevel) + Assassinate_Level = itembonuses.AssassinateLevel; + + if (GetLevel() >= 60){ //Innate Assassinate Ability if client as no bonuses. + if (!Assassinate_Level) + Assassinate_Level = 45; + + if (!Assassinate_Dmg) + Assassinate_Dmg = 32000; + } + + if(Assassinate_Dmg && Assassinate_Level && (defender->GetLevel() <= Assassinate_Level)){ + float ProcChance = 0.0f; + + if (skillInUse == SkillThrowing) + ProcChance = GetSpecialProcChances(11); + else + ProcChance = GetAssassinateProcChances(ReuseTime); + + if(ProcChance > MakeRandomFloat(0,1)) + return Assassinate_Dmg; + } + } + + return 0; +} + +float Mob::GetAssassinateProcChances(uint16 ReuseTime) +{ + int mydex = GetDEX(); + + if (mydex > 255) + mydex = 255; + + float ProcChance = 0.0f; + float ProcBonus = 0.0f; + + if (RuleB(Combat, AdjustSpecialProcPerMinute)) { + ProcChance = (static_cast(ReuseTime*1000) * + RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f); + ProcBonus += (10 + (static_cast(mydex/10) + static_cast(itembonuses.HeroicDEX /10)))/100.0f; + ProcChance += ProcChance * ProcBonus / 100.0f; + + } else { + /*Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up.*/ + ProcChance = (10 + (static_cast(mydex/10) + static_cast(itembonuses.HeroicDEX /10)))/100.0f; + + } + + return ProcChance; +} + void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte) { if (!CanDoSpecialAttack(other)) From 93900086e1a3609443686416a11e90f012ddec8a Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 30 Jun 2014 06:34:12 -0400 Subject: [PATCH 13/19] Fix for AA Finishg Blow rank 1-3. AA Data was missing and incorrectly added to wrong aaid. Required SQL --- utils/sql/git/required/2014_06_25_AA_Updates..sql | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/utils/sql/git/required/2014_06_25_AA_Updates..sql b/utils/sql/git/required/2014_06_25_AA_Updates..sql index d51948af9..3d7a048b6 100644 --- a/utils/sql/git/required/2014_06_25_AA_Updates..sql +++ b/utils/sql/git/required/2014_06_25_AA_Updates..sql @@ -20,4 +20,15 @@ INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ( INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '1', '439', '0', '32000'); INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '2', '345', '51', '0'); INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '1', '439', '0', '32000'); -INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '2', '345', '53', '0'); \ No newline at end of file +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '2', '345', '53', '0'); + +-- AA Finishing Blow Fix +DELETE FROM aa_effects WHERE aaid = 199 AND slot = 2; +DELETE FROM aa_effects WHERE aaid = 200 AND slot = 2; +DELETE FROM aa_effects WHERE aaid = 201 AND slot = 2; +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '1', '278', '500', '32000'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '2', '440', '50', '200'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '1', '278', '500', '32000'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '2', '440', '52', '200'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '1', '278', '500', '32000'); +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '2', '440', '54', '200'); \ No newline at end of file From 8edb73dc3ab4cf8dedf1d8e5a7401c6abf45c196 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 30 Jun 2014 07:18:47 -0400 Subject: [PATCH 14/19] Revised Finishing blow so that damage now receives all melee bonus. Support also for this effect if placed on items or spells. --- changelog.txt | 2 ++ zone/attack.cpp | 28 ++++++++++++------------ zone/bonuses.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/changelog.txt b/changelog.txt index 53585d982..82dcc497f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -17,6 +17,8 @@ system, or flat chance based on dex (formula updated). Kayen: Implemented SE_Assassinate, SE_AssassinateLevel - Defines assassinate damage and level requirements. Revised Assassinate mechanic so damage now receives all backstab bonuses, proc chance can be set to either (lives new Proc Per minute system, or flat chance based on dex (formula updated). Assassinate can now proc from THROW if behind target, various other adjustments. +Kayen: Fix to AA Finishing Blow missing aa_effects data, update required SQL. +Revised Finishing blow so that damage now receives all melee bonus. Support also for this effect if placed on items or spells. Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql diff --git a/zone/attack.cpp b/zone/attack.cpp index 4592f2fdf..3346f4aa7 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4443,27 +4443,25 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) { + if (defender && !defender->IsClient() && defender->GetHPRatio() < 10){ - if (!defender) - return false; + uint32 FB_Dmg = aabonuses.FinishingBlow[1] + spellbonuses.FinishingBlow[1] + itembonuses.FinishingBlow[1]; + + uint16 FB_Level = 0; //Get Highest Headshot Level + FB_Level = aabonuses.FinishingBlowLvl[0]; + if (FB_Level < spellbonuses.FinishingBlowLvl[0]) + FB_Level = spellbonuses.FinishingBlowLvl[0]; + else if (FB_Level < itembonuses.FinishingBlowLvl[0]) + FB_Level = itembonuses.FinishingBlowLvl[0]; - if (aabonuses.FinishingBlow[1] && !defender->IsClient() && defender->GetHPRatio() < 10){ + //Proc Chance value of 500 = 5% + uint32 ProcChance = (aabonuses.FinishingBlow[0] + spellbonuses.FinishingBlow[0] + spellbonuses.FinishingBlow[0])/10; - uint32 chance = aabonuses.FinishingBlow[0]/10; //500 = 5% chance. - uint32 damage = aabonuses.FinishingBlow[1]; - uint16 levelreq = aabonuses.FinishingBlowLvl[0]; - - if(defender->GetLevel() <= levelreq && (chance >= MakeRandomInt(0, 1000))){ - mlog(COMBAT__ATTACKS, "Landed a finishing blow: levelreq at %d, other level %d", levelreq , defender->GetLevel()); + if(FB_Level && FB_Dmg && (defender->GetLevel() <= FB_Level) && (ProcChance >= MakeRandomInt(0, 1000))){ entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName()); - defender->Damage(this, damage, SPELL_UNKNOWN, skillinuse); + DoSpecialAttackDamage(defender, skillinuse, FB_Dmg, 1, -1, 10, false, false); return true; } - else - { - mlog(COMBAT__ATTACKS, "FAILED a finishing blow: levelreq at %d, other level %d", levelreq , defender->GetLevel()); - return false; - } } return false; } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 0871e3679..8b46773fc 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1204,7 +1204,6 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) case SE_FinishingBlow: { - //base1 = chance, base2 = damage if (newbon->FinishingBlow[1] < base2){ newbon->FinishingBlow[0] = base1; @@ -2825,6 +2824,26 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_FinishingBlow: + { + //base1 = chance, base2 = damage + if (newbon->FinishingBlow[1] < base2){ + newbon->FinishingBlow[0] = effect_value; + newbon->FinishingBlow[1] = base2; + } + break; + } + + case SE_FinishingBlowLvl: + { + //base1 = level, base2 = ??? (Set to 200 in AA data, possible proc rate mod?) + if (newbon->FinishingBlowLvl[0] < effect_value){ + newbon->FinishingBlowLvl[0] = effect_value; + newbon->FinishingBlowLvl[1] = base2; + } + break; + } + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4258,6 +4277,40 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.HSLevel = effect_value; aabonuses.HSLevel = effect_value; itembonuses.HSLevel = effect_value; + break; + + case SE_Assassinate: + spellbonuses.Assassinate[0] = effect_value; + aabonuses.Assassinate[0] = effect_value; + itembonuses.Assassinate[0] = effect_value; + spellbonuses.Assassinate[1] = effect_value; + aabonuses.Assassinate[1] = effect_value; + itembonuses.Assassinate[1] = effect_value; + break; + + case SE_AssassinateLevel: + spellbonuses.AssassinateLevel = effect_value; + aabonuses.AssassinateLevel = effect_value; + itembonuses.AssassinateLevel = effect_value; + break; + + case SE_FinishingBlow: + spellbonuses.FinishingBlow[0] = effect_value; + aabonuses.FinishingBlow[0] = effect_value; + itembonuses.FinishingBlow[0] = effect_value; + spellbonuses.FinishingBlow[1] = effect_value; + aabonuses.FinishingBlow[1] = effect_value; + itembonuses.FinishingBlow[1] = effect_value; + break; + + case SE_FinishingBlowLvl: + spellbonuses.FinishingBlowLvl[0] = effect_value; + aabonuses.FinishingBlowLvl[0] = effect_value; + itembonuses.FinishingBlowLvl[0] = effect_value; + spellbonuses.FinishingBlowLvl[1] = effect_value; + aabonuses.FinishingBlowLvl[1] = effect_value; + itembonuses.FinishingBlowLvl[1] = effect_value; + break; } } From 5e7d2fd07de7a394b281ef539f0b1270873da5ad Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 30 Jun 2014 16:17:55 -0400 Subject: [PATCH 15/19] Implemented SE_PetMeleeMitigation - Bonus applied to pet owner. Gives AC to owner's pet. Related AA's to be added in a seperate update. --- changelog.txt | 1 + common/spdat.h | 2 +- zone/attack.cpp | 14 ++++++++++++-- zone/bonuses.cpp | 14 ++++++++++++++ zone/common.h | 1 + 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index 82dcc497f..0a22ccf8d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -19,6 +19,7 @@ Revised Assassinate mechanic so damage now receives all backstab bonuses, proc c system, or flat chance based on dex (formula updated). Assassinate can now proc from THROW if behind target, various other adjustments. Kayen: Fix to AA Finishing Blow missing aa_effects data, update required SQL. Revised Finishing blow so that damage now receives all melee bonus. Support also for this effect if placed on items or spells. +Kayen: Implemented SE_PetMeleeMitigation - Bonus applied to pet owner. Gives AC to owner's pet. Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql diff --git a/common/spdat.h b/common/spdat.h index 65bb9f692..23a50fc3f 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -544,7 +544,7 @@ typedef enum { #define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. #define SE_FcHealPctCritIncoming 395 // implemented[AA] - Increases chance of having a heal crit when cast on you. [focus limited] #define SE_FcHealAmtCrit 396 // implemented - Adds a direct healing amount to spells -//#define SE_PetMeleeMitigation 397 // *not implemented[AA] - additional mitigation to your pets. +#define SE_PetMeleeMitigation 397 // implemented[AA] - additional mitigation to your pets. Adds AC. #define SE_SwarmPetDuration 398 // implemented - Affects the duration of swarm pets #define SE_FcTwincast 399 // implemented - cast 2 spells for every 1 #define SE_HealGroupFromMana 400 // implemented - Drains mana and heals for each point of mana drained diff --git a/zone/attack.cpp b/zone/attack.cpp index 3346f4aa7..7b641bd96 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -560,11 +560,21 @@ void Mob::MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttac weight = (CastToClient()->CalcCurrentWeight() / 10.0); } else if (IsNPC()) { armor = CastToNPC()->GetRawAC(); + int PetACBonus = 0; if (!IsPet()) armor = (armor / RuleR(Combat, NPCACFactor)); + else{ + Mob *owner = nullptr; + owner = GetOwner(); + if (owner){ + PetACBonus = owner->aabonuses.PetMeleeMitigation + + owner->itembonuses.PetMeleeMitigation + + owner->spellbonuses.PetMeleeMitigation; + } + } - armor += spellbonuses.AC + itembonuses.AC + 1; + armor += spellbonuses.AC + itembonuses.AC + PetACBonus + 1; } if (opts) { @@ -4447,7 +4457,7 @@ bool Mob::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) uint32 FB_Dmg = aabonuses.FinishingBlow[1] + spellbonuses.FinishingBlow[1] + itembonuses.FinishingBlow[1]; - uint16 FB_Level = 0; //Get Highest Headshot Level + uint16 FB_Level = 0; FB_Level = aabonuses.FinishingBlowLvl[0]; if (FB_Level < spellbonuses.FinishingBlowLvl[0]) FB_Level = spellbonuses.FinishingBlowLvl[0]; diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 8b46773fc..5a13f2ccb 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1311,6 +1311,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_PetMeleeMitigation: + newbon->PetMeleeMitigation += base1; + break; + } } } @@ -2844,6 +2848,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_PetMeleeMitigation: + newbon->PetMeleeMitigation += effect_value; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4075,6 +4083,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.GivePetGroupTarget = false; break; + case SE_PetMeleeMitigation: + spellbonuses.PetMeleeMitigation = effect_value; + itembonuses.PetMeleeMitigation = effect_value; + aabonuses.PetMeleeMitigation = effect_value; + break; + case SE_RootBreakChance: spellbonuses.RootBreakChance = effect_value; aabonuses.RootBreakChance = effect_value; diff --git a/zone/common.h b/zone/common.h index 6d6ae581f..d9b0d53d3 100644 --- a/zone/common.h +++ b/zone/common.h @@ -427,6 +427,7 @@ struct StatBonuses { uint8 HSLevel; // Max Level Headshot will be effective at. uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg uint8 AssassinateLevel; // Max Level Assassinate will be effective at. + int32 PetMeleeMitigation; // Add AC to owner's pet. }; From c412038db8ef17f879016778d86bcb9254a833fd Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 1 Jul 2014 04:53:24 -0400 Subject: [PATCH 16/19] Updated SE_WaketheDead , max will now set duration. --- common/spdat.h | 2 +- zone/spell_effects.cpp | 9 +-------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/common/spdat.h b/common/spdat.h index 23a50fc3f..c8fd7d845 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -410,7 +410,7 @@ typedef enum { #define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType #define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live) #define SE_RaiseStatCap 262 // implemented -#define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master. +//#define SE_TradeSkillMastery 263 // not implemented - lets you raise more than one tradeskill above master. //#define SE_HastenedAASkill 264 // not implemented as bonus - Use redux field in aa_actions table for this effect #define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled #define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon. diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 51979eddc..be09bef4c 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2294,14 +2294,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #endif //meh dupe issue with npc casting this if(caster->IsClient()){ - //this spell doesn't appear to actually contain the information on duration inside of it oddly - int dur = 60; - if(spell_id == 3269) - dur += 15; - else if(spell_id == 3270) - dur += 30; - - caster->WakeTheDead(spell_id, caster->GetTarget(), dur); + caster->WakeTheDead(spell_id, caster->GetTarget(), spells[spell_id].max[i]); } break; } From 3b8993a302e5ef85ff6073ff40168d2f977cc79b Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 1 Jul 2014 04:55:50 -0400 Subject: [PATCH 17/19] minor fix --- zone/spell_effects.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index be09bef4c..376dcae7c 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2294,7 +2294,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) #endif //meh dupe issue with npc casting this if(caster->IsClient()){ - caster->WakeTheDead(spell_id, caster->GetTarget(), spells[spell_id].max[i]); + int dur = spells[spell_id].max[i]; + if (!dur) + dur = 60; + + caster->WakeTheDead(spell_id, caster->GetTarget(), dur); } break; } From ede7f9899c907836d4cf1ac19d2741520d714e70 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 1 Jul 2014 16:52:28 -0400 Subject: [PATCH 18/19] Renamed a few spell effects more appropriately. --- common/spdat.h | 6 +++--- zone/bonuses.cpp | 6 +++--- zone/bot.cpp | 2 +- zone/mob.cpp | 4 ++-- zone/spell_effects.cpp | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/common/spdat.h b/common/spdat.h index c8fd7d845..75d351fc2 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -506,13 +506,13 @@ typedef enum { //#define SE_ChangeTriggerType 356 // not used #define SE_FcMute 357 // implemented - silences casting of spells that contain specific spell effects (focus limited) #define SE_CurrentManaOnce 358 // implemented -#define SE_Invulnerabilty 359 // *not implemented - Invulnerability (Brell's Blessing) -#define SE_SpellOnKill 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level +//#define SE_PassiveSenseTrap 359 // *not implemented - Invulnerability (Brell's Blessing) +#define SE_ProcOnKillShot 360 // implemented - a buff that has a base1 % to cast spell base2 when you kill a "challenging foe" base3 min level #define SE_SpellOnDeath 361 // implemented - casts spell on death of buffed //#define SE_PotionBeltSlots 362 // *not implemented[AA] 'Quick Draw' expands the potion belt by one additional available item slot per rank. //#define SE_BandolierSlots 363 // *not implemented[AA] 'Battle Ready' expands the bandolier by one additional save slot per rank. #define SE_TripleAttackChance 364 // implemented -#define SE_SpellOnKill2 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin) +#define SE_ProcOnSpellKillShot 365 // implemented - chance to trigger a spell on kill when the kill is caused by a specific spell with this effect in it (10470 Venin) #define SE_ShieldEquipDmgMod 366 // implemented[AA] Damage modifier to melee if shield equiped. (base1 = dmg mod , base2 = ?) ie Shield Specialist AA #define SE_SetBodyType 367 // implemented - set body type of base1 so it can be affected by spells that are limited to that type (Plant, Animal, Undead, etc) //#define SE_FactionMod 368 // *not implemented - increases faction with base1 (faction id, live won't match up w/ ours) by base2 diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 5a13f2ccb..9072a2c9b 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -989,7 +989,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->CrippBlowChance += base1; break; - case SE_SpellOnKill: + case SE_ProcOnKillShot: for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3) { if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i+1] < base1))) @@ -2179,7 +2179,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->CriticalDoTChance += effect_value; break; - case SE_SpellOnKill: + case SE_ProcOnKillShot: { for(int e = 0; e < MAX_SPELL_TRIGGER*3; e+=3) { @@ -3785,7 +3785,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.CriticalDoTChance = effect_value; break; - case SE_SpellOnKill: + case SE_ProcOnKillShot: { for(int e = 0; e < MAX_SPELL_TRIGGER*3; e=3) { diff --git a/zone/bot.cpp b/zone/bot.cpp index 5bdf3cb02..e961bd7ec 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -1900,7 +1900,7 @@ void Bot::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->UnfailingDivinity += base1; break; - case SE_SpellOnKill: + case SE_ProcOnKillShot: for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3) { if(!newbon->SpellOnKill[i] || ((newbon->SpellOnKill[i] == base2) && (newbon->SpellOnKill[i+1] < base1))) diff --git a/zone/mob.cpp b/zone/mob.cpp index ed2072e21..ee468a0e6 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4139,9 +4139,9 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id) { if (spell_id != SPELL_UNKNOWN) { - if(IsEffectInSpell(spell_id, SE_SpellOnKill2)) { + if(IsEffectInSpell(spell_id, SE_ProcOnSpellKillShot)) { for (int i = 0; i < EFFECT_COUNT; i++) { - if (spells[spell_id].effectid[i] == SE_SpellOnKill2) + if (spells[spell_id].effectid[i] == SE_ProcOnSpellKillShot) { if (IsValidSpell(spells[spell_id].base2[i]) && spells[spell_id].max[i] <= level) { diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 376dcae7c..090fb4b75 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2860,8 +2860,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_CriticalHealChance: case SE_CriticalHealOverTime: case SE_CriticalDoTChance: - case SE_SpellOnKill: - case SE_SpellOnKill2: + case SE_ProcOnKillShot: + case SE_ProcOnSpellKillShot: case SE_CriticalDamageMob: case SE_LimitSpellGroup: case SE_ResistCorruption: From 5d85a26be1f278bcde8cfadf013db6f4c2b96137 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 1 Jul 2014 17:34:36 -0400 Subject: [PATCH 19/19] Update to SE_AStacker, B, C, D Will correclty use base value to stack with same type ie (A vs A) Highest base value will take hold. --- zone/bonuses.cpp | 12 ++++++++---- zone/common.h | 8 ++++---- zone/spells.cpp | 18 +++++++++++++++--- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 9072a2c9b..a316c4b3b 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2762,19 +2762,23 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; case SE_AStacker: - newbon->AStacker = true; + newbon->AStacker[0] = 1; + newbon->AStacker[1] = effect_value; break; case SE_BStacker: - newbon->BStacker = true; + newbon->BStacker[0] = 1; + newbon->BStacker[1] = effect_value; break; case SE_CStacker: - newbon->CStacker = true; + newbon->CStacker[0] = 1; + newbon->CStacker[1] = effect_value; break; case SE_DStacker: - newbon->DStacker = true; + newbon->DStacker[0] = 1; + newbon->DStacker[1] = effect_value; break; case SE_Berserk: diff --git a/zone/common.h b/zone/common.h index d9b0d53d3..88600492e 100644 --- a/zone/common.h +++ b/zone/common.h @@ -366,10 +366,10 @@ struct StatBonuses { bool NegateIfCombat; // Bool Drop buff if cast or melee int8 Screech; // -1 = Will be blocked if another Screech is +(1) int16 AlterNPCLevel; // amount of lvls +/- - bool AStacker; // For buff stack blocking - bool BStacker; // For buff stack blocking - bool CStacker; // For buff stack blocking - bool DStacker; // For buff stack blocking + int16 AStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value + int16 BStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value + int16 CStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value + int16 DStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value bool BerserkSPA; // berserk effect int16 Metabolism; // Food/drink consumption rates. diff --git a/zone/spells.cpp b/zone/spells.cpp index 78dce3379..59dbb6625 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2622,19 +2622,31 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, } /*Buff stacking prevention spell effects (446 - 449) works as follows... If B prevent A, if C prevent B, if D prevent C. + If checking same type ie A vs A, which ever effect base value is higher will take hold. Special check is added to make sure the buffs stack properly when applied from fade on duration effect, since the buff is not fully removed at the time of the trgger*/ - if (spellbonuses.BStacker) { + if (spellbonuses.AStacker[0]) { + if ((effect2 == SE_AStacker) && (sp2.effectid[i] <= spellbonuses.AStacker[1])) + return -1; + } + + if (spellbonuses.BStacker[0]) { + if ((effect2 == SE_BStacker) && (sp2.effectid[i] <= spellbonuses.BStacker[1])) + return -1; if ((effect2 == SE_AStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_BStacker))) return -1; } - if (spellbonuses.CStacker) { + if (spellbonuses.CStacker[0]) { + if ((effect2 == SE_CStacker) && (sp2.effectid[i] <= spellbonuses.CStacker[1])) + return -1; if ((effect2 == SE_BStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_CStacker))) return -1; } - if (spellbonuses.DStacker) { + if (spellbonuses.DStacker[0]) { + if ((effect2 == SE_DStacker) && (sp2.effectid[i] <= spellbonuses.DStacker[1])) + return -1; if ((effect2 == SE_CStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_DStacker))) return -1; }