Merge pull request #160 from KayenEQ/Development

Implemented SE_AStacker, BStacker, CStacker, DStacker
This commit is contained in:
Michael Cook 2014-06-24 20:51:24 -04:00
commit a4fe14a3d3
17 changed files with 353 additions and 103 deletions

View File

@ -1,5 +1,22 @@
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.
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) *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.
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)
Setting se_max to 1 for SkillDamageTaken effects (127) will allow for stackable mitigation/weakness same as quest function ModSkillDmgTaken.

View File

@ -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)

View File

@ -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
@ -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
@ -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
@ -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
@ -593,20 +593,20 @@ 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
#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_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 // *not implemented - Modifies melee damage by skill type
#define SE_DamageModifier2 459 // implemented - Modifies melee damage by skill type
// LAST
@ -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);

View File

@ -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;
}
}
@ -3188,11 +3192,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 +3216,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 +3232,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;
}
}
@ -3265,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) {
@ -3273,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;
}
}
@ -3286,15 +3301,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 +3337,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 +3358,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 +3374,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;
}
}
@ -4283,6 +4311,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 +4339,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 +4392,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;
}
@ -4449,6 +4481,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);

View File

@ -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)
@ -1107,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
@ -1234,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;
@ -1242,6 +1260,14 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
newbon->SpellProcChance += base1;
break;
case SE_Berserk:
newbon->BerserkSPA = true;
break;
case SE_Metabolism:
newbon->Metabolism += base1;
break;
}
}
}
@ -1813,6 +1839,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)
@ -1909,6 +1939,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)
@ -2256,9 +2295,11 @@ 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;
}
break;
}
@ -2268,6 +2309,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;
}
@ -2298,6 +2341,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;
}
@ -2307,6 +2352,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;
}
@ -2553,6 +2600,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.
@ -2661,6 +2713,31 @@ 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;
case SE_Berserk:
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) {
@ -3438,6 +3515,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++)
@ -3933,6 +4021,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;
@ -4033,6 +4127,24 @@ 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;
case SE_Metabolism:
spellbonuses.Metabolism = effect_value;
aabonuses.Metabolism = effect_value;
itembonuses.Metabolism = effect_value;
break;
}
}

View File

@ -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)
{

View File

@ -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
@ -289,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
@ -326,12 +328,12 @@ 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 MitigateMeleeRune[2]; // 0 = Mitigation value 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.
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
@ -350,6 +352,12 @@ 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
bool BerserkSPA; // berserk effect
int16 Metabolism; // Food/drink consumption rates.
// AAs
int8 Packrat; //weight reduction for items, 1 point = 10%
@ -378,6 +386,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'.

View File

@ -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]){
if(members[gi] && (members[gi]->GetMaxMana() > 0)){
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]){

View File

@ -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)); }

View File

@ -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];
@ -4334,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.
}
}

View File

@ -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

View File

@ -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);

View File

@ -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; }

View File

@ -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,17 +571,24 @@ 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++)
{
if(members[gi].member){
if(members[gi].GroupNumber == gid)
{
distance = caster->DistNoRoot(*members[gi].member);
if(distance <= range2){
manataken += (members[gi].member->GetMaxMana() - members[gi].member->GetMana());
numMem += 1;
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 += (manataken_tmp);
numMem += 1;
}
}
}
}
@ -584,6 +596,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){

View File

@ -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);

View File

@ -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;
}
@ -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:
@ -2886,6 +2894,14 @@ 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:
case SE_DoubleRiposte:
case SE_Berserk:
case SE_Vampirism:
case SE_Metabolism:
{
break;
}
@ -3518,6 +3534,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?

View File

@ -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) {