Merge pull request #105 from KayenEQ/master

Numhits system revised
This commit is contained in:
Michael Cook 2014-01-20 19:03:05 -08:00
commit 5121cc25a4
9 changed files with 168 additions and 210 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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