mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 17:51:28 +00:00
[Spells] Throwing procs fixed and other proc updates (#1871)
* first updating sbindex defines * updates * updates * proctypes added for organization * debug * updates * range procs cleaned up * skill proc clean up * fix * remove debugs * [Spells] Throwing procs fixed and other proc updates * [Spells] Throwing procs fixed and other proc updates bot fix * [Spells] Throwing procs fixed and other proc updates proctype updates
This commit is contained in:
parent
73acc3310c
commit
119b2d023f
@ -1609,19 +1609,19 @@ uint32 GetProcLimitTimer(int32 spell_id, int proc_type) {
|
||||
bool use_next_timer = false;
|
||||
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
||||
|
||||
if (proc_type == SE_WeaponProc) {
|
||||
if (proc_type == ProcType::MELEE_PROC) {
|
||||
if (spells[spell_id].effect_id[i] == SE_WeaponProc || spells[spell_id].effect_id[i] == SE_AddMeleeProc) {
|
||||
use_next_timer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_RangedProc) {
|
||||
if (proc_type == ProcType::RANGED_PROC) {
|
||||
if (spells[spell_id].effect_id[i] == SE_RangedProc) {
|
||||
use_next_timer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_DefensiveProc) {
|
||||
if (proc_type == ProcType::DEFENSIVE_PROC) {
|
||||
if (spells[spell_id].effect_id[i] == SE_DefensiveProc) {
|
||||
use_next_timer = true;
|
||||
}
|
||||
|
||||
@ -533,6 +533,15 @@ enum ReflectSpellType
|
||||
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
|
||||
REFLECT_ALL_SPELLS = 4,
|
||||
};
|
||||
//For better organizing in proc effects, not used in spells.
|
||||
enum ProcType
|
||||
{
|
||||
MELEE_PROC = 1,
|
||||
RANGED_PROC = 2,
|
||||
DEFENSIVE_PROC = 3,
|
||||
SKILL_PROC = 4,
|
||||
SKILL_PROC_SUCCESS = 5,
|
||||
};
|
||||
|
||||
enum SpellTypes : uint32
|
||||
{
|
||||
@ -1134,8 +1143,8 @@ typedef enum {
|
||||
#define SE_GravityEffect 424 // implemented - Pulls/pushes you toward/away the mob at a set pace
|
||||
//#define SE_Display 425 // *not implemented - Illusion: Flying Dragon(21626)
|
||||
#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window
|
||||
#define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt)
|
||||
#define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc
|
||||
#define SE_SkillProcAttempt 427 // implemented - chance to proc when using a skill(ie taunt)
|
||||
#define SE_LimitToSkill 428 // implemented, @Procs, limits what combat skills will effect a skill proc, base: skill value, limit: none, max: none
|
||||
#define SE_SkillProcSuccess 429 // implemented - chance to proc when tje skill in use successfully fires.
|
||||
//#define SE_PostEffect 430 // *not implemented - Fear of the Dark(27641) - Alters vision
|
||||
//#define SE_PostEffectData 431 // *not implemented - Fear of the Dark(27641) - Alters vision
|
||||
|
||||
178
zone/attack.cpp
178
zone/attack.cpp
@ -1603,12 +1603,12 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
///////////////////////////////////////////////////////////
|
||||
////// Send Attack Damage
|
||||
///////////////////////////////////////////////////////////
|
||||
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SKILL] == my_hit.skill &&
|
||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID])) {
|
||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
|
||||
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SKILL] == my_hit.skill &&
|
||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID])) {
|
||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] / 1000.0f;
|
||||
if (zone->random.Roll(chance))
|
||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty);
|
||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
|
||||
}
|
||||
other->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, my_hit.skill, true, -1, false, m_specialattacks);
|
||||
|
||||
@ -1616,9 +1616,6 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
|
||||
MeleeLifeTap(my_hit.damage_done);
|
||||
|
||||
if (my_hit.damage_done > 0 && HasSkillProcSuccess() && other && other->GetHP() > 0)
|
||||
TrySkillProc(other, my_hit.skill, 0, true, Hand);
|
||||
|
||||
CommonBreakInvisibleFromCombat();
|
||||
|
||||
if (GetTarget())
|
||||
@ -3471,7 +3468,6 @@ bool Mob::HasDefensiveProcs() const
|
||||
|
||||
bool Mob::HasSkillProcs() const
|
||||
{
|
||||
|
||||
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||
if (spellbonuses.SkillProc[i] || itembonuses.SkillProc[i] || aabonuses.SkillProc[i])
|
||||
return true;
|
||||
@ -4164,12 +4160,12 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
|
||||
//Spell Procs and Quest added procs
|
||||
for (int i = 0; i < MAX_PROCS; i++) {
|
||||
if (IsValidSpell(DefensiveProcs[i].spellID)) {
|
||||
if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc)) {
|
||||
if (!IsProcLimitTimerActive(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, ProcType::DEFENSIVE_PROC)) {
|
||||
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance) / 100.0f);
|
||||
if (zone->random.Roll(chance)) {
|
||||
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
|
||||
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID);
|
||||
SetProcLimitTimer(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, SE_DefensiveProc);
|
||||
SetProcLimitTimer(DefensiveProcs[i].base_spellID, DefensiveProcs[i].proc_reuse_time, ProcType::DEFENSIVE_PROC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4178,17 +4174,17 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
|
||||
//AA Procs
|
||||
if (IsClient()){
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
int32 aa_rank_id = aabonuses.DefensiveProc[i];
|
||||
int32 aa_spell_id = aabonuses.DefensiveProc[i + 1];
|
||||
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + 2];
|
||||
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + 3];
|
||||
int32 aa_rank_id = aabonuses.DefensiveProc[i + +SBIndex::COMBAT_PROC_ORIGIN_ID];
|
||||
int32 aa_spell_id = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
|
||||
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER];
|
||||
|
||||
if (aa_rank_id) {
|
||||
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc)) {
|
||||
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, ProcType::DEFENSIVE_PROC)) {
|
||||
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
|
||||
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
|
||||
ExecWeaponProc(nullptr, aa_spell_id, on);
|
||||
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, SE_DefensiveProc);
|
||||
SetProcLimitTimer(-aa_rank_id, aa_proc_reuse_timer, ProcType::DEFENSIVE_PROC);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4197,7 +4193,8 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::TryWeaponProc(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand) {
|
||||
void Mob::TryCombatProcs(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand, const EQ::ItemData* weapon_data) {
|
||||
|
||||
if (!on) {
|
||||
SetTarget(nullptr);
|
||||
LogError("A null Mob object was passed to Mob::TryWeaponProc for evaluation!");
|
||||
@ -4214,6 +4211,13 @@ void Mob::TryWeaponProc(const EQ::ItemInstance* weapon_g, Mob *on, uint16 hand)
|
||||
return;
|
||||
}
|
||||
|
||||
//used for special case when checking last ammo item on projectile hit.
|
||||
if (!weapon_g && weapon_data) {
|
||||
TryWeaponProc(nullptr, weapon_data, on, hand);
|
||||
TrySpellProc(nullptr, weapon_data, on, hand);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!weapon_g) {
|
||||
TrySpellProc(nullptr, (const EQ::ItemData*)nullptr, on);
|
||||
return;
|
||||
@ -4253,7 +4257,7 @@ void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon
|
||||
// Try innate proc on weapon
|
||||
// We can proc once here, either weapon or one aug
|
||||
bool proced = false; // silly bool to prevent augs from going if weapon does
|
||||
skillinuse = GetSkillByItemType(weapon->ItemType);
|
||||
|
||||
if (weapon->Proc.Type == EQ::item::ItemEffectCombatProc && IsValidSpell(weapon->Proc.Effect)) {
|
||||
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
|
||||
static_cast<float>(weapon->ProcRate)) / 100.0f;
|
||||
@ -4330,8 +4334,16 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
float ProcChance = 0.0f;
|
||||
ProcChance = GetProcChances(ProcBonus, hand);
|
||||
|
||||
if (hand == EQ::invslot::slotSecondary)
|
||||
bool passed_skill_limit_check = true;
|
||||
EQ::skills::SkillType skillinuse = EQ::skills::SkillHandtoHand;
|
||||
|
||||
if (weapon){
|
||||
skillinuse = GetSkillByItemType(weapon->ItemType);
|
||||
}
|
||||
|
||||
if (hand == EQ::invslot::slotSecondary) {
|
||||
ProcChance /= 2;
|
||||
}
|
||||
|
||||
bool rangedattk = false;
|
||||
if (weapon && hand == EQ::invslot::slotRange) {
|
||||
@ -4343,8 +4355,9 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
}
|
||||
}
|
||||
|
||||
if (!weapon && hand == EQ::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK))
|
||||
if (!weapon && hand == EQ::invslot::slotRange && GetSpecialAbility(SPECATK_RANGED_ATK)) {
|
||||
rangedattk = true;
|
||||
}
|
||||
|
||||
int16 poison_slot=-1;
|
||||
|
||||
@ -4353,8 +4366,9 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
continue; // If pets ever can proc from off hand, this will need to change
|
||||
|
||||
if (SpellProcs[i].base_spellID == POISON_PROC &&
|
||||
(!weapon || weapon->ItemType != EQ::item::ItemType1HPiercing))
|
||||
(!weapon || weapon->ItemType != EQ::item::ItemType1HPiercing)) {
|
||||
continue; // Old school poison will only proc with 1HP equipped.
|
||||
}
|
||||
|
||||
// Not ranged
|
||||
if (!rangedattk) {
|
||||
@ -4376,13 +4390,15 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
continue; // Process the poison proc last per @mackal
|
||||
}
|
||||
|
||||
if (!IsProcLimitTimerActive(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc)) {
|
||||
passed_skill_limit_check = PassLimitToSkill(skillinuse, SpellProcs[i].base_spellID, ProcType::MELEE_PROC);
|
||||
|
||||
if (passed_skill_limit_check && !IsProcLimitTimerActive(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, ProcType::MELEE_PROC)) {
|
||||
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
|
||||
if (zone->random.Roll(chance)) {
|
||||
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
|
||||
SendBeginCast(SpellProcs[i].spellID, 0);
|
||||
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
|
||||
SetProcLimitTimer(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, SE_WeaponProc);
|
||||
SetProcLimitTimer(SpellProcs[i].base_spellID, SpellProcs[i].proc_reuse_time, ProcType::MELEE_PROC);
|
||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, SpellProcs[i].base_spellID);
|
||||
}
|
||||
else {
|
||||
@ -4395,13 +4411,15 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
// ranged spell procs (buffs)
|
||||
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
|
||||
if (!IsProcLimitTimerActive(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc)) {
|
||||
passed_skill_limit_check = PassLimitToSkill(skillinuse, RangedProcs[i].base_spellID, ProcType::RANGED_PROC);
|
||||
|
||||
if (passed_skill_limit_check && !IsProcLimitTimerActive(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, ProcType::RANGED_PROC)) {
|
||||
float chance = ProcChance * (static_cast<float>(RangedProcs[i].chance) / 100.0f);
|
||||
if (zone->random.Roll(chance)) {
|
||||
LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
|
||||
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
|
||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, RangedProcs[i].base_spellID);
|
||||
SetProcLimitTimer(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, SE_RangedProc);
|
||||
SetProcLimitTimer(RangedProcs[i].base_spellID, RangedProcs[i].proc_reuse_time, ProcType::RANGED_PROC);
|
||||
}
|
||||
else {
|
||||
LogCombat("Ranged proc [{}] failed to proc [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
|
||||
@ -4411,7 +4429,7 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
}
|
||||
}
|
||||
|
||||
//AA Procs
|
||||
//AA Melee and Ranged Procs
|
||||
if (IsClient()) {
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
|
||||
@ -4423,22 +4441,25 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
|
||||
if (!rangedattk) {
|
||||
|
||||
aa_rank_id = aabonuses.SpellProc[i];
|
||||
aa_spell_id = aabonuses.SpellProc[i + 1];
|
||||
aa_proc_chance += aabonuses.SpellProc[i + 2];
|
||||
aa_proc_reuse_timer = aabonuses.SpellProc[i + 3];
|
||||
proc_type = SE_WeaponProc;
|
||||
aa_rank_id = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID];
|
||||
aa_spell_id = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
|
||||
aa_proc_chance += aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||
aa_proc_reuse_timer = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||
proc_type = ProcType::MELEE_PROC;
|
||||
}
|
||||
else {
|
||||
aa_rank_id = aabonuses.RangedProc[i];
|
||||
aa_spell_id = aabonuses.RangedProc[i + 1];
|
||||
aa_proc_chance += aabonuses.RangedProc[i + 2];
|
||||
aa_proc_reuse_timer = aabonuses.RangedProc[i + 3];
|
||||
proc_type = SE_RangedProc;
|
||||
aa_rank_id = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID];
|
||||
aa_spell_id = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
|
||||
aa_proc_chance += aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||
aa_proc_reuse_timer = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||
proc_type = ProcType::RANGED_PROC;
|
||||
}
|
||||
|
||||
if (aa_rank_id) {
|
||||
if (!IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, proc_type)) {
|
||||
|
||||
passed_skill_limit_check = PassLimitToSkill(skillinuse, 0, proc_type, aa_rank_id);
|
||||
|
||||
if (passed_skill_limit_check && !IsProcLimitTimerActive(-aa_rank_id, aa_proc_reuse_timer, proc_type)) {
|
||||
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
|
||||
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
|
||||
LogCombat("AA proc [{}] procing spell [{}] ([{}] percent chance)", aa_rank_id, aa_spell_id, chance);
|
||||
@ -4469,13 +4490,12 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
||||
}
|
||||
|
||||
if (HasSkillProcs() && hand != EQ::invslot::slotRange) { //We check ranged skill procs within the attack functions.
|
||||
uint16 skillinuse = 28;
|
||||
if (weapon)
|
||||
skillinuse = GetSkillByItemType(weapon->ItemType);
|
||||
|
||||
TrySkillProc(on, skillinuse, 0, false, hand);
|
||||
}
|
||||
|
||||
if (HasSkillProcSuccess() && hand != EQ::invslot::slotRange) { //We check ranged skill procs within the attack functions.
|
||||
TrySkillProc(on, skillinuse, 0, true, hand);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -5040,7 +5060,7 @@ void Mob::ApplyDamageTable(DamageHitInfo &hit)
|
||||
Log(Logs::Detail, Logs::Attack, "Damage table applied %d (max %d)", percent, damage_table.max_extra);
|
||||
}
|
||||
|
||||
void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, uint16 hand, bool IsDefensive)
|
||||
void Mob::TrySkillProc(Mob *on, EQ::skills::SkillType skill, uint16 ReuseTime, bool Success, uint16 hand, bool IsDefensive)
|
||||
{
|
||||
|
||||
if (!on) {
|
||||
@ -5049,12 +5069,19 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
return;
|
||||
}
|
||||
|
||||
if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill])
|
||||
if (on->HasDied()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*Allow one proc from each (Spell/Item/AA)
|
||||
Kayen: Due to limited avialability of effects on live it is too difficult
|
||||
to confirm how they stack at this time, will adjust formula when more data is avialablle to test.*/
|
||||
if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill]) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Allow one proc from each (Spell/Item/AA)
|
||||
Kayen: Due to limited avialability of effects on live it is too difficult
|
||||
to confirm how they stack at this time, will adjust formula when more data is avialablle to test.
|
||||
*/
|
||||
bool CanProc = true;
|
||||
|
||||
uint16 base_spell_id = 0;
|
||||
@ -5069,22 +5096,24 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
|
||||
if (spellbonuses.LimitToSkill[skill]) {
|
||||
|
||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
||||
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||
if (CanProc &&
|
||||
((!Success && spellbonuses.SkillProc[e] && IsValidSpell(spellbonuses.SkillProc[e]))
|
||||
|| (Success && spellbonuses.SkillProcSuccess[e] && IsValidSpell(spellbonuses.SkillProcSuccess[e])))) {
|
||||
((!Success && spellbonuses.SkillProc[i] && IsValidSpell(spellbonuses.SkillProc[i]))
|
||||
|| (Success && spellbonuses.SkillProcSuccess[i] && IsValidSpell(spellbonuses.SkillProcSuccess[i])))) {
|
||||
|
||||
if (Success)
|
||||
base_spell_id = spellbonuses.SkillProcSuccess[e];
|
||||
else
|
||||
base_spell_id = spellbonuses.SkillProc[e];
|
||||
if (Success) {
|
||||
base_spell_id = spellbonuses.SkillProcSuccess[i];
|
||||
}
|
||||
else {
|
||||
base_spell_id = spellbonuses.SkillProc[i];
|
||||
}
|
||||
|
||||
proc_spell_id = 0;
|
||||
ProcMod = 0;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
|
||||
if (spells[base_spell_id].effect_id[i] == SE_SkillProc || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
|
||||
if (spells[base_spell_id].effect_id[i] == SE_SkillProcAttempt || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
|
||||
proc_spell_id = spells[base_spell_id].base_value[i];
|
||||
ProcMod = static_cast<float>(spells[base_spell_id].limit_value[i]);
|
||||
}
|
||||
@ -5095,8 +5124,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
float final_chance = chance * (ProcMod / 100.0f);
|
||||
if (zone->random.Roll(final_chance)) {
|
||||
ExecWeaponProc(nullptr, proc_spell_id, on);
|
||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
|
||||
base_spell_id);
|
||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, base_spell_id);
|
||||
CanProc = false;
|
||||
break;
|
||||
}
|
||||
@ -5114,21 +5142,23 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
|
||||
if (itembonuses.LimitToSkill[skill]) {
|
||||
CanProc = true;
|
||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
||||
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||
if (CanProc &&
|
||||
((!Success && itembonuses.SkillProc[e] && IsValidSpell(itembonuses.SkillProc[e]))
|
||||
|| (Success && itembonuses.SkillProcSuccess[e] && IsValidSpell(itembonuses.SkillProcSuccess[e])))) {
|
||||
((!Success && itembonuses.SkillProc[i] && IsValidSpell(itembonuses.SkillProc[i]))
|
||||
|| (Success && itembonuses.SkillProcSuccess[i] && IsValidSpell(itembonuses.SkillProcSuccess[i])))) {
|
||||
|
||||
if (Success)
|
||||
base_spell_id = itembonuses.SkillProcSuccess[e];
|
||||
else
|
||||
base_spell_id = itembonuses.SkillProc[e];
|
||||
if (Success) {
|
||||
base_spell_id = itembonuses.SkillProcSuccess[i];
|
||||
}
|
||||
else {
|
||||
base_spell_id = itembonuses.SkillProc[i];
|
||||
}
|
||||
|
||||
proc_spell_id = 0;
|
||||
ProcMod = 0;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (spells[base_spell_id].effect_id[i] == SE_SkillProc || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
|
||||
if (spells[base_spell_id].effect_id[i] == SE_SkillProcAttempt || spells[base_spell_id].effect_id[i] == SE_SkillProcSuccess) {
|
||||
proc_spell_id = spells[base_spell_id].base_value[i];
|
||||
ProcMod = static_cast<float>(spells[base_spell_id].limit_value[i]);
|
||||
}
|
||||
@ -5161,16 +5191,16 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
int32 limit_value = 0;
|
||||
uint32 slot = 0;
|
||||
|
||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
||||
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||
if (CanProc &&
|
||||
((!Success && aabonuses.SkillProc[e])
|
||||
|| (Success && aabonuses.SkillProcSuccess[e]))) {
|
||||
((!Success && aabonuses.SkillProc[i])
|
||||
|| (Success && aabonuses.SkillProcSuccess[i]))) {
|
||||
int aaid = 0;
|
||||
|
||||
if (Success)
|
||||
base_spell_id = aabonuses.SkillProcSuccess[e];
|
||||
base_spell_id = aabonuses.SkillProcSuccess[i];
|
||||
else
|
||||
base_spell_id = aabonuses.SkillProc[e];
|
||||
base_spell_id = aabonuses.SkillProc[i];
|
||||
|
||||
proc_spell_id = 0;
|
||||
ProcMod = 0;
|
||||
@ -5190,7 +5220,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
||||
limit_value = effect.limit_value;
|
||||
slot = effect.slot;
|
||||
|
||||
if (effect_id == SE_SkillProc || effect_id == SE_SkillProcSuccess) {
|
||||
if (effect_id == SE_SkillProcAttempt || effect_id == SE_SkillProcSuccess) {
|
||||
proc_spell_id = base_value;
|
||||
ProcMod = static_cast<float>(limit_value);
|
||||
}
|
||||
@ -5225,12 +5255,14 @@ float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
|
||||
if (!ReuseTime && hand) {
|
||||
weapon_speed = GetWeaponSpeedbyHand(hand);
|
||||
ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
|
||||
if (hand == EQ::invslot::slotSecondary)
|
||||
if (hand == EQ::invslot::slotSecondary) {
|
||||
ProcChance /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
else {
|
||||
ProcChance = static_cast<float>(ReuseTime) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
|
||||
}
|
||||
|
||||
return ProcChance;
|
||||
}
|
||||
|
||||
@ -1074,11 +1074,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
case SE_WeaponProc:
|
||||
case SE_AddMeleeProc:
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (!newbon->SpellProc[i]) {
|
||||
newbon->SpellProc[i] = rank.id; //aa rank id
|
||||
newbon->SpellProc[i + 1] = base_value; //proc spell id
|
||||
newbon->SpellProc[i + 2] = limit_value; //proc rate modifer
|
||||
newbon->SpellProc[i + 3] = 0; //Lock out Timer
|
||||
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
||||
newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
||||
newbon->SpellProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
||||
newbon->SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
||||
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1086,11 +1086,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
|
||||
case SE_RangedProc:
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (!newbon->RangedProc[i]) {
|
||||
newbon->RangedProc[i] = rank.id; //aa rank id
|
||||
newbon->RangedProc[i + 1] = base_value; //proc spell id
|
||||
newbon->RangedProc[i + 2] = limit_value; //proc rate modifer
|
||||
newbon->RangedProc[i + 3] = 0; //Lock out Timer
|
||||
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
||||
newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
||||
newbon->RangedProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
||||
newbon->RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
||||
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1098,11 +1098,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
|
||||
case SE_DefensiveProc:
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (!newbon->DefensiveProc[i]) {
|
||||
newbon->DefensiveProc[i] = rank.id; //aa rank id
|
||||
newbon->DefensiveProc[i + 1] = base_value; //proc spell id
|
||||
newbon->DefensiveProc[i + 2] = limit_value; //proc rate modifer
|
||||
newbon->DefensiveProc[i + 3] = 0; //Lock out Timer
|
||||
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
||||
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
||||
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
||||
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
||||
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1118,23 +1118,23 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
newbon->Proc_Timer_Modifier = true;
|
||||
|
||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||
if (newbon->SpellProc[i] == rank.id) {
|
||||
if (!newbon->SpellProc[i + 3]) {
|
||||
newbon->SpellProc[i + 3] = limit_value;//Lock out Timer
|
||||
if (newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
||||
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
||||
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newbon->RangedProc[i] == rank.id) {
|
||||
if (!newbon->RangedProc[i + 3]) {
|
||||
newbon->RangedProc[i + 3] = limit_value;//Lock out Timer
|
||||
if (newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
||||
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
||||
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newbon->DefensiveProc[i] == rank.id) {
|
||||
if (!newbon->DefensiveProc[i + 3]) {
|
||||
newbon->DefensiveProc[i + 3] = limit_value;//Lock out Timer
|
||||
if (newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
||||
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
||||
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1208,9 +1208,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
|
||||
case SE_SkillAttackProc: {
|
||||
// You can only have one of these per client. [AA Dragon Punch]
|
||||
newbon->SkillAttackProc[SBIndex::SKILLPROC_CHANCE] = base_value; // Chance base 1000 = 100% proc rate
|
||||
newbon->SkillAttackProc[SBIndex::SKILLPROC_SKILL] = limit_value; // Skill to Proc Off
|
||||
newbon->SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID] = rank.spell; // spell to proc
|
||||
newbon->SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] = base_value; // Chance base 1000 = 100% proc rate
|
||||
newbon->SkillAttackProc[SBIndex::SKILLATK_PROC_SKILL] = limit_value; // Skill to Proc Off
|
||||
newbon->SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID] = rank.spell; // spell to proc
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1458,15 +1458,19 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
||||
break;
|
||||
|
||||
case SE_LimitToSkill: {
|
||||
|
||||
// Bad data or unsupported new skill
|
||||
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
||||
if (base_value > EQ::skills::HIGHEST_SKILL) {
|
||||
break;
|
||||
if (base_value <= EQ::skills::HIGHEST_SKILL)
|
||||
}
|
||||
if (base_value <= EQ::skills::HIGHEST_SKILL) {
|
||||
newbon->LimitToSkill[base_value] = true;
|
||||
newbon->LimitToSkill[EQ::skills::HIGHEST_SKILL + 3] = true; //Used as a general exists check
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SkillProc: {
|
||||
case SE_SkillProcAttempt: {
|
||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
||||
if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id)
|
||||
break; // Do not use the same aa id more than once.
|
||||
@ -3535,15 +3539,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
|
||||
|
||||
case SE_LimitToSkill:{
|
||||
// Bad data or unsupported new skill
|
||||
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
||||
if (effect_value > EQ::skills::HIGHEST_SKILL) {
|
||||
break;
|
||||
}
|
||||
if (effect_value <= EQ::skills::HIGHEST_SKILL){
|
||||
new_bonus->LimitToSkill[effect_value] = true;
|
||||
new_bonus->LimitToSkill[EQ::skills::HIGHEST_SKILL + 3] = true; //Used as a general exists check
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SkillProc:{
|
||||
case SE_SkillProcAttempt:{
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
@ -5528,7 +5534,7 @@ void Mob::NegateSpellEffectBonuses(uint16 spell_id)
|
||||
}
|
||||
}
|
||||
|
||||
case SE_SkillProc: {
|
||||
case SE_SkillProcAttempt: {
|
||||
for (int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if (negate_spellbonus) { spellbonuses.SkillProc[e] = effect_value; }
|
||||
|
||||
@ -3248,7 +3248,7 @@ void Bot::AI_Process()
|
||||
TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false);
|
||||
|
||||
TEST_COMBATANTS();
|
||||
TryWeaponProc(p_item, tar, EQ::invslot::slotPrimary);
|
||||
TryCombatProcs(p_item, tar, EQ::invslot::slotPrimary);
|
||||
|
||||
// bool tripleSuccess = false;
|
||||
|
||||
@ -3337,7 +3337,7 @@ void Bot::AI_Process()
|
||||
Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
|
||||
|
||||
TEST_COMBATANTS();
|
||||
TryWeaponProc(s_item, tar, EQ::invslot::slotSecondary);
|
||||
TryCombatProcs(s_item, tar, EQ::invslot::slotSecondary);
|
||||
|
||||
TEST_COMBATANTS();
|
||||
if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) {
|
||||
|
||||
@ -721,17 +721,17 @@ void Client::CompleteConnect()
|
||||
case SE_AddMeleeProc:
|
||||
case SE_WeaponProc:
|
||||
{
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel, GetProcLimitTimer(buffs[j1].spellid, SE_WeaponProc));
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid, x1), false, 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel, GetProcLimitTimer(buffs[j1].spellid, ProcType::MELEE_PROC));
|
||||
break;
|
||||
}
|
||||
case SE_DefensiveProc:
|
||||
{
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_DefensiveProc));
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, ProcType::DEFENSIVE_PROC));
|
||||
break;
|
||||
}
|
||||
case SE_RangedProc:
|
||||
{
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_RangedProc));
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, ProcType::RANGED_PROC));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,7 +414,7 @@ bool Client::Process() {
|
||||
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
|
||||
{
|
||||
EQ::ItemInstance *wpn = GetInv().GetItem(EQ::invslot::slotPrimary);
|
||||
TryWeaponProc(wpn, auto_attack_target, EQ::invslot::slotPrimary);
|
||||
TryCombatProcs(wpn, auto_attack_target, EQ::invslot::slotPrimary);
|
||||
TriggerDefensiveProcs(auto_attack_target, EQ::invslot::slotPrimary, false);
|
||||
|
||||
DoAttackRounds(auto_attack_target, EQ::invslot::slotPrimary);
|
||||
@ -460,7 +460,7 @@ bool Client::Process() {
|
||||
CheckIncreaseSkill(EQ::skills::SkillDualWield, auto_attack_target, -10);
|
||||
if (CheckDualWield()) {
|
||||
EQ::ItemInstance *wpn = GetInv().GetItem(EQ::invslot::slotSecondary);
|
||||
TryWeaponProc(wpn, auto_attack_target, EQ::invslot::slotSecondary);
|
||||
TryCombatProcs(wpn, auto_attack_target, EQ::invslot::slotSecondary);
|
||||
|
||||
DoAttackRounds(auto_attack_target, EQ::invslot::slotSecondary);
|
||||
}
|
||||
|
||||
@ -533,7 +533,7 @@ struct StatBonuses {
|
||||
int32 Metabolism; // Food/drink consumption rates.
|
||||
bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others.
|
||||
int32 FactionModPct; // Modifies amount of faction gained.
|
||||
bool LimitToSkill[EQ::skills::HIGHEST_SKILL + 2]; // Determines if we need to search for a skill proc.
|
||||
bool LimitToSkill[EQ::skills::HIGHEST_SKILL + 3]; // Determines if we need to search for a skill proc.
|
||||
uint32 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs.
|
||||
uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success.
|
||||
int32 SpellProc[MAX_AA_PROCS]; // Max number of spells containing melee spell procs.
|
||||
@ -671,9 +671,9 @@ namespace SBIndex {
|
||||
constexpr uint16 POSITION_FRONT = 1; // SPA 503-506
|
||||
constexpr uint16 PET_RAMPAGE_CHANCE = 0; // SPA 464,465
|
||||
constexpr uint16 PET_RAMPAGE_DMG_MOD = 1; // SPA 465,465
|
||||
constexpr uint16 SKILLPROC_CHANCE = 0; // SPA 427
|
||||
constexpr uint16 SKILLPROC_SKILL = 1; // SPA 427
|
||||
constexpr uint16 SKILLPROC_SPELL_ID = 2; // SPA 427
|
||||
constexpr uint16 SKILLATK_PROC_CHANCE = 0; // SPA 427
|
||||
constexpr uint16 SKILLATK_PROC_SKILL = 1; // SPA 427
|
||||
constexpr uint16 SKILLATK_PROC_SPELL_ID = 2; // SPA 427
|
||||
constexpr uint16 SLAYUNDEAD_RATE_MOD = 0; // SPA 219
|
||||
constexpr uint16 SLAYUNDEAD_DMG_MOD = 1; // SPA 219
|
||||
constexpr uint16 DOUBLE_RIPOSTE_CHANCE = 0; // SPA 223
|
||||
@ -688,14 +688,18 @@ namespace SBIndex {
|
||||
constexpr uint16 REFLECT_CHANCE = 0; // SPA 158
|
||||
constexpr uint16 REFLECT_RESISTANCE_MOD = 1; // SPA 158
|
||||
constexpr uint16 REFLECT_DMG_EFFECTIVENESS = 2; // SPA 158
|
||||
constexpr uint16 COMBAT_PROC_ORIGIN_ID = 0; // SPA
|
||||
constexpr uint16 COMBAT_PROC_SPELL_ID = 1; // SPA
|
||||
constexpr uint16 COMBAT_PROC_RATE_MOD = 2; // SPA
|
||||
constexpr uint16 COMBAT_PROC_REUSE_TIMER = 3; // SPA
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16 spellID;
|
||||
int32 spellID;
|
||||
uint16 chance;
|
||||
uint16 base_spellID;
|
||||
int32 base_spellID;
|
||||
int level_override;
|
||||
uint32 proc_reuse_time;
|
||||
} tProc;
|
||||
|
||||
32
zone/mob.cpp
32
zone/mob.cpp
@ -4213,15 +4213,17 @@ int Mob::GetSnaredAmount()
|
||||
|
||||
void Mob::TriggerDefensiveProcs(Mob *on, uint16 hand, bool FromSkillProc, int damage)
|
||||
{
|
||||
if (!on)
|
||||
if (!on) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FromSkillProc)
|
||||
if (!FromSkillProc) {
|
||||
on->TryDefensiveProc(this, hand);
|
||||
}
|
||||
|
||||
//Defensive Skill Procs
|
||||
if (damage < 0 && damage >= -4) {
|
||||
uint16 skillinuse = 0;
|
||||
EQ::skills::SkillType skillinuse = EQ::skills::SkillBlock;
|
||||
switch (damage) {
|
||||
case (-1):
|
||||
skillinuse = EQ::skills::SkillBlock;
|
||||
@ -4240,11 +4242,13 @@ void Mob::TriggerDefensiveProcs(Mob *on, uint16 hand, bool FromSkillProc, int da
|
||||
break;
|
||||
}
|
||||
|
||||
if (on->HasSkillProcs())
|
||||
if (on->HasSkillProcs()) {
|
||||
on->TrySkillProc(this, skillinuse, 0, false, hand, true);
|
||||
}
|
||||
|
||||
if (on->HasSkillProcSuccess())
|
||||
if (on && on->HasSkillProcSuccess()) {
|
||||
on->TrySkillProc(this, skillinuse, 0, true, hand, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5617,7 +5621,7 @@ void Mob::SlowMitigation(Mob* caster)
|
||||
}
|
||||
}
|
||||
|
||||
uint16 Mob::GetSkillByItemType(int ItemType)
|
||||
EQ::skills::SkillType Mob::GetSkillByItemType(int ItemType)
|
||||
{
|
||||
switch (ItemType) {
|
||||
case EQ::item::ItemType1HSlash:
|
||||
@ -5673,22 +5677,6 @@ uint8 Mob::GetItemTypeBySkill(EQ::skills::SkillType skill)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Mob::PassLimitToSkill(uint16 spell_id, uint16 skill) {
|
||||
|
||||
if (!IsValidSpell(spell_id))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (spells[spell_id].effect_id[i] == SE_LimitToSkill){
|
||||
if (spells[spell_id].base_value[i] == skill){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16 Mob::GetWeaponSpeedbyHand(uint16 hand) {
|
||||
|
||||
uint16 weapon_speed = 0;
|
||||
|
||||
@ -701,7 +701,7 @@ public:
|
||||
static uint32 RandomTimer(int min, int max);
|
||||
static uint8 GetDefaultGender(uint16 in_race, uint8 in_gender = 0xFF);
|
||||
static bool IsPlayerRace(uint16 in_race);
|
||||
uint16 GetSkillByItemType(int ItemType);
|
||||
EQ::skills::SkillType GetSkillByItemType(int ItemType);
|
||||
uint8 GetItemTypeBySkill(EQ::skills::SkillType skill);
|
||||
virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr);
|
||||
virtual void MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, const char *petname = nullptr, float in_size = 0.0f);
|
||||
@ -864,6 +864,7 @@ public:
|
||||
bool IsTargetedFocusEffect(int focus_type);
|
||||
bool HasPersistDeathIllusion(int32 spell_id);
|
||||
|
||||
|
||||
bool TryDoubleMeleeRoundEffect();
|
||||
bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; }
|
||||
inline void SetUseDoubleMeleeRoundDmgBonus(bool val) { use_double_melee_round_dmg_bonus = val; }
|
||||
@ -1446,13 +1447,13 @@ protected:
|
||||
bool spawned;
|
||||
void CalcSpellBonuses(StatBonuses* newbon);
|
||||
virtual void CalcBonuses();
|
||||
void TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); // hand = SlotCharm?
|
||||
bool PassLimitToSkill(uint16 spell_id, uint16 skill);
|
||||
void TrySkillProc(Mob *on, EQ::skills::SkillType skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); // hand = SlotCharm?
|
||||
bool PassLimitToSkill(EQ::skills::SkillType skill, int32 spell_id, int proc_type, int aa_id=0);
|
||||
bool PassLimitClass(uint32 Classes_, uint16 Class_);
|
||||
void TryDefensiveProc(Mob *on, uint16 hand = EQ::invslot::slotPrimary);
|
||||
void TryWeaponProc(const EQ::ItemInstance* inst, const EQ::ItemData* weapon, Mob *on, uint16 hand = EQ::invslot::slotPrimary);
|
||||
void TrySpellProc(const EQ::ItemInstance* inst, const EQ::ItemData* weapon, Mob *on, uint16 hand = EQ::invslot::slotPrimary);
|
||||
void TryWeaponProc(const EQ::ItemInstance* weapon, Mob *on, uint16 hand = EQ::invslot::slotPrimary);
|
||||
void TryCombatProcs(const EQ::ItemInstance* weapon, Mob *on, uint16 hand = EQ::invslot::slotPrimary, const EQ::ItemData* weapon_data = nullptr);
|
||||
void ExecWeaponProc(const EQ::ItemInstance* weapon, uint16 spell_id, Mob *on, int level_override = -1);
|
||||
virtual float GetProcChances(float ProcBonus, uint16 hand = EQ::invslot::slotPrimary);
|
||||
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = EQ::invslot::slotPrimary, Mob *on = nullptr);
|
||||
|
||||
@ -580,13 +580,13 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
||||
case SE_WeaponProc:
|
||||
// We need to reapply buff based procs
|
||||
// We need to do this here so suspended pets also regain their procs.
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel, GetProcLimitTimer(buffs[j1].spellid, SE_WeaponProc));
|
||||
AddProcToWeapon(GetProcID(buffs[j1].spellid,x1), false, 100+spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, buffs[j1].casterlevel, GetProcLimitTimer(buffs[j1].spellid, ProcType::MELEE_PROC));
|
||||
break;
|
||||
case SE_DefensiveProc:
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_DefensiveProc));
|
||||
AddDefensiveProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, ProcType::DEFENSIVE_PROC));
|
||||
break;
|
||||
case SE_RangedProc:
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, SE_RangedProc));
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100 + spells[buffs[j1].spellid].limit_value[x1], buffs[j1].spellid, GetProcLimitTimer(buffs[j1].spellid, ProcType::RANGED_PROC));
|
||||
break;
|
||||
case SE_Charm:
|
||||
case SE_Rune:
|
||||
|
||||
@ -196,12 +196,12 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int32 bas
|
||||
DoAttack(who, my_hit);
|
||||
|
||||
who->AddToHateList(this, hate, 0);
|
||||
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SKILL] == skill &&
|
||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID])) {
|
||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
|
||||
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SKILL] == skill &&
|
||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID])) {
|
||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] / 1000.0f;
|
||||
if (zone->random.Roll(chance))
|
||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], who, EQ::spells::CastingSlot::Item, 0, -1,
|
||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty);
|
||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID], who, EQ::spells::CastingSlot::Item, 0, -1,
|
||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
|
||||
}
|
||||
|
||||
who->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, skill, false);
|
||||
@ -212,11 +212,12 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int32 bas
|
||||
if (HasDied())
|
||||
return;
|
||||
|
||||
if (HasSkillProcs())
|
||||
if (HasSkillProcs()) {
|
||||
TrySkillProc(who, skill, ReuseTime * 1000);
|
||||
|
||||
if (my_hit.damage_done > 0 && HasSkillProcSuccess())
|
||||
}
|
||||
if (my_hit.damage_done > 0 && HasSkillProcSuccess()) {
|
||||
TrySkillProc(who, skill, ReuseTime * 1000, true);
|
||||
}
|
||||
}
|
||||
|
||||
// We should probably refactor this to take the struct not the packet
|
||||
@ -798,7 +799,7 @@ void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, co
|
||||
|
||||
const EQ::ItemInstance *_RangeWeapon = nullptr;
|
||||
const EQ::ItemInstance *_Ammo = nullptr;
|
||||
const EQ::ItemData *ammo_lost = nullptr;
|
||||
const EQ::ItemData *last_ammo_used = nullptr;
|
||||
|
||||
/*
|
||||
If LaunchProjectile is false this function will do archery damage on target,
|
||||
@ -830,7 +831,7 @@ void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, co
|
||||
if (_Ammo && _Ammo->GetItem() && _Ammo->GetItem()->ID == ammo_id)
|
||||
Ammo = _Ammo;
|
||||
else
|
||||
ammo_lost = database.GetItem(ammo_id);
|
||||
last_ammo_used = database.GetItem(ammo_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -900,34 +901,39 @@ void Mob::DoArcheryAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, co
|
||||
|
||||
other->Damage(this, TotalDmg, SPELL_UNKNOWN, EQ::skills::SkillArchery);
|
||||
|
||||
// Skill Proc Success
|
||||
if (TotalDmg > 0 && HasSkillProcSuccess() && other && !other->HasDied()) {
|
||||
if (ReuseTime)
|
||||
TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime);
|
||||
else
|
||||
TrySkillProc(other, EQ::skills::SkillArchery, 0, true, EQ::invslot::slotRange);
|
||||
}
|
||||
// end of old fuck
|
||||
|
||||
if (LaunchProjectile)
|
||||
return; // Shouldn't reach this point durring initial launch phase, but just in case.
|
||||
|
||||
// Weapon Proc
|
||||
if (RangeWeapon && other && !other->HasDied())
|
||||
TryWeaponProc(RangeWeapon, other, EQ::invslot::slotRange);
|
||||
if (RangeWeapon && other && !other->HasDied()) {
|
||||
TryCombatProcs(RangeWeapon, other, EQ::invslot::slotRange);
|
||||
}
|
||||
|
||||
// Ammo Proc
|
||||
if (ammo_lost)
|
||||
TryWeaponProc(nullptr, ammo_lost, other, EQ::invslot::slotRange);
|
||||
else if (Ammo && other && !other->HasDied())
|
||||
TryWeaponProc(Ammo, other, EQ::invslot::slotRange);
|
||||
// Ammo Proc, do not try spell procs if from ammo.
|
||||
if (last_ammo_used) {
|
||||
TryWeaponProc(nullptr, last_ammo_used, other, EQ::invslot::slotRange);
|
||||
}
|
||||
else if (Ammo && other && !other->HasDied()) {
|
||||
TryWeaponProc(Ammo, Ammo->GetItem(), other, EQ::invslot::slotRange);
|
||||
}
|
||||
|
||||
// Skill Proc
|
||||
// Skill Proc Attempt
|
||||
if (HasSkillProcs() && other && !other->HasDied()) {
|
||||
if (ReuseTime)
|
||||
if (ReuseTime) {
|
||||
TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime);
|
||||
else
|
||||
}
|
||||
else {
|
||||
TrySkillProc(other, EQ::skills::SkillArchery, 0, false, EQ::invslot::slotRange);
|
||||
}
|
||||
}
|
||||
|
||||
// Skill Proc Success ... can proc off hits OR misses
|
||||
if (HasSkillProcSuccess() && other && !other->HasDied()) {
|
||||
if (ReuseTime) {
|
||||
TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime, true);
|
||||
}
|
||||
else {
|
||||
TrySkillProc(other, EQ::skills::SkillArchery, 0, true, EQ::invslot::slotRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -991,7 +997,7 @@ bool Mob::TryProjectileAttack(Mob *other, const EQ::ItemData *item, EQ::skills::
|
||||
if (Ammo && Ammo->GetItem())
|
||||
ProjectileAtk[slot].ammo_id = Ammo->GetItem()->ID;
|
||||
|
||||
ProjectileAtk[slot].ammo_slot = 0;
|
||||
ProjectileAtk[slot].ammo_slot = AmmoSlot;
|
||||
ProjectileAtk[slot].skill = skillInUse;
|
||||
ProjectileAtk[slot].speed_mod = speed;
|
||||
|
||||
@ -1268,15 +1274,18 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
||||
|
||||
other->Damage(this, TotalDmg, SPELL_UNKNOWN, skillInUse);
|
||||
|
||||
if (TotalDmg > 0 && HasSkillProcSuccess() && !other->HasDied())
|
||||
TrySkillProc(other, skillInUse, 0, true, EQ::invslot::slotRange);
|
||||
|
||||
//try proc on hits and misses
|
||||
if(other && !other->HasDied())
|
||||
if (other && !other->HasDied()) {
|
||||
TrySpellProc(nullptr, (const EQ::ItemData*)nullptr, other, EQ::invslot::slotRange);
|
||||
}
|
||||
|
||||
if (HasSkillProcs() && other && !other->HasDied())
|
||||
if (HasSkillProcs() && other && !other->HasDied()) {
|
||||
TrySkillProc(other, skillInUse, 0, false, EQ::invslot::slotRange);
|
||||
}
|
||||
|
||||
if (HasSkillProcSuccess() && other && !other->HasDied()) {
|
||||
TrySkillProc(other, skillInUse, 0, true, EQ::invslot::slotRange);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
|
||||
@ -1355,7 +1364,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
|
||||
return;
|
||||
}
|
||||
|
||||
DoThrowingAttackDmg(other, RangeWeapon, item);
|
||||
DoThrowingAttackDmg(other, RangeWeapon, item, 0, 0, 0, 0, 0,ammo_slot);
|
||||
|
||||
// Consume Ammo, unless Ammo Consumption is disabled
|
||||
if (RuleB(Combat, ThrowingConsumesAmmo)) {
|
||||
@ -1378,8 +1387,8 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c
|
||||
return;
|
||||
}
|
||||
|
||||
const EQ::ItemInstance *_RangeWeapon = nullptr;
|
||||
const EQ::ItemData *ammo_lost = nullptr;
|
||||
const EQ::ItemInstance *m_RangeWeapon = nullptr;//throwing weapon
|
||||
const EQ::ItemData *last_ammo_used = nullptr;
|
||||
|
||||
/*
|
||||
If LaunchProjectile is false this function will do archery damage on target,
|
||||
@ -1394,12 +1403,14 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c
|
||||
} else {
|
||||
if (!RangeWeapon && range_id) {
|
||||
if (IsClient()) {
|
||||
_RangeWeapon = CastToClient()->m_inv[AmmoSlot];
|
||||
if (_RangeWeapon && _RangeWeapon->GetItem() &&
|
||||
_RangeWeapon->GetItem()->ID != range_id)
|
||||
RangeWeapon = _RangeWeapon;
|
||||
else
|
||||
ammo_lost = database.GetItem(range_id);
|
||||
m_RangeWeapon = CastToClient()->m_inv[AmmoSlot];
|
||||
|
||||
if (m_RangeWeapon && m_RangeWeapon->GetItem() && m_RangeWeapon->GetItem()->ID == range_id) {
|
||||
RangeWeapon = m_RangeWeapon;
|
||||
}
|
||||
else {
|
||||
last_ammo_used = database.GetItem(range_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1412,10 +1423,12 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c
|
||||
int WDmg = 0;
|
||||
|
||||
if (!weapon_damage) {
|
||||
if (IsClient() && RangeWeapon)
|
||||
if (IsClient() && RangeWeapon) {
|
||||
WDmg = GetWeaponDamage(other, RangeWeapon);
|
||||
else if (AmmoItem)
|
||||
}
|
||||
else if (AmmoItem) {
|
||||
WDmg = GetWeaponDamage(other, AmmoItem);
|
||||
}
|
||||
|
||||
if (LaunchProjectile) {
|
||||
TryProjectileAttack(other, AmmoItem, EQ::skills::SkillThrowing, WDmg, RangeWeapon,
|
||||
@ -1426,8 +1439,9 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c
|
||||
WDmg = weapon_damage;
|
||||
}
|
||||
|
||||
if (focus) // From FcBaseEffects
|
||||
if (focus) { // no longer used, keep for quests
|
||||
WDmg += WDmg * focus / 100;
|
||||
}
|
||||
|
||||
int TotalDmg = 0;
|
||||
|
||||
@ -1455,29 +1469,28 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c
|
||||
|
||||
other->Damage(this, TotalDmg, SPELL_UNKNOWN, EQ::skills::SkillThrowing);
|
||||
|
||||
if (TotalDmg > 0 && HasSkillProcSuccess() && other && !other->HasDied()) {
|
||||
if (ReuseTime)
|
||||
TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime);
|
||||
else
|
||||
TrySkillProc(other, EQ::skills::SkillThrowing, 0, true, EQ::invslot::slotRange);
|
||||
if (other && !other->HasDied()) {
|
||||
TryCombatProcs(RangeWeapon, other, EQ::invslot::slotRange, last_ammo_used);
|
||||
}
|
||||
// end old shit
|
||||
|
||||
if (LaunchProjectile)
|
||||
return;
|
||||
|
||||
// Throwing item Proc
|
||||
if (ammo_lost)
|
||||
TryWeaponProc(nullptr, ammo_lost, other, EQ::invslot::slotRange);
|
||||
else if (RangeWeapon && other && !other->HasDied())
|
||||
TryWeaponProc(RangeWeapon, other, EQ::invslot::slotRange);
|
||||
|
||||
if (HasSkillProcs() && other && !other->HasDied()) {
|
||||
if (ReuseTime)
|
||||
if (ReuseTime) {
|
||||
TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime);
|
||||
else
|
||||
}
|
||||
else {
|
||||
TrySkillProc(other, EQ::skills::SkillThrowing, 0, false, EQ::invslot::slotRange);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasSkillProcSuccess() && other && !other->HasDied()) {
|
||||
if (ReuseTime) {
|
||||
TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime, true);
|
||||
}
|
||||
else {
|
||||
TrySkillProc(other, EQ::skills::SkillThrowing, 0, true, EQ::invslot::slotRange);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsClient()) {
|
||||
CastToClient()->CheckIncreaseSkill(EQ::skills::SkillThrowing, GetTarget());
|
||||
}
|
||||
@ -1965,7 +1978,7 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell,
|
||||
Mob *hate_top = who->GetHateMost();
|
||||
|
||||
int level_difference = GetLevel() - who->GetLevel();
|
||||
bool Success = false;
|
||||
bool success = false;
|
||||
|
||||
// Support for how taunt worked pre 2000 on LIVE - Can not taunt NPC over your level.
|
||||
if ((RuleB(Combat, TauntOverLevel) == false) && (level_difference < 0) ||
|
||||
@ -1978,7 +1991,7 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell,
|
||||
if ((hate_top && hate_top->GetHPRatio() >= 20) || hate_top == nullptr || chance_bonus) {
|
||||
// SE_Taunt this is flat chance
|
||||
if (chance_bonus) {
|
||||
Success = zone->random.Roll(chance_bonus);
|
||||
success = zone->random.Roll(chance_bonus);
|
||||
} else {
|
||||
float tauntchance = 50.0f;
|
||||
|
||||
@ -2012,14 +2025,14 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell,
|
||||
|
||||
tauntchance /= 100.0f;
|
||||
|
||||
Success = tauntchance > zone->random.Real(0, 1);
|
||||
success = tauntchance > zone->random.Real(0, 1);
|
||||
}
|
||||
|
||||
if (Success) {
|
||||
if (success) {
|
||||
if (hate_top && hate_top != this) {
|
||||
int newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1 + bonus_hate;
|
||||
who->CastToNPC()->AddToHateList(this, newhate);
|
||||
Success = true;
|
||||
success = true;
|
||||
} else {
|
||||
who->CastToNPC()->AddToHateList(this, 12);
|
||||
}
|
||||
@ -2033,11 +2046,13 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell,
|
||||
MessageString(Chat::SpellFailure, FAILED_TAUNT);
|
||||
}
|
||||
|
||||
if (HasSkillProcs())
|
||||
if (HasSkillProcs()) {
|
||||
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000);
|
||||
}
|
||||
|
||||
if (Success && HasSkillProcSuccess())
|
||||
if (success && HasSkillProcSuccess()) {
|
||||
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::InstillDoubt(Mob *who) {
|
||||
@ -2061,6 +2076,7 @@ void Mob::InstillDoubt(Mob *who) {
|
||||
|
||||
//I think this formula needs work
|
||||
int value = 0;
|
||||
bool success = false;
|
||||
|
||||
//user's bonus
|
||||
value += GetSkill(EQ::skills::SkillIntimidation) + GetCHA() / 4;
|
||||
@ -2073,6 +2089,7 @@ void Mob::InstillDoubt(Mob *who) {
|
||||
//cast fear on them... should prolly be a different spell
|
||||
//and should be un-resistable.
|
||||
SpellOnTarget(229, who, 0, true, -2000);
|
||||
success = true;
|
||||
//is there a success message?
|
||||
} else {
|
||||
MessageString(Chat::LightBlue,NOT_SCARING);
|
||||
@ -2083,6 +2100,14 @@ void Mob::InstillDoubt(Mob *who) {
|
||||
entity_list.AEAttack(target, 50);
|
||||
}*/
|
||||
}
|
||||
|
||||
if (HasSkillProcs()) {
|
||||
TrySkillProc(who, EQ::skills::SkillIntimidation, InstillDoubtReuseTime * 1000);
|
||||
}
|
||||
|
||||
if (success && HasSkillProcSuccess()) {
|
||||
TrySkillProc(who, EQ::skills::SkillIntimidation, InstillDoubtReuseTime * 1000, true);
|
||||
}
|
||||
}
|
||||
|
||||
int Mob::TryHeadShot(Mob *defender, EQ::skills::SkillType skillInUse)
|
||||
@ -2228,12 +2253,12 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQ::skills::Sk
|
||||
}
|
||||
|
||||
other->AddToHateList(this, hate, 0);
|
||||
if (damage > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SKILL] == skillinuse &&
|
||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID])) {
|
||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
|
||||
if (damage > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SKILL] == skillinuse &&
|
||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID])) {
|
||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] / 1000.0f;
|
||||
if (zone->random.Roll(chance))
|
||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty);
|
||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
|
||||
}
|
||||
|
||||
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
|
||||
@ -2241,11 +2266,13 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQ::skills::Sk
|
||||
if (HasDied())
|
||||
return;
|
||||
|
||||
if (CanSkillProc && HasSkillProcs())
|
||||
if (CanSkillProc && HasSkillProcs()) {
|
||||
TrySkillProc(other, skillinuse, ReuseTime);
|
||||
}
|
||||
|
||||
if (CanSkillProc && (damage > 0) && HasSkillProcSuccess())
|
||||
if (CanSkillProc && (damage > 0) && HasSkillProcSuccess()) {
|
||||
TrySkillProc(other, skillinuse, ReuseTime, true);
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::CanDoSpecialAttack(Mob *other) {
|
||||
|
||||
@ -1821,7 +1821,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Weapon Proc: %s (id %d)", spells[effect_value].name, procid);
|
||||
#endif
|
||||
AddProcToWeapon(procid, false, 100 + spells[spell_id].limit_value[i], spell_id, caster_level, GetProcLimitTimer(spell_id, SE_WeaponProc));
|
||||
AddProcToWeapon(procid, false, 100 + spells[spell_id].limit_value[i], spell_id, caster_level, GetProcLimitTimer(spell_id, ProcType::MELEE_PROC));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1831,7 +1831,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Ranged Proc: %+i", effect_value);
|
||||
#endif
|
||||
AddRangedProc(procid, 100 + spells[spell_id].limit_value[i], spell_id, GetProcLimitTimer(spell_id, SE_RangedProc));
|
||||
AddRangedProc(procid, 100 + spells[spell_id].limit_value[i], spell_id, GetProcLimitTimer(spell_id, ProcType::RANGED_PROC));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1841,7 +1841,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Defensive Proc: %s (id %d)", spells[effect_value].name, procid);
|
||||
#endif
|
||||
AddDefensiveProc(procid, 100 + spells[spell_id].limit_value[i], spell_id, GetProcLimitTimer(spell_id, SE_DefensiveProc));
|
||||
AddDefensiveProc(procid, 100 + spells[spell_id].limit_value[i], spell_id, GetProcLimitTimer(spell_id, ProcType::DEFENSIVE_PROC));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3156,7 +3156,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
||||
case SE_LimitSpellClass:
|
||||
case SE_Sanctuary:
|
||||
case SE_PetMeleeMitigation:
|
||||
case SE_SkillProc:
|
||||
case SE_SkillProcAttempt:
|
||||
case SE_SkillProcSuccess:
|
||||
case SE_SpellResistReduction:
|
||||
case SE_Duration_HP_Pct:
|
||||
@ -8518,6 +8518,87 @@ bool Mob::PassCharmTargetRestriction(Mob *target) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mob::PassLimitToSkill(EQ::skills::SkillType skill, int32 spell_id, int proc_type, int aa_id)
|
||||
{
|
||||
/*
|
||||
Check if SE_AddMeleProc or SE_RangedProc have a skill limiter. Passes automatically if no skill limiters present.
|
||||
*/
|
||||
int32 proc_type_spaid = 0;
|
||||
if (proc_type == ProcType::MELEE_PROC) {
|
||||
proc_type_spaid = SE_AddMeleeProc;
|
||||
}
|
||||
if (proc_type == ProcType::RANGED_PROC) {
|
||||
proc_type_spaid = SE_RangedProc;
|
||||
}
|
||||
|
||||
bool match_proc_type = false;
|
||||
bool has_limit_check = false;
|
||||
|
||||
if (!aa_id && spellbonuses.LimitToSkill[EQ::skills::HIGHEST_SKILL + 3]) {
|
||||
|
||||
if (spell_id == SPELL_UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (spells[spell_id].effect_id[i] == proc_type_spaid) {
|
||||
match_proc_type = true;
|
||||
}
|
||||
if (match_proc_type && spells[spell_id].effect_id[i] == SE_LimitToSkill && spells[spell_id].base_value[i] <= EQ::skills::HIGHEST_SKILL) {
|
||||
|
||||
has_limit_check = true;
|
||||
if (spells[spell_id].base_value[i] == skill) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (aabonuses.LimitToSkill[EQ::skills::HIGHEST_SKILL + 3]) {
|
||||
|
||||
int rank_id = 1;
|
||||
AA::Rank *rank = zone->GetAlternateAdvancementRank(aa_id);
|
||||
|
||||
if (!rank) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AA::Ability *ability_in = rank->base_ability;
|
||||
if (!ability_in) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto &aa : aa_ranks) {
|
||||
auto ability_rank = zone->GetAlternateAdvancementAbilityAndRank(aa.first, aa.second.first);
|
||||
auto ability = ability_rank.first;
|
||||
auto rank = ability_rank.second;
|
||||
|
||||
if (!ability) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto &effect : rank->effects) {
|
||||
if (effect.effect_id == proc_type_spaid) {
|
||||
match_proc_type = true;
|
||||
}
|
||||
|
||||
if (match_proc_type && effect.effect_id == SE_LimitToSkill && effect.base_value <= EQ::skills::HIGHEST_SKILL) {
|
||||
has_limit_check = true;
|
||||
if (effect.base_value == skill) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_limit_check) {
|
||||
return false; //Limit was found, but not matched, fail.
|
||||
}
|
||||
else {
|
||||
return true; //No limit is present, automatically pass.
|
||||
}
|
||||
}
|
||||
|
||||
bool Mob::CanFocusUseRandomEffectivenessByType(focusType type)
|
||||
{
|
||||
switch (type) {
|
||||
@ -8760,7 +8841,7 @@ bool Mob::IsProcLimitTimerActive(int32 base_spell_id, uint32 proc_reuse_time, in
|
||||
|
||||
for (int i = 0; i < MAX_PROC_LIMIT_TIMERS; i++) {
|
||||
|
||||
if (proc_type == SE_WeaponProc) {
|
||||
if (proc_type == ProcType::MELEE_PROC) {
|
||||
if (spell_proclimit_spellid[i] == base_spell_id) {
|
||||
if (spell_proclimit_timer[i].Enabled()) {
|
||||
if (spell_proclimit_timer[i].GetRemainingTime() > 0) {
|
||||
@ -8773,7 +8854,7 @@ bool Mob::IsProcLimitTimerActive(int32 base_spell_id, uint32 proc_reuse_time, in
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (proc_type == SE_RangedProc) {
|
||||
else if (proc_type == ProcType::RANGED_PROC) {
|
||||
if (ranged_proclimit_spellid[i] == base_spell_id) {
|
||||
if (ranged_proclimit_timer[i].Enabled()) {
|
||||
if (ranged_proclimit_timer[i].GetRemainingTime() > 0) {
|
||||
@ -8786,7 +8867,7 @@ bool Mob::IsProcLimitTimerActive(int32 base_spell_id, uint32 proc_reuse_time, in
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (proc_type == SE_DefensiveProc) {
|
||||
else if (proc_type == ProcType::DEFENSIVE_PROC) {
|
||||
if (def_proclimit_spellid[i] == base_spell_id) {
|
||||
if (def_proclimit_timer[i].Enabled()) {
|
||||
if (def_proclimit_timer[i].GetRemainingTime() > 0) {
|
||||
@ -8813,7 +8894,7 @@ void Mob::SetProcLimitTimer(int32 base_spell_id, uint32 proc_reuse_time, int pro
|
||||
|
||||
for (int i = 0; i < MAX_PROC_LIMIT_TIMERS; i++) {
|
||||
|
||||
if (proc_type == SE_WeaponProc) {
|
||||
if (proc_type == ProcType::MELEE_PROC) {
|
||||
if (!spell_proclimit_spellid[i] && !is_set) {
|
||||
spell_proclimit_spellid[i] = base_spell_id;
|
||||
spell_proclimit_timer[i].SetTimer(proc_reuse_time);
|
||||
@ -8825,7 +8906,7 @@ void Mob::SetProcLimitTimer(int32 base_spell_id, uint32 proc_reuse_time, int pro
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_RangedProc) {
|
||||
if (proc_type == ProcType::RANGED_PROC) {
|
||||
if (!ranged_proclimit_spellid[i] && !is_set) {
|
||||
ranged_proclimit_spellid[i] = base_spell_id;
|
||||
ranged_proclimit_timer[i].SetTimer(proc_reuse_time);
|
||||
@ -8837,7 +8918,7 @@ void Mob::SetProcLimitTimer(int32 base_spell_id, uint32 proc_reuse_time, int pro
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_type == SE_DefensiveProc) {
|
||||
if (proc_type == ProcType::DEFENSIVE_PROC) {
|
||||
if (!def_proclimit_spellid[i] && !is_set) {
|
||||
def_proclimit_spellid[i] = base_spell_id;
|
||||
def_proclimit_timer[i].SetTimer(proc_reuse_time);
|
||||
|
||||
@ -1014,8 +1014,6 @@ void Mob::TuneMeleeMitigation(Mob *attacker, DamageHitInfo &hit, int ac_override
|
||||
|
||||
// +0.5 for rounding, min to 1 dmg
|
||||
hit.damage_done = std::max(static_cast<int>(roll * static_cast<double>(hit.base_damage) + 0.5), 1);
|
||||
|
||||
//Shout("mitigation %d vs offense %d. base %d rolled %f damage %d", mitigation, hit.offense, hit.base_damage, roll, hit.damage_done);
|
||||
}
|
||||
|
||||
int Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac)
|
||||
@ -1093,10 +1091,6 @@ int Mob::TuneACSum(bool skip_caps, int ac_override, int add_ac)
|
||||
auto over_cap = ac - softcap;
|
||||
ac = softcap + (over_cap * returns);
|
||||
}
|
||||
//Shout("ACSum ac %i softcap %i returns %.2f", ac, softcap, static_cast<float>(returns));
|
||||
}
|
||||
else {
|
||||
//Shout("ACSum ac %i", ac);
|
||||
}
|
||||
|
||||
return ac;
|
||||
@ -1384,7 +1378,6 @@ bool Mob::TuneCheckHitChance(Mob* other, DamageHitInfo &hit, int avoidance_overr
|
||||
|
||||
Mob *attacker = other;
|
||||
Mob *defender = this;
|
||||
//Shout("CheckHitChance(%s) attacked by %s", defender->GetName(), attacker->GetName());
|
||||
|
||||
if (defender->IsClient() && defender->CastToClient()->IsSitting())
|
||||
return true;
|
||||
@ -1402,7 +1395,6 @@ bool Mob::TuneCheckHitChance(Mob* other, DamageHitInfo &hit, int avoidance_overr
|
||||
// Then your chance to simply avoid the attack is checked (defender's avoidance roll beat the attacker's accuracy roll.)
|
||||
int tohit_roll = zone->random.Roll0(accuracy);
|
||||
int avoid_roll = zone->random.Roll0(avoidance);
|
||||
//Shout("CheckHitChance accuracy(%d => %d) avoidance(%d => %d)", accuracy, tohit_roll, avoidance, avoid_roll);
|
||||
|
||||
// tie breaker? Don't want to be biased any one way
|
||||
if (tohit_roll == avoid_roll)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user