From 57a216cb445091812aad3aff7c32f1a0027a324c Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 09:45:12 -0400 Subject: [PATCH 01/62] Implemented SE_AStacker, BStacker, CStacker, DStacker Effects are buff stacking blockers. --- changelog.txt | 5 +++++ common/spdat.cpp | 13 +++++++++++++ common/spdat.h | 9 +++++---- zone/bonuses.cpp | 16 ++++++++++++++++ zone/common.h | 4 ++++ zone/mob.h | 2 +- zone/spell_effects.cpp | 4 ++++ zone/spells.cpp | 24 +++++++++++++++++++++--- 8 files changed, 69 insertions(+), 8 deletions(-) diff --git a/changelog.txt b/changelog.txt index eabbad6fd..87c9144d4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 06/17/2014 == +Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. +These effects when present in buffs prevent each other from stacking, +Any effect with B prevents A, C prevents B, D prevents C. + == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) Setting se_max to 1 for SkillDamageTaken effects (127) will allow for stackable mitigation/weakness same as quest function ModSkillDmgTaken. diff --git a/common/spdat.cpp b/common/spdat.cpp index 013a917f1..3c4989a67 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -1009,6 +1009,19 @@ uint32 GetMorphTrigger(uint32 spell_id) return 0; } +bool IsCastonFadeDurationSpell(uint16 spell_id) +{ + for (int i = 0; i < EFFECT_COUNT; ++i) { + if (spells[spell_id].effectid[i] == SE_ImprovedSpellEffect + || spells[spell_id].effectid[i] == SE_BossSpellTrigger + || spells[spell_id].effectid[i] == SE_CastOnWearoff){ + + return true; + } + } + return false; +} + uint32 GetPartialMeleeRuneReduction(uint32 spell_id) { for (int i = 0; i < EFFECT_COUNT; ++i) diff --git a/common/spdat.h b/common/spdat.h index ada9e3249..1ef44e15b 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -593,10 +593,10 @@ typedef enum { #define SE_TriggerOnReqCaster 443 // implemented - triggers a spell which a certain criteria are met (below X amount of hp,mana,end, number of pets on hatelist) #define SE_ImprovedTaunt 444 // implemented - Locks Aggro On Caster and Decrease other Players Aggro by X% on NPC targets below level Y //#define SE_AddMercSlot 445 // *not implemented[AA] - [Hero's Barracks] Allows you to conscript additional mercs. -//#define SE_AStacker 446 // *not implementet - bufff stacking blocker ? (26219 | Qirik's Watch) -//#define SE_BStacker 447 // *not implemented -//#define SE_CStacker 448 // *not implemented -//#define SE_DStacker 449 // *not implemented +#define SE_AStacker 446 // implementet - bufff stacking blocker (26219 | Qirik's Watch) +#define SE_BStacker 447 // implemented +#define SE_CStacker 448 // implemented +#define SE_DStacker 449 // implemented #define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value #define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage @@ -833,6 +833,7 @@ bool IsBuffSpell(uint16 spell_id); bool IsPersistDeathSpell(uint16 spell_id); bool IsSuspendableSpell(uint16 spell_id); uint32 GetMorphTrigger(uint32 spell_id); +bool IsCastonFadeDurationSpell(uint16 spell_id); uint32 GetPartialMeleeRuneReduction(uint32 spell_id); uint32 GetPartialMagicRuneReduction(uint32 spell_id); uint32 GetPartialMeleeRuneAmount(uint32 spell_id); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index d699cdde2..bdbbe6b4e 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2661,6 +2661,22 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } break; + case SE_AStacker: + newbon->AStacker = true; + break; + + case SE_BStacker: + newbon->BStacker = true; + break; + + case SE_CStacker: + newbon->CStacker = true; + break; + + case SE_DStacker: + newbon->DStacker = true; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { diff --git a/zone/common.h b/zone/common.h index d5f516f63..dfb500d47 100644 --- a/zone/common.h +++ b/zone/common.h @@ -350,6 +350,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 // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/mob.h b/zone/mob.h index c3de2b576..4ab9d8a84 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -800,7 +800,7 @@ public: uint16 GetInstrumentMod(uint16 spell_id) const; int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, Mob *caster = nullptr, int ticsremaining = 0); int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0); - virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr); + virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1); uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; } // HP Event diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 4e10160ed..2c83ef1cd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2886,6 +2886,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_LimitCastTimeMax: case SE_TriggerOnReqCaster: case SE_FrenziedDevastation: + case SE_AStacker: + case SE_BStacker: + case SE_CStacker: + case SE_DStacker: { break; } diff --git a/zone/spells.cpp b/zone/spells.cpp index 54e98613e..21a2fe749 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -2542,7 +2542,7 @@ int CalcBuffDuration_formula(int level, int formula, int duration) // -1 if they can't stack and spellid2 should be stopped //currently, a spell will not land if it would overwrite a better spell on any effect //if all effects are better or the same, we overwrite, else we do nothing -int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1, Mob* caster2) +int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1, Mob* caster2, int buffslot) { const SPDat_Spell_Struct &sp1 = spells[spellid1]; const SPDat_Spell_Struct &sp2 = spells[spellid2]; @@ -2621,6 +2621,24 @@ 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. + 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 ((effect2 == SE_AStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_BStacker))) + return -1; + } + + if (spellbonuses.CStacker) { + if ((effect2 == SE_BStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_CStacker))) + return -1; + } + + if (spellbonuses.DStacker) { + if ((effect2 == SE_CStacker) && (!IsCastonFadeDurationSpell(spellid1) && buffs[buffslot].ticsremaining != 1 && IsEffectInSpell(spellid1, SE_DStacker))) + return -1; + } + if(effect2 == SE_StackingCommand_Overwrite) { overwrite_effect = sp2.base[i]; @@ -2901,7 +2919,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid if (curbuf.spellid != SPELL_UNKNOWN) { // there's a buff in this slot ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spell_id, - caster_level, entity_list.GetMobID(curbuf.casterid), caster); + caster_level, entity_list.GetMobID(curbuf.casterid), caster, buffslot); if (ret == -1) { // stop the spell mlog(SPELLS__BUFFS, "Adding buff %d failed: stacking prevented by spell %d in slot %d with caster level %d", spell_id, curbuf.spellid, buffslot, curbuf.casterlevel); @@ -3047,7 +3065,7 @@ int Mob::CanBuffStack(uint16 spellid, uint8 caster_level, bool iFailIfOverwrite) return(-1); //do not recast a buff we already have on, we recast fast enough that we dont need to refresh our buffs // there's a buff in this slot - ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spellid, caster_level); + ret = CheckStackConflict(curbuf.spellid, curbuf.casterlevel, spellid, caster_level, nullptr, nullptr, i); if(ret == 1) { // should overwrite current slot if(iFailIfOverwrite) { From da70a45d22a7eb757de8fdcba0ce008a669466a7 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 15:23:07 -0400 Subject: [PATCH 02/62] Implemented SE_DamageModifier2 --- changelog.txt | 1 + common/spdat.h | 2 +- zone/bonuses.cpp | 29 +++++++++++++++++++++++++++++ zone/common.h | 1 + zone/mob.cpp | 3 +++ 5 files changed, 35 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 87c9144d4..7002939e6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. These effects when present in buffs prevent each other from stacking, Any effect with B prevents A, C prevents B, D prevents C. +Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 1ef44e15b..7e0367fd7 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -606,7 +606,7 @@ typedef enum { //#define SE_AddHateOverTimePct 456 // not used //#define SE_ResourceTap 457 // not used //#define SE_FactionModPct 458 // not used -//#define SE_DamageModifier2 459 // *not implemented - Modifies melee damage by skill type +#define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type // LAST diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index bdbbe6b4e..03e1d76f6 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1099,6 +1099,15 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_DamageModifier2: + { + if(base2 == -1) + newbon->DamageModifier2[HIGHEST_SKILL+1] += base1; + else + newbon->DamageModifier2[base2] += base1; + break; + } + case SE_SlayUndead: { if(newbon->SlayUndead[1] < base1) @@ -1909,6 +1918,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_DamageModifier2: + { + if(base2 == -1) + newbon->DamageModifier2[HIGHEST_SKILL+1] += effect_value; + else + newbon->DamageModifier2[base2] += effect_value; + break; + } + case SE_MinDamageModifier: { if(base2 == -1) @@ -3454,6 +3472,17 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) break; } + case SE_DamageModifier2: + { + for(int e = 0; e < HIGHEST_SKILL+1; e++) + { + spellbonuses.DamageModifier2[e] = effect_value; + aabonuses.DamageModifier2[e] = effect_value; + itembonuses.DamageModifier2[e] = effect_value; + } + break; + } + case SE_MinDamageModifier: { for(int e = 0; e < HIGHEST_SKILL+1; e++) diff --git a/zone/common.h b/zone/common.h index dfb500d47..67386d910 100644 --- a/zone/common.h +++ b/zone/common.h @@ -279,6 +279,7 @@ struct StatBonuses { int16 HitChance; //HitChance/15 == % increase i = Accuracy (Item: Accuracy) int16 HitChanceEffect[HIGHEST_SKILL+2]; //Spell effect Chance to Hit, straight percent increase int16 DamageModifier[HIGHEST_SKILL+2]; //i + int16 DamageModifier2[HIGHEST_SKILL+2]; //i int16 MinDamageModifier[HIGHEST_SKILL+2]; //i int16 ProcChance; // ProcChance/10 == % increase i = CombatEffects int16 ProcChanceSPA; // ProcChance from spell effects diff --git a/zone/mob.cpp b/zone/mob.cpp index d5ff23a7d..5faeffa65 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4277,6 +4277,9 @@ int16 Mob::GetMeleeDamageMod_SE(uint16 skill) dmg_mod += itembonuses.DamageModifier[HIGHEST_SKILL+1] + spellbonuses.DamageModifier[HIGHEST_SKILL+1] + aabonuses.DamageModifier[HIGHEST_SKILL+1] + itembonuses.DamageModifier[skill] + spellbonuses.DamageModifier[skill] + aabonuses.DamageModifier[skill]; + dmg_mod += itembonuses.DamageModifier2[HIGHEST_SKILL+1] + spellbonuses.DamageModifier2[HIGHEST_SKILL+1] + aabonuses.DamageModifier2[HIGHEST_SKILL+1] + + itembonuses.DamageModifier2[skill] + spellbonuses.DamageModifier2[skill] + aabonuses.DamageModifier2[skill]; + if (HasShieldEquiped() && !IsOffHandAtk()) dmg_mod += itembonuses.ShieldEquipDmgMod[0] + spellbonuses.ShieldEquipDmgMod[0] + aabonuses.ShieldEquipDmgMod[0]; From aa6af15cb5cbd06e3054f24721b5f4841eec38df Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 15:49:56 -0400 Subject: [PATCH 03/62] Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) --- changelog.txt | 1 + common/spdat.h | 2 +- zone/spell_effects.cpp | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 7002939e6..698d84044 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,7 @@ Kayen: Implemented SE_AStacker, SE_BStacker, SE_CStacker, SE_DStacker. These effects when present in buffs prevent each other from stacking, Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) +Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 7e0367fd7..f03e944c9 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -602,7 +602,7 @@ typedef enum { #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage #define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken #define SE_TriggerSpellThreshold 454 // implemented Trigger effect on X amount of spell damage taken -//#define SE_AddHatePct 455 // not used +#define SE_AddHatePct 455 // implement - Modify total hate by % //#define SE_AddHateOverTimePct 456 // not used //#define SE_ResourceTap 457 // not used //#define SE_FactionModPct 458 // not used diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 2c83ef1cd..f78d0e5c5 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2668,6 +2668,14 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) SlowMitigation(caster); break; + case SE_AddHatePct: + { + if (IsNPC()) + CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100)); + + break; + } + // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: From a34a69b4c48759bffe7fad33928011575d3e8ee2 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 17 Jun 2014 16:08:19 -0400 Subject: [PATCH 04/62] Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) --- changelog.txt | 1 + common/spdat.h | 4 ++-- zone/spell_effects.cpp | 8 ++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 698d84044..6c87c8534 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,7 @@ These effects when present in buffs prevent each other from stacking, Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) +Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index f03e944c9..4edd6543b 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -602,8 +602,8 @@ typedef enum { #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage #define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken #define SE_TriggerSpellThreshold 454 // implemented Trigger effect on X amount of spell damage taken -#define SE_AddHatePct 455 // implement - Modify total hate by % -//#define SE_AddHateOverTimePct 456 // not used +#define SE_AddHatePct 455 // implemented Modify total hate by % +#define SE_AddHateOverTimePct 456 // implemented Modify total hate by % over time. //#define SE_ResourceTap 457 // not used //#define SE_FactionModPct 458 // not used #define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index f78d0e5c5..9a536b832 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -3530,6 +3530,14 @@ 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)); + + break; + } + default: { // do we need to do anyting here? From 70476bfb06b797c1abdb434feb2a2794fd2bebed Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 18 Jun 2014 06:25:14 -0400 Subject: [PATCH 05/62] Implemented SE_DoubleRiposte --- changelog.txt | 1 + common/spdat.h | 2 +- zone/attack.cpp | 4 ++++ zone/bonuses.cpp | 16 ++++++++++++++++ zone/common.h | 1 + 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 6c87c8534..3f4572dce 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,7 @@ Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) +Kayen: Implemented SE_DoubleRiposte (Modifies +/- your double riposte chance) == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 4edd6543b..ba671acea 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -370,7 +370,7 @@ typedef enum { #define SE_SkillDamageAmount 220 // implemented #define SE_Packrat 221 // implemented as bonus #define SE_BlockBehind 222 // implemented - Chance to block from behind (with our without Shield) -//#define SE_DoubleRiposte 223 // not used +#define SE_DoubleRiposte 223 // implemented - Chance to double riposte [not used on live] #define SE_GiveDoubleRiposte 224 // implemented[AA] #define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance. #define SE_TwoHandBash 226 // *not implemented as bonus diff --git a/zone/attack.cpp b/zone/attack.cpp index 34a1de47d..a3e5c37cd 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4449,6 +4449,10 @@ void Mob::DoRiposte(Mob* defender) { defender->spellbonuses.GiveDoubleRiposte[0] + defender->itembonuses.GiveDoubleRiposte[0]; + DoubleRipChance = defender->aabonuses.DoubleRiposte + + defender->spellbonuses.DoubleRiposte + + defender->itembonuses.DoubleRiposte; + //Live AA - Double Riposte if(DoubleRipChance && (DoubleRipChance >= MakeRandomInt(0, 100))) { mlog(COMBAT__ATTACKS, "Preforming a double riposed (%d percent chance)", DoubleRipChance); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 03e1d76f6..c549bdf72 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1116,6 +1116,11 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_DoubleRiposte: + { + newbon->DoubleRiposte += base1; + } + case SE_GiveDoubleRiposte: { //0=Regular Riposte 1=Skill Attack Riposte 2=Skill @@ -2571,6 +2576,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_DoubleRiposte: + { + newbon->DoubleRiposte += effect_value; + } + case SE_GiveDoubleRiposte: { //Only allow for regular double riposte chance. @@ -3978,6 +3988,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.MasteryofPast = effect_value; break; + case SE_DoubleRiposte: + spellbonuses.DoubleRiposte = effect_value; + itembonuses.DoubleRiposte = effect_value; + aabonuses.DoubleRiposte = effect_value; + break; + case SE_GiveDoubleRiposte: spellbonuses.GiveDoubleRiposte[0] = effect_value; itembonuses.GiveDoubleRiposte[0] = effect_value; diff --git a/zone/common.h b/zone/common.h index 67386d910..a88d8adda 100644 --- a/zone/common.h +++ b/zone/common.h @@ -383,6 +383,7 @@ struct StatBonuses { int16 PetCriticalHit; // Allow pets to critical hit with % value. int16 PetAvoidance; // Pet avoidance chance. int16 CombatStability; // Melee damage mitigation. + int16 DoubleRiposte; // Chance to double riposte int16 GiveDoubleRiposte[3]; // 0=Regular Chance, 1=Skill Attack Chance, 2=Skill uint16 RaiseSkillCap[2]; // Raise a specific skill cap (1 = value, 2=skill) int16 Ambidexterity; // Increase chance to duel wield by adding bonus 'skill'. From 5a14a85f52043199b589af6f13353205a1949db8 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Fri, 20 Jun 2014 18:10:29 -0400 Subject: [PATCH 06/62] Implemention for SE_Berserk, SE_Vampirism (These are not used on live) Fix for NPC not receiving spell bonus derived HP regen. --- changelog.txt | 6 +++++- common/spdat.h | 6 +++--- zone/attack.cpp | 20 ++++++++++++-------- zone/bonuses.cpp | 28 ++++++++++++++++++++++++++++ zone/common.h | 4 +++- zone/mob.cpp | 21 +++++++++------------ zone/npc.cpp | 12 ++++++------ zone/npc.h | 1 + 8 files changed, 67 insertions(+), 31 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3f4572dce..58955e931 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,7 +7,11 @@ Any effect with B prevents A, C prevents B, D prevents C. Kayen: Implemented SE_DamageModifier2 (Stacks with SE_DamageModifier, mods damage by skill type) Kayen: Implemented SE_AddHatePct (Modifies +/- your total hate on NPC by percent) Kayen: Implemented SE_AddHateOverTimePct (Modifies +/- your total hate on NPC by percent over time) -Kayen: Implemented SE_DoubleRiposte (Modifies +/- your double riposte chance) +Kayen: Implemented SE_DoubleRiposte (Modifies +/- your double riposte chance) *Not used in any live effects +Kayen: Implemented SE_Berserk (Sets client as 'Berserk' giving chance to crippling blow) *Not used in any live effects +Kayen: Implemented SE_Vampirsm (Stackable lifetap from melee effect) *Not used in any live effects +Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitrary hard cap of 100%, Negative value will now dmg client. +Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index ba671acea..c0813ea40 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -190,9 +190,9 @@ typedef enum { #define SE_DivineAura 40 // implemented #define SE_Destroy 41 // implemented - Disintegrate, Banishment of Shadows #define SE_ShadowStep 42 // implemented -//#define SE_Berserk 43 // not used -#define SE_Lycanthropy 44 // implemented -//#define SE_Vampirism 45 // not used +#define SE_Berserk 43 // implemented (*not used in any known live spell) Makes client 'Berserk' giving crip blow chance. +#define SE_Lycanthropy 44 // implemented +#define SE_Vampirism 45 // implemented (*not used in any known live spell) Stackable lifetap from melee. #define SE_ResistFire 46 // implemented #define SE_ResistCold 47 // implemented #define SE_ResistPoison 48 // implemented diff --git a/zone/attack.cpp b/zone/attack.cpp index a3e5c37cd..074288c3d 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4283,6 +4283,7 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack float critChance = 0.0f; + bool IsBerskerSPA = false; //1: Try Slay Undead if(defender && defender->GetBodyType() == BT_Undead || defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire){ @@ -4310,12 +4311,15 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack //are defined you will have an innate chance to hit at Level 1 regardless of bonuses. //Warning: Do not define these rules if you want live like critical hits. critChance += RuleI(Combat, MeleeBaseCritChance); - + if (IsClient()) { - critChance += RuleI(Combat, ClientBaseCritChance); + critChance += RuleI(Combat, ClientBaseCritChance); - if ((GetClass() == WARRIOR || GetClass() == BERSERKER) && GetLevel() >= 12) { - if (IsBerserk()) + if (spellbonuses.BerserkSPA || itembonuses.BerserkSPA || aabonuses.BerserkSPA) + IsBerskerSPA = true; + + if (((GetClass() == WARRIOR || GetClass() == BERSERKER) && GetLevel() >= 12) || IsBerskerSPA) { + if (IsBerserk() || IsBerskerSPA) critChance += RuleI(Combat, BerserkBaseCritChance); else critChance += RuleI(Combat, WarBerBaseCritChance); @@ -4360,15 +4364,15 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack uint16 critMod = 200; bool crip_success = false; int16 CripplingBlowChance = GetCrippBlowChance(); - + //Crippling Blow Chance: The percent value of the effect is applied //to the your Chance to Critical. (ie You have 10% chance to critical and you //have a 200% Chance to Critical Blow effect, therefore you have a 20% Chance to Critical Blow. - if (CripplingBlowChance || IsBerserk()) { - if (!IsBerserk()) + if (CripplingBlowChance || (IsBerserk() || IsBerskerSPA)) { + if (!IsBerserk() && !IsBerskerSPA) critChance *= float(CripplingBlowChance)/100.0f; - if (IsBerserk() || MakeRandomFloat(0, 1) < critChance) { + if ((IsBerserk() || IsBerskerSPA) || MakeRandomFloat(0, 1) < critChance) { critMod = 400; crip_success = true; } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index c549bdf72..09d7766a7 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1248,6 +1248,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_Vampirism: + newbon->Vampirism += base1; + break; + case SE_FrenziedDevastation: newbon->FrenziedDevastation += base2; break; @@ -1256,6 +1260,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->SpellProcChance += base1; break; + case SE_Berserk: + newbon->BerserkSPA = true; + break; + } } } @@ -1827,6 +1835,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_Vampirism: + newbon->Vampirism += effect_value; + break; + case SE_AllInstrumentMod: { if(effect_value > newbon->singingMod) @@ -2705,6 +2717,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->DStacker = true; break; + case SE_Berserk: + newbon->BerserkSPA = true; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4094,6 +4110,18 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.AbsorbMagicAtt[0] = effect_value; spellbonuses.AbsorbMagicAtt[1] = -1; break; + + case SE_Berserk: + spellbonuses.BerserkSPA = false; + aabonuses.BerserkSPA = false; + itembonuses.BerserkSPA = false; + break; + + case SE_Vampirism: + spellbonuses.Vampirism = effect_value; + aabonuses.Vampirism = effect_value; + itembonuses.Vampirism = effect_value; + break; } } diff --git a/zone/common.h b/zone/common.h index a88d8adda..67b616248 100644 --- a/zone/common.h +++ b/zone/common.h @@ -290,7 +290,8 @@ struct StatBonuses { int16 FlurryChance; int16 Accuracy[HIGHEST_SKILL+2]; //Accuracy/15 == % increase [Spell Effect: Accuracy) int16 HundredHands; //extra haste, stacks with all other haste i - int8 MeleeLifetap; //i + int16 MeleeLifetap; //i + int16 Vampirism; //i int16 HealRate; // Spell effect that influences effectiveness of heals int32 MaxHPChange; // Spell Effect int16 SkillDmgTaken[HIGHEST_SKILL+2]; // All Skills + -1 @@ -355,6 +356,7 @@ struct StatBonuses { bool BStacker; // For buff stack blocking bool CStacker; // For buff stack blocking bool DStacker; // For buff stack blocking + bool BerserkSPA; // berserk effect // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/mob.cpp b/zone/mob.cpp index 5faeffa65..06dbe4519 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -4337,22 +4337,19 @@ int16 Mob::GetSkillDmgAmt(uint16 skill) void Mob::MeleeLifeTap(int32 damage) { - if(damage > 0 && (spellbonuses.MeleeLifetap || itembonuses.MeleeLifetap || aabonuses.MeleeLifetap )) - { - int lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap; - - if(lifetap_amt > 100) - lifetap_amt = 100; - - else if (lifetap_amt < -99) - lifetap_amt = -99; + int16 lifetap_amt = 0; + lifetap_amt = spellbonuses.MeleeLifetap + itembonuses.MeleeLifetap + aabonuses.MeleeLifetap + + spellbonuses.Vampirism + itembonuses.Vampirism + aabonuses.Vampirism; + if(lifetap_amt && damage > 0){ lifetap_amt = damage * lifetap_amt / 100; - mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage); - //heal self for damage done.. - HealDamage(lifetap_amt); + + if (lifetap_amt > 0) + HealDamage(lifetap_amt); //Heal self for modified damage amount. + else + Damage(this, -lifetap_amt,0, SkillEvocation,false); //Dmg self for modified damage amount. } } diff --git a/zone/npc.cpp b/zone/npc.cpp index 3886d7c66..38989bccb 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -599,19 +599,19 @@ bool NPC::Process() //Lieka Edit:Fixing NPC regen.NPCs should regen to full during a set duration, not based on their HPs.Increase NPC's HPs by % of total HPs / tick. if((GetHP() < GetMaxHP()) && !IsPet()) { if(!IsEngaged()) {//NPC out of combat - if(hp_regen > OOCRegen) - SetHP(GetHP() + hp_regen); + if(GetNPCHPRegen() > OOCRegen) + SetHP(GetHP() + GetNPCHPRegen()); else SetHP(GetHP() + OOCRegen); } else - SetHP(GetHP()+hp_regen); + SetHP(GetHP()+GetNPCHPRegen()); } else if(GetHP() < GetMaxHP() && GetOwnerID() !=0) { if(!IsEngaged()) //pet - SetHP(GetHP()+hp_regen+bonus+(GetLevel()/5)); + SetHP(GetHP()+GetNPCHPRegen()+bonus+(GetLevel()/5)); else - SetHP(GetHP()+hp_regen+bonus); + SetHP(GetHP()+GetNPCHPRegen()+bonus); } else - SetHP(GetHP()+hp_regen); + SetHP(GetHP()+GetNPCHPRegen()); if(GetMana() < GetMaxMana()) { SetMana(GetMana()+mana_regen+bonus); diff --git a/zone/npc.h b/zone/npc.h index ae444c099..07c81e79b 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -256,6 +256,7 @@ public: virtual void DoClassAttacks(Mob *target); void CheckSignal(); inline bool IsTargetableWithHotkey() const { return no_target_hotkey; } + int32 GetNPCHPRegen() const { return hp_regen + itembonuses.HPRegen + spellbonuses.HPRegen; } //waypoint crap int GetMaxWp() const { return max_wp; } From c20f35b3e8bdf13cab8a40c6368226b68104eff4 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sat, 21 Jun 2014 10:12:24 -0400 Subject: [PATCH 07/62] minor fix --- zone/spell_effects.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 9a536b832..af20d3734 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2897,7 +2897,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_AStacker: case SE_BStacker: case SE_CStacker: - case SE_DStacker: + case SE_DStacker: + case SE_DoubleRiposte: + case SE_Berserk: + case SE_Vampirism: { break; } From a4769239fa93859b293eac6f79b60da27226a6f9 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 06:16:34 -0400 Subject: [PATCH 08/62] Fixes and Updates to spell and melee mitigation runes. -Fix for calculation error when rune was to be removed. -Updated to support these spell effect limit values which give a max amount per hit/spell that can be mitigated. -Updated to allow support for these spells effects when the max (rune value) is set to zero, which essentially gives you unlimited mitigation but typically there is a limit value set. --- changelog.txt | 1 + common/spdat.h | 2 +- zone/attack.cpp | 46 +++++++++++++++++++++++++++++++++------------- zone/bonuses.cpp | 6 ++++++ zone/common.h | 6 +++--- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/changelog.txt b/changelog.txt index 58955e931..97e4beb4a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -12,6 +12,7 @@ Kayen: Implemented SE_Berserk (Sets client as 'Berserk' giving chance to crippli Kayen: Implemented SE_Vampirsm (Stackable lifetap from melee effect) *Not used in any live effects Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitrary hard cap of 100%, Negative value will now dmg client. Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. +Kayen: Fixes and Updates for melee and spell mitigation runes. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index c0813ea40..3cd4a232a 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -307,7 +307,7 @@ typedef enum { #define SE_SpellDamageShield 157 // implemented - Petrad's Protection #define SE_Reflect 158 // implemented #define SE_AllStats 159 // implemented -#define SE_MakeDrunk 160 // implemented - poorly though, should check against tolerance +//#define SE_MakeDrunk 160 // *not implemented - Effect works entirely client side (Should check against tolerance) #define SE_MitigateSpellDamage 161 // implemented - rune with max value #define SE_MitigateMeleeDamage 162 // implemented - rune with max value #define SE_NegateAttacks 163 // implemented diff --git a/zone/attack.cpp b/zone/attack.cpp index 074288c3d..f3cdedc1c 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3188,11 +3188,11 @@ int32 Mob::ReduceDamage(int32 damage) { DisableMeleeRune = true; int damage_to_reduce = damage * spellbonuses.MeleeThresholdGuard[0] / 100; - if(damage_to_reduce > buffs[slot].melee_rune) + if(damage_to_reduce >= buffs[slot].melee_rune) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MeleeThresholdGuard %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].melee_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].melee_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3212,11 +3212,15 @@ int32 Mob::ReduceDamage(int32 damage) if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateMeleeRune[0] / 100; - if(damage_to_reduce > buffs[slot].melee_rune) + + if (spellbonuses.MitigateMeleeRune[2] && (damage_to_reduce > spellbonuses.MitigateMeleeRune[2])) + damage_to_reduce = spellbonuses.MitigateMeleeRune[2]; + + if(spellbonuses.MitigateMeleeRune[3] && (damage_to_reduce >= buffs[slot].melee_rune)) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].melee_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].melee_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3224,7 +3228,10 @@ int32 Mob::ReduceDamage(int32 damage) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining.", damage_to_reduce, buffs[slot].melee_rune); - buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); + + if (spellbonuses.MitigateMeleeRune[3]) + buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); + damage -= damage_to_reduce; } } @@ -3286,15 +3293,21 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateDotRune[0] / 100; - if(damage_to_reduce > buffs[slot].dot_rune) + + if (spellbonuses.MitigateDotRune[2] && (damage_to_reduce > spellbonuses.MitigateDotRune[2])) + damage_to_reduce = spellbonuses.MitigateDotRune[2]; + + if(spellbonuses.MitigateDotRune[3] && (damage_to_reduce >= buffs[slot].dot_rune)) { - damage -= damage_to_reduce; + damage -= buffs[slot].dot_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } else { - buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce); + if (spellbonuses.MitigateDotRune[3]) + buffs[slot].dot_rune = (buffs[slot].dot_rune - damage_to_reduce); + damage -= damage_to_reduce; } } @@ -3316,9 +3329,9 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi { DisableSpellRune = true; int damage_to_reduce = damage * spellbonuses.SpellThresholdGuard[0] / 100; - if(damage_to_reduce > buffs[slot].magic_rune) + if(damage_to_reduce >= buffs[slot].magic_rune) { - damage -= damage_to_reduce; + damage -= buffs[slot].magic_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3337,11 +3350,15 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(slot >= 0) { int damage_to_reduce = damage * spellbonuses.MitigateSpellRune[0] / 100; - if(damage_to_reduce > buffs[slot].magic_rune) + + if (spellbonuses.MitigateSpellRune[2] && (damage_to_reduce > spellbonuses.MitigateSpellRune[2])) + damage_to_reduce = spellbonuses.MitigateSpellRune[2]; + + if(spellbonuses.MitigateSpellRune[3] && (damage_to_reduce >= buffs[slot].magic_rune)) { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateSpellDamage %d damage negated, %d" " damage remaining, fading buff.", damage_to_reduce, buffs[slot].magic_rune); - damage -= damage_to_reduce; + damage -= buffs[slot].magic_rune; if(!TryFadeEffect(slot)) BuffFadeBySlot(slot); } @@ -3349,7 +3366,10 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi { mlog(SPELLS__EFFECT_VALUES, "Mob::ReduceDamage SE_MitigateMeleeDamage %d damage negated, %d" " damage remaining.", damage_to_reduce, buffs[slot].magic_rune); - buffs[slot].magic_rune = (buffs[slot].magic_rune - damage_to_reduce); + + if (spellbonuses.MitigateSpellRune[3]) + buffs[slot].magic_rune = (buffs[slot].magic_rune - damage_to_reduce); + damage -= damage_to_reduce; } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 09d7766a7..ed5be19e7 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2303,6 +2303,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateMeleeRune[0] < effect_value){ newbon->MitigateMeleeRune[0] = effect_value; newbon->MitigateMeleeRune[1] = buffslot; + newbon->MitigateMeleeRune[2] = base2; + newbon->MitigateMeleeRune[3] = max; } break; } @@ -2333,6 +2335,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateSpellRune[0] < effect_value){ newbon->MitigateSpellRune[0] = effect_value; newbon->MitigateSpellRune[1] = buffslot; + newbon->MitigateSpellRune[2] = base2; + newbon->MitigateSpellRune[3] = max; } break; } @@ -2342,6 +2346,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (newbon->MitigateDotRune[0] < effect_value){ newbon->MitigateDotRune[0] = effect_value; newbon->MitigateDotRune[1] = buffslot; + newbon->MitigateDotRune[2] = base2; + newbon->MitigateDotRune[3] = max; } break; } diff --git a/zone/common.h b/zone/common.h index 67b616248..0cec22336 100644 --- a/zone/common.h +++ b/zone/common.h @@ -329,11 +329,11 @@ struct StatBonuses { bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses) int16 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage uint16 NegateAttacks[2]; // 0 = bool HasEffect 1 = Buff Slot - uint16 MitigateMeleeRune[2]; // 0 = Mitigation value 1 = Buff Slot + uint16 MitigateMeleeRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per hit 3 = Rune Amt uint16 MeleeThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. uint16 SpellThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. - uint16 MitigateSpellRune[2]; // 0 = Mitigation value 1 = Buff Slot - uint16 MitigateDotRune[2]; // 0 = Mitigation value 1 = Buff Slot + uint16 MitigateSpellRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per spell 3 = Rune Amt + uint16 MitigateDotRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per tick 3 = Rune Amt uint32 TriggerMeleeThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger uint32 TriggerSpellThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger uint16 ManaAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Buff Slot From 8ad9ad578c5fb22c9c7f7cc5c158214bb417cc04 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 10:30:18 -0400 Subject: [PATCH 09/62] Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. --- changelog.txt | 1 + zone/attack.cpp | 14 +++++++++++--- zone/bonuses.cpp | 1 + zone/common.h | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 97e4beb4a..e22f02697 100644 --- a/changelog.txt +++ b/changelog.txt @@ -13,6 +13,7 @@ Kayen: Implemented SE_Vampirsm (Stackable lifetap from melee effect) *Not used i Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitrary hard cap of 100%, Negative value will now dmg client. Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. Kayen: Fixes and Updates for melee and spell mitigation runes. +Kayen: Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/zone/attack.cpp b/zone/attack.cpp index f3cdedc1c..99682eee5 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3176,7 +3176,11 @@ int32 Mob::ReduceDamage(int32 damage) if(!TryFadeEffect(slot)) BuffFadeBySlot(slot , true); } - return -6; + + if (spellbonuses.NegateAttacks[2] && (damage > spellbonuses.NegateAttacks[2])) + damage -= spellbonuses.NegateAttacks[2]; + else + return -6; } } @@ -3272,7 +3276,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi int32 slot = -1; // See if we block the spell outright first - if (spellbonuses.NegateAttacks[0]){ + if (!iBuffTic && spellbonuses.NegateAttacks[0]){ slot = spellbonuses.NegateAttacks[1]; if(slot >= 0) { if(--buffs[slot].numhits == 0) { @@ -3280,7 +3284,11 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(!TryFadeEffect(slot)) BuffFadeBySlot(slot , true); } - return 0; + + if (spellbonuses.NegateAttacks[2] && (damage > spellbonuses.NegateAttacks[2])) + damage -= spellbonuses.NegateAttacks[2]; + else + return 0; } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index ed5be19e7..ffb13edd8 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2294,6 +2294,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne if (!newbon->NegateAttacks[0]){ newbon->NegateAttacks[0] = 1; newbon->NegateAttacks[1] = buffslot; + newbon->NegateAttacks[2] = max; } break; } diff --git a/zone/common.h b/zone/common.h index 0cec22336..b687d07df 100644 --- a/zone/common.h +++ b/zone/common.h @@ -328,7 +328,7 @@ struct StatBonuses { uint16 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have. bool NegateEffects; // Check if you contain a buff with negate effect. (only spellbonuses) int16 SkillDamageAmount2[HIGHEST_SKILL+2]; // Adds skill specific damage - uint16 NegateAttacks[2]; // 0 = bool HasEffect 1 = Buff Slot + uint16 NegateAttacks[3]; // 0 = bool HasEffect 1 = Buff Slot 2 = Max damage absorbed per hit uint16 MitigateMeleeRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per hit 3 = Rune Amt uint16 MeleeThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. uint16 SpellThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. From f28a392f71c927fb8171be7adfa216743c4c640d Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 15:55:04 -0400 Subject: [PATCH 10/62] SE_NegateAttacks buff stacking optimized. --- zone/bonuses.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index ffb13edd8..481ec668a 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2291,7 +2291,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_NegateAttacks: { - if (!newbon->NegateAttacks[0]){ + if (!newbon->NegateAttacks[0] || + ((newbon->NegateAttacks[0] && newbon->NegateAttacks[2]) && (newbon->NegateAttacks[2] < max))){ newbon->NegateAttacks[0] = 1; newbon->NegateAttacks[1] = buffslot; newbon->NegateAttacks[2] = max; From 41b190930f9b855b88bba63b12bb1a4b0215f531 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 22 Jun 2014 23:10:29 -0400 Subject: [PATCH 11/62] Kayen: Implemented SE_Metabolism - Modifies food/drink consumption rates. [Data for AA is already in database] --- changelog.txt | 1 + common/spdat.h | 2 +- zone/bonuses.cpp | 15 +++++++++++++++ zone/client.cpp | 20 ++++++-------------- zone/common.h | 3 ++- zone/spell_effects.cpp | 1 + 6 files changed, 26 insertions(+), 16 deletions(-) diff --git a/changelog.txt b/changelog.txt index e22f02697..f0dd21757 100644 --- a/changelog.txt +++ b/changelog.txt @@ -14,6 +14,7 @@ Kayen: Minor fixes to how lifetap from melee effects are calced. Removed arbitra Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived from spell buffs. Kayen: Fixes and Updates for melee and spell mitigation runes. Kayen: Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. +Kayen: Implemented SE_Metabolism - Modifies food/drink consumption rates. [Data for AA is already in database] == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/common/spdat.h b/common/spdat.h index 3cd4a232a..b302e8314 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -380,7 +380,7 @@ typedef enum { //#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability #define SE_StunBashChance 231 // implemented - increase chance to stun from bash. #define SE_DivineSave 232 // implemented (base1 == % chance on death to insta-res) (base2 == spell cast on save) -//#define SE_Metabolism 233 // *not implemented - (Crown of Feathers) Increase metabolism? +#define SE_Metabolism 233 // implemented - Modifies food/drink consumption rates. //#define SE_ReduceApplyPoisonTime 234 // not implemented as bonus - reduces the time to apply poison #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. //#define SE_FreePet 236 // not used diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 481ec668a..3ce6becca 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1264,6 +1264,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->BerserkSPA = true; break; + case SE_Metabolism: + newbon->Metabolism += base1; + break; + } } } @@ -2729,6 +2733,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->BerserkSPA = true; break; + + case SE_Metabolism: + newbon->Metabolism += effect_value; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4130,6 +4139,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.Vampirism = effect_value; itembonuses.Vampirism = effect_value; break; + + case SE_Metabolism: + spellbonuses.Metabolism = effect_value; + aabonuses.Metabolism = effect_value; + itembonuses.Metabolism = effect_value; + break; } } diff --git a/zone/client.cpp b/zone/client.cpp index 7aa7bd748..2ce193346 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8134,20 +8134,12 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_ uint16 cons_mod = 180; - switch(GetAA(aaInnateMetabolism)){ - case 1: - cons_mod = cons_mod * 110 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - case 2: - cons_mod = cons_mod * 125 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - case 3: - cons_mod = cons_mod * 150 * RuleI(Character, ConsumptionMultiplier) / 10000; - break; - default: - cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; - break; - } + int16 metabolism_bonus = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism; + + if (metabolism_bonus) + cons_mod = cons_mod * metabolism_bonus* RuleI(Character, ConsumptionMultiplier) / 10000; + else + cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; if(type == ItemTypeFood) { diff --git a/zone/common.h b/zone/common.h index b687d07df..f94962ee1 100644 --- a/zone/common.h +++ b/zone/common.h @@ -356,7 +356,8 @@ struct StatBonuses { bool BStacker; // For buff stack blocking bool CStacker; // For buff stack blocking bool DStacker; // For buff stack blocking - bool BerserkSPA; // berserk effect + bool BerserkSPA; // berserk effect + int16 Metabolism; // Food/drink consumption rates. // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index af20d3734..b46f34a6e 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2901,6 +2901,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_DoubleRiposte: case SE_Berserk: case SE_Vampirism: + case SE_Metabolism: { break; } From 58175a54426c04a1a540ec747e5737f32b73ca45 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Mon, 23 Jun 2014 08:37:23 -0400 Subject: [PATCH 12/62] Update to SE_BalanaceMana, SE_BalanceHP to support limit value which caps max mana/hp that can be taken per player. --- changelog.txt | 1 + zone/client.cpp | 2 +- zone/groups.cpp | 26 ++++++++++++++++++++------ zone/groups.h | 4 ++-- zone/raids.cpp | 23 +++++++++++++++++------ zone/raids.h | 4 ++-- zone/spell_effects.cpp | 8 ++++---- 7 files changed, 47 insertions(+), 21 deletions(-) diff --git a/changelog.txt b/changelog.txt index f0dd21757..c4fa6cecf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -15,6 +15,7 @@ Kayen: Fix to issue that prevented NPC's from receiving HP Regeneration derived Kayen: Fixes and Updates for melee and spell mitigation runes. Kayen: Update to SE_NegateAttack, 'max' value can now set upper limit of damage absorbed. DOT ticks will no longer be absorbed. Kayen: Implemented SE_Metabolism - Modifies food/drink consumption rates. [Data for AA is already in database] +Kayen: Update to SE_BalanaceMana, SE_BalanceHP to support limit value which caps max mana/hp that can be taken per player. == 06/13/2014 == Kayen: For table 'npc_spell_effects_entries' setting se_max for damage shield effects (59) will now determine the DS Type (ie burning) diff --git a/zone/client.cpp b/zone/client.cpp index 2ce193346..4ec3ce2d7 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8137,7 +8137,7 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_ int16 metabolism_bonus = spellbonuses.Metabolism + itembonuses.Metabolism + aabonuses.Metabolism; if (metabolism_bonus) - cons_mod = cons_mod * metabolism_bonus* RuleI(Character, ConsumptionMultiplier) / 10000; + cons_mod = cons_mod * metabolism_bonus * RuleI(Character, ConsumptionMultiplier) / 10000; else cons_mod = cons_mod * RuleI(Character, ConsumptionMultiplier) / 100; diff --git a/zone/groups.cpp b/zone/groups.cpp index aa50ba2c9..245765c32 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -1095,7 +1095,7 @@ void Group::HealGroup(uint32 heal_amt, Mob* caster, int32 range) } -void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) +void Group::BalanceHP(int32 penalty, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -1103,7 +1103,7 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) if (!range) range = 200; - int dmgtaken = 0, numMem = 0; + int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0; float distance; float range2 = range*range; @@ -1114,7 +1114,12 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) if(members[gi]){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ - dmgtaken += (members[gi]->GetMaxHP() - members[gi]->GetHP()); + + dmgtaken_tmp = members[gi]->GetMaxHP() - members[gi]->GetHP(); + if (limit && (dmgtaken_tmp > limit)) + dmgtaken_tmp = limit; + + dmgtaken += (dmgtaken_tmp); numMem += 1; } } @@ -1140,7 +1145,7 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster) } } -void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) +void Group::BalanceMana(int32 penalty, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -1151,14 +1156,19 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) float distance; float range2 = range*range; - int manataken = 0, numMem = 0; + int manataken = 0, numMem = 0, manataken_tmp = 0; unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ - manataken += (members[gi]->GetMaxMana() - members[gi]->GetMana()); + + manataken_tmp = members[gi]->GetMaxMana() - members[gi]->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; + + manataken += (manataken_tmp); numMem += 1; } } @@ -1166,6 +1176,10 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster) manataken += manataken * penalty / 100; manataken /= numMem; + + if (limit && (manataken > limit)) + manataken = limit; + for(gi = 0; gi < MAX_GROUP_MEMBERS; gi++) { if(members[gi]){ diff --git a/zone/groups.h b/zone/groups.h index c5a3f8ab1..fe21ff3a4 100644 --- a/zone/groups.h +++ b/zone/groups.h @@ -86,8 +86,8 @@ public: uint16 GetAvgLevel(); bool LearnMembers(); void VerifyGroup(); - void BalanceHP(int32 penalty, int32 range = 0, Mob* caster = nullptr); - void BalanceMana(int32 penalty, int32 range = 0, Mob* caster = nullptr); + void BalanceHP(int32 penalty, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); + void BalanceMana(int32 penalty, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); void HealGroup(uint32 heal_amt, Mob* caster, int32 range = 0); inline void SetGroupAAs(GroupLeadershipAA_Struct *From) { memcpy(&LeaderAbilities, From, sizeof(GroupLeadershipAA_Struct)); } inline void GetGroupAAs(GroupLeadershipAA_Struct *Into) { memcpy(Into, &LeaderAbilities, sizeof(GroupLeadershipAA_Struct)); } diff --git a/zone/raids.cpp b/zone/raids.cpp index bf6f76d5c..be0b697db 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -504,7 +504,7 @@ void Raid::HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range) } -void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) +void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -512,7 +512,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) if (!range) range = 200; - int dmgtaken = 0, numMem = 0; + int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0; int gi = 0; float distance; @@ -525,7 +525,12 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) { distance = caster->DistNoRoot(*members[gi].member); if(distance <= range2){ - dmgtaken += (members[gi].member->GetMaxHP() - members[gi].member->GetHP()); + + dmgtaken_tmp = members[gi].member->GetMaxHP() - members[gi].member->GetHP(); + if (limit && (dmgtaken_tmp > limit)) + dmgtaken_tmp = limit; + + dmgtaken += (dmgtaken_tmp); numMem += 1; } } @@ -555,7 +560,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster) } } -void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) +void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster, int32 limit) { if (!caster) return; @@ -566,7 +571,7 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) float distance; float range2 = range*range; - int manataken = 0, numMem = 0; + int manataken = 0, numMem = 0, manataken_tmp = 0; int gi = 0; for(; gi < MAX_RAID_MEMBERS; gi++) { @@ -575,7 +580,12 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) { distance = caster->DistNoRoot(*members[gi].member); if(distance <= range2){ - manataken += (members[gi].member->GetMaxMana() - members[gi].member->GetMana()); + + manataken_tmp = members[gi].member->GetMaxMana() - members[gi].member->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; + + manataken += (manataken_tmp); numMem += 1; } } @@ -584,6 +594,7 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster) manataken += manataken * penalty / 100; manataken /= numMem; + for(gi = 0; gi < MAX_RAID_MEMBERS; gi++) { if(members[gi].member){ diff --git a/zone/raids.h b/zone/raids.h index c8c2f61e4..be12788e6 100644 --- a/zone/raids.h +++ b/zone/raids.h @@ -147,8 +147,8 @@ public: void CastGroupSpell(Mob* caster,uint16 spellid, uint32 gid); void SplitExp(uint32 exp, Mob* other); uint32 GetTotalRaidDamage(Mob* other); - void BalanceHP(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); - void BalanceMana(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr); + void BalanceHP(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); + void BalanceMana(int32 penalty, uint32 gid, int32 range = 0, Mob* caster = nullptr, int32 limit = 0); void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, int32 range = 0); void SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr); void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index b46f34a6e..b846e0058 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2393,7 +2393,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceHP(spell.base[i], gid, spell.range, caster); + r->BalanceHP(spell.base[i], gid, spell.range, caster, spell.base2[i]); break; } } @@ -2403,7 +2403,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceHP(spell.base[i], spell.range, caster); + g->BalanceHP(spell.base[i], spell.range, caster, spell.base2[i]); break; } @@ -2421,7 +2421,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) gid = r->GetGroup(caster->GetName()); if(gid < 11) { - r->BalanceMana(spell.base[i], gid, spell.range, caster); + r->BalanceMana(spell.base[i], gid, spell.range, caster, spell.base2[i]); break; } } @@ -2431,7 +2431,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if(!g) break; - g->BalanceMana(spell.base[i], spell.range, caster); + g->BalanceMana(spell.base[i], spell.range, caster, spell.base2[i]); break; } From a6589e283bd67349a3fb8c76c0789ac93327fcaa Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 23 Jun 2014 16:56:37 -0700 Subject: [PATCH 13/62] Some potential fixes for clang, not complete --- luabind/luabind/detail/format_signature.hpp | 15 ++- zone/groups.cpp | 2 +- zone/lua_general.cpp | 52 +++++----- zone/lua_mob.cpp | 8 +- zone/lua_mob.h | 4 +- zone/lua_parser.cpp | 22 ++-- zone/lua_parser.h | 12 ++- zone/lua_parser_events.cpp | 106 ++++++++++---------- 8 files changed, 114 insertions(+), 107 deletions(-) diff --git a/luabind/luabind/detail/format_signature.hpp b/luabind/luabind/detail/format_signature.hpp index 56e796363..ec56b6196 100644 --- a/luabind/luabind/detail/format_signature.hpp +++ b/luabind/luabind/detail/format_signature.hpp @@ -13,12 +13,17 @@ # include # include -namespace luabind { +namespace luabind { namespace adl { -class object; -class argument; -template -struct table; + class object; + class argument; + template + struct table; +} // namespace adl + +using adl::object; +using adl::argument; +using adl::table; } // namespace luabind diff --git a/zone/groups.cpp b/zone/groups.cpp index aa50ba2c9..3f5b376ee 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -447,7 +447,7 @@ bool Group::UpdatePlayer(Mob* update){ //update their player profile PlayerProfile_Struct &pp = update->CastToClient()->GetPP(); for (i = 0; i < MAX_GROUP_MEMBERS; i++) { - if(membername[0] == '\0') + if(membername[i][0] == '\0') memset(pp.groupMembers[i], 0, 64); else strn0cpy(pp.groupMembers[i], membername[i], 64); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index cfe21dc51..645932d1b 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -27,7 +27,7 @@ struct Appearances { }; struct lua_registered_event { std::string encounter_name; - luabind::object lua_reference; + luabind::adl::object lua_reference; QuestEventID event_id; }; @@ -43,7 +43,7 @@ void unload_encounter(std::string name) { parse->EventEncounter(EVENT_ENCOUNTER_UNLOAD, name, 0); } -void register_event(std::string package_name, std::string name, int evt, luabind::object func) { +void register_event(std::string package_name, std::string name, int evt, luabind::adl::object func) { lua_registered_event e; e.encounter_name = name; e.lua_reference = func; @@ -84,7 +84,7 @@ void unregister_event(std::string package_name, std::string name, int evt) { } } -void register_npc_event(std::string name, int evt, int npc_id, luabind::object func) { +void register_npc_event(std::string name, int evt, int npc_id, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { std::stringstream package_name; package_name << "npc_" << npc_id; @@ -100,7 +100,7 @@ void unregister_npc_event(std::string name, int evt, int npc_id) { unregister_event(package_name.str(), name, evt); } -void register_player_event(std::string name, int evt, luabind::object func) { +void register_player_event(std::string name, int evt, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { register_event("player", name, evt, func); } @@ -110,7 +110,7 @@ void unregister_player_event(std::string name, int evt) { unregister_event("player", name, evt); } -void register_item_event(std::string name, int evt, int item_id, luabind::object func) { +void register_item_event(std::string name, int evt, int item_id, luabind::adl::object func) { std::string package_name = "item_"; package_name += std::to_string(static_cast(item_id)); @@ -126,7 +126,7 @@ void unregister_item_event(std::string name, int evt, int item_id) { unregister_event(package_name, name, evt); } -void register_spell_event(std::string name, int evt, int spell_id, luabind::object func) { +void register_spell_event(std::string name, int evt, int spell_id, luabind::adl::object func) { if(luabind::type(func) == LUA_TFUNCTION) { std::stringstream package_name; package_name << "spell_" << spell_id; @@ -392,7 +392,7 @@ bool lua_bury_player_corpse(uint32 char_id) { return quest_manager.buryplayercorpse(char_id); } -void lua_task_selector(luabind::object table) { +void lua_task_selector(luabind::adl::object table) { if(luabind::type(table) != LUA_TTABLE) { return; } @@ -422,7 +422,7 @@ void lua_task_set_selector(int task_set) { quest_manager.tasksetselector(task_set); } -void lua_enable_task(luabind::object table) { +void lua_enable_task(luabind::adl::object table) { if(luabind::type(table) != LUA_TTABLE) { return; } @@ -449,7 +449,7 @@ void lua_enable_task(luabind::object table) { quest_manager.enabletask(count, tasks); } -void lua_disable_task(luabind::object table) { +void lua_disable_task(luabind::adl::object table) { if(luabind::type(table) != LUA_TTABLE) { return; } @@ -743,8 +743,8 @@ void lua_cross_zone_message_player_by_name(uint32 type, const char *player, cons quest_manager.CrossZoneMessagePlayerByName(type, player, message); } -luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc, Lua_Client client) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L, Lua_NPC npc, Lua_Client client) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = npc; Client *c = client; @@ -759,8 +759,8 @@ luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc, Lua_Client client) { return ret; } -luabind::object lua_get_qglobals(lua_State *L, Lua_Client client) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L, Lua_Client client) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = nullptr; Client *c = client; @@ -775,8 +775,8 @@ luabind::object lua_get_qglobals(lua_State *L, Lua_Client client) { return ret; } -luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L, Lua_NPC npc) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = npc; Client *c = nullptr; @@ -791,8 +791,8 @@ luabind::object lua_get_qglobals(lua_State *L, Lua_NPC npc) { return ret; } -luabind::object lua_get_qglobals(lua_State *L) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_qglobals(lua_State *L) { + luabind::adl::object ret = luabind::newtable(L); NPC *n = nullptr; Client *c = nullptr; @@ -846,8 +846,8 @@ int lua_get_zone_instance_version() { return zone->GetInstanceVersion(); } -luabind::object lua_get_characters_in_instance(lua_State *L, uint16 instance_id) { - luabind::object ret = luabind::newtable(L); +luabind::adl::object lua_get_characters_in_instance(lua_State *L, uint16 instance_id) { + luabind::adl::object ret = luabind::newtable(L); std::list charid_list; uint16 i = 1; @@ -868,11 +868,11 @@ int lua_get_zone_weather() { return zone->zone_weather; } -luabind::object lua_get_zone_time(lua_State *L) { +luabind::adl::object lua_get_zone_time(lua_State *L) { TimeOfDay_Struct eqTime; zone->zone_time.getEQTimeOfDay(time(0), &eqTime); - luabind::object ret = luabind::newtable(L); + luabind::adl::object ret = luabind::newtable(L); ret["zone_hour"] = eqTime.hour - 1; ret["zone_minute"] = eqTime.minute; ret["zone_time"] = (eqTime.hour - 1) * 100 + eqTime.minute; @@ -909,7 +909,7 @@ void lua_remove_spawn_point(uint32 spawn2_id) { } } -void lua_add_spawn_point(luabind::object table) { +void lua_add_spawn_point(luabind::adl::object table) { if(!zone) return; @@ -1280,10 +1280,10 @@ luabind::scope lua_register_general() { luabind::def("cross_zone_signal_client_by_char_id", &lua_cross_zone_signal_client_by_char_id), luabind::def("cross_zone_signal_client_by_name", &lua_cross_zone_signal_client_by_name), luabind::def("cross_zone_message_player_by_name", &lua_cross_zone_message_player_by_name), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*,Lua_Client))&lua_get_qglobals), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*,Lua_NPC))&lua_get_qglobals), - luabind::def("get_qglobals", (luabind::object(*)(lua_State*))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC,Lua_Client))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_Client))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*,Lua_NPC))&lua_get_qglobals), + luabind::def("get_qglobals", (luabind::adl::object(*)(lua_State*))&lua_get_qglobals), luabind::def("get_entity_list", &lua_get_entity_list), luabind::def("get_zone_id", &lua_get_zone_id), luabind::def("get_zone_long_name", &lua_get_zone_long_name), diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 17588caef..50a8b50a7 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -103,7 +103,7 @@ bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_striket return self->Attack(other, hand, from_riposte, is_strikethrough, is_from_spell); } -bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::object opts) { +bool Lua_Mob::Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::adl::object opts) { Lua_Safe_Call_Bool(); ExtraAttackOptions options; @@ -1429,7 +1429,7 @@ void Lua_Mob::SetGender(int in) { self->SendIllusionPacket(self->GetRace(), in); } -void Lua_Mob::SendIllusionPacket(luabind::object illusion) { +void Lua_Mob::SendIllusionPacket(luabind::adl::object illusion) { Lua_Safe_Call_Void(); if(luabind::type(illusion) != LUA_TTABLE) { @@ -1881,7 +1881,7 @@ luabind::scope lua_register_mob() { .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool))&Lua_Mob::Attack) .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool))&Lua_Mob::Attack) .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool))&Lua_Mob::Attack) - .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool,luabind::object))&Lua_Mob::Attack) + .def("Attack", (bool(Lua_Mob::*)(Lua_Mob,int,bool,bool,bool,luabind::adl::object))&Lua_Mob::Attack) .def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int))&Lua_Mob::Damage) .def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,bool))&Lua_Mob::Damage) .def("Damage", (void(Lua_Mob::*)(Lua_Mob,int,int,int,bool,int))&Lua_Mob::Damage) @@ -2125,7 +2125,7 @@ luabind::scope lua_register_mob() { .def("SetTexture", (void(Lua_Mob::*)(int))&Lua_Mob::SetTexture) .def("SetRace", (void(Lua_Mob::*)(int))&Lua_Mob::SetRace) .def("SetGender", (void(Lua_Mob::*)(int))&Lua_Mob::SetGender) - .def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::object))&Lua_Mob::SendIllusionPacket) + .def("SendIllusionPacket", (void(Lua_Mob::*)(luabind::adl::object))&Lua_Mob::SendIllusionPacket) .def("QuestReward", (void(Lua_Mob::*)(Lua_Client))&Lua_Mob::QuestReward) .def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32))&Lua_Mob::QuestReward) .def("QuestReward", (void(Lua_Mob::*)(Lua_Client,uint32,uint32))&Lua_Mob::QuestReward) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index b3e44805a..a5c00c5f0 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -47,7 +47,7 @@ public: bool Attack(Lua_Mob other, int hand, bool from_riposte); bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough); bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell); - bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::object opts); + bool Attack(Lua_Mob other, int hand, bool from_riposte, bool is_strikethrough, bool is_from_spell, luabind::adl::object opts); void Damage(Lua_Mob from, int damage, int spell_id, int attack_skill); void Damage(Lua_Mob from, int damage, int spell_id, int attack_skill, bool avoidable); void Damage(Lua_Mob from, int damage, int spell_id, int attack_skill, bool avoidable, int buffslot); @@ -294,7 +294,7 @@ public: void SetTexture(int in); void SetRace(int in); void SetGender(int in); - void SendIllusionPacket(luabind::object illusion); + void SendIllusionPacket(luabind::adl::object illusion); void QuestReward(Lua_Client c); void QuestReward(Lua_Client c, uint32 silver); void QuestReward(Lua_Client c, uint32 silver, uint32 gold); diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index c3cb841af..9f082993c 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -121,7 +121,7 @@ extern Zone *zone; struct lua_registered_event { std::string encounter_name; - luabind::object lua_reference; + luabind::adl::object lua_reference; QuestEventID event_id; }; @@ -257,7 +257,7 @@ int LuaParser::EventGlobalNPC(QuestEventID evt, NPC* npc, Mob *init, std::string } int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func) { + std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -275,7 +275,7 @@ int LuaParser::_EventNPC(std::string package_name, QuestEventID evt, NPC* npc, M lua_createtable(L, 0, 0); //always push self Lua_NPC l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); lua_setfield(L, -2, "self"); @@ -352,7 +352,7 @@ int LuaParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::string d } int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func) { + std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -369,7 +369,7 @@ int LuaParser::_EventPlayer(std::string package_name, QuestEventID evt, Client * lua_createtable(L, 0, 0); //push self Lua_Client l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "self"); @@ -429,7 +429,7 @@ int LuaParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob * } int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob, - std::string data, uint32 extra_data, std::vector *extra_pointers, luabind::object *l_func) { + std::string data, uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -446,12 +446,12 @@ int LuaParser::_EventItem(std::string package_name, QuestEventID evt, Client *cl lua_createtable(L, 0, 0); //always push self Lua_ItemInst l_item(item); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "self"); Lua_Client l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "owner"); @@ -508,7 +508,7 @@ int LuaParser::EventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spe } int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func) { + std::vector *extra_pointers, luabind::adl::object *l_func) { const char *sub_name = LuaEvents[evt]; int start = lua_gettop(L); @@ -528,11 +528,11 @@ int LuaParser::_EventSpell(std::string package_name, QuestEventID evt, NPC* npc, //always push self even if invalid if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } lua_setfield(L, -2, "self"); diff --git a/zone/lua_parser.h b/zone/lua_parser.h index 7c4843ccd..b30e3d3b7 100644 --- a/zone/lua_parser.h +++ b/zone/lua_parser.h @@ -17,7 +17,9 @@ class NPC; struct lua_registered_event; namespace luabind { - class object; + namespace adl { + class object; + } } class LuaParser : public QuestInterface { @@ -73,13 +75,13 @@ public: private: int _EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func = nullptr); + std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func = nullptr); + std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventItem(std::string package_name, QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, - uint32 extra_data, std::vector *extra_pointers, luabind::object *l_func = nullptr); + uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventSpell(std::string package_name, QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, - std::vector *extra_pointers, luabind::object *l_func = nullptr); + std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventEncounter(std::string package_name, QuestEventID evt, std::string encounter_name, uint32 extra_data, std::vector *extra_pointers); diff --git a/zone/lua_parser_events.cpp b/zone/lua_parser_events.cpp index c46107844..8064106dc 100644 --- a/zone/lua_parser_events.cpp +++ b/zone/lua_parser_events.cpp @@ -31,7 +31,7 @@ void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *in npc->DoQuestPause(init); Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); @@ -45,7 +45,7 @@ void handle_npc_event_say(QuestInterface *parse, lua_State* L, NPC* npc, Mob *in void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); @@ -57,7 +57,7 @@ void handle_npc_event_trade(QuestInterface *parse, lua_State* L, NPC* npc, Mob * for(size_t i = 0; i < extra_pointers->size(); ++i) { std::string prefix = "item" + std::to_string(static_cast(i + 1)); Lua_ItemInst l_inst = reinterpret_cast(extra_pointers->at(i)); - luabind::object l_inst_o = luabind::object(L, l_inst); + luabind::adl::object l_inst_o = luabind::adl::object(L, l_inst); l_inst_o.push(L); lua_setfield(L, -2, prefix.c_str()); @@ -98,7 +98,7 @@ void handle_npc_event_hp(QuestInterface *parse, lua_State* L, NPC* npc, Mob *ini void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); } @@ -106,7 +106,7 @@ void handle_npc_single_mob(QuestInterface *parse, lua_State* L, NPC* npc, Mob *i void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); } @@ -114,7 +114,7 @@ void handle_npc_single_client(QuestInterface *parse, lua_State* L, NPC* npc, Mob void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_NPC l_npc(reinterpret_cast(init)); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); lua_setfield(L, -2, "other"); } @@ -122,7 +122,7 @@ void handle_npc_single_npc(QuestInterface *parse, lua_State* L, NPC* npc, Mob *i void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(init)); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); @@ -133,7 +133,7 @@ void handle_npc_task_accepted(QuestInterface *parse, lua_State* L, NPC* npc, Mob void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -144,7 +144,7 @@ void handle_npc_popup(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -155,7 +155,7 @@ void handle_npc_waypoint(QuestInterface *parse, lua_State* L, NPC* npc, Mob *ini void handle_npc_hate(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -179,7 +179,7 @@ void handle_npc_timer(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Mob l_mob(init); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -190,12 +190,12 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, int spell_id = std::stoi(sep.arg[1]); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -209,12 +209,12 @@ void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s int spell_id = std::stoi(data); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -249,7 +249,7 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st Mob *o = entity_list.GetMobID(std::stoi(sep.arg[0])); Lua_Mob l_mob(o); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "other"); @@ -259,12 +259,12 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st int spell_id = std::stoi(sep.arg[2]); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -284,12 +284,12 @@ void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* cl const Item_Struct *item = database.GetItem(extra_data); if(item) { Lua_Item l_item(item); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } else { Lua_Item l_item(nullptr); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } @@ -298,7 +298,7 @@ void handle_player_discover_item(QuestInterface *parse, lua_State* L, Client* cl void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } @@ -306,7 +306,7 @@ void handle_player_fish_forage_success(QuestInterface *parse, lua_State* L, Clie void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Object l_object(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_object_o = luabind::object(L, l_object); + luabind::adl::object l_object_o = luabind::adl::object(L, l_object); l_object_o.push(L); lua_setfield(L, -2, "object"); } @@ -314,7 +314,7 @@ void handle_player_click_object(QuestInterface *parse, lua_State* L, Client* cli void handle_player_click_door(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Door l_door(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_door_o = luabind::object(L, l_door); + luabind::adl::object l_door_o = luabind::adl::object(L, l_door); l_door_o.push(L); lua_setfield(L, -2, "door"); } @@ -334,7 +334,7 @@ void handle_player_popup_response(QuestInterface *parse, lua_State* L, Client* c void handle_player_pick_up(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); } @@ -344,11 +344,11 @@ void handle_player_cast(QuestInterface *parse, lua_State* L, Client* client, std int spell_id = std::stoi(data); if(IsValidSpell(spell_id)) { Lua_Spell l_spell(&spells[spell_id]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); } @@ -370,7 +370,7 @@ void handle_player_zone(QuestInterface *parse, lua_State* L, Client* client, std void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(extra_pointers->at(1))); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); } @@ -378,7 +378,7 @@ void handle_player_duel_win(QuestInterface *parse, lua_State* L, Client* client, void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Client l_client(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); lua_setfield(L, -2, "other"); } @@ -386,12 +386,12 @@ void handle_player_duel_loss(QuestInterface *parse, lua_State* L, Client* client void handle_player_loot(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); Lua_Corpse l_corpse(reinterpret_cast(extra_pointers->at(1))); - luabind::object l_corpse_o = luabind::object(L, l_corpse); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); l_corpse_o.push(L); lua_setfield(L, -2, "corpse"); } @@ -426,7 +426,7 @@ void handle_player_command(QuestInterface *parse, lua_State* L, Client* client, lua_pushstring(L, command.c_str()); lua_setfield(L, -2, "command"); - luabind::object args = luabind::newtable(L); + luabind::adl::object args = luabind::newtable(L); int max_args = sep.GetMaxArgNum(); for(int i = 1; i < max_args; ++i) { if(strlen(sep.arg[i]) > 0) { @@ -450,7 +450,7 @@ void handle_player_combine(QuestInterface *parse, lua_State* L, Client* client, void handle_player_feign(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_NPC l_npc(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); lua_setfield(L, -2, "other"); } @@ -476,7 +476,7 @@ void handle_player_respawn(QuestInterface *parse, lua_State* L, Client* client, void handle_player_packet(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_Packet l_packet(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_packet_o = luabind::object(L, l_packet); + luabind::adl::object l_packet_o = luabind::adl::object(L, l_packet); l_packet_o.push(L); lua_setfield(L, -2, "packet"); @@ -505,18 +505,18 @@ void handle_item_proc(QuestInterface *parse, lua_State* L, Client* client, ItemI std::vector *extra_pointers) { Lua_Mob l_mob(mob); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); lua_setfield(L, -2, "target"); if(IsValidSpell(extra_data)) { Lua_Spell l_spell(&spells[extra_data]); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } else { Lua_Spell l_spell(nullptr); - luabind::object l_spell_o = luabind::object(L, l_spell); + luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell); l_spell_o.push(L); lua_setfield(L, -2, "spell"); } @@ -526,12 +526,12 @@ void handle_item_loot(QuestInterface *parse, lua_State* L, Client* client, ItemI std::vector *extra_pointers) { if(mob && mob->IsCorpse()) { Lua_Corpse l_corpse(mob->CastToCorpse()); - luabind::object l_corpse_o = luabind::object(L, l_corpse); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); l_corpse_o.push(L); lua_setfield(L, -2, "corpse"); } else { Lua_Corpse l_corpse(nullptr); - luabind::object l_corpse_o = luabind::object(L, l_corpse); + luabind::adl::object l_corpse_o = luabind::adl::object(L, l_corpse); l_corpse_o.push(L); lua_setfield(L, -2, "corpse"); } @@ -546,7 +546,7 @@ void handle_item_equip(QuestInterface *parse, lua_State* L, Client* client, Item void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "aug"); @@ -557,7 +557,7 @@ void handle_item_augment(QuestInterface *parse, lua_State* L, Client* client, It void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); @@ -568,7 +568,7 @@ void handle_item_augment_insert(QuestInterface *parse, lua_State* L, Client* cli void handle_item_augment_remove(QuestInterface *parse, lua_State* L, Client* client, ItemInst* item, Mob *mob, std::string data, uint32 extra_data, std::vector *extra_pointers) { Lua_ItemInst l_item(reinterpret_cast(extra_pointers->at(0))); - luabind::object l_item_o = luabind::object(L, l_item); + luabind::adl::object l_item_o = luabind::adl::object(L, l_item); l_item_o.push(L); lua_setfield(L, -2, "item"); @@ -588,15 +588,15 @@ void handle_spell_effect(QuestInterface *parse, lua_State* L, NPC* npc, Client* std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } @@ -613,15 +613,15 @@ void handle_spell_tic(QuestInterface *parse, lua_State* L, NPC* npc, Client* cli std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } @@ -644,15 +644,15 @@ void handle_spell_fade(QuestInterface *parse, lua_State* L, NPC* npc, Client* cl std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } @@ -669,15 +669,15 @@ void handle_translocate_finish(QuestInterface *parse, lua_State* L, NPC* npc, Cl std::vector *extra_pointers) { if(npc) { Lua_Mob l_npc(npc); - luabind::object l_npc_o = luabind::object(L, l_npc); + luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc); l_npc_o.push(L); } else if(client) { Lua_Mob l_client(client); - luabind::object l_client_o = luabind::object(L, l_client); + luabind::adl::object l_client_o = luabind::adl::object(L, l_client); l_client_o.push(L); } else { Lua_Mob l_mob(nullptr); - luabind::object l_mob_o = luabind::object(L, l_mob); + luabind::adl::object l_mob_o = luabind::adl::object(L, l_mob); l_mob_o.push(L); } From 660db94607d0b11924b6b9968d933df00c689144 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 24 Jun 2014 08:24:11 -0400 Subject: [PATCH 14/62] Fix to SE_BlanaceMana to only check classes in group that have mana. --- zone/groups.cpp | 2 +- zone/raids.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/zone/groups.cpp b/zone/groups.cpp index 1af5cc34e..6aee5f38b 100644 --- a/zone/groups.cpp +++ b/zone/groups.cpp @@ -1160,7 +1160,7 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster, int32 limit) unsigned int gi = 0; for(; gi < MAX_GROUP_MEMBERS; gi++) { - if(members[gi]){ + if(members[gi] && (members[gi]->GetMaxMana() > 0)){ distance = caster->DistNoRoot(*members[gi]); if(distance <= range2){ diff --git a/zone/raids.cpp b/zone/raids.cpp index be0b697db..c712fc4bd 100644 --- a/zone/raids.cpp +++ b/zone/raids.cpp @@ -578,15 +578,17 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster, int3 if(members[gi].member){ if(members[gi].GroupNumber == gid) { - distance = caster->DistNoRoot(*members[gi].member); - if(distance <= range2){ + if (members[gi].member->GetMaxMana() > 0) { + distance = caster->DistNoRoot(*members[gi].member); + if(distance <= range2){ - manataken_tmp = members[gi].member->GetMaxMana() - members[gi].member->GetMana(); - if (limit && (manataken_tmp > limit)) - manataken_tmp = limit; + manataken_tmp = members[gi].member->GetMaxMana() - members[gi].member->GetMana(); + if (limit && (manataken_tmp > limit)) + manataken_tmp = limit; - manataken += (manataken_tmp); - numMem += 1; + manataken += (manataken_tmp); + numMem += 1; + } } } } From 6ef11777e3aedf49901f99e1f1d43d0b67b3770a Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 24 Jun 2014 22:04:13 -0400 Subject: [PATCH 15/62] Implemented an enumerator list for numhits type variables. Implemented type 4 outgoing spell damage numhits type. --- zone/attack.cpp | 20 ++++++++++---------- zone/bot.cpp | 6 +++--- zone/common.h | 14 ++++++++++++++ zone/mob.cpp | 6 +++--- zone/special_attacks.cpp | 10 +++++----- zone/spell_effects.cpp | 8 ++++---- zone/spells.cpp | 18 ++++++++++++------ 7 files changed, 51 insertions(+), 31 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 99682eee5..4592f2fdf 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1350,7 +1350,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b MeleeLifeTap(damage); if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //break invis when you attack if(invisible) { @@ -1965,7 +1965,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool MeleeLifeTap(damage); if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //break invis when you attack if(invisible) { @@ -3421,7 +3421,7 @@ int32 Mob::ReduceAllDamage(int32 damage) TryTriggerOnValueAmount(false, true); } - CheckNumHitsRemaining(8); + CheckNumHitsRemaining(NUMHIT_IncomingDamage); return(damage); } @@ -3527,10 +3527,10 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } if (spell_id == SPELL_UNKNOWN && skill_used) { - CheckNumHitsRemaining(1); //Incoming Hit Attempts + CheckNumHitsRemaining(NUMHIT_IncomingHitAttempts); if (attacker) - attacker->CheckNumHitsRemaining(2); //Outgoing Hit Attempts + attacker->CheckNumHitsRemaining(NUMHIT_OutgoingHitAttempts); } if(attacker){ @@ -3604,7 +3604,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } if (skill_used) - CheckNumHitsRemaining(6); //Incomming Hit Success on Defender + CheckNumHitsRemaining(NUMHIT_IncomingHitSuccess); ReduceAllDamage(damage); @@ -4021,7 +4021,7 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam int chance = ProcChance * (DefensiveProcs[i].chance); if ((MakeRandomInt(0, 100) < chance)) { ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); - CheckNumHitsRemaining(10,0,DefensiveProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_DefensiveSpellProcs,0,DefensiveProcs[i].base_spellID); } } } @@ -4208,7 +4208,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, "Spell proc %d procing spell %d (%.2f percent chance)", i, SpellProcs[i].spellID, chance); ExecWeaponProc(nullptr, SpellProcs[i].spellID, on); - CheckNumHitsRemaining(11, 0, SpellProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs, 0, SpellProcs[i].base_spellID); } else { mlog(COMBAT__PROCS, "Spell proc %d failed to proc %d (%.2f percent chance)", @@ -4224,7 +4224,7 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, "Ranged proc %d procing spell %d (%.2f percent chance)", i, RangedProcs[i].spellID, chance); ExecWeaponProc(nullptr, RangedProcs[i].spellID, on); - CheckNumHitsRemaining(11, 0, RangedProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs, 0, RangedProcs[i].base_spellID); } else { mlog(COMBAT__PROCS, "Ranged proc %d failed to proc %d (%.2f percent chance)", @@ -4594,7 +4594,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, float chance) int ProcChance = chance * (float)SkillProcs[i].chance; if ((MakeRandomInt(0, 100) < ProcChance)) { ExecWeaponProc(nullptr, SkillProcs[i].spellID, on); - CheckNumHitsRemaining(11,0, SkillProcs[i].base_spellID); + CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, SkillProcs[i].base_spellID); } } } diff --git a/zone/bot.cpp b/zone/bot.cpp index 3b996e7a8..5bdf3cb02 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3389,7 +3389,7 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes return; if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); if((skillinuse == SkillDragonPunch) && GetAA(aaDragonPunch) && MakeRandomInt(0, 99) < 25){ SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); @@ -6632,7 +6632,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b MeleeLifeTap(damage); if (damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //break invis when you attack if(invisible) { @@ -8092,7 +8092,7 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if (HasDied()) return; if (max_damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ diff --git a/zone/common.h b/zone/common.h index f94962ee1..a8e8a17c9 100644 --- a/zone/common.h +++ b/zone/common.h @@ -150,6 +150,20 @@ enum TradeState { TradeCompleting }; +enum { //Numhits type + NUMHIT_IncomingHitAttempts = 1, //Attempted incoming melee attacks (hit or miss) on YOU. + NUMHIT_OutgoingHitAttempts = 2, //Attempted outgoing melee attacks (hit or miss) on YOUR TARGET. + NUMHIT_IncomingSpells = 3, //Incoming detrimental spells + NUMHIT_OutgoingSpells = 4, //Outgoing deterimental spells + NUMHIT_OutgoingHitSuccess = 5, //Successful outgoing melee attack HIT on YOUR TARGET. + NUMHIT_IncomingHitSuccess = 6, //Successful incoming melee attack HIT on YOU. + NUMHIT_MatchingSpells = 7, //Any casted spell matching/triggering a focus effect. + NUMHIT_IncomingDamage = 8, //Successful incoming spell or melee dmg attack on YOU + NUMHIT_ReflectSpell = 9, //Incoming Reflected spells. + NUMHIT_DefensiveSpellProcs = 10, //Defensive buff procs + NUMHIT_OffensiveSpellProcs = 11 //Offensive buff procs +}; + //this is our internal representation of the BUFF struct, can put whatever we want in it struct Buffs_Struct { uint16 spellid; diff --git a/zone/mob.cpp b/zone/mob.cpp index 06dbe4519..138c159cd 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3155,7 +3155,7 @@ void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger) if(IsValidSpell(trigger_spell_id) && GetTarget()){ SpellFinished(trigger_spell_id, GetTarget(),10, 0, -1, spells[trigger_spell_id].ResistDiff); - CheckNumHitsRemaining(7,0, focus_spell); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,0, focus_spell); } } } @@ -3408,7 +3408,7 @@ int32 Mob::GetVulnerability(Mob* caster, uint32 spell_id, uint32 ticsremaining) value += tmp_focus; if (tmp_buffslot >= 0) - CheckNumHitsRemaining(7, tmp_buffslot); + CheckNumHitsRemaining(NUMHIT_MatchingSpells, tmp_buffslot); } return value; } @@ -3509,7 +3509,7 @@ void Mob::TrySympatheticProc(Mob *target, uint32 spell_id) SpellFinished(focus_trigger, target, 10, 0, -1, spells[focus_trigger].ResistDiff); } - CheckNumHitsRemaining(7, 0, focus_spell); + CheckNumHitsRemaining(NUMHIT_MatchingSpells, 0, focus_spell); } } diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 4bbd808cc..f9f324b6d 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -156,7 +156,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, if (HasDied()) return; if (max_damage > 0) - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); //[AA Dragon Punch] value[0] = 100 for 25%, chance value[1] = skill if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skill){ @@ -951,7 +951,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item TryCriticalHit(other, SkillArchery, TotalDmg); other->AddToHateList(this, hate, 0, false); - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); } } else @@ -1056,7 +1056,7 @@ void NPC::RangedAttack(Mob* other) TryCriticalHit(GetTarget(), SkillArchery, TotalDmg); GetTarget()->AddToHateList(this, hate, 0, false); GetTarget()->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery); - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); } else { @@ -1281,7 +1281,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite TryCriticalHit(other, SkillThrowing, TotalDmg); int32 hate = (2*WDmg); other->AddToHateList(this, hate, 0, false); - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); } } @@ -2196,7 +2196,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if (HasDied()) return; - CheckNumHitsRemaining(5); + CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); if(aabonuses.SpecialAttackKBProc[0] && aabonuses.SpecialAttackKBProc[1] == skillinuse){ int kb_chance = 25; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index b846e0058..6f71a56eb 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -5275,7 +5275,7 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id) 1: [Incoming Hit Attempts] (323=SE_DefensiveProc, 172=SE_AvoidMeleeChance, 1=SE_ArmorClass, 40=SE_DivineAura) 2: [Outgoing Hit Attempts] (185=SE_DamageModifer, 184=SE_HitChance) 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_FcSpellVulnerability) //Note: Determinetal spells only unless proven otherwise - 4: NONE + 4: [Outgoing Spells] 5: [Outgoing Hit Successes] (220=SE_SkillDamageAmount, 178=SE_MeleeLifetap, 121=SE_ReverseDS, ?373=SE_CastOnWearoff) 6: [Incoming Hit Successes] (59=SE_DamageShield, 197=SE_SkillDamageTaken, 162=define SE_MitigateMeleeDamage) 7: [Matching Spells] *When focus is triggered (focus effects) @@ -5591,7 +5591,7 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, } if ((!limit_exists) || (limit_exists && skill_found)){ dmg += temp_dmg; - CheckNumHitsRemaining(7,i); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,i); } } @@ -5599,7 +5599,7 @@ int32 Mob::GetFcDamageAmtIncoming(Mob *caster, uint32 spell_id, bool use_skill, int32 focus = caster->CalcFocusEffect(focusFcDamageAmtIncoming, buffs[i].spellid, spell_id); if(focus){ dmg += focus; - CheckNumHitsRemaining(7,i); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,i); } } } @@ -5653,7 +5653,7 @@ int32 Mob::GetFocusIncoming(focusType type, int effect, Mob *caster, uint32 spel value = tmp_focus; if (tmp_buffslot >= 0) - CheckNumHitsRemaining(7, tmp_buffslot); + CheckNumHitsRemaining(NUMHIT_MatchingSpells, tmp_buffslot); } } diff --git a/zone/spells.cpp b/zone/spells.cpp index 21a2fe749..32140849b 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1250,7 +1250,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } if(IsClient()) { - CheckNumHitsRemaining(7); + CheckNumHitsRemaining(NUMHIT_MatchingSpells); TrySympatheticProc(target, spell_id); } @@ -3401,7 +3401,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r if(IsEffectInSpell(buffs[b].spellid, SE_BlockNextSpellFocus)) { focus = CalcFocusEffect(focusBlockNextSpell, buffs[b].spellid, spell_id); if(focus) { - CheckNumHitsRemaining(7,b); + CheckNumHitsRemaining(NUMHIT_MatchingSpells,b); Message_StringID(MT_SpellFailure, SPELL_WOULDNT_HOLD); safe_delete(action_packet); return false; @@ -3450,7 +3450,7 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } if(reflect_chance) { Message_StringID(MT_Spells, SPELL_REFLECT, GetCleanName(), spelltar->GetCleanName()); - CheckNumHitsRemaining(9); + CheckNumHitsRemaining(NUMHIT_ReflectSpell); SpellOnTarget(spell_id, this, true, use_resist_adjust, resist_adjust); safe_delete(action_packet); return false; @@ -3501,7 +3501,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } } - spelltar->CheckNumHitsRemaining(3); + spelltar->CheckNumHitsRemaining(NUMHIT_IncomingSpells); + CheckNumHitsRemaining(NUMHIT_OutgoingSpells); safe_delete(action_packet); return false; @@ -3654,8 +3655,13 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } - if (spelltar && IsDetrimentalSpell(spell_id)) - spelltar->CheckNumHitsRemaining(3); //Incoming spells + if (IsDetrimentalSpell(spell_id)) { + + CheckNumHitsRemaining(NUMHIT_OutgoingSpells); + + if (spelltar) + spelltar->CheckNumHitsRemaining(NUMHIT_IncomingSpells); + } // send the action packet again now that the spell is successful // NOTE: this is what causes the buff icon to appear on the client, if From b23af6d436ca98d57fd7f7068dbff0b545f2316b Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 25 Jun 2014 14:14:55 -0400 Subject: [PATCH 16/62] 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 17/62] 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 18/62] 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 19/62] 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 20/62] 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 21/62] 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 22/62] 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 23/62] 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 24/62] 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 25/62] 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 26/62] 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 27/62] 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 28/62] 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 29/62] 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 30/62] 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 2ef6d3f93e35be28ae19d70643c3d3cda52fbaf0 Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 30 Jun 2014 14:09:03 -0700 Subject: [PATCH 31/62] Removed older AZone build options, use eqemu-zone-utils instead --- CMakeLists.txt | 5 -- utils/CMakeLists.txt | 7 --- utils/azone2/CMakeLists.txt | 119 ------------------------------------ 3 files changed, 131 deletions(-) delete mode 100644 utils/CMakeLists.txt delete mode 100644 utils/azone2/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 45d3f6c50..4732ca8d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,7 +229,6 @@ ENDIF(EQEMU_ENABLE_BOTS) #What to build OPTION(EQEMU_BUILD_SERVER "Build the game server." ON) OPTION(EQEMU_BUILD_LOGIN "Build the login server." OFF) -OPTION(EQEMU_BUILD_AZONE "Build azone utility." OFF) OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF) OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON) OPTION(EQEMU_BUILD_LUA "Build Lua parser." OFF) @@ -319,10 +318,6 @@ IF(EQEMU_BUILD_LOGIN) ADD_SUBDIRECTORY(loginserver) ENDIF(EQEMU_BUILD_LOGIN) -IF(EQEMU_BUILD_AZONE) - ADD_SUBDIRECTORY(utils) -ENDIF(EQEMU_BUILD_AZONE) - IF(EQEMU_BUILD_TESTS) ADD_SUBDIRECTORY(tests) ENDIF(EQEMU_BUILD_TESTS) diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt deleted file mode 100644 index 4aec544ee..000000000 --- a/utils/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) - -IF(UNIX) - ADD_DEFINITIONS(-fPIC) -ENDIF(UNIX) - -ADD_SUBDIRECTORY(azone2) diff --git a/utils/azone2/CMakeLists.txt b/utils/azone2/CMakeLists.txt deleted file mode 100644 index 3567df948..000000000 --- a/utils/azone2/CMakeLists.txt +++ /dev/null @@ -1,119 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) - -IF(NOT MSVC) - ADD_DEFINITIONS(-fpermissive) -ENDIF(NOT MSVC) - -#azone common -SET(azone_common_sources - dat.cpp - file.cpp - global.cpp - pfs.cpp - ter.cpp - wld.cpp - zon.cpp - zonv4.cpp -) - -SET(azone_common_headers - 3d.hpp - 3d_base.hpp - archive.hpp - dat.hpp - file.hpp - file_loader.hpp - global.hpp - octree.hpp - pfs.hpp - s3d.h - ter.hpp - types.h - wld.hpp - wld_structs.hpp - zon.hpp - zonv4.hpp -) - -ADD_LIBRARY(azone_common ${azone_common_sources} ${azone_common_headers}) -SET(LIBRARY_OUTPUT_PATH ../../Bin) - -#azone -SET(azone_sources - azone.cpp -) - -SET(azone_headers - azone.h -) - -ADD_EXECUTABLE(azone ${azone_sources} ${azone_headers}) -TARGET_LINK_LIBRARIES(azone azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) -IF(MSVC) - SET_TARGET_PROPERTIES(azone PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - TARGET_LINK_LIBRARIES(azone "Ws2_32.lib") -ENDIF(MSVC) - -IF(UNIX) - TARGET_LINK_LIBRARIES(azone "z") -ENDIF(UNIX) - -SET(EXECUTABLE_OUTPUT_PATH ../../Bin) - -#awater -SET(awater_sources - awater.cpp -) - -SET(awater_headers - awater.h -) - -ADD_EXECUTABLE(awater ${awater_sources} ${awater_headers}) -TARGET_LINK_LIBRARIES(awater azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) -IF(MSVC) - SET_TARGET_PROPERTIES(awater PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - TARGET_LINK_LIBRARIES(awater "Ws2_32.lib") -ENDIF(MSVC) - -IF(UNIX) - TARGET_LINK_LIBRARIES(awater "z") -ENDIF(UNIX) - -SET(EXECUTABLE_OUTPUT_PATH ../../Bin) - -#listobj -SET(listobj_sources - listobj.cpp -) - -SET(listobj_headers -) - -ADD_EXECUTABLE(listobj ${listobj_sources} ${listobj_headers}) -TARGET_LINK_LIBRARIES(listobj azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) -IF(MSVC) - SET_TARGET_PROPERTIES(listobj PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - TARGET_LINK_LIBRARIES(listobj "Ws2_32.lib") -ENDIF(MSVC) - -IF(UNIX) - TARGET_LINK_LIBRARIES(listobj "z") -ENDIF(UNIX) - -#on windows: glmodelviewer -IF(MSVC) - SET(glmodelviewer_sources - GLModelViewer.cpp - ) - - SET(glmodelviewer_headers - GLModelViewer.h - ) - - ADD_EXECUTABLE(glmodelviewer WIN32 ${glmodelviewer_sources} ${glmodelviewer_headers}) - TARGET_LINK_LIBRARIES(glmodelviewer azone_common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} "opengl32.lib" "GLU32.lib" "Ws2_32.lib") - SET_TARGET_PROPERTIES(glmodelviewer PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") - - SET(EXECUTABLE_OUTPUT_PATH ../../Bin) -ENDIF(MSVC) From c412038db8ef17f879016778d86bcb9254a833fd Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 1 Jul 2014 04:53:24 -0400 Subject: [PATCH 32/62] 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 33/62] 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 34/62] 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 35/62] 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; } From ee6d7ae6bae35974f553bd23cc86e66189c18de4 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 2 Jul 2014 08:42:18 -0400 Subject: [PATCH 36/62] Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self. --- changelog.txt | 3 +++ common/spdat.h | 4 ++-- zone/bonuses.cpp | 8 ++++++++ zone/common.h | 1 + zone/spell_effects.cpp | 36 ++++++++++++++++++++++++++++++++++++ zone/spells.cpp | 3 +++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/changelog.txt b/changelog.txt index 0a22ccf8d..08527447b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 07/2/2014 == +Kayen: Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self. + == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. diff --git a/common/spdat.h b/common/spdat.h index 75d351fc2..0c2cf4b1f 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -455,11 +455,11 @@ typedef enum { #define SE_MitigateDamageShield 305 // implemented - off hand attacks only (Shielding Resistance) //#define SE_ArmyOfTheDead 306 // *not implemented NecroAA - This ability calls up to five shades of nearby corpses back to life to serve the necromancer. The soulless abominations will mindlessly fight the target until called back to the afterlife some time later. The first rank summons up to three shades that serve for 60 seconds, and each additional rank adds one more possible shade and increases their duration by 15 seconds //#define SE_Appraisal 307 // *not implemented Rogue AA - This ability allows you to estimate the selling price of an item you are holding on your cursor. -#define SE_SuspendMinion 308 // not implemented as bonus +#define SE_SuspendMinion 308 // implemented #define SE_GateCastersBindpoint 309 // implemented - Gate to casters bind point #define SE_ReduceReuseTimer 310 // implemented #define SE_LimitCombatSkills 311 // implemented - Excludes focus from procs (except if proc is a memorizable spell) -//#define SE_Sanctuary 312 // *not implemented +#define SE_Sanctuary 312 // implemented - Places caster at bottom hate list, effect fades if cast cast spell on targets other than self. #define SE_ForageAdditionalItems 313 // implemented[AA] - chance to forage additional items #define SE_Invisibility2 314 // implemented - fixed duration invisible #define SE_InvisVsUndead2 315 // implemented - fixed duration ITU diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index a316c4b3b..0e521a6db 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2856,6 +2856,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->PetMeleeMitigation += effect_value; break; + case SE_Sanctuary: + newbon->Sanctuary = true; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4330,6 +4334,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) itembonuses.FinishingBlowLvl[1] = effect_value; break; + case SE_Sanctuary: + spellbonuses.Sanctuary = effect_value; + break; + } } } diff --git a/zone/common.h b/zone/common.h index 88600492e..0768a0835 100644 --- a/zone/common.h +++ b/zone/common.h @@ -372,6 +372,7 @@ struct StatBonuses { int16 DStacker[1]; // For buff stack blocking 0=Exists 1=Effect_value bool BerserkSPA; // berserk effect int16 Metabolism; // Food/drink consumption rates. + bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others. // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 090fb4b75..7bb227bd0 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2732,6 +2732,22 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } + case SE_Sanctuary: + { + std::list npc_list; + entity_list.GetNPCList(npc_list); + + for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { + + NPC* npc = *itr; + + if (npc && npc->CheckAggro(this)) + npc->SetHate(caster, 1); + + } + break; + } + // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: @@ -2960,6 +2976,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_Berserk: case SE_Vampirism: case SE_Metabolism: + case SE_FinishingBlow: + case SE_FinishingBlowLvl: + case SE_Assassinate: + case SE_AssassinateLevel: { break; } @@ -3604,6 +3624,22 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste break; } + case SE_Sanctuary: + { + std::list npc_list; + entity_list.GetNPCList(npc_list); + + for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { + + NPC* npc = *itr; + + if (npc && npc->CheckAggro(this)) + npc->SetHate(caster, 1); + + } + break; + } + default: { // do we need to do anyting here? diff --git a/zone/spells.cpp b/zone/spells.cpp index 59dbb6625..6a87f2409 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -183,6 +183,9 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot); return(false); } + //It appears that the Sanctuary effect is removed by a check on the client side (keep this however for redundancy) + if (spellbonuses.Sanctuary && (spells[spell_id].targettype != ST_Self && GetTarget() != this) || IsDetrimentalSpell(spell_id)) + BuffFadeByEffect(SE_Sanctuary); if(IsClient()){ int chance = CastToClient()->GetFocusEffect(focusFcMute, spell_id); From 4a49a11e73e495bd3c27813dd904710069eefa89 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 2 Jul 2014 11:18:50 -0400 Subject: [PATCH 37/62] Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. --- changelog.txt | 2 +- common/spdat.h | 2 +- zone/mob.h | 1 + zone/spell_effects.cpp | 32 ++++++++++++++++++++++++++++++-- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 08527447b..ac53a761b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,7 +2,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 07/2/2014 == Kayen: Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self. - +Kayen: Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. diff --git a/common/spdat.h b/common/spdat.h index 0c2cf4b1f..3b9d88995 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -604,7 +604,7 @@ typedef enum { #define SE_TriggerSpellThreshold 454 // implemented Trigger effect on X amount of spell damage taken #define SE_AddHatePct 455 // implemented Modify total hate by % #define SE_AddHateOverTimePct 456 // implemented Modify total hate by % over time. -//#define SE_ResourceTap 457 // not used +#define SE_ResourceTap 457 // implemented Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. //#define SE_FactionModPct 458 // not used #define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type diff --git a/zone/mob.h b/zone/mob.h index 5c1240e83..4f7b47c03 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -229,6 +229,7 @@ public: bool TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier); void SpellProjectileEffect(); bool TrySpellProjectile(Mob* spell_target, uint16 spell_id); + void ResourceTap(int32 damage, uint16 spell_id); //Buff void BuffProcess(); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 7bb227bd0..498e5d7ec 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -224,9 +224,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) dmg = (int32) (dmg * partial / 100); //handles AAs and what not... - if(caster) + if(caster) { dmg = caster->GetActSpellDamage(spell_id, dmg, this); - + caster->ResourceTap(-dmg, spell_id); + } + dmg = -dmg; Damage(caster, dmg, spell_id, spell.skill, false, buffslot, false); } @@ -3367,6 +3369,8 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste if(caster->IsNPC()) effect_value = caster->CastToNPC()->GetActSpellDamage(spell_id, effect_value, this); + + caster->ResourceTap(-effect_value, spell_id); } effect_value = -effect_value; @@ -6283,4 +6287,28 @@ bool Mob::TrySpellProjectile(Mob* spell_target, uint16 spell_id){ return true; } +void Mob::ResourceTap(int32 damage, uint16 spellid){ + //'this' = caster + if (!IsValidSpell(spellid)) + return; + for (int i = 0; i <= EFFECT_COUNT; i++) + { + if (spells[spellid].effectid[i] == SE_ResourceTap){ + + damage += (damage * spells[spellid].base[i])/100; + + if (spells[spellid].max[i] && (damage > spells[spellid].max[i])) + damage = spells[spellid].max[i]; + + if (spells[spellid].base2[i] == 0) //HP Tap + SetHP((GetHP()+ damage)); + + if (spells[spellid].base2[i] == 1) //Mana Tap + SetMana(GetMana() + damage); + + if (spells[spellid].base2[i] == 2 && IsClient()) //Endurance Tap + CastToClient()->SetEndurance(CastToClient()->GetEndurance() + damage); + } + } +} From 35e72692c1a6fd415c93284bff9218d309e34e3e Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 2 Jul 2014 11:54:59 -0400 Subject: [PATCH 38/62] Implemented SE_FactionModPct - Modifies faction gains and losses by percent. --- changelog.txt | 1 + common/spdat.h | 2 +- zone/bonuses.cpp | 26 ++++++++++++++++++++++++++ zone/client.cpp | 3 +++ zone/common.h | 1 + 5 files changed, 32 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index ac53a761b..26da2b13c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) == 07/2/2014 == Kayen: Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self. Kayen: Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. +Kayen: Implemented SE_FactionModPct - Modifies faction gains and losses by percent. == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. diff --git a/common/spdat.h b/common/spdat.h index 3b9d88995..c579a1af7 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -605,7 +605,7 @@ typedef enum { #define SE_AddHatePct 455 // implemented Modify total hate by % #define SE_AddHateOverTimePct 456 // implemented Modify total hate by % over time. #define SE_ResourceTap 457 // implemented Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. -//#define SE_FactionModPct 458 // not used +#define SE_FactionModPct 458 // implemented Modifies faction gains and losses by percent. #define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type // LAST diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 0e521a6db..e27378207 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1315,6 +1315,16 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->PetMeleeMitigation += base1; break; + case SE_FactionModPct: + { + if((base1 < 0) && (newbon->FactionModPct > base1)) + newbon->FactionModPct = base1; + + else if(newbon->FactionModPct < base1) + newbon->FactionModPct = base1; + break; + } + } } } @@ -2860,6 +2870,16 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->Sanctuary = true; break; + case SE_FactionModPct: + { + if((effect_value < 0) && (newbon->FactionModPct > effect_value)) + newbon->FactionModPct = effect_value; + + else if(newbon->FactionModPct < effect_value) + newbon->FactionModPct = effect_value; + break; + } + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4338,6 +4358,12 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.Sanctuary = effect_value; break; + case SE_FactionModPct: + spellbonuses.FactionModPct = effect_value; + itembonuses.FactionModPct = effect_value; + aabonuses.FactionModPct = effect_value; + break; + } } } diff --git a/zone/client.cpp b/zone/client.cpp index 4ec3ce2d7..12a9ada67 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -7629,6 +7629,9 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui if(npc_value[i] != 0) { tmpValue = current_value + mod + npc_value[i]; + int16 FactionModPct = spellbonuses.FactionModPct + itembonuses.FactionModPct + aabonuses.FactionModPct; + tmpValue += (tmpValue * FactionModPct) / 100; + // Make sure faction hits don't go to GMs... if (m_pp.gm==1 && (tmpValue < current_value)) { tmpValue = current_value; diff --git a/zone/common.h b/zone/common.h index 0768a0835..9cb80211a 100644 --- a/zone/common.h +++ b/zone/common.h @@ -373,6 +373,7 @@ struct StatBonuses { bool BerserkSPA; // berserk effect int16 Metabolism; // Food/drink consumption rates. bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others. + int16 FactionModPct; // Modifies amount of faction gained. // AAs int8 Packrat; //weight reduction for items, 1 point = 10% From 542c0913d6bf2560eb3067dcf58243a0865a4e23 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 2 Jul 2014 14:00:50 -0400 Subject: [PATCH 39/62] Re-Implemented SE_TriggerMeleeThreshold and SE_TriggerSpellThreshold correctly - Trigger spell if owner of buff takes more than the specified damage amount in a SINGLE hit, then fade the buff. --- changelog.txt | 2 ++ common/spdat.h | 4 ++-- zone/attack.cpp | 37 +++++-------------------------------- zone/bonuses.cpp | 24 ++++-------------------- zone/mob.cpp | 3 +-- zone/mob.h | 1 + 6 files changed, 15 insertions(+), 56 deletions(-) diff --git a/changelog.txt b/changelog.txt index 26da2b13c..e6d342c55 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) Kayen: Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self. Kayen: Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. Kayen: Implemented SE_FactionModPct - Modifies faction gains and losses by percent. +Kayen: Re-Implemented SE_TriggerMeleeThreshold and SE_TriggerSpellThreshold correctly - Trigger spell if owner of buff +takes more than the specified damage amount in a SINGLE hit, then fade the buff. == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. diff --git a/common/spdat.h b/common/spdat.h index c579a1af7..1b202f19a 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -600,8 +600,8 @@ typedef enum { #define SE_MitigateDotDamage 450 // implemented DOT spell mitigation rune with max value #define SE_MeleeThresholdGuard 451 // implemented Partial Melee Rune that only is lowered if melee hits are over X amount of damage #define SE_SpellThresholdGuard 452 // implemented Partial Spell Rune that only is lowered if spell hits are over X amount of damage -#define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken -#define SE_TriggerSpellThreshold 454 // implemented Trigger effect on X amount of spell damage taken +#define SE_TriggerMeleeThreshold 453 // implemented Trigger effect on X amount of melee damage taken in a single hit +#define SE_TriggerSpellThreshold 454 // implemented Trigger effect on X amount of spell damage taken in a single hit #define SE_AddHatePct 455 // implemented Modify total hate by % #define SE_AddHateOverTimePct 456 // implemented Modify total hate by % over time. #define SE_ResourceTap 457 // implemented Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. diff --git a/zone/attack.cpp b/zone/attack.cpp index 7b641bd96..fdbc46d24 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3251,20 +3251,6 @@ int32 Mob::ReduceDamage(int32 damage) } } - if (spellbonuses.TriggerMeleeThreshold[2]){ - slot = spellbonuses.TriggerMeleeThreshold[1]; - - if (slot >= 0) { - if(damage > buffs[slot].melee_rune) { - if(!TryFadeEffect(slot)) - BuffFadeBySlot(slot); - } - else{ - buffs[slot].melee_rune = (buffs[slot].melee_rune - damage); - } - } - } - if(damage < 1) return -6; @@ -3393,27 +3379,13 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi } } - if (spellbonuses.TriggerSpellThreshold[2]){ - slot = spellbonuses.TriggerSpellThreshold[1]; - - if (slot >= 0) { - if(damage > buffs[slot].magic_rune) { - if(!TryFadeEffect(slot)) - BuffFadeBySlot(slot); - } - else{ - buffs[slot].magic_rune = (buffs[slot].magic_rune - damage); - } - } - } - if(damage < 1) return 0; if (spellbonuses.AbsorbMagicAtt[0] && spellbonuses.AbsorbMagicAtt[1] >= 0) damage = RuneAbsorb(damage, SE_AbsorbMagicAtt); - + if(damage < 1) return 0; } @@ -3599,6 +3571,8 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons if(spell_id == SPELL_UNKNOWN) { damage = ReduceDamage(damage); mlog(COMBAT__HITS, "Melee Damage reduced to %d", damage); + ReduceAllDamage(damage); + TryTriggerThreshHold(damage, SE_TriggerMeleeThreshold, attacker); } else { int32 origdmg = damage; damage = AffectMagicalDamage(damage, spell_id, iBuffTic, attacker); @@ -3610,14 +3584,13 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons //Kayen: Probably need to add a filter for this - Not sure if this msg is correct but there should be a message for spell negate/runes. Message(263, "%s tries to cast on YOU, but YOUR magical skin absorbs the spell.",attacker->GetCleanName()); } - + ReduceAllDamage(damage); + TryTriggerThreshHold(damage, SE_TriggerSpellThreshold, attacker); } if (skill_used) CheckNumHitsRemaining(NUMHIT_IncomingHitSuccess); - ReduceAllDamage(damage); - if(IsClient() && CastToClient()->sneaking){ CastToClient()->sneaking = false; SendAppearancePacket(AT_Sneak, 0); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index e27378207..01e2e4f91 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2425,24 +2425,12 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne } case SE_TriggerMeleeThreshold: - { - if (newbon->TriggerMeleeThreshold[2] < base2){ - newbon->TriggerMeleeThreshold[0] = effect_value; - newbon->TriggerMeleeThreshold[1] = buffslot; - newbon->TriggerMeleeThreshold[2] = base2; - } + newbon->TriggerMeleeThreshold = true; break; - } case SE_TriggerSpellThreshold: - { - if (newbon->TriggerSpellThreshold[2] < base2){ - newbon->TriggerSpellThreshold[0] = effect_value; - newbon->TriggerSpellThreshold[1] = buffslot; - newbon->TriggerSpellThreshold[2] = base2; - } + newbon->TriggerSpellThreshold = true; break; - } case SE_ShieldBlock: newbon->ShieldBlock += effect_value; @@ -4218,15 +4206,11 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) break; case SE_TriggerMeleeThreshold: - spellbonuses.TriggerMeleeThreshold[0] = effect_value; - spellbonuses.TriggerMeleeThreshold[1] = effect_value; - spellbonuses.TriggerMeleeThreshold[2] = effect_value; + spellbonuses.TriggerMeleeThreshold = effect_value; break; case SE_TriggerSpellThreshold: - spellbonuses.TriggerSpellThreshold[0] = effect_value; - spellbonuses.TriggerSpellThreshold[1] = effect_value; - spellbonuses.TriggerSpellThreshold[2] = effect_value; + spellbonuses.TriggerSpellThreshold = effect_value; break; case SE_DivineAura: diff --git a/zone/mob.cpp b/zone/mob.cpp index ee468a0e6..5272b373f 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3452,8 +3452,7 @@ bool Mob::TryFadeEffect(int slot) { for(int i = 0; i < EFFECT_COUNT; i++) { - if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnWearoff || spells[buffs[slot].spellid].effectid[i] == SE_EffectOnFade - || spells[buffs[slot].spellid].effectid[i] == SE_TriggerMeleeThreshold || spells[buffs[slot].spellid].effectid[i] == SE_TriggerSpellThreshold) + if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnWearoff || spells[buffs[slot].spellid].effectid[i] == SE_EffectOnFade) { uint16 spell_id = spells[buffs[slot].spellid].base[i]; BuffFadeBySlot(slot); diff --git a/zone/mob.h b/zone/mob.h index 4f7b47c03..4d6983643 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -230,6 +230,7 @@ public: void SpellProjectileEffect(); bool TrySpellProjectile(Mob* spell_target, uint16 spell_id); void ResourceTap(int32 damage, uint16 spell_id); + void TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker); //Buff void BuffProcess(); From 8453d5bc4889d8505915f14fc3e91bdaf93b572f Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Wed, 2 Jul 2014 21:38:26 -0400 Subject: [PATCH 40/62] Renamed various Cast on Fade spell effects to more accurately describe their functions. Missing code from prior commit. --- common/spdat.cpp | 8 ++--- zone/common.h | 4 +-- zone/mob.cpp | 2 +- zone/spell_effects.cpp | 74 ++++++++++++++++++++++++++++++------------ 4 files changed, 61 insertions(+), 27 deletions(-) diff --git a/common/spdat.cpp b/common/spdat.cpp index 3c4989a67..49cb8fe16 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -1003,7 +1003,7 @@ bool IsSuspendableSpell(uint16 spell_id) uint32 GetMorphTrigger(uint32 spell_id) { for (int i = 0; i < EFFECT_COUNT; ++i) - if (spells[spell_id].effectid[i] == SE_ImprovedSpellEffect) + if (spells[spell_id].effectid[i] == SE_CastOnFadeEffect) return spells[spell_id].base[i]; return 0; @@ -1012,9 +1012,9 @@ uint32 GetMorphTrigger(uint32 spell_id) bool IsCastonFadeDurationSpell(uint16 spell_id) { for (int i = 0; i < EFFECT_COUNT; ++i) { - if (spells[spell_id].effectid[i] == SE_ImprovedSpellEffect - || spells[spell_id].effectid[i] == SE_BossSpellTrigger - || spells[spell_id].effectid[i] == SE_CastOnWearoff){ + if (spells[spell_id].effectid[i] == SE_CastOnFadeEffect + || spells[spell_id].effectid[i] == SE_CastOnFadeEffectNPC + || spells[spell_id].effectid[i] == SE_CastOnFadeEffectAlways){ return true; } diff --git a/zone/common.h b/zone/common.h index 9cb80211a..10b3d2200 100644 --- a/zone/common.h +++ b/zone/common.h @@ -348,8 +348,8 @@ struct StatBonuses { uint16 SpellThresholdGuard[3]; // 0 = Mitigation value 1 = Buff Slot 2 = Min damage to trigger. uint16 MitigateSpellRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per spell 3 = Rune Amt uint16 MitigateDotRune[4]; // 0 = Mitigation value 1 = Buff Slot 2 = Max mitigation per tick 3 = Rune Amt - uint32 TriggerMeleeThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger - uint32 TriggerSpellThreshold[3]; // 0 = Spell Effect ID 1 = Buff slot 2 = Damage Amount to Trigger + bool TriggerMeleeThreshold; // Has Melee Threshhold + bool TriggerSpellThreshold; // Has Spell Threshhold uint16 ManaAbsorbPercentDamage[2]; // 0 = Mitigation value 1 = Buff Slot int16 ShieldBlock; // Chance to Shield Block int16 BlockBehind; // Chance to Block Behind (with our without shield) diff --git a/zone/mob.cpp b/zone/mob.cpp index 5272b373f..cf7b2d243 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3452,7 +3452,7 @@ bool Mob::TryFadeEffect(int slot) { for(int i = 0; i < EFFECT_COUNT; i++) { - if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnWearoff || spells[buffs[slot].spellid].effectid[i] == SE_EffectOnFade) + if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnFadeEffectAlways || spells[buffs[slot].spellid].effectid[i] == SE_CastOnRuneFadeEffect) { uint16 spell_id = spells[buffs[slot].spellid].base[i]; BuffFadeBySlot(slot); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 498e5d7ec..c30d03432 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1317,18 +1317,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_TriggerMeleeThreshold: - { - buffs[buffslot].melee_rune = spells[spell_id].base2[i]; - break; - } - - case SE_TriggerSpellThreshold: - { - buffs[buffslot].magic_rune = spells[spell_id].base2[i]; - break; - } - case SE_DistanceRemoval: { buffs[buffslot].caston_x = int(GetX()); @@ -2864,10 +2852,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_FcTwincast: case SE_DelayDeath: case SE_InterruptCasting: - case SE_ImprovedSpellEffect: - case SE_BossSpellTrigger: - case SE_CastOnWearoff: - case SE_EffectOnFade: + case SE_CastOnFadeEffect: + case SE_CastOnFadeEffectNPC: + case SE_CastOnFadeEffectAlways: + case SE_CastOnRuneFadeEffect: case SE_MaxHPChange: case SE_SympatheticProc: case SE_FcDamageAmt: @@ -2982,6 +2970,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_FinishingBlowLvl: case SE_Assassinate: case SE_AssassinateLevel: + case SE_FactionModPct: { break; } @@ -3569,9 +3558,9 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste break; } // These effects always trigger when they fade. - case SE_ImprovedSpellEffect: - case SE_BossSpellTrigger: - case SE_CastOnWearoff: + case SE_CastOnFadeEffect: + case SE_CastOnFadeEffectNPC: + case SE_CastOnFadeEffectAlways: { if (ticsremaining == 1) { @@ -5378,7 +5367,7 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id) 2: [Outgoing Hit Attempts] (185=SE_DamageModifer, 184=SE_HitChance) 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_FcSpellVulnerability) //Note: Determinetal spells only unless proven otherwise 4: [Outgoing Spells] - 5: [Outgoing Hit Successes] (220=SE_SkillDamageAmount, 178=SE_MeleeLifetap, 121=SE_ReverseDS, ?373=SE_CastOnWearoff) + 5: [Outgoing Hit Successes] (220=SE_SkillDamageAmount, 178=SE_MeleeLifetap, 121=SE_ReverseDS, ?373=SE_CastOnFadeEffectAlways) 6: [Incoming Hit Successes] (59=SE_DamageShield, 197=SE_SkillDamageTaken, 162=define SE_MitigateMeleeDamage) 7: [Matching Spells] *When focus is triggered (focus effects) 8: [Incoming Hits or Spells] (329=SE_ManaAbsorbPercentDamage) @@ -6312,3 +6301,48 @@ void Mob::ResourceTap(int32 damage, uint16 spellid){ } } } + +void Mob::TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker){ + + if (damage <= 0) + return; + + if ((SE_TriggerMeleeThreshold == effect_id) && !spellbonuses.TriggerMeleeThreshold ) + return; + else if ((SE_TriggerSpellThreshold == effect_id) && !spellbonuses.TriggerSpellThreshold) + return; + + int buff_count = GetMaxTotalSlots(); + + for(int slot = 0; slot < buff_count; slot++) { + + if(IsValidSpell(buffs[slot].spellid)){ + + for(int i = 0; i < EFFECT_COUNT; i++){ + + if (spells[buffs[slot].spellid].effectid[i] == effect_id){ + + uint16 spell_id = spells[buffs[slot].spellid].base[i]; + + if (damage > spells[buffs[slot].spellid].base2[i]){ + + BuffFadeBySlot(slot); + + if (IsValidSpell(spell_id)) { + + if (IsBeneficialSpell(spell_id)) + SpellFinished(spell_id, this, 10, 0, -1, spells[spell_id].ResistDiff); + + else if(attacker) + SpellFinished(spell_id, attacker, 10, 0, -1, spells[spell_id].ResistDiff); + } + } + } + } + } + } +} + + + + \ No newline at end of file From a92b4c04e99f3f94e8ef050dcadd341bfecfed65 Mon Sep 17 00:00:00 2001 From: Chris M Date: Wed, 2 Jul 2014 22:17:45 -0500 Subject: [PATCH 41/62] Initial Socket Server implementation with CMakeLists.txt updated. Socket server will connect to world at this point. --- CMakeLists.txt | 1 + common/EmuTCPConnection.cpp | 27 ++++- common/EmuTCPConnection.h | 2 +- common/logtypes.h | 7 ++ common/platform.h | 1 + socket_server/CMakeLists.txt | 44 +++++++++ socket_server/database.cpp | 131 +++++++++++++++++++++++++ socket_server/database.h | 54 ++++++++++ socket_server/socket_server.cpp | 115 ++++++++++++++++++++++ socket_server/socket_server_config.cpp | 28 ++++++ socket_server/socket_server_config.h | 55 +++++++++++ socket_server/worldserver.cpp | 69 +++++++++++++ socket_server/worldserver.h | 35 +++++++ world/CMakeLists.txt | 2 + world/console.cpp | 16 ++- world/net.cpp | 4 + world/socket_server.cpp | 127 ++++++++++++++++++++++++ world/socket_server.h | 23 +++++ 18 files changed, 735 insertions(+), 6 deletions(-) create mode 100644 socket_server/CMakeLists.txt create mode 100644 socket_server/database.cpp create mode 100644 socket_server/database.h create mode 100644 socket_server/socket_server.cpp create mode 100644 socket_server/socket_server_config.cpp create mode 100644 socket_server/socket_server_config.h create mode 100644 socket_server/worldserver.cpp create mode 100644 socket_server/worldserver.h create mode 100644 world/socket_server.cpp create mode 100644 world/socket_server.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4732ca8d0..1d3adcc25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,6 +312,7 @@ IF(EQEMU_BUILD_SERVER) ADD_SUBDIRECTORY(zone) ADD_SUBDIRECTORY(ucs) ADD_SUBDIRECTORY(queryserv) + ADD_SUBDIRECTORY(socket_server) ADD_SUBDIRECTORY(eqlaunch) ENDIF(EQEMU_BUILD_SERVER) IF(EQEMU_BUILD_LOGIN) diff --git a/common/EmuTCPConnection.cpp b/common/EmuTCPConnection.cpp index 465d16c1e..39c297ccf 100644 --- a/common/EmuTCPConnection.cpp +++ b/common/EmuTCPConnection.cpp @@ -366,7 +366,22 @@ bool EmuTCPConnection::LineOutQueuePush(char* line) { safe_delete_array(line); return(true); } - + if (strcmp(line, "**PACKETMODESS**") == 0) { + MSendQueue.lock(); + safe_delete_array(sendbuf); + if (TCPMode == modeConsole) + Send((const uchar*) "\0**PACKETMODESS**\r", 18); + TCPMode = modePacket; + PacketMode = packetModeSocket_Server; + EmuTCPNetPacket_Struct* tnps = 0; + while ((tnps = InModeQueue.pop())) { + SendPacket(tnps); + safe_delete_array(tnps); + } + MSendQueue.unlock(); + safe_delete_array(line); + return(true); + } } return(TCPConnection::LineOutQueuePush(line)); @@ -419,7 +434,15 @@ bool EmuTCPConnection::ConnectIP(uint32 irIP, uint16 irPort, char* errbuf) { sendbuf_used = sendbuf_size; sendbuf = new uchar[sendbuf_size]; memcpy(sendbuf, "\0**PACKETMODEQS**\r", sendbuf_size); - } else { + } + else if (PacketMode == packetModeSocket_Server) { + safe_delete_array(sendbuf); + sendbuf_size = 18; + sendbuf_used = sendbuf_size; + sendbuf = new uchar[sendbuf_size]; + memcpy(sendbuf, "\0**PACKETMODESS**\r", sendbuf_size); + } + else { //default: packetModeZone safe_delete_array(sendbuf); sendbuf_size = 20; diff --git a/common/EmuTCPConnection.h b/common/EmuTCPConnection.h index ff7dd8995..947ee9480 100644 --- a/common/EmuTCPConnection.h +++ b/common/EmuTCPConnection.h @@ -30,7 +30,7 @@ class EmuTCPServer; class EmuTCPConnection : public TCPConnection { public: enum eTCPMode { modeConsole, modeTransition, modePacket }; - enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ }; + enum ePacketMode { packetModeZone, packetModeLauncher, packetModeLogin, packetModeUCS, packetModeQueryServ, packetModeSocket_Server }; EmuTCPConnection(uint32 ID, EmuTCPServer* iServer, SOCKET iSock, uint32 irIP, uint16 irPort, bool iOldFormat = false); EmuTCPConnection(bool iOldFormat = false, EmuTCPServer* iRelayServer = 0, eTCPMode iMode = modePacket); // for outgoing connections diff --git a/common/logtypes.h b/common/logtypes.h index cadfbf71a..1776c9518 100644 --- a/common/logtypes.h +++ b/common/logtypes.h @@ -65,6 +65,13 @@ LOG_TYPE( QUERYSERV, CLIENT, DISABLED ) LOG_TYPE( QUERYSERV, TRACE, DISABLED ) LOG_TYPE( QUERYSERV, PACKETS, DISABLED) +LOG_CATEGORY(SOCKET_SERVER) +LOG_TYPE(SOCKET_SERVER, INIT, ENABLED) +LOG_TYPE(SOCKET_SERVER, ERROR, ENABLED) +LOG_TYPE(SOCKET_SERVER, CLIENT, DISABLED) +LOG_TYPE(SOCKET_SERVER, TRACE, DISABLED) +LOG_TYPE(SOCKET_SERVER, PACKETS, DISABLED) + LOG_CATEGORY( SPAWNS ) LOG_TYPE( SPAWNS, MAIN, DISABLED ) LOG_TYPE( SPAWNS, CONDITIONS, DISABLED ) diff --git a/common/platform.h b/common/platform.h index efb176ec4..7eaae045b 100644 --- a/common/platform.h +++ b/common/platform.h @@ -8,6 +8,7 @@ enum EQEmuExePlatform ExePlatformWorld, ExePlatformLogin, ExePlatformQueryServ, + ExePlatformSocket_Server, ExePlatformUCS, ExePlatformLaunch, ExePlatformSharedMemory, diff --git a/socket_server/CMakeLists.txt b/socket_server/CMakeLists.txt new file mode 100644 index 000000000..f647863d9 --- /dev/null +++ b/socket_server/CMakeLists.txt @@ -0,0 +1,44 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +SET(socket_server_sources + database.cpp + socket_server.cpp + socket_server_config.cpp + worldserver.cpp +) + +SET(socket_server_headers + database.h + socket_server_config.h + worldserver.h +) + +ADD_EXECUTABLE(socket_server ${socket_server_sources} ${socket_server_headers}) + +INSTALL(TARGETS socket_server RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) + +ADD_DEFINITIONS(-DQSERV) + +TARGET_LINK_LIBRARIES(socket_server Common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY}) + +IF(MSVC) + SET_TARGET_PROPERTIES(socket_server PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") + TARGET_LINK_LIBRARIES(socket_server "Ws2_32.lib") +ENDIF(MSVC) + +IF(MINGW) + TARGET_LINK_LIBRARIES(socket_server "WS2_32") +ENDIF(MINGW) + +IF(UNIX) + TARGET_LINK_LIBRARIES(socket_server "${CMAKE_DL_LIBS}") + TARGET_LINK_LIBRARIES(socket_server "z") + TARGET_LINK_LIBRARIES(socket_server "m") + IF(NOT DARWIN) + TARGET_LINK_LIBRARIES(socket_server "rt") + ENDIF(NOT DARWIN) + TARGET_LINK_LIBRARIES(socket_server "pthread") + ADD_DEFINITIONS(-fPIC) +ENDIF(UNIX) + +SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/Bin) diff --git a/socket_server/database.cpp b/socket_server/database.cpp new file mode 100644 index 000000000..a2c04bbb4 --- /dev/null +++ b/socket_server/database.cpp @@ -0,0 +1,131 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + +#include "../common/debug.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Disgrace: for windows compile +#ifdef _WINDOWS +#include +#define snprintf _snprintf +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#else +#include "../common/unix.h" +#include +#endif + +#include "database.h" +#include "../common/eq_packet_structs.h" +#include "../common/StringUtil.h" +#include "../common/servertalk.h" + +Database::Database () +{ + DBInitVars(); +} + +/* +Establish a connection to a mysql database with the supplied parameters +*/ + +Database::Database(const char* host, const char* user, const char* passwd, const char* database, uint32 port) +{ + DBInitVars(); + Connect(host, user, passwd, database, port); +} + +bool Database::Connect(const char* host, const char* user, const char* passwd, const char* database, uint32 port) +{ + uint32 errnum= 0; + char errbuf[MYSQL_ERRMSG_SIZE]; + if (!Open(host, user, passwd, database, port, &errnum, errbuf)) + { + LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf); + HandleMysqlError(errnum); + + return false; + } + else + { + LogFile->write(EQEMuLog::Status, "Using database '%s' at %s:%d",database,host,port); + return true; + } +} + +void Database::DBInitVars() { + +} + + + +void Database::HandleMysqlError(uint32 errnum) { +} + +/* + +Close the connection to the database +*/ +Database::~Database() +{ +} + +bool Database::GetVariable(const char* varname, char* varvalue, uint16 varvalue_len) { + + char errbuf[MYSQL_ERRMSG_SIZE]; + char* query = 0; + MYSQL_RES *result; + MYSQL_ROW row; + + if (!RunQuery(query,MakeAnyLenString(&query, "select `value` from `variables` where `varname`='%s'", varname), errbuf, &result)) { + + _log(UCS__ERROR, "Unable to get message count from database. %s %s", query, errbuf); + + safe_delete_array(query); + + return false; + } + + safe_delete_array(query); + + if (mysql_num_rows(result) != 1) { + + mysql_free_result(result); + + return false; + } + + row = mysql_fetch_row(result); + + snprintf(varvalue, varvalue_len, "%s", row[0]); + + mysql_free_result(result); + + return true; +} \ No newline at end of file diff --git a/socket_server/database.h b/socket_server/database.h new file mode 100644 index 000000000..6500ffad6 --- /dev/null +++ b/socket_server/database.h @@ -0,0 +1,54 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef CHATSERVER_DATABASE_H +#define CHATSERVER_DATABASE_H + +#define AUTHENTICATION_TIMEOUT 60 +#define INVALID_ID 0xFFFFFFFF + +#include "../common/debug.h" +#include "../common/types.h" +#include "../common/dbcore.h" +#include "../common/linked_list.h" +#include "../common/servertalk.h" +#include +#include +#include + +//atoi is not uint32 or uint32 safe!!!! +#define atoul(str) strtoul(str, nullptr, 10) + +class Database : public DBcore { +public: + Database(); + Database(const char* host, const char* user, const char* passwd, const char* database,uint32 port); + bool Connect(const char* host, const char* user, const char* passwd, const char* database,uint32 port); + ~Database(); + + bool GetVariable(const char* varname, char* varvalue, uint16 varvalue_len); +protected: + void HandleMysqlError(uint32 errnum); +private: + void DBInitVars(); + +}; + +#endif + diff --git a/socket_server/socket_server.cpp b/socket_server/socket_server.cpp new file mode 100644 index 000000000..eed4751d1 --- /dev/null +++ b/socket_server/socket_server.cpp @@ -0,0 +1,115 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "../common/debug.h" +#include "../common/opcodemgr.h" +#include "../common/EQStreamFactory.h" +#include "../common/rulesys.h" +#include "../common/servertalk.h" +#include "../common/platform.h" +#include "../common/crash.h" +#include "database.h" +#include "socket_server_config.h" +#include "worldserver.h" +#include + +#include +volatile bool RunLoops = true; +TimeoutManager timeout_manager; +Database database; +std::string WorldShortName; + +const socket_server_config *Config; +WorldServer *worldserver = 0; + +void CatchSignal(int sig_num) { + RunLoops = false; + if(worldserver) + worldserver->Disconnect(); +} + +int main() { + RegisterExecutablePlatform(ExePlatformSocket_Server); + set_exception_handler(); + Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect + _log(SOCKET_SERVER__INIT, "Starting EQEmu Socket Server."); + if (!socket_server_config::LoadConfig()) { + _log(SOCKET_SERVER__INIT, "Loading server configuration failed."); + return 1; + } + + Config = socket_server_config::get(); + + if(!load_log_settings(Config->LogSettingsFile.c_str())) + _log(SOCKET_SERVER__INIT, "Warning: Unable to read %s", Config->LogSettingsFile.c_str()); + else + _log(SOCKET_SERVER__INIT, "Log settings loaded from %s", Config->LogSettingsFile.c_str()); + + WorldShortName = Config->ShortName; + + /* + _log(SOCKET_SERVER__INIT, "Connecting to MySQL..."); + + if (!database.Connect( + Config->QSDatabaseHost.c_str(), + Config->QSDatabaseUsername.c_str(), + Config->QSDatabasePassword.c_str(), + Config->QSDatabaseDB.c_str(), + Config->QSDatabasePort)) { + _log(WORLD__INIT_ERR, "Cannot continue without a database connection."); + return 1; + } + */ + + if (signal(SIGINT, CatchSignal) == SIG_ERR) { + _log(SOCKET_SERVER__ERROR, "Could not set signal handler"); + return 1; + } + if (signal(SIGTERM, CatchSignal) == SIG_ERR) { + _log(SOCKET_SERVER__ERROR, "Could not set signal handler"); + return 1; + } + + worldserver = new WorldServer; + worldserver->Connect(); + + while(RunLoops) { + Timer::SetCurrentTime(); + if (InterserverTimer.Check()) { + if (worldserver->TryReconnect() && (!worldserver->Connected())) + worldserver->AsyncConnect(); + } + worldserver->Process(); + timeout_manager.CheckTimeouts(); + Sleep(100); + } +} + +void UpdateWindowTitle(char* iNewTitle) { +#ifdef _WINDOWS + char tmp[500]; + if (iNewTitle) { + snprintf(tmp, sizeof(tmp), "SOCKET_SERVER: %s", iNewTitle); + } + else { + snprintf(tmp, sizeof(tmp), "SOCKET_SERVER"); + } + SetConsoleTitle(tmp); +#endif +} diff --git a/socket_server/socket_server_config.cpp b/socket_server/socket_server_config.cpp new file mode 100644 index 000000000..8f08eba9d --- /dev/null +++ b/socket_server/socket_server_config.cpp @@ -0,0 +1,28 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "../common/debug.h" +#include "socket_server_config.h" + +socket_server_config *socket_server_config::_chat_config = nullptr; + +std::string socket_server_config::GetByName(const std::string &var_name) const { + return(EQEmuConfig::GetByName(var_name)); +} + diff --git a/socket_server/socket_server_config.h b/socket_server/socket_server_config.h new file mode 100644 index 000000000..bc86107d3 --- /dev/null +++ b/socket_server/socket_server_config.h @@ -0,0 +1,55 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef __socket_server_config_H +#define __socket_server_config_H + +#include "../common/EQEmuConfig.h" + +class socket_server_config : public EQEmuConfig { +public: + virtual std::string GetByName(const std::string &var_name) const; + +private: + + static socket_server_config *_chat_config; + +public: + + // Produce a const singleton + static const socket_server_config *get() { + if (_chat_config == nullptr) + LoadConfig(); + return(_chat_config); + } + + // Load the config + static bool LoadConfig() { + if (_chat_config != nullptr) + delete _chat_config; + _chat_config=new socket_server_config; + _config=_chat_config; + + return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server"); + } + +}; + +#endif + diff --git a/socket_server/worldserver.cpp b/socket_server/worldserver.cpp new file mode 100644 index 000000000..f4e7cdf76 --- /dev/null +++ b/socket_server/worldserver.cpp @@ -0,0 +1,69 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include "../common/debug.h" +#include +#include +#include +#include +#include +#include +#include + +#include "../common/servertalk.h" +#include "worldserver.h" +#include "socket_server_config.h" +#include "database.h" +#include "lfguild.h" +#include "../common/packet_functions.h" +#include "../common/md5.h" +#include "../common/packet_dump.h" + +extern WorldServer worldserver; +extern const socket_server_config *Config; +extern Database database; + +WorldServer::WorldServer() +: WorldConnection(EmuTCPConnection::packetModeSocket_Server, Config->SharedKey.c_str()){ + pTryReconnect = true; +} + +WorldServer::~WorldServer(){ +} + +void WorldServer::OnConnected(){ + _log(SOCKET_SERVER__INIT, "Connected to World."); + WorldConnection::OnConnected(); +} + +void WorldServer::Process(){ + WorldConnection::Process(); + if (!Connected()) + return; + + ServerPacket *pack = 0; + while((pack = tcpc.PopPacket())){ + _log(SOCKET_SERVER__TRACE, "Received Opcode: %4X", pack->opcode); + switch(pack->opcode) { + case 0: { break; } + case ServerOP_KeepAlive: { break; } + } + } + + safe_delete(pack); + return; +} \ No newline at end of file diff --git a/socket_server/worldserver.h b/socket_server/worldserver.h new file mode 100644 index 000000000..167342248 --- /dev/null +++ b/socket_server/worldserver.h @@ -0,0 +1,35 @@ +/* EQEMu: Everquest Server Emulator + Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY except by those people which sell it, which + are required to give you total support for your newly bought product; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef WORLDSERVER_H +#define WORLDSERVER_H + +#include "../common/worldconn.h" +#include "../common/eq_packet_structs.h" + +class WorldServer : public WorldConnection +{ + public: + WorldServer(); + virtual ~WorldServer(); + virtual void Process(); + + private: + virtual void OnConnected(); +}; +#endif + diff --git a/world/CMakeLists.txt b/world/CMakeLists.txt index 3ac008267..594f77bc1 100644 --- a/world/CMakeLists.txt +++ b/world/CMakeLists.txt @@ -23,6 +23,7 @@ SET(world_sources perl_EQW.cpp perl_HTTPRequest.cpp queryserv.cpp + socket_server.cpp ucs.cpp wguild_mgr.cpp world_logsys.cpp @@ -53,6 +54,7 @@ SET(world_headers LoginServerList.h net.h queryserv.h + socket_server.h SoFCharCreateData.h ucs.h wguild_mgr.h diff --git a/world/console.cpp b/world/console.cpp index 57161487d..5a9ee60f5 100644 --- a/world/console.cpp +++ b/world/console.cpp @@ -46,6 +46,7 @@ #include "LauncherList.h" #include "ucs.h" #include "queryserv.h" +#include "socket_server.h" #ifdef _WINDOWS #define snprintf _snprintf @@ -60,6 +61,7 @@ extern ClientList client_list; extern LauncherList launcher_list; extern UCSConnection UCSLink; extern QueryServConnection QSLink; +extern Socket_Server_Connection SSLink; extern volatile bool RunLoops; ConsoleList console_list; @@ -250,18 +252,26 @@ bool Console::Process() { _log(WORLD__CONSOLE,"New launcher from %s:%d", inet_ntoa(in), GetPort()); launcher_list.Add(tcpc); tcpc = 0; - } else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS) + } + else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeUCS) { _log(WORLD__CONSOLE,"New UCS Connection from %s:%d", inet_ntoa(in), GetPort()); UCSLink.SetConnection(tcpc); tcpc = 0; } - else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeQueryServ) + else if(tcpc->GetPacketMode() == EmuTCPConnection::packetModeQueryServ) { _log(WORLD__CONSOLE,"New QS Connection from %s:%d", inet_ntoa(in), GetPort()); QSLink.SetConnection(tcpc); tcpc = 0; - } else { + } + else if (tcpc->GetPacketMode() == EmuTCPConnection::packetModeSocket_Server) + { + _log(WORLD__CONSOLE, "New Socket Server Connection from %s:%d", inet_ntoa(in), GetPort()); + SSLink.SetConnection(tcpc); + tcpc = 0; + } + else { _log(WORLD__CONSOLE,"Unsupported packet mode from %s:%d", inet_ntoa(in), GetPort()); } return false; diff --git a/world/net.cpp b/world/net.cpp index d7179bffe..f8d3410c0 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -86,6 +86,7 @@ #include "AdventureManager.h" #include "ucs.h" #include "queryserv.h" +#include "socket_server.h" TimeoutManager timeout_manager; EQStreamFactory eqsf(WorldStream,9000); @@ -97,6 +98,7 @@ LoginServerList loginserverlist; EQWHTTPServer http_server; UCSConnection UCSLink; QueryServConnection QSLink; +Socket_Server_Connection SSLink; LauncherList launcher_list; AdventureManager adventure_manager; DBAsync *dbasync = nullptr; @@ -454,6 +456,8 @@ int main(int argc, char** argv) { QSLink.Process(); + SSLink.Process(); + LFPGroupList.Process(); adventure_manager.Process(); diff --git a/world/socket_server.cpp b/world/socket_server.cpp new file mode 100644 index 000000000..826a95620 --- /dev/null +++ b/world/socket_server.cpp @@ -0,0 +1,127 @@ +#include "../common/debug.h" +#include "Socket_Server.h" +#include "WorldConfig.h" +#include "clientlist.h" +#include "zonelist.h" +#include "../common/logsys.h" +#include "../common/logtypes.h" +#include "../common/md5.h" +#include "../common/EmuTCPConnection.h" +#include "../common/packet_dump.h" + +extern ClientList client_list; +extern ZSList zoneserver_list; + +Socket_Server_Connection::Socket_Server_Connection() +{ + Stream = 0; + authenticated = false; +} + +void Socket_Server_Connection::SetConnection(EmuTCPConnection *inStream) +{ + if(Stream) + { + _log(SOCKET_SERVER__ERROR, "Incoming Socket_Server Connection while we were already connected to a Socket_Server."); + Stream->Disconnect(); + } + + Stream = inStream; + + authenticated = false; +} + +bool Socket_Server_Connection::Process() +{ + if (!Stream || !Stream->Connected()) + return false; + + ServerPacket *pack = 0; + + while((pack = Stream->PopPacket())) + { + if (!authenticated) + { + if (WorldConfig::get()->SharedKey.length() > 0) + { + if (pack->opcode == ServerOP_ZAAuth && pack->size == 16) + { + uint8 tmppass[16]; + + MD5::Generate((const uchar*) WorldConfig::get()->SharedKey.c_str(), WorldConfig::get()->SharedKey.length(), tmppass); + + if (memcmp(pack->pBuffer, tmppass, 16) == 0) + authenticated = true; + else + { + struct in_addr in; + in.s_addr = GetIP(); + _log(SOCKET_SERVER__ERROR, "Socket_Server authorization failed."); + ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed); + SendPacket(pack); + delete pack; + Disconnect(); + return false; + } + } + else + { + struct in_addr in; + in.s_addr = GetIP(); + _log(SOCKET_SERVER__ERROR, "Socket_Server_ authorization failed."); + ServerPacket* pack = new ServerPacket(ServerOP_ZAAuthFailed); + SendPacket(pack); + delete pack; + Disconnect(); + return false; + } + } + else + { + _log(SOCKET_SERVER__ERROR,"**WARNING** You have not configured a world shared key in your config file. You should add a STRING element to your element to prevent unauthorized zone access."); + authenticated = true; + } + delete pack; + continue; + } + switch(pack->opcode) + { + case 0: + break; + + case ServerOP_KeepAlive: + { + // ignore this + break; + } + case ServerOP_ZAAuth: + { + _log(SOCKET_SERVER__ERROR, "Got authentication from Socket_Server_ when they are already authenticated."); + break; + } + case ServerOP_LFGuildUpdate: + { + zoneserver_list.SendPacket(pack); + break; + } + default: + { + _log(SOCKET_SERVER__ERROR, "Unknown ServerOPcode from Socket_Server_ 0x%04x, size %d", pack->opcode, pack->size); + DumpPacket(pack->pBuffer, pack->size); + break; + } + } + + delete pack; + } + return(true); +} + +bool Socket_Server_Connection::SendPacket(ServerPacket* pack) +{ + if(!Stream) + return false; + + return Stream->SendPacket(pack); +} + diff --git a/world/socket_server.h b/world/socket_server.h new file mode 100644 index 000000000..7cb39c2d6 --- /dev/null +++ b/world/socket_server.h @@ -0,0 +1,23 @@ +#ifndef Socket_Server__H +#define Socket_Server__H + +#include "../common/types.h" +#include "../common/EmuTCPConnection.h" +#include "../common/servertalk.h" + +class Socket_Server_Connection +{ +public: + Socket_Server_Connection(); + void SetConnection(EmuTCPConnection *inStream); + bool Process(); + bool SendPacket(ServerPacket* pack); + void Disconnect() { if(Stream) Stream->Disconnect(); } + void SendMessage(const char *From, const char *Message); +private: + inline uint32 GetIP() const { return Stream ? Stream->GetrIP() : 0; } + EmuTCPConnection *Stream; + bool authenticated; +}; + +#endif /*Socket_Server__H_*/ From 90f74d6847f30f1b8922bed06b2205cf246966d9 Mon Sep 17 00:00:00 2001 From: Chris M Date: Thu, 3 Jul 2014 03:25:58 -0500 Subject: [PATCH 42/62] More Socket Server work. Made Socket server a by default disabled option in the CMake configuration while development is underway. For now, do not use. --- CMakeLists.txt | 8 ++ socket_server/CMakeLists.txt | 2 +- socket_server/socket_server.cpp | 166 ++++++++++++++++++++++++++++++++ socket_server/worldserver.cpp | 1 - 4 files changed, 175 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d3adcc25..55d9a4cfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -229,6 +229,7 @@ ENDIF(EQEMU_ENABLE_BOTS) #What to build OPTION(EQEMU_BUILD_SERVER "Build the game server." ON) OPTION(EQEMU_BUILD_LOGIN "Build the login server." OFF) +OPTION(EQEMU_BUILD_SOCKET_SERVER "Build the socket server." OFF) OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF) OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON) OPTION(EQEMU_BUILD_LUA "Build Lua parser." OFF) @@ -297,6 +298,13 @@ IF(EQEMU_BUILD_LUA) ENDIF(EQEMU_SANITIZE_LUA_LIBS) ENDIF(EQEMU_BUILD_LUA) +IF(EQEMU_BUILD_SOCKET_SERVER) + FIND_PACKAGE(Boost COMPONENTS system filesystem thread REQUIRED) + INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/dependencies/websocketpp") + ADD_DEFINITIONS(-D_WEBSOCKETPP_CPP11_STL_) + +ENDIF(EQEMU_BUILD_SOCKET_SERVER) + INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm/glm") IF(EQEMU_BUILD_LUA) diff --git a/socket_server/CMakeLists.txt b/socket_server/CMakeLists.txt index f647863d9..abaec0f21 100644 --- a/socket_server/CMakeLists.txt +++ b/socket_server/CMakeLists.txt @@ -19,7 +19,7 @@ INSTALL(TARGETS socket_server RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) ADD_DEFINITIONS(-DQSERV) -TARGET_LINK_LIBRARIES(socket_server Common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY}) +TARGET_LINK_LIBRARIES(socket_server Common ${Boost_LIBRARIES} debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY}) IF(MSVC) SET_TARGET_PROPERTIES(socket_server PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") diff --git a/socket_server/socket_server.cpp b/socket_server/socket_server.cpp index eed4751d1..997d9965f 100644 --- a/socket_server/socket_server.cpp +++ b/socket_server/socket_server.cpp @@ -17,6 +17,26 @@ */ +#include +#include +#include +/*#include +#include +#include */ +#include + +typedef websocketpp::server server; + +using websocketpp::connection_hdl; +using websocketpp::lib::placeholders::_1; +using websocketpp::lib::placeholders::_2; +using websocketpp::lib::bind; + +using websocketpp::lib::thread; +using websocketpp::lib::mutex; +using websocketpp::lib::unique_lock; +using websocketpp::lib::condition_variable; + #include "../common/debug.h" #include "../common/opcodemgr.h" #include "../common/EQStreamFactory.h" @@ -44,7 +64,150 @@ void CatchSignal(int sig_num) { worldserver->Disconnect(); } +/* Web Sockets Start Shit */ + +enum action_type { + SUBSCRIBE, + UNSUBSCRIBE, + MESSAGE +}; + +struct action { + action(action_type t, connection_hdl h) : type(t), hdl(h) {} + action(action_type t, connection_hdl h, server::message_ptr m) + : type(t), hdl(h), msg(m) {} + + action_type type; + websocketpp::connection_hdl hdl; + server::message_ptr msg; +}; + +class broadcast_server { +public: + broadcast_server() { + // Initialize Asio Transport + m_server.init_asio(); + + // Register handler callbacks + m_server.set_open_handler(bind(&broadcast_server::on_open, this, ::_1)); + m_server.set_close_handler(bind(&broadcast_server::on_close, this, ::_1)); + m_server.set_message_handler(bind(&broadcast_server::on_message, this, ::_1, ::_2)); + } + + void run(uint16_t port) { + // listen on specified port + m_server.listen(port); + + // Start the server accept loop + m_server.start_accept(); + + // Start the ASIO io_service run loop + try { + m_server.run(); + } + catch (const std::exception & e) { + std::cout << e.what() << std::endl; + } + catch (websocketpp::lib::error_code e) { + std::cout << e.message() << std::endl; + } + catch (...) { + std::cout << "other exception" << std::endl; + } + } + + void on_open(connection_hdl hdl) { + unique_lock lock(m_action_lock); + //std::cout << "on_open" << std::endl; + m_actions.push(action(SUBSCRIBE, hdl)); + lock.unlock(); + m_action_cond.notify_one(); + } + + void on_close(connection_hdl hdl) { + unique_lock lock(m_action_lock); + //std::cout << "on_close" << std::endl; + m_actions.push(action(UNSUBSCRIBE, hdl)); + lock.unlock(); + m_action_cond.notify_one(); + } + + void on_message(connection_hdl hdl, server::message_ptr msg) { + // queue message up for sending by processing thread + unique_lock lock(m_action_lock); + msg->set_payload("Niggers"); + // std::cout << "on_message" << std::endl; + m_actions.push(action(MESSAGE, hdl, msg)); + lock.unlock(); + m_action_cond.notify_one(); + } + + void process_messages() { + while (1) { + unique_lock lock(m_action_lock); + + while (m_actions.empty()) { + m_action_cond.wait(lock); + } + + action a = m_actions.front(); + m_actions.pop(); + + lock.unlock(); + + if (a.type == SUBSCRIBE) { + unique_lock con_lock(m_connection_lock); + m_connections.insert(a.hdl); + } + else if (a.type == UNSUBSCRIBE) { + unique_lock con_lock(m_connection_lock); + m_connections.erase(a.hdl); + } + else if (a.type == MESSAGE) { + unique_lock con_lock(m_connection_lock); + + con_list::iterator it; + for (it = m_connections.begin(); it != m_connections.end(); ++it) { + m_server.send(*it, a.msg); + } + } + else { + // undefined. + } + } + } +private: + typedef std::set> con_list; + + server m_server; + con_list m_connections; + std::queue m_actions; + + mutex m_action_lock; + mutex m_connection_lock; + condition_variable m_action_cond; +}; + +/* Web Sockets Shit End*/ + int main() { + + try { + broadcast_server server_instance; + + // Start a thread to run the processing loop + thread t(bind(&broadcast_server::process_messages, &server_instance)); + + // Run the asio loop with the main thread + server_instance.run(9002); + + t.join(); + + } + catch (std::exception & e) { + std::cout << e.what() << std::endl; + } + RegisterExecutablePlatform(ExePlatformSocket_Server); set_exception_handler(); Timer InterserverTimer(INTERSERVER_TIMER); // does auto-reconnect @@ -99,6 +262,9 @@ int main() { timeout_manager.CheckTimeouts(); Sleep(100); } + + + } void UpdateWindowTitle(char* iNewTitle) { diff --git a/socket_server/worldserver.cpp b/socket_server/worldserver.cpp index f4e7cdf76..9c6afa138 100644 --- a/socket_server/worldserver.cpp +++ b/socket_server/worldserver.cpp @@ -28,7 +28,6 @@ #include "worldserver.h" #include "socket_server_config.h" #include "database.h" -#include "lfguild.h" #include "../common/packet_functions.h" #include "../common/md5.h" #include "../common/packet_dump.h" From ee741048e960b9ee13a49d10ffe00e3e9b6852b6 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 3 Jul 2014 08:48:27 -0400 Subject: [PATCH 43/62] Implemented SE_LimitSpellClass - Focus Limits spell to pre defined categories. (3=Cures,3=Offensive, 6=Lifetap) --- common/spdat.cpp | 18 ++++++ common/spdat.h | 15 ++--- zone/mob.h | 2 + zone/spell_effects.cpp | 121 +++++++++++++++++++++++++++++++++++++---- 4 files changed, 139 insertions(+), 17 deletions(-) diff --git a/common/spdat.cpp b/common/spdat.cpp index 49cb8fe16..75f1e9b88 100644 --- a/common/spdat.cpp +++ b/common/spdat.cpp @@ -157,6 +157,24 @@ bool IsFearSpell(uint16 spell_id) return IsEffectInSpell(spell_id, SE_Fear); } +bool IsCureSpell(uint16 spell_id) +{ + const SPDat_Spell_Struct &sp = spells[spell_id]; + + bool CureEffect = false; + + for(int i = 0; i < EFFECT_COUNT; i++){ + if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter + || sp.effectid[i] == SE_CurseCounter || sp.effectid[i] == SE_CorruptionCounter) + CureEffect = true; + } + + if (CureEffect && IsBeneficialSpell(spell_id)) + return true; + + return false; +} + bool IsSlowSpell(uint16 spell_id) { const SPDat_Spell_Struct &sp = spells[spell_id]; diff --git a/common/spdat.h b/common/spdat.h index 1b202f19a..69b6573b0 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -36,7 +36,7 @@ #define EFFECT_COUNT 12 #define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2) #define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists. -#define MaxLimitInclude 12 //Number(x 0.5) of focus Limiters that have inclusive checksm used when calcing focus effects +#define MaxLimitInclude 16 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects const int Z_AGGRO=10; @@ -436,7 +436,7 @@ typedef enum { #define SE_FcDamageAmt 286 // implemented - adds direct spell damage #define SE_SpellDurationIncByTic 287 // implemented #define SE_SpecialAttackKBProc 288 // implemented[AA] - Chance to to do a knockback from special attacks [AA Dragon Punch]. -#define SE_ImprovedSpellEffect 289 // implemented - Triggers only if fades after natural duration. +#define SE_CastOnFadeEffect 289 // implemented - Triggers only if fades after natural duration. #define SE_IncreaseRunSpeedCap 290 // implemented[AA] - increases run speed over the hard cap #define SE_Purify 291 // implemented - Removes determental effects #define SE_StrikeThrough2 292 // implemented[AA] - increasing chance of bypassing an opponent's special defenses, such as dodge, block, parry, and riposte. @@ -480,7 +480,7 @@ typedef enum { #define SE_CriticalDamageMob 330 // implemented #define SE_Salvage 331 // implemented - chance to recover items that would be destroyed in failed tradeskill combine //#define SE_SummonToCorpse 332 // *not implemented AA - Call of the Wild (Druid/Shaman Res spell with no exp) -#define SE_EffectOnFade 333 // implemented +#define SE_CastOnRuneFadeEffect 333 // implemented #define SE_BardAEDot 334 // implemented #define SE_BlockNextSpellFocus 335 // implemented - base1 chance to block next spell ie Puratus (8494) //#define SE_IllusionaryTarget 336 // not used @@ -520,11 +520,11 @@ typedef enum { #define SE_ResistCorruption 370 // implemented #define SE_AttackSpeed4 371 // implemented - stackable slow effect 'Inhibit Melee' //#define SE_ForageSkill 372 // *not implemented[AA] Will increase the skill cap for those that have the Forage skill and grant the skill and raise the cap to those that do not. -#define SE_CastOnWearoff 373 // implemented - Triggers only if fades after natural duration. +#define SE_CastOnFadeEffectAlways 373 // implemented - Triggers if fades after natural duration OR from rune/numhits fades. #define SE_ApplyEffect 374 // implemented #define SE_DotCritDmgIncrease 375 // implemented - Increase damage of DoT critical amount //#define SE_Fling 376 // *not implemented - used in 2 test spells (12945 | Movement Test Spell 1) -#define SE_BossSpellTrigger 377 // implemented - Triggers only if fades after natural duration. +#define SE_CastOnFadeEffectNPC 377 // implemented - Triggers only if fades after natural duration (On live these are usually players spells that effect an NPC). #define SE_SpellEffectResistChance 378 // implemented - Increase chance to resist specific spell effect (base1=value, base2=spell effect id) #define SE_ShadowStepDirectional 379 // implemented - handled by client #define SE_Knockdown 380 // implemented - small knock back(handled by client) @@ -550,8 +550,8 @@ typedef enum { #define SE_HealGroupFromMana 400 // implemented - Drains mana and heals for each point of mana drained #define SE_ManaDrainWithDmg 401 // implemented - Deals damage based on the amount of mana drained #define SE_EndDrainWithDmg 402 // implemented - Deals damage for the amount of endurance drained -//#define SE_LimitSpellClass 403 // *not implemented - unclear what this refers too (not 'right click' spell bar) -//#define SE_LimitSpellSubclass 404 // *not implemented - unclear what this refers too (not 'right click' spell bar) +#define SE_LimitSpellClass 403 // implemented - Limits to specific types of spells (see CheckSpellCategory) +#define SE_LimitSpellSubclass 404 // *not implemented - Limits to specific types of spells (see CheckSpellCategory) [Categories NOT defined yet] #define SE_TwoHandBluntBlock 405 // implemented - chance to block attacks when using two hand blunt weapons (similiar to shield block) #define SE_CastonNumHitFade 406 // implemented - casts a spell when a buff fades due to its numhits being depleted #define SE_CastonFocusEffect 407 // implemented - casts a spell if focus limits are met (ie triggers when a focus effects is applied) @@ -787,6 +787,7 @@ bool IsSummonSpell(uint16 spellid); bool IsEvacSpell(uint16 spellid); bool IsDamageSpell(uint16 spellid); bool IsFearSpell(uint16 spellid); +bool IsCureSpell(uint16 spellid); bool BeneficialSpell(uint16 spell_id); bool GroupOnlySpell(uint16 spell_id); int GetSpellEffectIndex(uint16 spell_id, int effect); diff --git a/zone/mob.h b/zone/mob.h index 4d6983643..0476a20dc 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -231,6 +231,8 @@ public: bool TrySpellProjectile(Mob* spell_target, uint16 spell_id); void ResourceTap(int32 damage, uint16 spell_id); void TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker); + bool CheckSpellCategory(uint16 spell_id, int category_id, int effect_id); + //Buff void BuffProcess(); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index c30d03432..dcc6b6e1b 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2971,6 +2971,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_Assassinate: case SE_AssassinateLevel: case SE_FactionModPct: + case SE_LimitSpellClass: { break; } @@ -4128,6 +4129,8 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) 6/7 SE_LimitTarget 8/9 SE_LimitSpellGroup: 10/11 SE_LimitCastingSkill: + 12/13 SE_LimitSpellClass: + 14/15 SE_LimitSpellSubClass: Remember: Update MaxLimitInclude in spdat.h if adding new limits that require Includes */ int FocusCount = 0; @@ -4322,16 +4325,40 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) break; case SE_LimitCastingSkill: - if(base1 < 0) { - if(-base1 == spell.skill) - LimitFailure = true; - } - else { - LimitInclude[10] = true; - if(base1 == spell.skill) - LimitInclude[11] = true; - } - break; + if(base1 < 0) { + if(-base1 == spell.skill) + LimitFailure = true; + } + else { + LimitInclude[10] = true; + if(base1 == spell.skill) + LimitInclude[11] = true; + } + break; + + case SE_LimitSpellClass: + if(base1 < 0) { //Exclude + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)); + return(0); + } + else { + LimitInclude[12] = true; + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellClass)); //Include + LimitInclude[13] = true; + } + break; + + case SE_LimitSpellSubclass: + if(base1 < 0) { //Exclude + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)); + return(0); + } + else { + LimitInclude[14] = true; + if (CheckSpellCategory(spell_id, base1, SE_LimitSpellSubclass)); //Include + LimitInclude[15] = true; + } + break; case SE_LimitClass: //Do not use this limit more then once per spell. If multiple class, treat value like items would. @@ -4575,6 +4602,8 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo 6/7 SE_LimitTarget 8/9 SE_LimitSpellGroup: 10/11 SE_LimitCastingSkill: + 12/13 SE_LimitSpellClass: + 14/15 SE_LimitSpellSubClass: Remember: Update MaxLimitInclude in spdat.h if adding new limits that require Includes */ @@ -4764,6 +4793,30 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo Caston_spell_id = focus_spell.base[i]; break; + case SE_LimitSpellClass: + if(focus_spell.base[i] < 0) { //Exclude + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)); + return(0); + } + else { + LimitInclude[12] = true; + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellClass)); //Include + LimitInclude[13] = true; + } + break; + + case SE_LimitSpellSubclass: + if(focus_spell.base[i] < 0) { //Exclude + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)); + return(0); + } + else { + LimitInclude[14] = true; + if (CheckSpellCategory(spell_id, focus_spell.base[i], SE_LimitSpellSubclass)); //Include + LimitInclude[15] = true; + } + break; + //handle effects case SE_ImprovedDamage: @@ -6343,6 +6396,54 @@ void Mob::TryTriggerThreshHold(int32 damage, int effect_id, Mob* attacker){ } } +bool Mob::CheckSpellCategory(uint16 spell_id, int category_id, int effect_id){ + if (!IsValidSpell(spell_id) || !category_id) + return false; + int effectid = 0; + int category = 0; + + /*Category ID SE_LimitSpellClass [(+) Include (-) Exclude] + 1 = UNK + 2 = Cures + 3 = Offensive Spells + 4 = UNK + 5 = UNK + 6 = Lifetap + */ + + /*Category ID SE_LimitSpellSubClass [(+) Include (-) Exclude] + 5 = UNK + 8 = UNK + */ + + if (effect_id == SE_LimitSpellClass) { + + switch(category_id) + { + case 2: + if (IsCureSpell(spell_id)) + return true; + break; + + case 3: + if (IsDetrimentalSpell(spell_id)) + return true; + break; + + case 6: + if (spells[spell_id].targettype == ST_Tap || spells[spell_id].targettype == ST_TargetAETap) + return true; + break; + } + } + + else if (effect_id == SE_LimitSpellSubclass) { + //Pending Implementation when category types are figured out. + return false; + } + + return false; +} \ No newline at end of file From 0d2127f874f389fc7144d25385e8c9eeb5a935d0 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 3 Jul 2014 10:55:59 -0400 Subject: [PATCH 44/62] Changed SE_LimitMaxMana to SE_MeleeVulnerability - Weakness/Mitigation verse melee damage (Despite lives SPA lable as the former it clearly is not what the effect does from all spell examples) --- changelog.txt | 3 +++ common/spdat.h | 2 +- zone/bonuses.cpp | 8 ++++++++ zone/common.h | 1 + zone/mob.cpp | 7 ++++++- zone/spell_effects.cpp | 12 +----------- 6 files changed, 20 insertions(+), 13 deletions(-) diff --git a/changelog.txt b/changelog.txt index e6d342c55..56307b361 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,9 @@ Kayen: Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/ Kayen: Implemented SE_FactionModPct - Modifies faction gains and losses by percent. Kayen: Re-Implemented SE_TriggerMeleeThreshold and SE_TriggerSpellThreshold correctly - Trigger spell if owner of buff takes more than the specified damage amount in a SINGLE hit, then fade the buff. +Kayen: Implemented SE_LimitSpellClass - Focus Limits spell to pre defined categories. (3=Cures,3=Offensive, 6=Lifetap) +Kayen: Changed SE_LimitMaxMana to SE_MeleeVulnerability - Weakness/Mitigation verse melee damage +(Despite lives SPA lable as the former it clearly is not what the effect does from all spell examples) == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. diff --git a/common/spdat.h b/common/spdat.h index 69b6573b0..02dca8ff7 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -538,7 +538,7 @@ typedef enum { //#define SE_SummonCorpseZone 388 // *not implemented - summons a corpse from any zone(nec AA) #define SE_FcTimerRefresh 389 // implemented - Refresh spell icons //#define SE_FcTimerLockout 390 // *not implemented - Sets recast timers to specific value, focus limited. -#define SE_LimitManaMax 391 // implemented +#define SE_MeleeVulnerability 391 // implemented [Live SPA has this as LimitManaMax however that is clearly not the effect used] #define SE_FcHealAmt 392 // implemented - Adds or removes healing from spells #define SE_FcHealPctIncoming 393 // implemented - HealRate with focus restrictions. #define SE_FcHealAmtIncoming 394 // implemented - Adds/Removes amount of healing on target by X value with foucs restrictions. diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 01e2e4f91..48a3d95e1 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1315,6 +1315,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->PetMeleeMitigation += base1; break; + case SE_MeleeVulnerability: + newbon->MeleeVulnerability += base1; + break; + case SE_FactionModPct: { if((base1 < 0) && (newbon->FactionModPct > base1)) @@ -2854,6 +2858,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->PetMeleeMitigation += effect_value; break; + case SE_MeleeVulnerability: + newbon->MeleeVulnerability += effect_value; + break; + case SE_Sanctuary: newbon->Sanctuary = true; break; diff --git a/zone/common.h b/zone/common.h index 10b3d2200..e3a9dfb09 100644 --- a/zone/common.h +++ b/zone/common.h @@ -374,6 +374,7 @@ struct StatBonuses { int16 Metabolism; // Food/drink consumption rates. bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others. int16 FactionModPct; // Modifies amount of faction gained. + int16 MeleeVulnerability; // Weakness/mitigation to melee damage // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/mob.cpp b/zone/mob.cpp index cf7b2d243..59e02568b 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3419,6 +3419,8 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) { int skilldmg_mod = 0; + int16 MeleeVuln = spellbonuses.MeleeVulnerability + itembonuses.MeleeVulnerability + aabonuses.MeleeVulnerability; + // All skill dmg mod + Skill specific skilldmg_mod += itembonuses.SkillDmgTaken[HIGHEST_SKILL+1] + spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] + itembonuses.SkillDmgTaken[skill_used] + spellbonuses.SkillDmgTaken[skill_used]; @@ -3427,6 +3429,8 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) if ((SkillDmgTaken_Mod[skill_used]) || (SkillDmgTaken_Mod[HIGHEST_SKILL+1])) skilldmg_mod += SkillDmgTaken_Mod[skill_used] + SkillDmgTaken_Mod[HIGHEST_SKILL+1]; + skilldmg_mod += MeleeVuln; + if(skilldmg_mod < -100) skilldmg_mod = -100; @@ -3452,7 +3456,8 @@ bool Mob::TryFadeEffect(int slot) { for(int i = 0; i < EFFECT_COUNT; i++) { - if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnFadeEffectAlways || spells[buffs[slot].spellid].effectid[i] == SE_CastOnRuneFadeEffect) + if (spells[buffs[slot].spellid].effectid[i] == SE_CastOnFadeEffectAlways || + spells[buffs[slot].spellid].effectid[i] == SE_CastOnRuneFadeEffect) { uint16 spell_id = spells[buffs[slot].spellid].base[i]; BuffFadeBySlot(slot); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index dcc6b6e1b..8c49414d7 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2942,7 +2942,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_FcIncreaseNumHits: case SE_CastonFocusEffect: case SE_FcHealAmtIncoming: - case SE_LimitManaMax: + case SE_MeleeVulnerability: case SE_DoubleRangedAttack: case SE_ShieldEquipHateMod: case SE_ShieldEquipDmgMod: @@ -4287,11 +4287,6 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) LimitFailure = true; break; - case SE_LimitManaMax: - if(spell.mana > base1) - LimitFailure = true; - break; - case SE_LimitTarget: if (base1 < 0) { if (-base1 == spell.targettype) //Exclude @@ -4718,11 +4713,6 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo return 0; break; - case SE_LimitManaMax: - if(spell.mana > focus_spell.base[i]) - return 0; - break; - case SE_LimitTarget: if (focus_spell.base[i] < 0) { if (-focus_spell.base[i] == spell.targettype) //Exclude From 28493488acd3c81ed2b8f3b34de6f1f0151e8f33 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 3 Jul 2014 11:00:23 -0400 Subject: [PATCH 45/62] Updated SE_BardAEDot to no longer damage target while target is moving (consistent with live) --- changelog.txt | 1 + zone/spell_effects.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 56307b361..c86b926fa 100644 --- a/changelog.txt +++ b/changelog.txt @@ -9,6 +9,7 @@ takes more than the specified damage amount in a SINGLE hit, then fade the buff. Kayen: Implemented SE_LimitSpellClass - Focus Limits spell to pre defined categories. (3=Cures,3=Offensive, 6=Lifetap) Kayen: Changed SE_LimitMaxMana to SE_MeleeVulnerability - Weakness/Mitigation verse melee damage (Despite lives SPA lable as the former it clearly is not what the effect does from all spell examples) +Kayen: Updated SE_BardAEDot to no longer damage target while target is moving (consistent with live) == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 8c49414d7..dfe8489c0 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2328,6 +2328,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) // SE_CurrentHP is calculated at first tick if its a dot/buff if (buffslot >= 0) break; + //This effect does no damage if target is moving. + if (IsMoving()) + break; // for offensive spells check if we have a spell rune on int32 dmg = effect_value; @@ -3391,7 +3394,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste { effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster); - if (invulnerable || /*effect_value > 0 ||*/ DivineAura()) + if (IsMoving() || invulnerable || /*effect_value > 0 ||*/ DivineAura()) break; if(effect_value < 0) { From 5a30d3ed034e0ea848674190fe32967196a12f38 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Thu, 3 Jul 2014 11:37:38 -0400 Subject: [PATCH 46/62] Update SE_InterruptCasting: Will now work for instant spells (as well as over time). --- changelog.txt | 1 + zone/spell_effects.cpp | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index c86b926fa..1e371109d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -10,6 +10,7 @@ Kayen: Implemented SE_LimitSpellClass - Focus Limits spell to pre defined catego Kayen: Changed SE_LimitMaxMana to SE_MeleeVulnerability - Weakness/Mitigation verse melee damage (Despite lives SPA lable as the former it clearly is not what the effect does from all spell examples) Kayen: Updated SE_BardAEDot to no longer damage target while target is moving (consistent with live) +Kayen: Update SE_InterruptCasting: Will now work for instant spells (as well as over time). == 06/25/2014 == Kayen: Updated SE_Hate (Renamed from SE_Hate2) to now properly work for instant +/- hate spells. diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index dfe8489c0..61333edfd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -2712,6 +2712,16 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } + case SE_InterruptCasting:{ + if (buffslot >= 0) + break; + + if(IsCasting() && MakeRandomInt(0, 100) <= spells[spell_id].base[i]) + InterruptSpell(); + + break; + } + case SE_MassGroupBuff:{ SetMGB(true); @@ -2854,7 +2864,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_ApplyEffect: case SE_FcTwincast: case SE_DelayDeath: - case SE_InterruptCasting: case SE_CastOnFadeEffect: case SE_CastOnFadeEffectNPC: case SE_CastOnFadeEffectAlways: From 2734307ba270424f17bd119c6c4a70da0cedc053 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Thu, 3 Jul 2014 15:48:17 -0700 Subject: [PATCH 47/62] Added LastInsertID() to MySQLRequestResult --- common/MySQLRequestResult.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/MySQLRequestResult.h b/common/MySQLRequestResult.h index 807efdfc0..ef2dcd104 100644 --- a/common/MySQLRequestResult.h +++ b/common/MySQLRequestResult.h @@ -41,6 +41,7 @@ public: uint32 RowsAffected() const {return m_RowsAffected;} uint32 RowCount() const {return m_RowCount;} uint32 ColumnCount() const {return m_ColumnCount;} + uint32 LastInsertedID() const {return m_LastInsertedID;} MySQLRequestRow& begin() { return m_CurrentRow; } MySQLRequestRow& end() { return m_OneBeyondRow;} From c645b81890fb434a2e8fd2f32a4426edc03be657 Mon Sep 17 00:00:00 2001 From: Chris M Date: Thu, 3 Jul 2014 18:16:43 -0500 Subject: [PATCH 48/62] Removing socket server from cmake for now and maintaining it in its own branch until push to master --- CMakeLists.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 55d9a4cfb..a9dd5a96b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -298,13 +298,6 @@ IF(EQEMU_BUILD_LUA) ENDIF(EQEMU_SANITIZE_LUA_LIBS) ENDIF(EQEMU_BUILD_LUA) -IF(EQEMU_BUILD_SOCKET_SERVER) - FIND_PACKAGE(Boost COMPONENTS system filesystem thread REQUIRED) - INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/dependencies/websocketpp") - ADD_DEFINITIONS(-D_WEBSOCKETPP_CPP11_STL_) - -ENDIF(EQEMU_BUILD_SOCKET_SERVER) - INCLUDE_DIRECTORIES("${ZLIB_INCLUDE_DIRS}" "${MySQL_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/common/glm/glm") IF(EQEMU_BUILD_LUA) @@ -320,7 +313,6 @@ IF(EQEMU_BUILD_SERVER) ADD_SUBDIRECTORY(zone) ADD_SUBDIRECTORY(ucs) ADD_SUBDIRECTORY(queryserv) - ADD_SUBDIRECTORY(socket_server) ADD_SUBDIRECTORY(eqlaunch) ENDIF(EQEMU_BUILD_SERVER) IF(EQEMU_BUILD_LOGIN) From e599555ddbacd04c9586ff41766425efc8b6be33 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 4 Jul 2014 00:46:53 -0400 Subject: [PATCH 49/62] Fix case-sensitive issue --- world/socket_server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/socket_server.cpp b/world/socket_server.cpp index 826a95620..3c6631c49 100644 --- a/world/socket_server.cpp +++ b/world/socket_server.cpp @@ -1,5 +1,5 @@ #include "../common/debug.h" -#include "Socket_Server.h" +#include "socket_server.h" #include "WorldConfig.h" #include "clientlist.h" #include "zonelist.h" From 192f9f0cb5ef3cfecb8c3a99d9f02e0c6188ae07 Mon Sep 17 00:00:00 2001 From: KimLS Date: Thu, 3 Jul 2014 21:49:14 -0700 Subject: [PATCH 50/62] Fix for GCC+11 compile --- common/MySQLRequestResult.h | 5 ++++- common/MySQLRequestRow.cpp | 11 ++++++++++- common/MySQLRequestRow.h | 3 ++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/common/MySQLRequestResult.h b/common/MySQLRequestResult.h index ef2dcd104..05f363722 100644 --- a/common/MySQLRequestResult.h +++ b/common/MySQLRequestResult.h @@ -10,6 +10,8 @@ #include <../common/types.h> #include <../common/MySQLRequestRow.h> #include +#include +#include class MySQLRequestResult { private: @@ -52,4 +54,5 @@ private: }; -#endif \ No newline at end of file +#endif + diff --git a/common/MySQLRequestRow.cpp b/common/MySQLRequestRow.cpp index 5fc4a40e8..d00cbc835 100644 --- a/common/MySQLRequestRow.cpp +++ b/common/MySQLRequestRow.cpp @@ -19,6 +19,15 @@ MySQLRequestRow::MySQLRequestRow(MySQLRequestRow&& moveItem) moveItem.m_MySQLRow = nullptr; } +MySQLRequestRow& MySQLRequestRow::operator=(MySQLRequestRow& moveItem) +{ + m_Result = moveItem.m_Result; + m_MySQLRow = moveItem.m_MySQLRow; + + moveItem.m_Result = nullptr; + moveItem.m_MySQLRow = nullptr; +} + MySQLRequestRow::MySQLRequestRow(MYSQL_RES *result) : m_Result(result), m_MySQLRow(mysql_fetch_row(m_Result)) { @@ -51,4 +60,4 @@ char* MySQLRequestRow::operator[](int index) { return m_MySQLRow[index]; -} \ No newline at end of file +} diff --git a/common/MySQLRequestRow.h b/common/MySQLRequestRow.h index 615a75371..8e979acab 100644 --- a/common/MySQLRequestRow.h +++ b/common/MySQLRequestRow.h @@ -23,6 +23,7 @@ public: MySQLRequestRow(MYSQL_RES *result); MySQLRequestRow(const MySQLRequestRow& row); MySQLRequestRow(MySQLRequestRow&& moveItem); + MySQLRequestRow& operator=(MySQLRequestRow& moveItem); MySQLRequestRow& operator++(); MySQLRequestRow operator++(int); bool operator==(const MySQLRequestRow& rhs); @@ -34,4 +35,4 @@ public: -#endif \ No newline at end of file +#endif From eb6248176690c5b728a233e2f63f4329965a637c Mon Sep 17 00:00:00 2001 From: KimLS Date: Thu, 3 Jul 2014 23:35:19 -0700 Subject: [PATCH 51/62] Missing return value --- common/MySQLRequestRow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/MySQLRequestRow.cpp b/common/MySQLRequestRow.cpp index d00cbc835..46bdaffd9 100644 --- a/common/MySQLRequestRow.cpp +++ b/common/MySQLRequestRow.cpp @@ -26,6 +26,8 @@ MySQLRequestRow& MySQLRequestRow::operator=(MySQLRequestRow& moveItem) moveItem.m_Result = nullptr; moveItem.m_MySQLRow = nullptr; + + return *this; } MySQLRequestRow::MySQLRequestRow(MYSQL_RES *result) From 3b9e9ae0fde8acdcc1c88cb3b98e87eba5956dcd Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 4 Jul 2014 13:57:09 -0400 Subject: [PATCH 52/62] Hopefully fix compile issue with some VS versions --- common/MySQLRequestResult.h | 4 ++-- common/MySQLRequestRow.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/MySQLRequestResult.h b/common/MySQLRequestResult.h index 05f363722..0bf644c98 100644 --- a/common/MySQLRequestResult.h +++ b/common/MySQLRequestResult.h @@ -7,8 +7,8 @@ #endif #include -#include <../common/types.h> -#include <../common/MySQLRequestRow.h> +#include "../common/types.h" +#include "../common/MySQLRequestRow.h" #include #include #include diff --git a/common/MySQLRequestRow.h b/common/MySQLRequestRow.h index 8e979acab..535699fea 100644 --- a/common/MySQLRequestRow.h +++ b/common/MySQLRequestRow.h @@ -8,7 +8,7 @@ #include #include -#include <../common/types.h> +#include "../common/types.h" class MySQLRequestRow : public std::iterator { From 58d585e2a6b4d3d1f7ba481ffd0d302154fd7828 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Fri, 4 Jul 2014 23:35:15 -0400 Subject: [PATCH 53/62] Updated SE_Sanctuary - Adjust way hate lowering effect worked to be more accurate Updated SE_SympatheticProc - Revised proc rate formula to be accurate to live. Sympathetic foci on items with proc rate mod will now benefit from that modifier. Sympathetic foci can now be placed on AA's (This should always be slot1 in the AA) Implemented SE_IllusionPersistence- Allows illusions to last until you die or the illusion is forcibly removed. Added rule 'PreNerftBardAEDot' for SE_BardAEDot to allow it to once again do damage to moving targets. (Set to true) --- changelog.txt | 11 + common/ruletypes.h | 1 + common/spdat.h | 2 +- .../git/required/2014_07_04_AA_Updates.sql | 6 + zone/bonuses.cpp | 19 ++ zone/bot.cpp | 6 +- zone/client.h | 5 +- zone/common.h | 2 +- zone/hate_list.cpp | 10 + zone/mob.cpp | 8 + zone/mob.h | 3 +- zone/spell_effects.cpp | 229 ++++++++++-------- 12 files changed, 187 insertions(+), 115 deletions(-) create mode 100644 utils/sql/git/required/2014_07_04_AA_Updates.sql diff --git a/changelog.txt b/changelog.txt index 1e371109d..59f39c327 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,16 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 07/5/2014 == +Kayen: Updated SE_Sanctuary - Adjust way hate lowering effect worked to be more accurate +Kayen: Updated SE_SympatheticProc - Revised proc rate formula to be accurate to live. +Sympathetic foci on items with proc rate mod will now benefit from that modifier. +Sympathetic foci can now be placed on AA's (This should always be slot1 in the AA) +Kayen: Implemented SE_IllusionPersistence- Allows illusions to last until you die or the illusion is forcibly removed. +Kayen: Added rule 'PreNerftBardAEDot' for SE_BardAEDot to allow it to once again do damage to moving targets. (Set to true) + +Required SQL: utils/sql/git/required/2014_07_04_AA_Update.sql + + == 07/2/2014 == Kayen: Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self. Kayen: Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. diff --git a/common/ruletypes.h b/common/ruletypes.h index 6f5fe0769..8c9ac543e 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -310,6 +310,7 @@ RULE_INT ( Spells, FRProjectileItem_SOF, 80684) // Item id for SOF clients for F RULE_INT ( Spells, FRProjectileItem_NPC, 80684) // Item id for NPC Fire 'spell projectile'. RULE_BOOL ( Spells, UseLiveSpellProjectileGFX, false) // Use spell projectile graphics set in the spells_new table (player_1). Server must be using UF+ spell file. RULE_BOOL ( Spells, FocusCombatProcs, false) //Allow all combat procs to receive focus effects. +RULE_BOOL ( Spells, PreNerfBardAEDoT, false) //Allow bard AOE dots to damage targets when moving. RULE_CATEGORY_END() RULE_CATEGORY( Combat ) diff --git a/common/spdat.h b/common/spdat.h index 02dca8ff7..42091338a 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -385,7 +385,7 @@ typedef enum { #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. //#define SE_FreePet 236 // not used #define SE_GivePetGroupTarget 237 // implemented[AA] - (Pet Affinity) -//#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_IllusionPersistence 238 // 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 // implemented - increase the amount of mana returned to you when reclaiming your pet. diff --git a/utils/sql/git/required/2014_07_04_AA_Updates.sql b/utils/sql/git/required/2014_07_04_AA_Updates.sql new file mode 100644 index 000000000..a943e8c15 --- /dev/null +++ b/utils/sql/git/required/2014_07_04_AA_Updates.sql @@ -0,0 +1,6 @@ +-- AA Permanent Illusion +INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('158', '1', '238', '1', '0'); + +-- AA Sanctuary +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 ('1209', 'Sanctuary', '12', '1', '1209', '4294967295', '1209', '1209', '3', '5912', '0', '0', '14', '4320', '4', '0', '70', '0', '8', '4294967295', '3', '0', '1', '1209', '1', '0', '0', '0', '0'); +INSERT INTO `aa_actions` (`aaid`, `rank`, `reuse_time`, `spell_id`, `target`, `nonspell_action`, `nonspell_mana`, `nonspell_duration`, `redux_aa`, `redux_rate`, `redux_aa2`, `redux_rate2`) VALUES ('1209', '0', '4320', '5912', '1', '0', '0', '0', '0', '0', '0', '0'); diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 48a3d95e1..b21eeaa0a 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1329,6 +1329,10 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } + case SE_IllusionPersistence: + newbon->IllusionPersistence = true; + break; + } } } @@ -2876,6 +2880,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne break; } + case SE_IllusionPersistence: + newbon->IllusionPersistence = true; + break; + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { @@ -4356,6 +4364,17 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) aabonuses.FactionModPct = effect_value; break; + case SE_MeleeVulnerability: + spellbonuses.MeleeVulnerability = effect_value; + itembonuses.MeleeVulnerability = effect_value; + aabonuses.MeleeVulnerability = effect_value; + break; + + case SE_IllusionPersistence: + spellbonuses.IllusionPersistence = effect_value; + itembonuses.IllusionPersistence = effect_value; + aabonuses.IllusionPersistence = effect_value; + break; } } } diff --git a/zone/bot.cpp b/zone/bot.cpp index e961bd7ec..a1a31740e 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -7641,10 +7641,8 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel { if(bottype == BotfocusSympatheticProc) { - float ProcChance, ProcBonus; - int16 ProcRateMod = focus_spell.base[i]; //Baseline is 100 for most Sympathetic foci - int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time); - GetSympatheticProcChances(ProcBonus, ProcChance, cast_time, ProcRateMod); + + float ProcChance = GetSympatheticProcChances(spell_id, focus_spell.base[i]); if(MakeRandomFloat(0, 1) <= ProcChance) value = focus_id; diff --git a/zone/client.h b/zone/client.h index 9e2503df2..e26465628 100644 --- a/zone/client.h +++ b/zone/client.h @@ -776,7 +776,10 @@ public: int GetSpentAA() { return m_pp.aapoints_spent; } void RefundAA(); void IncrementAA(int aa_id); - + int32 GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2); + int32 GetAAEffectid(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, true, false,false); } + int32 GetAABase1(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, true,false); } + int32 GetAABase2(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, false,true); } int16 acmod(); // Item methods diff --git a/zone/common.h b/zone/common.h index e3a9dfb09..98e2ebcec 100644 --- a/zone/common.h +++ b/zone/common.h @@ -431,7 +431,7 @@ struct StatBonuses { 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. - + bool IllusionPersistence; // Causes illusions not to fade. }; typedef struct diff --git a/zone/hate_list.cpp b/zone/hate_list.cpp index 68dd2a6cb..abe32b5a7 100644 --- a/zone/hate_list.cpp +++ b/zone/hate_list.cpp @@ -308,6 +308,16 @@ Mob *HateList::GetTop(Mob *center) } } + if (cur->ent->Sanctuary()) { + if(hate == -1) + { + top = cur->ent; + hate = 1; + } + ++iterator; + continue; + } + if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){ if(hate == -1) { diff --git a/zone/mob.cpp b/zone/mob.cpp index 59e02568b..93b9f5047 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -2761,6 +2761,14 @@ bool Mob::DivineAura() const return false; } +bool Mob::Sanctuary() const +{ + if (spellbonuses.Sanctuary) + return true; + + return false; +} + int16 Mob::GetResist(uint8 type) const { if (IsNPC()) diff --git a/zone/mob.h b/zone/mob.h index 0476a20dc..cb44dd80c 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -820,6 +820,7 @@ public: void SetNextIncHPEvent( int inchpevent ); bool DivineAura() const; + bool Sanctuary() const; bool HasNPCSpecialAtk(const char* parse); int GetSpecialAbility(int ability); @@ -1009,7 +1010,7 @@ protected: Map::Vertex UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached); void PrintRoute(); - virtual float GetSympatheticProcChances(float &ProcBonus, float &ProcChance, int32 cast_time, int16 ProcRateMod); + virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0); enum {MAX_PROCS = 4}; tProc PermaProcs[MAX_PROCS]; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 61333edfd..b92ea524c 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1430,7 +1430,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) for(int x = 0; x < 7; x++){ SendWearChange(x); } - if(caster && caster->GetAA(aaPermanentIllusion)) + if(caster && (caster->spellbonuses.IllusionPersistence || caster->aabonuses.IllusionPersistence + || caster->itembonuses.IllusionPersistence)) buffs[buffslot].persistant_buff = 1; else buffs[buffslot].persistant_buff = 0; @@ -2329,7 +2330,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) if (buffslot >= 0) break; //This effect does no damage if target is moving. - if (IsMoving()) + if (!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) break; // for offensive spells check if we have a spell rune on @@ -2735,22 +2736,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_Sanctuary: - { - std::list npc_list; - entity_list.GetNPCList(npc_list); - - for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { - - NPC* npc = *itr; - - if (npc && npc->CheckAggro(this)) - npc->SetHate(caster, 1); - - } - break; - } - // Handled Elsewhere case SE_ImmuneFleeing: case SE_NegateSpellEffect: @@ -2984,6 +2969,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_AssassinateLevel: case SE_FactionModPct: case SE_LimitSpellClass: + case SE_Sanctuary: { break; } @@ -3403,7 +3389,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste { effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster); - if (IsMoving() || invulnerable || /*effect_value > 0 ||*/ DivineAura()) + if ((!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) || invulnerable || /*effect_value > 0 ||*/ DivineAura()) break; if(effect_value < 0) { @@ -3630,21 +3616,6 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste break; } - case SE_Sanctuary: - { - std::list npc_list; - entity_list.GetNPCList(npc_list); - - for(std::list::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) { - - NPC* npc = *itr; - - if (npc && npc->CheckAggro(this)) - npc->SetHate(caster, 1); - - } - break; - } default: { @@ -4084,39 +4055,41 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) CalcBonuses(); } -/* No longer used. -int16 Client::CalcAAFocusEffect(focusType type, uint16 focus_spell, uint16 spell_id) +int32 Client::GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2) { - uint32 slots = 0; - uint32 aa_AA = 0; - uint32 aa_value = 0; + int32 aa_effects_data[3] = { 0 }; + uint32 effect = 0; + int32 base1 = 0; + int32 base2 = 0; + uint32 slot = 0; - int32 value = 0; - // Iterate through all of the client's AAs - for (int i = 0; i < MAX_PP_AA_ARRAY; i++) + + std::map >::const_iterator find_iter = aa_effects.find(aa_ID); + if(find_iter == aa_effects.end()) + return 0; + + for (std::map::const_iterator iter = aa_effects[aa_ID].begin(); iter != aa_effects[aa_ID].end(); ++iter) { - aa_AA = this->aa[i]->AA; - aa_value = this->aa[i]->value; - if (aa_AA > 0 || aa_value > 0) - { - slots = zone->GetTotalAALevels(aa_AA); - if (slots > 0) - for(int j = 1;j <= slots; j++) - { - switch (aa_effects[aa_AA][j].skill_id) - { - case SE_TriggerOnCast: - // If focus_spell matches the spell listed in the DB, load these restrictions - if(type == focusTriggerOnCast && focus_spell == aa_effects[aa_AA][j].base1) - value = CalcAAFocus(type, aa_AA, spell_id); - break; - } - } + effect = iter->second.skill_id; + base1 = iter->second.base1; + base2 = iter->second.base2; + slot = iter->second.slot; + + if (slot && slot == slot_id) { + + if (GetEffect) + return effect; + + if (GetBase1) + return base1; + + if (GetBase2) + return base2; } } - return value; + + return 0; } -*/ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) @@ -4496,9 +4469,11 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) value = base1; break; - case SE_SympatheticProc: - //No AA support at this time. - break; + //Note if using these as AA, make sure this is first focus used. + case SE_SympatheticProc: + if(type == focusSympatheticProc) + value = base2; + break; case SE_FcDamageAmt: if(type == focusFcDamageAmt) @@ -4962,16 +4937,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo case SE_SympatheticProc: if(type == focusSympatheticProc) { - float ProcChance, ProcBonus; - int16 ProcRateMod = focus_spell.base[i]; //Baseline is 100 for most Sympathetic foci - int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time); - GetSympatheticProcChances(ProcBonus, ProcChance, cast_time, ProcRateMod); - - if(MakeRandomFloat(0, 1) <= ProcChance) - value = focus_id; - - else - value = 0; + value = focus_id; } break; @@ -5089,8 +5055,8 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { return 0; uint16 proc_spellid = 0; - uint8 SizeProcList = 0; uint8 MAX_SYMPATHETIC = 10; + float ProcChance = 0.0f; std::vector SympatheticProcList; @@ -5101,7 +5067,7 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { for(int x=0; x<=21; x++) { - if (SizeProcList > MAX_SYMPATHETIC) + if (SympatheticProcList.size() > MAX_SYMPATHETIC) continue; TempItem = nullptr; @@ -5109,20 +5075,22 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { if (!ins) continue; TempItem = ins->GetItem(); - if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) { + if (TempItem && TempItem->Focus.Effect > 0 && IsValidSpell(TempItem->Focus.Effect)) { - proc_spellid = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id); + proc_spellid = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id); + + if (IsValidSpell(proc_spellid)){ - if (proc_spellid > 0) - { - SympatheticProcList.push_back(proc_spellid); - SizeProcList = SympatheticProcList.size(); - } + ProcChance = GetSympatheticProcChances(spell_id, spells[TempItem->Focus.Effect].base[0], TempItem->ProcRate); + + if(MakeRandomFloat(0, 1) <= ProcChance) + SympatheticProcList.push_back(proc_spellid); + } } for(int y = 0; y < MAX_AUGMENT_SLOTS; ++y) { - if (SizeProcList > MAX_SYMPATHETIC) + if (SympatheticProcList.size() > MAX_SYMPATHETIC) continue; ItemInst *aug = nullptr; @@ -5130,14 +5098,16 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { if(aug) { const Item_Struct* TempItemAug = aug->GetItem(); - if (TempItemAug && TempItemAug->Focus.Effect > 0 && TempItemAug->Focus.Effect != SPELL_UNKNOWN) { + if (TempItemAug && TempItemAug->Focus.Effect > 0 && IsValidSpell(TempItemAug->Focus.Effect)) { proc_spellid = CalcFocusEffect(type, TempItemAug->Focus.Effect, spell_id); - if (proc_spellid > 0) - { - SympatheticProcList.push_back(proc_spellid); - SizeProcList = SympatheticProcList.size(); + if (IsValidSpell(proc_spellid)){ + + ProcChance = GetSympatheticProcChances(spell_id, spells[TempItem->Focus.Effect].base[0], TempItemAug->ProcRate); + + if(MakeRandomFloat(0, 1) <= ProcChance) + SympatheticProcList.push_back(proc_spellid); } } } @@ -5152,26 +5122,57 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) { uint32 buff_max = GetMaxTotalSlots(); for (buff_slot = 0; buff_slot < buff_max; buff_slot++) { - if (SizeProcList > MAX_SYMPATHETIC) + if (SympatheticProcList.size() > MAX_SYMPATHETIC) continue; focusspellid = buffs[buff_slot].spellid; - if (focusspellid == 0 || focusspellid >= SPDAT_RECORDS) + if (IsValidSpell(focusspellid)) continue; proc_spellid = CalcFocusEffect(type, focusspellid, spell_id); - if (proc_spellid > 0) - { - SympatheticProcList.push_back(proc_spellid); - SizeProcList = SympatheticProcList.size(); - } + if (IsValidSpell(proc_spellid)){ + + ProcChance = GetSympatheticProcChances(spell_id, spells[focusspellid].base[0]); + + if(MakeRandomFloat(0, 1) <= ProcChance) + SympatheticProcList.push_back(proc_spellid); + } } } - if (SizeProcList > 0) + /*Note: At present, ff designing custom AA to have a sympathetic proc effect, only use one focus + effect within the aa_effects data for each AA*[No live AA's use this effect to my knowledge]*/ + if (aabonuses.FocusEffects[type]){ + + uint32 aa_AA = 0; + uint32 aa_value = 0; + + for (int i = 0; i < MAX_PP_AA_ARRAY; i++) + { + aa_AA = this->aa[i]->AA; + aa_value = this->aa[i]->value; + if (aa_AA < 1 || aa_value < 1) + continue; + + if (SympatheticProcList.size() > MAX_SYMPATHETIC) + continue; + + proc_spellid = CalcAAFocus(type, aa_AA, spell_id); + + if (IsValidSpell(proc_spellid)){ + + ProcChance = GetSympatheticProcChances(spell_id, GetAABase1(aa_AA, 1)); + + if(MakeRandomFloat(0, 1) <= ProcChance) + SympatheticProcList.push_back(proc_spellid); + } + } + } + + if (SympatheticProcList.size() > 0) { - uint8 random = MakeRandomInt(0, SizeProcList-1); + uint8 random = MakeRandomInt(0, SympatheticProcList.size()-1); int FinalSympatheticProc = SympatheticProcList[random]; SympatheticProcList.clear(); return FinalSympatheticProc; @@ -5674,17 +5675,31 @@ bool Mob::AffectedBySpellExcludingSlot(int slot, int effect) return false; } -float Mob::GetSympatheticProcChances(float &ProcBonus, float &ProcChance, int32 cast_time, int16 ProcRateMod) { +float Mob::GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate) { - ProcChance = 0; + float ProcChance = 0.0f; + int32 total_cast_time = 0; + float cast_time_mod = 0.0f; + ProcRateMod -= 100; + - if(cast_time > 0) - { - ProcChance = ((float)cast_time * RuleR(Casting, AvgSpellProcsPerMinute) / 60000.0f); - ProcChance = ProcChance * (float)(ProcRateMod/100); - } - return ProcChance; -} + if (spells[spell_id].recast_time >= spells[spell_id].recovery_time) + total_cast_time = spells[spell_id].recast_time + spells[spell_id].cast_time; + else + total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time; + + if (total_cast_time > 0 && total_cast_time <= 2500) + cast_time_mod = 0.25f; + else if (total_cast_time > 2500 && total_cast_time < 7000) + cast_time_mod = 0.167*((static_cast(total_cast_time) - 1000.0f)/1000.0f); + else + cast_time_mod = static_cast(total_cast_time) / 7000.0f; + + ProcChance = (RuleR(Casting, AvgSpellProcsPerMinute)/100.0f) * (static_cast(100.0f + ProcRateMod) / 10.0f) + * cast_time_mod * (static_cast(100.0f + ItemProcRate)/100.0f); + + return ProcChance; + } bool Mob::DoHPToManaCovert(uint16 mana_cost) { From d514eef59b8906a176f59822a2f67cf127762899 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sat, 5 Jul 2014 10:10:55 -0700 Subject: [PATCH 54/62] Added LengthOfColumn method because of stupid BLOBs --- common/MySQLRequestResult.cpp | 29 +++++++++++++++++++++++++++++ common/MySQLRequestResult.h | 3 +++ 2 files changed, 32 insertions(+) diff --git a/common/MySQLRequestResult.cpp b/common/MySQLRequestResult.cpp index 16d7fe9a0..8fc47cfca 100644 --- a/common/MySQLRequestResult.cpp +++ b/common/MySQLRequestResult.cpp @@ -32,6 +32,10 @@ MySQLRequestResult::MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected, u m_RowsAffected = rowsAffected; m_RowCount = rowCount; m_ColumnCount = columnCount; + // If we actually need the column length it will be requested + // at that time, no need to pull it in just to cache it. + // Normal usage would have it as nullptr most likely anyways. + m_ColumnLengths = nullptr; m_LastInsertedID = lastInsertedID; m_ErrorNumber = errorNumber; } @@ -51,6 +55,7 @@ void MySQLRequestResult::ZeroOut() m_Success = false; m_Result = nullptr; m_ErrorBuffer = nullptr; + m_ColumnLengths = nullptr; m_RowCount = 0; m_RowsAffected = 0; m_LastInsertedID = 0; @@ -61,6 +66,28 @@ MySQLRequestResult::~MySQLRequestResult() FreeInternals(); } +uint32 MySQLRequestResult::LengthOfColumn(int columnIndex) +{ + if (m_ColumnLengths == nullptr && m_Result != nullptr) + m_ColumnLengths = mysql_fetch_lengths(m_Result); + + // If someone screws up and tries to get the length of a + // column when no result occured (check Success! argh!) + // then we always return 0. Also applies if mysql screws + // up and can't get the column lengths for whatever reason. + if (m_ColumnLengths == nullptr) + return 0; + + // Want to index check to be sure we don't read passed + // the end of the array. Just default to 0 in that case. + // We *shouldn't* need this or the previous checks if all + // interface code is correctly written. + if (columnIndex >= m_ColumnCount) + return 0; + + return m_ColumnLengths[columnIndex]; +} + MySQLRequestResult::MySQLRequestResult(MySQLRequestResult&& moveItem) : m_CurrentRow(moveItem.m_CurrentRow), m_OneBeyondRow() { @@ -70,6 +97,7 @@ MySQLRequestResult::MySQLRequestResult(MySQLRequestResult&& moveItem) m_RowCount = moveItem.m_RowCount; m_RowsAffected = moveItem.m_RowsAffected; m_LastInsertedID = moveItem.m_LastInsertedID; + m_ColumnLengths = moveItem.m_ColumnLengths; // Keeps deconstructor from double freeing // pre move instance. @@ -95,6 +123,7 @@ MySQLRequestResult& MySQLRequestResult::operator=(MySQLRequestResult&& other) m_LastInsertedID = other.m_LastInsertedID; m_CurrentRow = other.m_CurrentRow; m_OneBeyondRow = other.m_OneBeyondRow; + m_ColumnLengths = other.m_ColumnLengths; // Keeps deconstructor from double freeing // pre move instance. diff --git a/common/MySQLRequestResult.h b/common/MySQLRequestResult.h index 05f363722..4859a625f 100644 --- a/common/MySQLRequestResult.h +++ b/common/MySQLRequestResult.h @@ -17,6 +17,7 @@ class MySQLRequestResult { private: MYSQL_RES* m_Result; char* m_ErrorBuffer; + unsigned long* m_ColumnLengths; MySQLRequestRow m_CurrentRow; MySQLRequestRow m_OneBeyondRow; @@ -44,6 +45,8 @@ public: uint32 RowCount() const {return m_RowCount;} uint32 ColumnCount() const {return m_ColumnCount;} uint32 LastInsertedID() const {return m_LastInsertedID;} + // default to 0 index since we mostly use it that way anyways. + uint32 LengthOfColumn(int columnIndex = 0); MySQLRequestRow& begin() { return m_CurrentRow; } MySQLRequestRow& end() { return m_OneBeyondRow;} From 0e438942e41dda8bd78ad601a267e1efd97a7915 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 6 Jul 2014 18:58:16 -0400 Subject: [PATCH 55/62] Complete revision of SE_SkillProc, SE_LimitToSkill, SE_SkillProcSuccess (now implemented correctly) to function more accurately and efficiently, AA supported. This may need to be updated in the future, if more live spells readily become avialable to test with. --- changelog.txt | 1 + common/spdat.h | 4 +- zone/attack.cpp | 274 +++++++++++++++++++++++++++++---------- zone/bonuses.cpp | 75 ++++++++++- zone/bot.cpp | 20 +-- zone/bot.h | 2 +- zone/client_packet.cpp | 7 - zone/common.h | 3 + zone/mob.cpp | 50 +++++++ zone/mob.h | 13 +- zone/special_attacks.cpp | 89 ++++++++----- zone/spell_effects.cpp | 32 +---- zone/spells.cpp | 31 ----- 13 files changed, 415 insertions(+), 186 deletions(-) diff --git a/changelog.txt b/changelog.txt index 59f39c327..a55917f97 100644 --- a/changelog.txt +++ b/changelog.txt @@ -7,6 +7,7 @@ Sympathetic foci on items with proc rate mod will now benefit from that modifier Sympathetic foci can now be placed on AA's (This should always be slot1 in the AA) Kayen: Implemented SE_IllusionPersistence- Allows illusions to last until you die or the illusion is forcibly removed. Kayen: Added rule 'PreNerftBardAEDot' for SE_BardAEDot to allow it to once again do damage to moving targets. (Set to true) +Kayen: Completely revised SE_SkillProc, SE_LimitToSkill, SE_SkillProcSuccess to overall just work better and more accurately, AA support. Required SQL: utils/sql/git/required/2014_07_04_AA_Update.sql diff --git a/common/spdat.h b/common/spdat.h index 42091338a..69082d305 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -37,6 +37,8 @@ #define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2) #define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists. #define MaxLimitInclude 16 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects +#define MAX_SKILL_PROCS 4 //Number of spells to check skill procs from. (This is arbitrary) [Single spell can have multiple proc checks] + const int Z_AGGRO=10; @@ -576,7 +578,7 @@ typedef enum { //#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window #define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt) #define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc -#define SE_SkillProc2 429 // implemented - chance to proc when using a skill (most have hit limits) +#define SE_SkillProcSuccess 429 // implemented - chance to proc when tje skill in use successfully fires. //#define SE_PostEffect 430 // *not implemented - Fear of the Dark(27641) - Alters vision //#define SE_PostEffectData 431 // *not implemented - Fear of the Dark(27641) - Alters vision //#define SE_ExpandMaxActiveTrophyBen 432 // not used diff --git a/zone/attack.cpp b/zone/attack.cpp index fdbc46d24..6bf7b744c 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1359,8 +1359,11 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b MeleeLifeTap(damage); - if (damage > 0) + if (damage > 0){ CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); + if (HasSkillProcSuccess() && other && other->GetHP() > 0) + TrySkillProc(other, skillinuse, 0, true, Hand); + } //break invis when you attack if(invisible) { @@ -2018,9 +2021,12 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool if (!GetTarget()) return true; //We killed them - if(!bRiposte && other->GetHP() > 0 ) { + if(!bRiposte && other && other->GetHP() > 0) { TryWeaponProc(nullptr, weapon, other, Hand); //no weapon TrySpellProc(nullptr, weapon, other, Hand); + + if (damage > 0 && HasSkillProcSuccess()) + TrySkillProc(other, skillinuse, 0, true, Hand); } TriggerDefensiveProcs(nullptr, other, Hand, damage); @@ -3426,9 +3432,20 @@ bool Mob::HasDefensiveProcs() const bool Mob::HasSkillProcs() const { - for (int i = 0; i < MAX_PROCS; i++) - if (SkillProcs[i].spellID != SPELL_UNKNOWN) + + for(int i = 0; i < MAX_SKILL_PROCS; i++){ + if (spellbonuses.SkillProc[i] || itembonuses.SkillProc[i] || aabonuses.SkillProc[i]) return true; + } + return false; +} + +bool Mob::HasSkillProcSuccess() const +{ + for(int i = 0; i < MAX_SKILL_PROCS; i++){ + if (spellbonuses.SkillProcSuccess[i] || itembonuses.SkillProcSuccess[i] || aabonuses.SkillProcSuccess[i]) + return true; + } return false; } @@ -3911,22 +3928,7 @@ float Mob::GetProcChances(float ProcBonus, uint16 weapon_speed, uint16 hand) int mydex = GetDEX(); float ProcChance = 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; - } - - //calculate the weapon speed in ms, so we can use the rule to compare against. - // fast as a client can swing, so should be the floor of the proc chance - if (weapon_speed < RuleI(Combat, MinHastedDelay)) - weapon_speed = RuleI(Combat, MinHastedDelay); + weapon_speed = GetWeaponSpeedbyHand(hand); if (RuleB(Combat, AdjustProcPerMinute)) { ProcChance = (static_cast(weapon_speed) * @@ -3948,25 +3950,10 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 w ProcBonus = 0; ProcChance = 0; - switch(hand){ - case 13: - weapon_speed = attack_timer.GetDuration(); - break; - case 14: - weapon_speed = attack_dw_timer.GetDuration(); - break; - case 11: - return 0; - break; - } + weapon_speed = GetWeaponSpeedbyHand(hand); - //calculate the weapon speed in ms, so we can use the rule to compare against. - //weapon_speed = ((int)(weapon_speed*(100.0f+attack_speed)*PermaHaste)); - if(weapon_speed < RuleI(Combat, MinHastedDelay)) // fast as a client can swing, so should be the floor of the proc chance - weapon_speed = RuleI(Combat, MinHastedDelay); - - ProcChance = ((float)weapon_speed * RuleR(Combat, AvgDefProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms - ProcBonus += float(myagi) * RuleR(Combat, DefProcPerMinAgiContrib) / 100.0f; + ProcChance = (static_cast(weapon_speed) * RuleR(Combat, AvgDefProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms + ProcBonus += static_cast(myagi) * RuleR(Combat, DefProcPerMinAgiContrib) / 100.0f; ProcChance = ProcChance + (ProcChance * ProcBonus); mlog(COMBAT__PROCS, "Defensive Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus); @@ -3981,13 +3968,9 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam return; } - bool bSkillProc = HasSkillProcs(); bool bDefensiveProc = HasDefensiveProcs(); - if (!bDefensiveProc && !bSkillProc) - return; - - if (!bDefensiveProc && (bSkillProc && damage >= 0)) + if (!bDefensiveProc) return; float ProcChance, ProcBonus; @@ -4001,29 +3984,14 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam if (bDefensiveProc){ for (int i = 0; i < MAX_PROCS; i++) { if (DefensiveProcs[i].spellID != SPELL_UNKNOWN) { - int chance = ProcChance * (DefensiveProcs[i].chance); - if ((MakeRandomInt(0, 100) < chance)) { + float chance = ProcChance * (static_cast(DefensiveProcs[i].chance)/100.0f); + if ((MakeRandomInt(0, 1) <= chance)) { ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); CheckNumHitsRemaining(NUMHIT_DefensiveSpellProcs,0,DefensiveProcs[i].base_spellID); } } } } - - if (bSkillProc && damage < 0){ - - if (damage == -1) - TrySkillProc(on, SkillBlock, ProcChance); - - if (damage == -2) - TrySkillProc(on, SkillParry, ProcChance); - - if (damage == -3) - TrySkillProc(on, SkillRiposte, ProcChance); - - if (damage == -4) - TrySkillProc(on, SkillDodge, ProcChance); - } } void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) { @@ -4032,7 +4000,7 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) { LogFile->write(EQEMuLog::Error, "A null Mob object was passed to Mob::TryWeaponProc for evaluation!"); return; } - + if (!IsAttackAllowed(on)) { mlog(COMBAT__PROCS, "Preventing procing off of unattackable things."); return; @@ -4059,6 +4027,7 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) { void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand) { + if (!weapon) return; uint16 skillinuse = 28; @@ -4135,8 +4104,6 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on } } // TODO: Powersource procs - if (HasSkillProcs()) - TrySkillProc(on, skillinuse, ProcChance); return; } @@ -4217,6 +4184,14 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, } } + if (HasSkillProcs() && hand != 11){ //We check ranged skill procs within the attack functions. + uint16 skillinuse = 28; + if (weapon) + skillinuse = GetSkillByItemType(weapon->ItemType); + + TrySkillProc(on, skillinuse, 0, false, hand); + } + return; } @@ -4560,7 +4535,7 @@ uint16 Mob::GetDamageTable(SkillUseTypes skillinuse) } } -void Mob::TrySkillProc(Mob *on, uint16 skill, float chance) +void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, uint16 hand, bool IsDefensive) { if (!on) { @@ -4569,17 +4544,174 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, float chance) return; } - for (int i = 0; i < MAX_PROCS; i++) { - if (SkillProcs[i].spellID != SPELL_UNKNOWN){ - if (PassLimitToSkill(SkillProcs[i].base_spellID,skill)){ - int ProcChance = chance * (float)SkillProcs[i].chance; - if ((MakeRandomInt(0, 100) < ProcChance)) { - ExecWeaponProc(nullptr, SkillProcs[i].spellID, on); - CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, SkillProcs[i].base_spellID); + if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill]) + return; + + /*Allow one proc from each (Spell/Item/AA) + Kayen: Due to limited avialability of effects on live it is too difficult + to confirm how they stack at this time, will adjust formula when more data is avialablle to test.*/ + bool CanProc = true; + + uint16 base_spell_id = 0; + uint16 proc_spell_id = 0; + float ProcMod = 0; + float chance = 0; + + if (IsDefensive) + chance = on->GetSkillProcChances(ReuseTime, hand); + else + chance = GetSkillProcChances(ReuseTime, hand); + + if (spellbonuses.LimitToSkill[skill]){ + + for(int e = 0; e < MAX_SKILL_PROCS; e++){ + + if (CanProc && + (!Success && spellbonuses.SkillProc[e] && IsValidSpell(spellbonuses.SkillProc[e])) + || (Success && spellbonuses.SkillProcSuccess[e] && IsValidSpell(spellbonuses.SkillProcSuccess[e]))) { + base_spell_id = spellbonuses.SkillProc[e]; + base_spell_id = 0; + ProcMod = 0; + + for (int i = 0; i < EFFECT_COUNT; i++) { + + if (spells[base_spell_id].effectid[i] == SE_SkillProc) { + proc_spell_id = spells[base_spell_id].base[i]; + ProcMod = static_cast(spells[base_spell_id].base2[i]); + } + + else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].effectid[i] <= HIGHEST_SKILL) { + + if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) { + float final_chance = chance * (ProcMod / 100.0f); + if (MakeRandomFloat(0, 1) <= final_chance) { + ExecWeaponProc(nullptr, proc_spell_id, on); + CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, base_spell_id); + CanProc = false; + break; + } + } + } + else { + proc_spell_id = 0; + ProcMod = 0; + } } } } } + + if (itembonuses.LimitToSkill[skill]){ + CanProc = true; + for(int e = 0; e < MAX_SKILL_PROCS; e++){ + + if (CanProc && + (!Success && itembonuses.SkillProc[e] && IsValidSpell(itembonuses.SkillProc[e])) + || (Success && itembonuses.SkillProcSuccess[e] && IsValidSpell(itembonuses.SkillProcSuccess[e]))) { + base_spell_id = itembonuses.SkillProc[e]; + base_spell_id = 0; + ProcMod = 0; + + for (int i = 0; i < EFFECT_COUNT; i++) { + + if (spells[base_spell_id].effectid[i] == SE_SkillProc) { + proc_spell_id = spells[base_spell_id].base[i]; + ProcMod = static_cast(spells[base_spell_id].base2[i]); + } + + else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].effectid[i] <= HIGHEST_SKILL) { + + if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) { + float final_chance = chance * (ProcMod / 100.0f); + if (MakeRandomFloat(0, 1) <= final_chance) { + ExecWeaponProc(nullptr, proc_spell_id, on); + CanProc = false; + break; + } + } + } + else { + proc_spell_id = 0; + ProcMod = 0; + } + } + } + } + } + + if (IsClient() && aabonuses.LimitToSkill[skill]){ + + CanProc = true; + uint32 effect = 0; + int32 base1 = 0; + int32 base2 = 0; + uint32 slot = 0; + + for(int e = 0; e < MAX_SKILL_PROCS; e++){ + + if (CanProc && + (!Success && aabonuses.SkillProc[e]) + || (Success && aabonuses.SkillProcSuccess[e])){ + int aaid = aabonuses.SkillProc[e]; + base_spell_id = 0; + ProcMod = 0; + + std::map >::const_iterator find_iter = aa_effects.find(aaid); + if(find_iter == aa_effects.end()) + break; + + for (std::map::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) { + effect = iter->second.skill_id; + base1 = iter->second.base1; + base2 = iter->second.base2; + slot = iter->second.slot; + + if (effect == SE_SkillProc) { + proc_spell_id = base1; + ProcMod = static_cast(base2); + } + + else if (effect == SE_LimitToSkill && effect <= HIGHEST_SKILL) { + + if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) { + float final_chance = chance * (ProcMod / 100.0f); + + if (MakeRandomFloat(0, 1) <= final_chance) { + ExecWeaponProc(nullptr, proc_spell_id, on); + CanProc = false; + break; + } + } + } + else { + proc_spell_id = 0; + ProcMod = 0; + } + } + } + } + } +} + +float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) { + + uint16 weapon_speed; + float ProcChance = 0; + + if (!ReuseTime && hand) { + + weapon_speed = GetWeaponSpeedbyHand(hand); + + ProcChance = static_cast(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f); + + if (hand != 13) + ProcChance /= 2; + } + + else + ProcChance = static_cast(ReuseTime) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f); + + return ProcChance; } bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) { diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index b21eeaa0a..7bc691a9a 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) { @@ -1333,6 +1333,41 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) newbon->IllusionPersistence = true; break; + case SE_LimitToSkill:{ + if (base1 <= HIGHEST_SKILL) + newbon->LimitToSkill[base1] = true; + break; + } + + case SE_SkillProc:{ + for(int e = 0; e < MAX_SKILL_PROCS; e++) + { + if(newbon->SkillProc[e] && newbon->SkillProc[e] == aaid) + break; //Do not use the same aa id more than once. + + else if(!newbon->SkillProc[e]){ + newbon->SkillProc[e] = aaid; + break; + } + } + break; + } + + case SE_SkillProcSuccess:{ + + for(int e = 0; e < MAX_SKILL_PROCS; e++) + { + if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid) + break; //Do not use the same spell id more than once. + + else if(!newbon->SkillProcSuccess[e]){ + newbon->SkillProcSuccess[e] = aaid; + break; + } + } + break; + } + } } } @@ -2884,6 +2919,44 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->IllusionPersistence = true; break; + case SE_LimitToSkill:{ + if (effect_value <= HIGHEST_SKILL){ + newbon->LimitToSkill[effect_value] = true; + Shout("BONUS Set Limit = %i", effect_value); + } + break; + } + + case SE_SkillProc:{ + + for(int e = 0; e < MAX_SKILL_PROCS; e++) + { + if(newbon->SkillProc[e] && newbon->SkillProc[e] == spell_id) + break; //Do not use the same spell id more than once. + + else if(!newbon->SkillProc[e]){ + newbon->SkillProc[e] = spell_id; + break; + } + } + break; + } + + case SE_SkillProcSuccess:{ + + for(int e = 0; e < MAX_SKILL_PROCS; e++) + { + if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == spell_id) + break; //Do not use the same spell id more than once. + + else if(!newbon->SkillProcSuccess[e]){ + newbon->SkillProcSuccess[e] = spell_id; + break; + } + } + break; + } + //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table if (IsAISpellEffect) { diff --git a/zone/bot.cpp b/zone/bot.cpp index a1a31740e..86a2a9b64 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -3292,7 +3292,7 @@ bool Bot::CheckBotDoubleAttack(bool tripleAttack) { return false; } -void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte) +void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime) { if (!CanDoSpecialAttack(other)) return; @@ -3396,10 +3396,11 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes other->Stun(100); } - if (CanSkillProc && HasSkillProcs()){ - float chance = 10.0f*RuleR(Combat, AvgProcsPerMinute)/60000.0f; - TrySkillProc(other, skillinuse, chance); - } + if (CanSkillProc && HasSkillProcs()) + TrySkillProc(other, skillinuse, ReuseTime); + + if (CanSkillProc && (damage > 0) && HasSkillProcSuccess()) + TrySkillProc(other, skillinuse, ReuseTime, true); } void Bot::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) { @@ -8102,10 +8103,11 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. } - if (HasSkillProcs()){ - float chance = (float)ReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f; - TrySkillProc(who, skill, chance); - } + if (HasSkillProcs()) + TrySkillProc(who, skill, ReuseTime*1000); + + if (max_damage > 0 && HasSkillProcSuccess()) + TrySkillProc(who, skill, ReuseTime*1000, true); if(max_damage == -3 && !(who->GetHP() <= 0)) DoRiposte(who); diff --git a/zone/bot.h b/zone/bot.h index 485d37377..84f04e85b 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -185,7 +185,7 @@ public: virtual void RogueAssassinate(Mob* other); virtual void DoClassAttacks(Mob *target, bool IsRiposte=false); virtual bool TryHeadShot(Mob* defender, SkillUseTypes skillInUse); - virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false); + virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false, int ReuseTime =0); virtual void ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg); bool CanDoSpecialAttack(Mob *other); virtual int32 CheckAggroAmount(uint16 spellid); diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index fa708acaf..61b432db5 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -9490,13 +9490,6 @@ void Client::CompleteConnect() AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid); break; } - case SE_SkillProc2: - case SE_SkillProc: - { - AddSkillProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid); - break; - } - } } } diff --git a/zone/common.h b/zone/common.h index 98e2ebcec..2aa0101be 100644 --- a/zone/common.h +++ b/zone/common.h @@ -375,6 +375,9 @@ struct StatBonuses { bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others. int16 FactionModPct; // Modifies amount of faction gained. int16 MeleeVulnerability; // Weakness/mitigation to melee damage + bool LimitToSkill[HIGHEST_SKILL+2]; // Determines if we need to search for a skill proc. + uint16 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs. + uint16 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success. // AAs int8 Packrat; //weight reduction for items, 1 point = 10% diff --git a/zone/mob.cpp b/zone/mob.cpp index 93b9f5047..f9b275631 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -3050,6 +3050,34 @@ void Mob::TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand, in return; on->TryDefensiveProc(weapon, this, hand, damage); + + //Defensive Skill Procs + if (damage < 0 && damage >= -4) { + uint16 skillinuse = 0; + switch (damage) { + case (-1): + skillinuse = SkillBlock; + break; + + case (-2): + skillinuse = SkillParry; + break; + + case (-3): + skillinuse = SkillRiposte; + break; + + case (-4): + skillinuse = SkillDodge; + break; + } + + if (on->HasSkillProcs()) + on->TrySkillProc(this, skillinuse, 0, false, hand, true); + + if (on->HasSkillProcSuccess()) + on->TrySkillProc(this, skillinuse, 0, true, hand, true); + } } void Mob::SetDeltas(float dx, float dy, float dz, float dh) { @@ -4714,6 +4742,28 @@ bool Mob::PassLimitToSkill(uint16 spell_id, uint16 skill) { return false; } +uint16 Mob::GetWeaponSpeedbyHand(uint16 hand) { + + uint16 weapon_speed = 0; + 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); + + return weapon_speed; +} + int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { if (!IsValidSpell(spell_id)) diff --git a/zone/mob.h b/zone/mob.h index cb44dd80c..fcb0ece3d 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -506,9 +506,8 @@ public: bool AddDefensiveProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool RemoveDefensiveProc(uint16 spell_id, bool bAll = false); bool HasDefensiveProcs() const; - bool AddSkillProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); - bool RemoveSkillProc(uint16 spell_id, bool bAll = false); bool HasSkillProcs() const; + bool HasSkillProcSuccess() const; bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false); bool HasProcs() const; @@ -700,9 +699,9 @@ public: 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, 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); + 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, int ReuseTime=0); + virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false, int ReuseTime=0); + virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0, int ReuseTime=0); bool CanDoSpecialAttack(Mob *other); bool Flurry(ExtraAttackOptions *opts); bool Rampage(ExtraAttackOptions *opts); @@ -987,7 +986,7 @@ protected: bool focused; void CalcSpellBonuses(StatBonuses* newbon); virtual void CalcBonuses(); - void TrySkillProc(Mob *on, uint16 skill, float chance); + void TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); bool PassLimitToSkill(uint16 spell_id, uint16 skill); bool PassLimitClass(uint32 Classes_, uint16 Class_); void TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand = 13, int damage=0); @@ -999,6 +998,8 @@ protected: virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13); virtual float GetSpecialProcChances(uint16 hand); virtual float GetAssassinateProcChances(uint16 ReuseTime); + virtual float GetSkillProcChances(uint16 ReuseTime, uint16 hand = 0); + uint16 GetWeaponSpeedbyHand(uint16 hand); 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 4ffa21ab4..4eb19b61d 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -171,11 +171,12 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. } - if (HasSkillProcs()){ - float chance = (float)ReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f; - TrySkillProc(who, skill, chance); - } - + if (HasSkillProcs()) + TrySkillProc(who, skill, ReuseTime*1000); + + if (max_damage > 0 && HasSkillProcSuccess()) + TrySkillProc(who, skill, ReuseTime*1000, true); + if(max_damage == -3 && !who->HasDied()) DoRiposte(who); } @@ -847,7 +848,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) { } } -void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus) +void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime) { if (!CanDoSpecialAttack(other)) return; @@ -967,20 +968,33 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FATAL_BOW_SHOT, GetName()); other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery); - + + if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && other && !other->HasDied()){ + if (ReuseTime) + TrySkillProc(other, SkillArchery, ReuseTime); + else + TrySkillProc(other, SkillArchery, 0, true, 11); + } } //try proc on hits and misses - if((RangeWeapon != nullptr) && GetTarget() && other && (other->GetHP() > -10)) + if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied()) { TryWeaponProc(RangeWeapon, other, 11); } //Arrow procs because why not? - if((Ammo != NULL) && GetTarget() && other && (other->GetHP() > -10)) + if((Ammo != NULL) && GetTarget() && other && !other->HasDied()) { TryWeaponProc(Ammo, other, 11); } + + if (HasSkillProcs() && GetTarget() && other && !other->HasDied()){ + if (ReuseTime) + TrySkillProc(other, SkillArchery, ReuseTime); + else + TrySkillProc(other, SkillArchery, 0, false, 11); + } } void NPC::RangedAttack(Mob* other) @@ -1253,7 +1267,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51 } } -void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus) +void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime) { if (!CanDoSpecialAttack(other)) return; @@ -1309,10 +1323,25 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite TotalDmg = -5; other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillThrowing); + + if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && other && !other->HasDied()){ + if (ReuseTime) + TrySkillProc(other, SkillThrowing, ReuseTime); + else + TrySkillProc(other, SkillThrowing, 0, true, 11); + } } if((RangeWeapon != nullptr) && GetTarget() && other && (other->GetHP() > -10)) TryWeaponProc(RangeWeapon, other, 11); + + if (HasSkillProcs() && GetTarget() && other && !other->HasDied()){ + if (ReuseTime) + TrySkillProc(other, SkillThrowing, ReuseTime); + else + TrySkillProc(other, SkillThrowing, 0, false, 11); + } + } void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skillInUse) { @@ -1891,6 +1920,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { Mob *hate_top = who->GetHateMost(); float level_difference = GetLevel() - who->GetLevel(); + bool Success = false; //Support for how taunt worked pre 2000 on LIVE - Can not taunt NPC over your level. if ((RuleB(Combat,TauntOverLevel) == false) && (level_difference < 0) || who->GetSpecialAbility(IMMUNE_TAUNT)){ @@ -1903,7 +1933,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { int32 newhate = 0; float tauntchance = 50.0f; - + if(always_succeed) tauntchance = 101.0f; @@ -1940,6 +1970,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { if (hate_top && hate_top != this){ newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1; who->CastToNPC()->AddToHateList(this, newhate); + Success = true; } else who->CastToNPC()->AddToHateList(this,12); @@ -1955,10 +1986,12 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { else Message_StringID(MT_SpellFailure,FAILED_TAUNT); - if (HasSkillProcs()){ - float chance = (float)TauntReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f; - TrySkillProc(who, SkillTaunt, chance); - } + if (HasSkillProcs()) + TrySkillProc(who, SkillTaunt, TauntReuseTime*1000); + + + if (Success && HasSkillProcSuccess()) + TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true); } @@ -2045,20 +2078,7 @@ float Mob::GetSpecialProcChances(uint16 hand) 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); + weapon_speed = GetWeaponSpeedbyHand(hand); if (RuleB(Combat, AdjustSpecialProcPerMinute)) { ProcChance = (static_cast(weapon_speed) * @@ -2138,7 +2158,7 @@ float Mob::GetAssassinateProcChances(uint16 ReuseTime) return ProcChance; } -void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte) +void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime) { if (!CanDoSpecialAttack(other)) return; @@ -2244,10 +2264,11 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); } - if (CanSkillProc && HasSkillProcs()){ - float chance = 10.0f*RuleR(Combat, AvgProcsPerMinute)/60000.0f; - TrySkillProc(other, skillinuse, chance); - } + if (CanSkillProc && HasSkillProcs()) + TrySkillProc(other, skillinuse, ReuseTime); + + if (CanSkillProc && (damage > 0) && HasSkillProcSuccess()) + TrySkillProc(other, skillinuse, ReuseTime, true); } bool Mob::CanDoSpecialAttack(Mob *other) diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index b92ea524c..84c1ec889 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1773,20 +1773,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) break; } - case SE_SkillProc2: - case SE_SkillProc: - { - uint16 procid = GetProcID(spell_id, i); -#ifdef SPELL_EFFECT_SPAM - snprintf(effect_desc, _EDLEN, "Weapon Proc: %s (id %d)", spells[effect_value].name, procid); -#endif - if(spells[spell_id].base2[i] == 0) - AddSkillProc(procid, 100, spell_id); - else - AddSkillProc(procid, spells[spell_id].base2[i]+100, spell_id); - break; - } - case SE_NegateAttacks: { #ifdef SPELL_EFFECT_SPAM @@ -2257,6 +2243,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) *Max is lower value then Weapon base, possibly min hit vs Weapon Damage range ie. MakeRandInt(max,base) */ int16 focus = 0; + int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time; if(caster->IsClient()) focus = caster->CastToClient()->GetFocusEffect(focusFcBaseEffects, spell_id); @@ -2264,15 +2251,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) switch(spells[spell_id].skill) { case SkillThrowing: - caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i], focus); + caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i], focus, ReuseTime); break; case SkillArchery: - caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i],focus); + caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i],focus,ReuseTime); break; default: - caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base[i], spells[spell_id].skill, spells[spell_id].base2[i], focus); + caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base[i], spells[spell_id].skill, spells[spell_id].base2[i], focus, ReuseTime); break; } break; @@ -2970,6 +2957,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) case SE_FactionModPct: case SE_LimitSpellClass: case SE_Sanctuary: + case SE_PetMeleeMitigation: + case SE_SkillProc: + case SE_SkillProcSuccess: { break; } @@ -3683,14 +3673,6 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) break; } - case SE_SkillProc2: - case SE_SkillProc: - { - uint16 procid = GetProcID(buffs[slot].spellid, i); - RemoveSkillProc(procid); - break; - } - case SE_DefensiveProc: { uint16 procid = GetProcID(buffs[slot].spellid, i); diff --git a/zone/spells.cpp b/zone/spells.cpp index 6a87f2409..f8ce8baa0 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -5103,37 +5103,6 @@ bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll) return true; } -bool Mob::AddSkillProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id) -{ - if(spell_id == SPELL_UNKNOWN) - return(false); - - int i; - for (i = 0; i < MAX_PROCS; i++) { - if (SkillProcs[i].spellID == SPELL_UNKNOWN) { - SkillProcs[i].spellID = spell_id; - SkillProcs[i].chance = iChance; - SkillProcs[i].base_spellID = base_spell_id; - mlog(SPELLS__PROCS, "Added spell-granted skill proc spell %d with chance %d to slot %d", spell_id, iChance, i); - return true; - } - } - return false; -} - -bool Mob::RemoveSkillProc(uint16 spell_id, bool bAll) -{ - for (int i = 0; i < MAX_PROCS; i++) { - if (bAll || SkillProcs[i].spellID == spell_id) { - SkillProcs[i].spellID = SPELL_UNKNOWN; - SkillProcs[i].chance = 0; - SkillProcs[i].base_spellID = SPELL_UNKNOWN; - mlog(SPELLS__PROCS, "Removed Skill proc %d from slot %d", spell_id, i); - } - } - return true; -} - bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id) { if(spell_id == SPELL_UNKNOWN) From 923adc3ea5c747849bf6dd953cdfaedbd3229817 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 6 Jul 2014 16:01:10 -0700 Subject: [PATCH 56/62] Added FieldName for column name requests --- common/MySQLRequestResult.cpp | 21 ++++++++++++++++++--- common/MySQLRequestResult.h | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/common/MySQLRequestResult.cpp b/common/MySQLRequestResult.cpp index 8fc47cfca..56e62ae37 100644 --- a/common/MySQLRequestResult.cpp +++ b/common/MySQLRequestResult.cpp @@ -32,10 +32,11 @@ MySQLRequestResult::MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected, u m_RowsAffected = rowsAffected; m_RowCount = rowCount; m_ColumnCount = columnCount; - // If we actually need the column length it will be requested - // at that time, no need to pull it in just to cache it. + // If we actually need the column length / fields it will be + // requested at that time, no need to pull it in just to cache it. // Normal usage would have it as nullptr most likely anyways. m_ColumnLengths = nullptr; + m_Fields = nullptr; m_LastInsertedID = lastInsertedID; m_ErrorNumber = errorNumber; } @@ -56,6 +57,7 @@ void MySQLRequestResult::ZeroOut() m_Result = nullptr; m_ErrorBuffer = nullptr; m_ColumnLengths = nullptr; + m_Fields = nullptr; m_RowCount = 0; m_RowsAffected = 0; m_LastInsertedID = 0; @@ -88,6 +90,17 @@ uint32 MySQLRequestResult::LengthOfColumn(int columnIndex) return m_ColumnLengths[columnIndex]; } +const std::string MySQLRequestResult::FieldName(int columnIndex) +{ + if (columnIndex >= m_ColumnCount || m_Result == nullptr) + return std::string(); + + if (m_Fields == nullptr) + m_Fields = mysql_fetch_fields(m_Result); + + return std::string(m_Fields[columnIndex].name); +} + MySQLRequestResult::MySQLRequestResult(MySQLRequestResult&& moveItem) : m_CurrentRow(moveItem.m_CurrentRow), m_OneBeyondRow() { @@ -98,6 +111,7 @@ MySQLRequestResult::MySQLRequestResult(MySQLRequestResult&& moveItem) m_RowsAffected = moveItem.m_RowsAffected; m_LastInsertedID = moveItem.m_LastInsertedID; m_ColumnLengths = moveItem.m_ColumnLengths; + m_Fields = moveItem.m_Fields; // Keeps deconstructor from double freeing // pre move instance. @@ -124,7 +138,8 @@ MySQLRequestResult& MySQLRequestResult::operator=(MySQLRequestResult&& other) m_CurrentRow = other.m_CurrentRow; m_OneBeyondRow = other.m_OneBeyondRow; m_ColumnLengths = other.m_ColumnLengths; - + m_Fields = other.m_Fields; + // Keeps deconstructor from double freeing // pre move instance. other.ZeroOut(); diff --git a/common/MySQLRequestResult.h b/common/MySQLRequestResult.h index 4859a625f..6cb110b1d 100644 --- a/common/MySQLRequestResult.h +++ b/common/MySQLRequestResult.h @@ -16,6 +16,7 @@ class MySQLRequestResult { private: MYSQL_RES* m_Result; + MYSQL_FIELD* m_Fields; char* m_ErrorBuffer; unsigned long* m_ColumnLengths; MySQLRequestRow m_CurrentRow; @@ -47,6 +48,7 @@ public: uint32 LastInsertedID() const {return m_LastInsertedID;} // default to 0 index since we mostly use it that way anyways. uint32 LengthOfColumn(int columnIndex = 0); + const std::string FieldName(int columnIndex); MySQLRequestRow& begin() { return m_CurrentRow; } MySQLRequestRow& end() { return m_OneBeyondRow;} From c175369ff65242a96e4e3f50c3d9e9cefe920f12 Mon Sep 17 00:00:00 2001 From: Arthur Ice Date: Sun, 6 Jul 2014 16:15:54 -0700 Subject: [PATCH 57/62] string based QueryDatabase --- common/dbcore.cpp | 5 +++++ common/dbcore.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/common/dbcore.cpp b/common/dbcore.cpp index ce1b41bdc..9b6236e5a 100644 --- a/common/dbcore.cpp +++ b/common/dbcore.cpp @@ -58,6 +58,11 @@ void DBcore::ping() { MDatabase.unlock(); } +MySQLRequestResult DBcore::QueryDatabase(std::string query, bool retryOnFailureOnce) +{ + return QueryDatabase(query.c_str(), query.length(), retryOnFailureOnce); +} + MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, bool retryOnFailureOnce) { LockMutex lock(&MDatabase); diff --git a/common/dbcore.h b/common/dbcore.h index 13a395eac..2c3602a81 100644 --- a/common/dbcore.h +++ b/common/dbcore.h @@ -7,6 +7,7 @@ #endif #include +#include #include "../common/types.h" #include "../common/Mutex.h" #include "../common/linked_list.h" @@ -24,6 +25,7 @@ public: eStatus GetStatus() { return pStatus; } bool RunQuery(const char* query, uint32 querylen, char* errbuf = 0, MYSQL_RES** result = 0, uint32* affected_rows = 0, uint32* last_insert_id = 0, uint32* errnum = 0, bool retry = true); MySQLRequestResult QueryDatabase(const char* query, uint32 querylen, bool retryOnFailureOnce = true); + MySQLRequestResult QueryDatabase(std::string query, bool retryOnFailureOnce = true); uint32 DoEscapeString(char* tobuf, const char* frombuf, uint32 fromlen); void ping(); MYSQL* getMySQL(){ return &mysql; } From d22d0a8145587e0a7460a1b14ebea1bb28f84bfc Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Sun, 6 Jul 2014 20:13:19 -0400 Subject: [PATCH 58/62] Update to how FcBaseEffect focus modifies SE_SkillAttack damage. --- zone/special_attacks.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 4eb19b61d..46bd810ad 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -875,6 +875,9 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item else WDmg = weapon_damage; + if (focus) //From FcBaseEffects + WDmg += WDmg*focus/100; + if((WDmg > 0) || (ADmg > 0)) { if(WDmg < 0) @@ -949,7 +952,6 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item other->MeleeMitigation(this, TotalDmg, minDmg); if(TotalDmg > 0) { - TotalDmg += TotalDmg*focus/100; ApplyMeleeDamageBonus(SkillArchery, TotalDmg); TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillArchery); TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillArchery) / 100) + GetSkillDmgAmt(SkillArchery); @@ -1282,9 +1284,12 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite if (!weapon_damage && item != nullptr) WDmg = GetWeaponDamage(other, item); - else + else WDmg = weapon_damage; + if (focus) //From FcBaseEffects + WDmg += WDmg*focus/100; + int32 TotalDmg = 0; uint32 Assassinate_Dmg = 0; @@ -1308,7 +1313,6 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite other->MeleeMitigation(this, TotalDmg, minDmg); if(TotalDmg > 0) { - TotalDmg += TotalDmg*focus/100; ApplyMeleeDamageBonus(SkillThrowing, TotalDmg); TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillThrowing); TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillThrowing) / 100) + GetSkillDmgAmt(SkillThrowing); @@ -2175,6 +2179,9 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes if(weapon_damage > 0){ + if (focus) //From FcBaseEffects + weapon_damage += weapon_damage*focus/100; + if(GetClass() == BERSERKER){ int bonus = 3 + GetLevel()/10; weapon_damage = weapon_damage * (100+bonus) / 100; @@ -2210,7 +2217,6 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes other->AvoidDamage(this, damage, CanRiposte); other->MeleeMitigation(this, damage, min_hit); if(damage > 0) { - damage += damage*focus/100; ApplyMeleeDamageBonus(skillinuse, damage); damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse); damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse); From b27ff80c751354a739669e4f31a0066cb75fc8e8 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 8 Jul 2014 08:04:56 -0400 Subject: [PATCH 59/62] fix for random int -> float error --- zone/attack.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 6bf7b744c..37759bc9a 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -3983,9 +3983,9 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam if (bDefensiveProc){ for (int i = 0; i < MAX_PROCS; i++) { - if (DefensiveProcs[i].spellID != SPELL_UNKNOWN) { + if (IsValidSpell(DefensiveProcs[i].spellID)) { float chance = ProcChance * (static_cast(DefensiveProcs[i].chance)/100.0f); - if ((MakeRandomInt(0, 1) <= chance)) { + if ((MakeRandomFloat(0, 1) <= chance)) { ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on); CheckNumHitsRemaining(NUMHIT_DefensiveSpellProcs,0,DefensiveProcs[i].base_spellID); } From 2918f6bc07547fb353679a770ff3a97fdf445eb6 Mon Sep 17 00:00:00 2001 From: KayenEQ Date: Tue, 8 Jul 2014 18:27:31 -0400 Subject: [PATCH 60/62] removal of debug msg --- zone/bonuses.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 7bc691a9a..e9501c4dd 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -2922,7 +2922,6 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne case SE_LimitToSkill:{ if (effect_value <= HIGHEST_SKILL){ newbon->LimitToSkill[effect_value] = true; - Shout("BONUS Set Limit = %i", effect_value); } break; } From 4707e0f858d52bd1bca787c2e701d30133d4c4e3 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 8 Jul 2014 21:21:44 -0400 Subject: [PATCH 61/62] Inline a few functions that should be --- zone/mob.cpp | 16 ---------------- zone/mob.h | 4 ++-- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/zone/mob.cpp b/zone/mob.cpp index f9b275631..340dfdfea 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -2753,22 +2753,6 @@ void Mob::Warp( float x, float y, float z ) SendPosition(); } -bool Mob::DivineAura() const -{ - if (spellbonuses.DivineAura) - return true; - - return false; -} - -bool Mob::Sanctuary() const -{ - if (spellbonuses.Sanctuary) - return true; - - return false; -} - int16 Mob::GetResist(uint8 type) const { if (IsNPC()) diff --git a/zone/mob.h b/zone/mob.h index fcb0ece3d..4cd6d5f49 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -818,8 +818,8 @@ public: inline int& GetNextIncHPEvent() { return nextinchpevent; } void SetNextIncHPEvent( int inchpevent ); - bool DivineAura() const; - bool Sanctuary() const; + inline bool DivineAura() const { return spellbonuses.DivineAura; } + inline bool Sanctuary() const { return spellbonuses.Sanctuary; } bool HasNPCSpecialAtk(const char* parse); int GetSpecialAbility(int ability); From a96784aa1856d4bbe1f3a3d9ed942656e069e823 Mon Sep 17 00:00:00 2001 From: JJ Date: Wed, 9 Jul 2014 19:19:51 -0400 Subject: [PATCH 62/62] Minor typos. --- CMakeLists.txt | 2 +- .../{2014_06_25_AA_Updates..sql => 2014_06_25_AA_Updates.sql} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename utils/sql/git/required/{2014_06_25_AA_Updates..sql => 2014_06_25_AA_Updates.sql} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9dd5a96b..38332b49c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -233,7 +233,7 @@ OPTION(EQEMU_BUILD_SOCKET_SERVER "Build the socket server." OFF) OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF) OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON) OPTION(EQEMU_BUILD_LUA "Build Lua parser." OFF) -OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Inport/Export Data Programs." ON) +OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON) #C++11 stuff IF(NOT MSVC) diff --git a/utils/sql/git/required/2014_06_25_AA_Updates..sql b/utils/sql/git/required/2014_06_25_AA_Updates.sql similarity index 100% rename from utils/sql/git/required/2014_06_25_AA_Updates..sql rename to utils/sql/git/required/2014_06_25_AA_Updates.sql