diff --git a/changelog.txt b/changelog.txt index 181fb6628..4cf1c32d6 100644 --- a/changelog.txt +++ b/changelog.txt @@ -5,6 +5,7 @@ cavedude: Live-Like weather system (Thanks to robregen for figuring it out!) demonstar55: Implemented not_extendable spell flag demonstar55: Moved Spell Casting Reinforcement to DB demonstar55: Moved Mez Mastery to DB +Kayen: Complete revision of the numhits systems to utilize 'numhits type' field in spell file. == 01/18/2014 == sorvani: Implemented for Lua eq.get_characters_in_instance(uint16 instance_id), return a Lua HashTable diff --git a/zone/attack.cpp b/zone/attack.cpp index 00af8113b..f2c97153a 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -182,9 +182,6 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c //The old code basically meant that any in high level (50+) combat, //both parties always had 95% chance to hit the other one. /*/ - //If chance bonus set in spell data for Skill Attacks is 10k allow to hit without calculations. - if (chance_mod == 10000) - return true; Mob *attacker=other; Mob *defender=this; @@ -281,8 +278,6 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c if(bonus > 0) { chancetohit -= ((bonus * chancetohit) / 1000); mlog(COMBAT__TOHIT, "Applied avoidance chance %.2f/10, yeilding %.2f", bonus, chancetohit); - if (defender->spellbonuses.AvoidMeleeChance) - defender->CheckHitsRemaining(0, false, false,SE_AvoidMeleeChance); } if(attacker->IsNPC()) @@ -330,6 +325,11 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c chancetohit = 5; } + CheckNumHitsRemaining(1); + + if (attacker) + attacker->CheckNumHitsRemaining(2); + //I dont know the best way to handle a garunteed hit discipline being used //agains a garunteed riposte (for example) discipline... for now, garunteed hit wins @@ -1117,6 +1117,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b mlog(COMBAT__ATTACKS, "Attack canceled, invalid circumstances."); return false; // Only bards can attack while casting } + if(DivineAura() && !GetGM()) {//cant attack while invulnerable unless your a gm mlog(COMBAT__ATTACKS, "Attack canceled, Divine Aura is in effect."); Message_StringID(MT_DefaultText, DIVINE_AURA_NO_ATK); //You can't attack while invulnerable! @@ -1247,7 +1248,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b hate *= opts->hate_percent; hate += opts->hate_flat; } - + //check to see if we hit.. if(!other->CheckHitChance(this, skillinuse, Hand)) { mlog(COMBAT__ATTACKS, "Attack missed. Damage set to 0."); @@ -1326,8 +1327,6 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b //heal self for damage done.. HealDamage(lifetap_amt); - if (spellbonuses.MeleeLifetap) - CheckHitsRemaining(0, false,false, SE_MeleeLifetap); } //break invis when you attack @@ -2058,6 +2057,7 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack killerMob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1)); } } else { + char buffer[48] = { 0 }; snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast(attack_skill)); if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0) @@ -3128,8 +3128,12 @@ int32 Mob::ReduceDamage(int32 damage) if (spellbonuses.NegateAttacks[0]){ slot = spellbonuses.NegateAttacks[1]; if(slot >= 0) { - if(CheckHitsRemaining(slot, false, true)) - return -6; + if(--buffs[slot].numhits == 0) { + + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot , true); + } + return -6; } } @@ -3156,7 +3160,6 @@ int32 Mob::ReduceDamage(int32 damage) " damage remaining.", damage_to_reduce, buffs[slot].melee_rune); buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); damage -= damage_to_reduce; - CheckHitsRemaining(slot); } } } @@ -3182,8 +3185,7 @@ int32 Mob::ReduceDamage(int32 damage) " damage remaining.", damage_to_reduce, buffs[slot].melee_rune); buffs[slot].melee_rune = (buffs[slot].melee_rune - damage_to_reduce); damage -= damage_to_reduce; - if (!CheckHitsRemaining(slot)) - UpdateRuneFlags(); + UpdateRuneFlags(); } } } @@ -3198,7 +3200,6 @@ int32 Mob::ReduceDamage(int32 damage) } else{ buffs[slot].melee_rune = (buffs[slot].melee_rune - damage); - CheckHitsRemaining(slot); } } } @@ -3212,16 +3213,6 @@ int32 Mob::ReduceDamage(int32 damage) if(damage < 1) return -6; - if (spellbonuses.ManaAbsorbPercentDamage[0]){ - slot = spellbonuses.ManaAbsorbPercentDamage[1]; - if(GetMana() > damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100) { - damage -= (damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100); - SetMana(GetMana() - damage); - TryTriggerOnValueAmount(false, true); - CheckHitsRemaining(slot); - } - } - return(damage); } @@ -3237,8 +3228,12 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if (spellbonuses.NegateAttacks[0]){ slot = spellbonuses.NegateAttacks[1]; if(slot >= 0) { - if(CheckHitsRemaining(slot, false, true)) - return 0; + if(--buffs[slot].numhits == 0) { + + if(!TryFadeEffect(slot)) + BuffFadeBySlot(slot , true); + } + return 0; } } @@ -3272,7 +3267,6 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi { buffs[slot].melee_rune = (buffs[slot].magic_rune - damage_to_reduce); damage -= damage_to_reduce; - CheckHitsRemaining(slot); } } } @@ -3299,8 +3293,7 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi " damage remaining.", damage_to_reduce, buffs[slot].magic_rune); buffs[slot].magic_rune = (buffs[slot].magic_rune - damage_to_reduce); damage -= damage_to_reduce; - if (!CheckHitsRemaining(slot)) - UpdateRuneFlags(); + UpdateRuneFlags(); } } } @@ -3315,7 +3308,6 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi } else{ buffs[slot].melee_rune = (buffs[slot].magic_rune - damage); - CheckHitsRemaining(slot); } } } @@ -3329,20 +3321,26 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi if(damage < 1) return 0; - - if (spellbonuses.ManaAbsorbPercentDamage[0]){ - slot = spellbonuses.ManaAbsorbPercentDamage[1]; - if(GetMana() > damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100) { - damage -= (damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100); - SetMana(GetMana() - damage); - TryTriggerOnValueAmount(false, true); - CheckHitsRemaining(slot); - } - } } return damage; } +int32 Mob::ReduceAllDamage(int32 damage) +{ + if(damage <= 0) + return damage; + + if(spellbonuses.ManaAbsorbPercentDamage[0] && (GetMana() > damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100)) { + damage -= (damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100); + SetMana(GetMana() - damage); + TryTriggerOnValueAmount(false, true); + } + + CheckNumHitsRemaining(8); + + return(damage); +} + bool Mob::HasProcs() const { for (int i = 0; i < MAX_PROCS; i++) @@ -3441,9 +3439,6 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons // damage shield calls this function with spell_id set, so its unavoidable if (attacker && damage > 0 && spell_id == SPELL_UNKNOWN && skill_used != SkillArchery && skill_used != SkillThrowing) { DamageShield(attacker); - - if (spellbonuses.DamageShield) - CheckHitsRemaining(0, false, false, SE_DamageShield); } if(attacker){ @@ -3511,11 +3506,12 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons } if (damage == 0 && attacker && origdmg != damage && IsClient()) { //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()); + Message(263, "%s tries to cast on YOU, but YOUR magical skin absorbs the spell.",attacker->GetCleanName()); } } + ReduceAllDamage(damage); if(IsClient() && CastToClient()->sneaking){ CastToClient()->sneaking = false; @@ -3919,7 +3915,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); - CheckHitsRemaining(0, false, false, 0, DefensiveProcs[i].base_spellID); + CheckNumHitsRemaining(10,0,DefensiveProcs[i].base_spellID); } } } @@ -4087,6 +4083,7 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct* weapon, Mob *on if(MakeRandomInt(0, 100) < chance) { mlog(COMBAT__PROCS, "Spell proc %d procing spell %d (%d percent chance)", i, SpellProcs[i].spellID, chance); ExecWeaponProc(nullptr, SpellProcs[i].spellID, on); + CheckNumHitsRemaining(11, 0, SpellProcs[i].base_spellID); } else { mlog(COMBAT__PROCS, "Spell proc %d failed to proc %d (%d percent chance)", i, SpellProcs[i].spellID, chance); } @@ -4097,7 +4094,7 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct* weapon, Mob *on if(MakeRandomInt(0, 100) < chance) { mlog(COMBAT__PROCS, "Ranged proc %d procing spell %d", i, RangedProcs[i].spellID, RangedProcs[i].chance); ExecWeaponProc(nullptr, RangedProcs[i].spellID, on); - CheckHitsRemaining(0, false, false, 0, RangedProcs[i].base_spellID); + CheckNumHitsRemaining(11, 0, RangedProcs[i].base_spellID); } else { mlog(COMBAT__PROCS, "Ranged proc %d failed to proc %d", i, RangedProcs[i].spellID, RangedProcs[i].chance); } @@ -4358,10 +4355,6 @@ void Mob::ApplyMeleeDamageBonus(uint16 skill, int32 &damage){ } damage += damage * GetMeleeDamageMod_SE(skill) / 100; - - //Rogue sneak attack disciplines make use of this, they are active for one hit - if (spellbonuses.HitChanceEffect[HIGHEST_SKILL+1] || spellbonuses.HitChanceEffect[skill]) - CheckHitsRemaining(0, false, false, SE_HitChance,0,true,skill); } bool Mob::HasDied() { @@ -4435,7 +4428,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); - CheckHitsRemaining(0, false, false, 0, SkillProcs[i].base_spellID); + CheckNumHitsRemaining(11,0, SkillProcs[i].base_spellID); } } } diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index bbb55f989..66abe90b4 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1148,7 +1148,6 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon) break; } - case SE_DivineSave: { if(newbon->DivineSaveChance[0] < base1) @@ -2460,6 +2459,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne newbon->TriggerOnValueAmount = true; break; + case SE_DivineAura: + newbon->DivineAura = true; + break; + } } } @@ -3768,6 +3771,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id) spellbonuses.TriggerSpellThreshold[1] = effect_value; spellbonuses.TriggerSpellThreshold[2] = effect_value; break; + + case SE_DivineAura: + spellbonuses.DivineAura = false; + break; } } diff --git a/zone/bot.cpp b/zone/bot.cpp index a87dd5878..cbccbbb69 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -6604,9 +6604,6 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b mlog(COMBAT__DAMAGE, "Melee lifetap healing for %d damage.", damage); //heal self for damage done.. HealDamage(lifetap_amt); - - if (spellbonuses.MeleeLifetap) - CheckHitsRemaining(0, false,false, SE_MeleeLifetap); } //break invis when you attack diff --git a/zone/common.h b/zone/common.h index 4dfb229d7..a8685846f 100644 --- a/zone/common.h +++ b/zone/common.h @@ -323,6 +323,7 @@ struct StatBonuses { bool CriticalRegenDecay; // increase critical regen chance, decays based on spell level cast bool CriticalHealDecay; // increase critical heal chance, decays based on spell level cast bool CriticalDotDecay; // increase critical dot chance, decays based on spell level cast + bool DivineAura; // invulnerability //bool AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect //bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect diff --git a/zone/mob.cpp b/zone/mob.cpp index bd06b2788..cf9073710 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -178,6 +178,7 @@ Mob::Mob(const char* in_name, findable = false; trackable = true; has_shieldequiped = false; + has_numhits = false; if(in_aa_title>0) aa_title = in_aa_title; @@ -2732,21 +2733,9 @@ void Mob::Warp( float x, float y, float z ) bool Mob::DivineAura() const { - uint32 l; - uint32 buff_count = GetMaxTotalSlots(); - for (l = 0; l < buff_count; l++) - { - if (buffs[l].spellid != SPELL_UNKNOWN) - { - for (int k = 0; k < EFFECT_COUNT; k++) - { - if (spells[buffs[l].spellid].effectid[k] == SE_DivineAura) - { - return true; - } - } - } - } + if (spellbonuses.DivineAura) + return true; + return false; } @@ -3156,7 +3145,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); - CheckHitsRemaining(0, false,false, 0, focus_spell); + CheckNumHitsRemaining(7,0, focus_spell); } } } @@ -3361,7 +3350,7 @@ int32 Mob::GetVulnerability(int32 damage, Mob *caster, uint32 spell_id, uint32 t //Apply spell derived vulnerabilities if (spellbonuses.FocusEffects[focusSpellVulnerability]){ - + int32 tmp_focus = 0; int tmp_buffslot = -1; @@ -3394,7 +3383,7 @@ int32 Mob::GetVulnerability(int32 damage, Mob *caster, uint32 spell_id, uint32 t damage += damage * tmp_focus / 100; if (tmp_buffslot >= 0) - CheckHitsRemaining(tmp_buffslot); + CheckNumHitsRemaining(7, tmp_buffslot); } return damage; } @@ -3402,7 +3391,7 @@ int32 Mob::GetVulnerability(int32 damage, Mob *caster, uint32 spell_id, uint32 t int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) { int skilldmg_mod = 0; - + // 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]; @@ -3414,8 +3403,7 @@ int16 Mob::GetSkillDmgTaken(const SkillUseTypes skill_used) if(skilldmg_mod < -100) skilldmg_mod = -100; - if (spellbonuses.SkillDmgTaken[HIGHEST_SKILL+1] || spellbonuses.SkillDmgTaken[skill_used]) - CheckHitsRemaining(0, false,false, SE_SkillDamageTaken,0,true,skill_used); + CheckNumHitsRemaining(6); return skilldmg_mod; } @@ -3458,7 +3446,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_TriggerMeleeThreshold || spells[buffs[slot].spellid].effectid[i] == SE_TriggerSpellThreshold) { uint16 spell_id = spells[buffs[slot].spellid].base[i]; BuffFadeBySlot(slot); @@ -3515,7 +3503,8 @@ void Mob::TrySympatheticProc(Mob *target, uint32 spell_id) else SpellFinished(focus_trigger, target, 10, 0, -1, spells[focus_trigger].ResistDiff); } - CheckHitsRemaining(0, false,false, 0, focus_spell); + + CheckNumHitsRemaining(7, 0, focus_spell); } } @@ -4289,9 +4278,6 @@ int16 Mob::GetMeleeDamageMod_SE(uint16 skill) if(dmg_mod < -100) dmg_mod = -100; - if (spellbonuses.DamageModifier[HIGHEST_SKILL+1] || spellbonuses.DamageModifier[skill]) - CheckHitsRemaining(0, false, false, SE_DamageModifier,0,true,skill); - return dmg_mod; } @@ -4338,13 +4324,8 @@ int16 Mob::GetSkillDmgAmt(uint16 skill) skill_dmg += spellbonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount2[HIGHEST_SKILL+1] + itembonuses.SkillDamageAmount2[skill] + spellbonuses.SkillDamageAmount2[skill]; - // Deplete the buff if needed - if (spellbonuses.SkillDamageAmount[HIGHEST_SKILL+1] || spellbonuses.SkillDamageAmount[skill]) - CheckHitsRemaining(0, false,false, SE_SkillDamageAmount,0,true,skill); - - if (spellbonuses.SkillDamageAmount2[HIGHEST_SKILL+1] || spellbonuses.SkillDamageAmount2[skill]) - CheckHitsRemaining(0, false,false, SE_SkillDamageAmount2,0,true,skill); - + CheckNumHitsRemaining(5); + return skill_dmg; } @@ -4352,10 +4333,7 @@ bool Mob::TryReflectSpell(uint32 spell_id) { if(!GetTarget()) return false; - - if(GetTarget()->spellbonuses.reflect_chance) - CheckHitsRemaining(0, false, false, SE_Reflect); - + if(MakeRandomInt(0, 99) < (GetTarget()->itembonuses.reflect_chance + GetTarget()->spellbonuses.reflect_chance)) return true; @@ -4583,8 +4561,6 @@ void Mob::CastOnNumHitFade(uint32 spell_id) if(!IsValidSpell(spell_id)) return; - uint32 buff_max = GetMaxTotalSlots(); - for(int i = 0; i < EFFECT_COUNT; i++) { if (spells[spell_id].effectid[i] == SE_CastonNumHitFade) diff --git a/zone/mob.h b/zone/mob.h index 66246cd6b..07749b458 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -251,8 +251,9 @@ public: int16 GetBuffSlotFromType(uint16 type); uint16 GetSpellIDFromSlot(uint8 slot); int CountDispellableBuffs(); - bool CheckHitsRemaining(uint32 buff_slot, bool when_spell_done=false, bool negate=false,uint16 type=0, - uint16 spell_id=0, bool use_skill=false,uint16 skill=0); + 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; } void SpreadVirus(uint16 spell_id, uint16 casterID); bool IsNimbusEffectActive(uint32 nimbus_effect); void SetNimbusEffect(uint32 nimbus_effect); @@ -656,6 +657,7 @@ public: int32 ReduceDamage(int32 damage); 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 DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0); @@ -1055,6 +1057,7 @@ protected: int16 rooted_mod; //Modifier to root break chance, defined when root is cast on a target. bool offhand; bool has_shieldequiped; + bool has_numhits; // Bind wound Timer bindwound_timer; diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index 524db430c..5f38356dd 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -183,6 +183,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial) numhit += caster->CastToClient()->GetFocusEffect(focusIncreaseNumHits, spell_id); } + Numhits(true); buffs[buffslot].numhits = numhit; } @@ -3881,6 +3882,25 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses) } } + if (HasNumhits()){ + + uint32 buff_max = GetMaxTotalSlots(); + bool found_numhits = false; + + for(uint32 d = 0; d < buff_max; d++) { + + if(IsValidSpell(buffs[d].spellid) && (buffs[d].numhits > 0)) { + Numhits(true); + found_numhits = true; + } + } + + if (!found_numhits) + Numhits(false); + } + + Numhits(false); + buffs[slot].spellid = SPELL_UNKNOWN; if(IsPet() && GetOwner() && GetOwner()->IsClient()) { SendPetBuffsToClient(); @@ -5274,123 +5294,91 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id) { return realTotal + realTotal2 + realTotal3; } -bool Mob::CheckHitsRemaining(uint32 buff_slot, bool when_spell_done, bool negate, uint16 type, uint16 spell_id,bool use_skill,uint16 skill) +void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id) { - /* - TO DO: Rewrite code so it checks for numhits by type not after each specified spell effect is triggered... Field 175 = numhits type 1: [Incoming Hit Attempts] (323=SE_DefensiveProc, 172=SE_AvoidMeleeChance, 1=SE_ArmorClass, 40=SE_DivineAura) - 2: [Outgoing Hit Attempts] (184=SE_DamageModifer, 185=SE_HitChance) - 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_SpellVulnerability) + 2: [Outgoing Hit Attempts] (185=SE_DamageModifer, 184=SE_HitChance) + 3: [Incoming Spells] (180=SE_ResistSpellChance, 296=SE_SpellVulnerability) //Note: Determinetal spells only unless proven otherwise 4: NONE - 5: [Outgoing Hit Successes] (196=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_CastOnWearoff) 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) - 9: [Reflected Spells] - 10: [Defensive Procs] - 11: [Melee Procs] + 9: [Reflected Spells] If successful + 10: [Defensive Procs] Only count down buff of the proc that executed + 11: [Melee Procs] Only count down the buff of the proc that executed */ + if (!HasNumhits()) + return; + bool bDepleted = false; - //Effects: Cast: SE_ResistSpellChance, SE_Reflect, SE_SpellDamageShield - //Effects: Attack: SE_MeleeLifetap : SE_DamageShield, SE_AvoidMeleeChance, SE_SkillProc - //Effects: Skill: SE_DamageModifier, SE_SkillDamageTaken, SE_SkillDamageAmount, SE_HitChance - //For spell buffs that are limited typically when you are attacked or are subject to an attack/cast and we do not know the buff slot. - if (type){ - uint32 buff_max = GetMaxTotalSlots(); + uint32 buff_max = GetMaxTotalSlots(); + + //Spell specific procs [Type 7,10,11] + if (IsValidSpell(spell_id)){ + for(uint32 d = 0; d < buff_max; d++) { - if((buffs[d].spellid != SPELL_UNKNOWN) && (buffs[d].numhits > 0) && IsEffectInSpell(buffs[d].spellid, type)){ - if (!use_skill){ - if(--buffs[d].numhits == 0) { - if(!TryFadeEffect(d)){ - CastOnNumHitFade(buffs[d].spellid); - BuffFadeBySlot(d, true); - } - } - } - else{ - bDepleted = false; - for (int j = 0; j < EFFECT_COUNT; j++) { - if (bDepleted) - continue; - if ((buffs[d].spellid != SPELL_UNKNOWN) && (spells[buffs[d].spellid].effectid[j] == type)) { - if(spells[buffs[d].spellid].base2[j] == -1 || spells[buffs[d].spellid].base2[j] == skill) { - bDepleted = true; - if(--buffs[d].numhits == 0) { - if(!TryFadeEffect(d)){ - CastOnNumHitFade(buffs[d].spellid); - BuffFadeBySlot(d, true); - continue; - } - } - } - } - } - } - } - } - return false; - } + + if((buffs[d].spellid == spell_id) && (buffs[d].numhits > 0) && (spells[buffs[d].spellid].numhitstype == type)){ - // For spell buffs that are limited by the number of times it can successfully trigger a spell. - // Effects: SE_TriggerOnCast, SE_SympatheticProc,SE_DefensiveProc, SE_SkillProc, SE_RangedProc - if(spell_id){ - uint32 buff_count = GetMaxTotalSlots(); - for(uint32 d = 0; d < buff_count; d++){ - if((buffs[d].spellid != SPELL_UNKNOWN) && (buffs[d].numhits > 0) && buffs[d].spellid == spell_id){ if(--buffs[d].numhits == 0) { - if(!TryFadeEffect(d)){ - CastOnNumHitFade(buffs[d].spellid); - BuffFadeBySlot(d, true); - return false; - } - } - } - } - return false; - } - - // For focusTypes that limit the number of spell casts it will effect. - // Effect: Focus effects ie SE_ImprovedDamage ect - if(when_spell_done) { - uint32 buff_max = GetMaxTotalSlots(); - // Go through all possible saved spells with limited hits, the place in the array is the same as the buff slot - for(int d = 0; d < buff_max; d++) { - if(!m_spellHitsLeft[d]) - continue; - // Double check to make sure the saved spell matches the buff in that slot - if (m_spellHitsLeft[d] == buffs[d].spellid) { - if(buffs[d].numhits > 1) { - buffs[d].numhits--; - return true; - } - else { + CastOnNumHitFade(buffs[d].spellid); if(!TryFadeEffect(d)) BuffFadeBySlot(d, true); - CastOnNumHitFade(m_spellHitsLeft[d]); - m_spellHitsLeft[d] = 0; } } } - return false; } - // For lowering numhits when we already know the effects buff_slot - // Effects: SE_SpellVulnerability,SE_MitigateMeleeDamage,SE_MitigateMeleeDamage2,SE_NegateAttacks,SE_MitigateSpellDamage,SE_ManaAbsorbPercentDamage - if(spells[buffs[buff_slot].spellid].numhits > 0 || negate) { - if(buffs[buff_slot].numhits > 1) { - buffs[buff_slot].numhits--; - return true; - } - else if(!TryFadeEffect(buff_slot)) { - CastOnNumHitFade(buffs[buff_slot].spellid); - BuffFadeBySlot(buff_slot, true); - return false; + else if (type == 7){ + if (buff_slot > 0){ + + if(--buffs[buff_slot].numhits == 0) { + CastOnNumHitFade(buffs[buff_slot].spellid); + if(!TryFadeEffect(buff_slot)) + BuffFadeBySlot(buff_slot , true); + } + } + + else { + + for(int d = 0; d < buff_max; d++) { + + if(!m_spellHitsLeft[d]) + continue; + + if ((IsValidSpell(buffs[d].spellid)) && (m_spellHitsLeft[d] == buffs[d].spellid)) { + if(--buffs[d].numhits == 0) { + CastOnNumHitFade(buffs[d].spellid); + m_spellHitsLeft[d] = 0; + if(!TryFadeEffect(d)) + BuffFadeBySlot(d, true); + } + } + } + } + } + + + else{ + + for(uint32 d = 0; d < buff_max; d++) { + + if((IsValidSpell(buffs[d].spellid)) && (buffs[d].numhits > 0) && (spells[buffs[d].spellid].numhitstype == type)){ + + if(--buffs[d].numhits == 0) { + CastOnNumHitFade(buffs[d].spellid); + if(!TryFadeEffect(d)){ + BuffFadeBySlot(d, true); + } + } + + } } } - return false; } //for some stupid reason SK procs return theirs one base off... @@ -5627,7 +5615,7 @@ int32 Mob::GetAdditionalDamage(Mob *caster, uint32 spell_id, bool use_skill, uin } if ((!limit_exists) || (limit_exists && skill_found)){ dmg += temp_dmg; - CheckHitsRemaining(i); + CheckNumHitsRemaining(7,i); } } @@ -5635,7 +5623,7 @@ int32 Mob::GetAdditionalDamage(Mob *caster, uint32 spell_id, bool use_skill, uin int32 focus = caster->CalcFocusEffect(focusAdditionalDamage, buffs[i].spellid, spell_id); if(focus){ dmg += focus; - CheckHitsRemaining(i); + CheckNumHitsRemaining(7,i); } } } diff --git a/zone/spells.cpp b/zone/spells.cpp index eb5337719..a078a11c5 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1234,16 +1234,9 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, return; } } - if(IsClient()) { - uint32 buff_max = GetMaxTotalSlots(); - for (int buffSlot = 0; buffSlot < buff_max; buffSlot++) { - if (buffs[buffSlot].spellid == 0 || buffs[buffSlot].spellid >= SPDAT_RECORDS) - continue; - - if(spells[buffs[buffSlot].spellid].numhits > 0) - CheckHitsRemaining(buffSlot, true); - } + if(IsClient()) { + CheckNumHitsRemaining(7); TrySympatheticProc(target, spell_id); } @@ -3369,7 +3362,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) { - CheckHitsRemaining(b); + CheckNumHitsRemaining(7,b); Message_StringID(MT_SpellFailure, SPELL_WOULDNT_HOLD); safe_delete(action_packet); return false; @@ -3418,12 +3411,16 @@ 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); SpellOnTarget(spell_id, this, true, use_resist_adjust, resist_adjust); safe_delete(action_packet); return false; } } + if (spelltar && IsDetrimentalSpell(spell_id)) + spelltar->CheckNumHitsRemaining(3); + // resist check - every spell can be resisted, beneficial or not // add: ok this isn't true, eqlive's spell data is fucked up, buffs are // not all unresistable, so changing this to only check certain spells @@ -3563,14 +3560,12 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r } } - if(spelltar->spellbonuses.SpellDamageShield && IsDetrimentalSpell(spell_id)){ - spelltar->DamageShield(this, true); - spelltar->CheckHitsRemaining(0, false, false, SE_DamageShield); - } + if(spelltar->spellbonuses.SpellDamageShield && IsDetrimentalSpell(spell_id)) + spelltar->DamageShield(this, true); TrySpellTrigger(spelltar, spell_id); TryApplyEffect(spelltar, spell_id); - + if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) { int32 aggro_amount = CheckAggroAmount(spell_id, isproc); mlog(SPELLS__CASTING, "Spell %d cast on %s generated %d hate", spell_id, spelltar->GetName(), aggro_amount); @@ -4343,9 +4338,6 @@ int16 Mob::CalcResistChanceBonus() if(IsClient()) resistchance += aabonuses.ResistSpellChance; - if (spellbonuses.ResistSpellChance) - CheckHitsRemaining(0, false, false, SE_ResistSpellChance); - return resistchance; }