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;
|
bool use_next_timer = false;
|
||||||
for (int i = 0; i < EFFECT_COUNT; ++i) {
|
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) {
|
if (spells[spell_id].effect_id[i] == SE_WeaponProc || spells[spell_id].effect_id[i] == SE_AddMeleeProc) {
|
||||||
use_next_timer = true;
|
use_next_timer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc_type == SE_RangedProc) {
|
if (proc_type == ProcType::RANGED_PROC) {
|
||||||
if (spells[spell_id].effect_id[i] == SE_RangedProc) {
|
if (spells[spell_id].effect_id[i] == SE_RangedProc) {
|
||||||
use_next_timer = true;
|
use_next_timer = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc_type == SE_DefensiveProc) {
|
if (proc_type == ProcType::DEFENSIVE_PROC) {
|
||||||
if (spells[spell_id].effect_id[i] == SE_DefensiveProc) {
|
if (spells[spell_id].effect_id[i] == SE_DefensiveProc) {
|
||||||
use_next_timer = true;
|
use_next_timer = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -533,6 +533,15 @@ enum ReflectSpellType
|
|||||||
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
|
RELFECT_ALL_SINGLE_TARGET_SPELLS = 3,
|
||||||
REFLECT_ALL_SPELLS = 4,
|
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
|
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_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_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_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_SkillProcAttempt 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_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_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_PostEffect 430 // *not implemented - Fear of the Dark(27641) - Alters vision
|
||||||
//#define SE_PostEffectData 431 // *not implemented - Fear of the Dark(27641) - Alters vision
|
//#define SE_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
|
////// Send Attack Damage
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SKILL] == my_hit.skill &&
|
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::SKILLPROC_SPELL_ID])) {
|
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID])) {
|
||||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
|
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] / 1000.0f;
|
||||||
if (zone->random.Roll(chance))
|
if (zone->random.Roll(chance))
|
||||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
||||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty);
|
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);
|
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);
|
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();
|
CommonBreakInvisibleFromCombat();
|
||||||
|
|
||||||
if (GetTarget())
|
if (GetTarget())
|
||||||
@ -3471,7 +3468,6 @@ bool Mob::HasDefensiveProcs() const
|
|||||||
|
|
||||||
bool Mob::HasSkillProcs() const
|
bool Mob::HasSkillProcs() const
|
||||||
{
|
{
|
||||||
|
|
||||||
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||||
if (spellbonuses.SkillProc[i] || itembonuses.SkillProc[i] || aabonuses.SkillProc[i])
|
if (spellbonuses.SkillProc[i] || itembonuses.SkillProc[i] || aabonuses.SkillProc[i])
|
||||||
return true;
|
return true;
|
||||||
@ -4164,12 +4160,12 @@ void Mob::TryDefensiveProc(Mob *on, uint16 hand) {
|
|||||||
//Spell Procs and Quest added procs
|
//Spell Procs and Quest added procs
|
||||||
for (int i = 0; i < MAX_PROCS; i++) {
|
for (int i = 0; i < MAX_PROCS; i++) {
|
||||||
if (IsValidSpell(DefensiveProcs[i].spellID)) {
|
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);
|
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance) / 100.0f);
|
||||||
if (zone->random.Roll(chance)) {
|
if (zone->random.Roll(chance)) {
|
||||||
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
|
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
|
||||||
CheckNumHitsRemaining(NumHit::DefensiveSpellProcs, 0, DefensiveProcs[i].base_spellID);
|
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
|
//AA Procs
|
||||||
if (IsClient()){
|
if (IsClient()){
|
||||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||||
int32 aa_rank_id = aabonuses.DefensiveProc[i];
|
int32 aa_rank_id = aabonuses.DefensiveProc[i + +SBIndex::COMBAT_PROC_ORIGIN_ID];
|
||||||
int32 aa_spell_id = aabonuses.DefensiveProc[i + 1];
|
int32 aa_spell_id = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
|
||||||
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + 2];
|
int32 aa_proc_chance = 100 + aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||||
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + 3];
|
uint32 aa_proc_reuse_timer = aabonuses.DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER];
|
||||||
|
|
||||||
if (aa_rank_id) {
|
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);
|
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
|
||||||
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
|
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
|
||||||
ExecWeaponProc(nullptr, aa_spell_id, on);
|
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) {
|
if (!on) {
|
||||||
SetTarget(nullptr);
|
SetTarget(nullptr);
|
||||||
LogError("A null Mob object was passed to Mob::TryWeaponProc for evaluation!");
|
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;
|
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) {
|
if (!weapon_g) {
|
||||||
TrySpellProc(nullptr, (const EQ::ItemData*)nullptr, on);
|
TrySpellProc(nullptr, (const EQ::ItemData*)nullptr, on);
|
||||||
return;
|
return;
|
||||||
@ -4253,7 +4257,7 @@ void Mob::TryWeaponProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon
|
|||||||
// Try innate proc on weapon
|
// Try innate proc on weapon
|
||||||
// We can proc once here, either weapon or one aug
|
// We can proc once here, either weapon or one aug
|
||||||
bool proced = false; // silly bool to prevent augs from going if weapon does
|
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)) {
|
if (weapon->Proc.Type == EQ::item::ItemEffectCombatProc && IsValidSpell(weapon->Proc.Effect)) {
|
||||||
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
|
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
|
||||||
static_cast<float>(weapon->ProcRate)) / 100.0f;
|
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;
|
float ProcChance = 0.0f;
|
||||||
ProcChance = GetProcChances(ProcBonus, hand);
|
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;
|
ProcChance /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
bool rangedattk = false;
|
bool rangedattk = false;
|
||||||
if (weapon && hand == EQ::invslot::slotRange) {
|
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;
|
rangedattk = true;
|
||||||
|
}
|
||||||
|
|
||||||
int16 poison_slot=-1;
|
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
|
continue; // If pets ever can proc from off hand, this will need to change
|
||||||
|
|
||||||
if (SpellProcs[i].base_spellID == POISON_PROC &&
|
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.
|
continue; // Old school poison will only proc with 1HP equipped.
|
||||||
|
}
|
||||||
|
|
||||||
// Not ranged
|
// Not ranged
|
||||||
if (!rangedattk) {
|
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
|
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);
|
float chance = ProcChance * (static_cast<float>(SpellProcs[i].chance) / 100.0f);
|
||||||
if (zone->random.Roll(chance)) {
|
if (zone->random.Roll(chance)) {
|
||||||
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
|
LogCombat("Spell proc [{}] procing spell [{}] ([{}] percent chance)", i, SpellProcs[i].spellID, chance);
|
||||||
SendBeginCast(SpellProcs[i].spellID, 0);
|
SendBeginCast(SpellProcs[i].spellID, 0);
|
||||||
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
|
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);
|
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, SpellProcs[i].base_spellID);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -4395,13 +4411,15 @@ void Mob::TrySpellProc(const EQ::ItemInstance *inst, const EQ::ItemData *weapon,
|
|||||||
// ranged spell procs (buffs)
|
// ranged spell procs (buffs)
|
||||||
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
|
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);
|
float chance = ProcChance * (static_cast<float>(RangedProcs[i].chance) / 100.0f);
|
||||||
if (zone->random.Roll(chance)) {
|
if (zone->random.Roll(chance)) {
|
||||||
LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
|
LogCombat("Ranged proc [{}] procing spell [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
|
||||||
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
|
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
|
||||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, RangedProcs[i].base_spellID);
|
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 {
|
else {
|
||||||
LogCombat("Ranged proc [{}] failed to proc [{}] ([{}] percent chance)", i, RangedProcs[i].spellID, chance);
|
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()) {
|
if (IsClient()) {
|
||||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
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) {
|
if (!rangedattk) {
|
||||||
|
|
||||||
aa_rank_id = aabonuses.SpellProc[i];
|
aa_rank_id = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID];
|
||||||
aa_spell_id = aabonuses.SpellProc[i + 1];
|
aa_spell_id = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
|
||||||
aa_proc_chance += aabonuses.SpellProc[i + 2];
|
aa_proc_chance += aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||||
aa_proc_reuse_timer = aabonuses.SpellProc[i + 3];
|
aa_proc_reuse_timer = aabonuses.SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||||
proc_type = SE_WeaponProc;
|
proc_type = ProcType::MELEE_PROC;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
aa_rank_id = aabonuses.RangedProc[i];
|
aa_rank_id = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID];
|
||||||
aa_spell_id = aabonuses.RangedProc[i + 1];
|
aa_spell_id = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_SPELL_ID];
|
||||||
aa_proc_chance += aabonuses.RangedProc[i + 2];
|
aa_proc_chance += aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||||
aa_proc_reuse_timer = aabonuses.RangedProc[i + 3];
|
aa_proc_reuse_timer = aabonuses.RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD];
|
||||||
proc_type = SE_RangedProc;
|
proc_type = ProcType::RANGED_PROC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aa_rank_id) {
|
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);
|
float chance = ProcChance * (static_cast<float>(aa_proc_chance) / 100.0f);
|
||||||
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
|
if (zone->random.Roll(chance) && IsValidSpell(aa_spell_id)) {
|
||||||
LogCombat("AA proc [{}] procing spell [{}] ([{}] percent chance)", aa_rank_id, aa_spell_id, chance);
|
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.
|
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);
|
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;
|
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);
|
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) {
|
if (!on) {
|
||||||
@ -5049,12 +5069,19 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill])
|
if (on->HasDied()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*Allow one proc from each (Spell/Item/AA)
|
if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill]) {
|
||||||
Kayen: Due to limited avialability of effects on live it is too difficult
|
return;
|
||||||
to confirm how they stack at this time, will adjust formula when more data is avialablle to test.*/
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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;
|
bool CanProc = true;
|
||||||
|
|
||||||
uint16 base_spell_id = 0;
|
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]) {
|
if (spellbonuses.LimitToSkill[skill]) {
|
||||||
|
|
||||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||||
if (CanProc &&
|
if (CanProc &&
|
||||||
((!Success && spellbonuses.SkillProc[e] && IsValidSpell(spellbonuses.SkillProc[e]))
|
((!Success && spellbonuses.SkillProc[i] && IsValidSpell(spellbonuses.SkillProc[i]))
|
||||||
|| (Success && spellbonuses.SkillProcSuccess[e] && IsValidSpell(spellbonuses.SkillProcSuccess[e])))) {
|
|| (Success && spellbonuses.SkillProcSuccess[i] && IsValidSpell(spellbonuses.SkillProcSuccess[i])))) {
|
||||||
|
|
||||||
if (Success)
|
if (Success) {
|
||||||
base_spell_id = spellbonuses.SkillProcSuccess[e];
|
base_spell_id = spellbonuses.SkillProcSuccess[i];
|
||||||
else
|
}
|
||||||
base_spell_id = spellbonuses.SkillProc[e];
|
else {
|
||||||
|
base_spell_id = spellbonuses.SkillProc[i];
|
||||||
|
}
|
||||||
|
|
||||||
proc_spell_id = 0;
|
proc_spell_id = 0;
|
||||||
ProcMod = 0;
|
ProcMod = 0;
|
||||||
|
|
||||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
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];
|
proc_spell_id = spells[base_spell_id].base_value[i];
|
||||||
ProcMod = static_cast<float>(spells[base_spell_id].limit_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);
|
float final_chance = chance * (ProcMod / 100.0f);
|
||||||
if (zone->random.Roll(final_chance)) {
|
if (zone->random.Roll(final_chance)) {
|
||||||
ExecWeaponProc(nullptr, proc_spell_id, on);
|
ExecWeaponProc(nullptr, proc_spell_id, on);
|
||||||
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
|
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0, base_spell_id);
|
||||||
base_spell_id);
|
|
||||||
CanProc = false;
|
CanProc = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5114,21 +5142,23 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
|||||||
|
|
||||||
if (itembonuses.LimitToSkill[skill]) {
|
if (itembonuses.LimitToSkill[skill]) {
|
||||||
CanProc = true;
|
CanProc = true;
|
||||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||||
if (CanProc &&
|
if (CanProc &&
|
||||||
((!Success && itembonuses.SkillProc[e] && IsValidSpell(itembonuses.SkillProc[e]))
|
((!Success && itembonuses.SkillProc[i] && IsValidSpell(itembonuses.SkillProc[i]))
|
||||||
|| (Success && itembonuses.SkillProcSuccess[e] && IsValidSpell(itembonuses.SkillProcSuccess[e])))) {
|
|| (Success && itembonuses.SkillProcSuccess[i] && IsValidSpell(itembonuses.SkillProcSuccess[i])))) {
|
||||||
|
|
||||||
if (Success)
|
if (Success) {
|
||||||
base_spell_id = itembonuses.SkillProcSuccess[e];
|
base_spell_id = itembonuses.SkillProcSuccess[i];
|
||||||
else
|
}
|
||||||
base_spell_id = itembonuses.SkillProc[e];
|
else {
|
||||||
|
base_spell_id = itembonuses.SkillProc[i];
|
||||||
|
}
|
||||||
|
|
||||||
proc_spell_id = 0;
|
proc_spell_id = 0;
|
||||||
ProcMod = 0;
|
ProcMod = 0;
|
||||||
|
|
||||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
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];
|
proc_spell_id = spells[base_spell_id].base_value[i];
|
||||||
ProcMod = static_cast<float>(spells[base_spell_id].limit_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;
|
int32 limit_value = 0;
|
||||||
uint32 slot = 0;
|
uint32 slot = 0;
|
||||||
|
|
||||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
for (int i = 0; i < MAX_SKILL_PROCS; i++) {
|
||||||
if (CanProc &&
|
if (CanProc &&
|
||||||
((!Success && aabonuses.SkillProc[e])
|
((!Success && aabonuses.SkillProc[i])
|
||||||
|| (Success && aabonuses.SkillProcSuccess[e]))) {
|
|| (Success && aabonuses.SkillProcSuccess[i]))) {
|
||||||
int aaid = 0;
|
int aaid = 0;
|
||||||
|
|
||||||
if (Success)
|
if (Success)
|
||||||
base_spell_id = aabonuses.SkillProcSuccess[e];
|
base_spell_id = aabonuses.SkillProcSuccess[i];
|
||||||
else
|
else
|
||||||
base_spell_id = aabonuses.SkillProc[e];
|
base_spell_id = aabonuses.SkillProc[i];
|
||||||
|
|
||||||
proc_spell_id = 0;
|
proc_spell_id = 0;
|
||||||
ProcMod = 0;
|
ProcMod = 0;
|
||||||
@ -5190,7 +5220,7 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, ui
|
|||||||
limit_value = effect.limit_value;
|
limit_value = effect.limit_value;
|
||||||
slot = effect.slot;
|
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;
|
proc_spell_id = base_value;
|
||||||
ProcMod = static_cast<float>(limit_value);
|
ProcMod = static_cast<float>(limit_value);
|
||||||
}
|
}
|
||||||
@ -5225,12 +5255,14 @@ float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
|
|||||||
if (!ReuseTime && hand) {
|
if (!ReuseTime && hand) {
|
||||||
weapon_speed = GetWeaponSpeedbyHand(hand);
|
weapon_speed = GetWeaponSpeedbyHand(hand);
|
||||||
ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
|
ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
|
||||||
if (hand == EQ::invslot::slotSecondary)
|
if (hand == EQ::invslot::slotSecondary) {
|
||||||
ProcChance /= 2;
|
ProcChance /= 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else {
|
||||||
ProcChance = static_cast<float>(ReuseTime) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
|
ProcChance = static_cast<float>(ReuseTime) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
return ProcChance;
|
return ProcChance;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1074,11 +1074,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
case SE_WeaponProc:
|
case SE_WeaponProc:
|
||||||
case SE_AddMeleeProc:
|
case SE_AddMeleeProc:
|
||||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||||
if (!newbon->SpellProc[i]) {
|
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
||||||
newbon->SpellProc[i] = rank.id; //aa rank id
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
||||||
newbon->SpellProc[i + 1] = base_value; //proc spell id
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
||||||
newbon->SpellProc[i + 2] = limit_value; //proc rate modifer
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
||||||
newbon->SpellProc[i + 3] = 0; //Lock out Timer
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1086,11 +1086,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
|
|
||||||
case SE_RangedProc:
|
case SE_RangedProc:
|
||||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||||
if (!newbon->RangedProc[i]) {
|
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
||||||
newbon->RangedProc[i] = rank.id; //aa rank id
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
||||||
newbon->RangedProc[i + 1] = base_value; //proc spell id
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
||||||
newbon->RangedProc[i + 2] = limit_value; //proc rate modifer
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
||||||
newbon->RangedProc[i + 3] = 0; //Lock out Timer
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1098,11 +1098,11 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
|
|
||||||
case SE_DefensiveProc:
|
case SE_DefensiveProc:
|
||||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||||
if (!newbon->DefensiveProc[i]) {
|
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID]) {
|
||||||
newbon->DefensiveProc[i] = rank.id; //aa rank id
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] = rank.id; //aa rank id
|
||||||
newbon->DefensiveProc[i + 1] = base_value; //proc spell id
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_SPELL_ID] = base_value; //proc spell id
|
||||||
newbon->DefensiveProc[i + 2] = limit_value; //proc rate modifer
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_RATE_MOD] = limit_value; //proc rate modifer
|
||||||
newbon->DefensiveProc[i + 3] = 0; //Lock out Timer
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = 0; //Lock out Timer
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1118,23 +1118,23 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
newbon->Proc_Timer_Modifier = true;
|
newbon->Proc_Timer_Modifier = true;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
for (int i = 0; i < MAX_AA_PROCS; i += 4) {
|
||||||
if (newbon->SpellProc[i] == rank.id) {
|
if (newbon->SpellProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
||||||
if (!newbon->SpellProc[i + 3]) {
|
if (!newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
||||||
newbon->SpellProc[i + 3] = limit_value;//Lock out Timer
|
newbon->SpellProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newbon->RangedProc[i] == rank.id) {
|
if (newbon->RangedProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
||||||
if (!newbon->RangedProc[i + 3]) {
|
if (!newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
||||||
newbon->RangedProc[i + 3] = limit_value;//Lock out Timer
|
newbon->RangedProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newbon->DefensiveProc[i] == rank.id) {
|
if (newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_ORIGIN_ID] == rank.id) {
|
||||||
if (!newbon->DefensiveProc[i + 3]) {
|
if (!newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER]) {
|
||||||
newbon->DefensiveProc[i + 3] = limit_value;//Lock out Timer
|
newbon->DefensiveProc[i + SBIndex::COMBAT_PROC_REUSE_TIMER] = limit_value;//Lock out Timer
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1208,9 +1208,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
|
|
||||||
case SE_SkillAttackProc: {
|
case SE_SkillAttackProc: {
|
||||||
// You can only have one of these per client. [AA Dragon Punch]
|
// 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::SKILLATK_PROC_CHANCE] = base_value; // Chance base 1000 = 100% proc rate
|
||||||
newbon->SkillAttackProc[SBIndex::SKILLPROC_SKILL] = limit_value; // Skill to Proc Off
|
newbon->SkillAttackProc[SBIndex::SKILLATK_PROC_SKILL] = limit_value; // Skill to Proc Off
|
||||||
newbon->SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID] = rank.spell; // spell to proc
|
newbon->SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID] = rank.spell; // spell to proc
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1458,15 +1458,19 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_LimitToSkill: {
|
case SE_LimitToSkill: {
|
||||||
|
|
||||||
// Bad data or unsupported new skill
|
// Bad data or unsupported new skill
|
||||||
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
if (base_value > EQ::skills::HIGHEST_SKILL) {
|
||||||
break;
|
break;
|
||||||
if (base_value <= EQ::skills::HIGHEST_SKILL)
|
}
|
||||||
|
if (base_value <= EQ::skills::HIGHEST_SKILL) {
|
||||||
newbon->LimitToSkill[base_value] = true;
|
newbon->LimitToSkill[base_value] = true;
|
||||||
|
newbon->LimitToSkill[EQ::skills::HIGHEST_SKILL + 3] = true; //Used as a general exists check
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SE_SkillProc: {
|
case SE_SkillProcAttempt: {
|
||||||
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
for (int e = 0; e < MAX_SKILL_PROCS; e++) {
|
||||||
if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id)
|
if (newbon->SkillProc[e] && newbon->SkillProc[e] == rank.id)
|
||||||
break; // Do not use the same aa id more than once.
|
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:{
|
case SE_LimitToSkill:{
|
||||||
// Bad data or unsupported new skill
|
// Bad data or unsupported new skill
|
||||||
if (limit_value > EQ::skills::HIGHEST_SKILL)
|
if (effect_value > EQ::skills::HIGHEST_SKILL) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
if (effect_value <= EQ::skills::HIGHEST_SKILL){
|
if (effect_value <= EQ::skills::HIGHEST_SKILL){
|
||||||
new_bonus->LimitToSkill[effect_value] = true;
|
new_bonus->LimitToSkill[effect_value] = true;
|
||||||
|
new_bonus->LimitToSkill[EQ::skills::HIGHEST_SKILL + 3] = true; //Used as a general exists check
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SE_SkillProc:{
|
case SE_SkillProcAttempt:{
|
||||||
|
|
||||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
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++)
|
for (int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||||
{
|
{
|
||||||
if (negate_spellbonus) { spellbonuses.SkillProc[e] = effect_value; }
|
if (negate_spellbonus) { spellbonuses.SkillProc[e] = effect_value; }
|
||||||
|
|||||||
@ -3248,7 +3248,7 @@ void Bot::AI_Process()
|
|||||||
TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false);
|
TriggerDefensiveProcs(tar, EQ::invslot::slotPrimary, false);
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
TryWeaponProc(p_item, tar, EQ::invslot::slotPrimary);
|
TryCombatProcs(p_item, tar, EQ::invslot::slotPrimary);
|
||||||
|
|
||||||
// bool tripleSuccess = false;
|
// bool tripleSuccess = false;
|
||||||
|
|
||||||
@ -3337,7 +3337,7 @@ void Bot::AI_Process()
|
|||||||
Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
|
Attack(tar, EQ::invslot::slotSecondary); // Single attack with offhand
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
TryWeaponProc(s_item, tar, EQ::invslot::slotSecondary);
|
TryCombatProcs(s_item, tar, EQ::invslot::slotSecondary);
|
||||||
|
|
||||||
TEST_COMBATANTS();
|
TEST_COMBATANTS();
|
||||||
if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) {
|
if (CanThisClassDoubleAttack() && CheckBotDoubleAttack()) {
|
||||||
|
|||||||
@ -721,17 +721,17 @@ void Client::CompleteConnect()
|
|||||||
case SE_AddMeleeProc:
|
case SE_AddMeleeProc:
|
||||||
case SE_WeaponProc:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case SE_DefensiveProc:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case SE_RangedProc:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -414,7 +414,7 @@ bool Client::Process() {
|
|||||||
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
|
else if (auto_attack_target->GetHP() > -10) // -10 so we can watch people bleed in PvP
|
||||||
{
|
{
|
||||||
EQ::ItemInstance *wpn = GetInv().GetItem(EQ::invslot::slotPrimary);
|
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);
|
TriggerDefensiveProcs(auto_attack_target, EQ::invslot::slotPrimary, false);
|
||||||
|
|
||||||
DoAttackRounds(auto_attack_target, EQ::invslot::slotPrimary);
|
DoAttackRounds(auto_attack_target, EQ::invslot::slotPrimary);
|
||||||
@ -460,7 +460,7 @@ bool Client::Process() {
|
|||||||
CheckIncreaseSkill(EQ::skills::SkillDualWield, auto_attack_target, -10);
|
CheckIncreaseSkill(EQ::skills::SkillDualWield, auto_attack_target, -10);
|
||||||
if (CheckDualWield()) {
|
if (CheckDualWield()) {
|
||||||
EQ::ItemInstance *wpn = GetInv().GetItem(EQ::invslot::slotSecondary);
|
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);
|
DoAttackRounds(auto_attack_target, EQ::invslot::slotSecondary);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -533,7 +533,7 @@ struct StatBonuses {
|
|||||||
int32 Metabolism; // Food/drink consumption rates.
|
int32 Metabolism; // Food/drink consumption rates.
|
||||||
bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others.
|
bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others.
|
||||||
int32 FactionModPct; // Modifies amount of faction gained.
|
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 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs.
|
||||||
uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success.
|
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.
|
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 POSITION_FRONT = 1; // SPA 503-506
|
||||||
constexpr uint16 PET_RAMPAGE_CHANCE = 0; // SPA 464,465
|
constexpr uint16 PET_RAMPAGE_CHANCE = 0; // SPA 464,465
|
||||||
constexpr uint16 PET_RAMPAGE_DMG_MOD = 1; // SPA 465,465
|
constexpr uint16 PET_RAMPAGE_DMG_MOD = 1; // SPA 465,465
|
||||||
constexpr uint16 SKILLPROC_CHANCE = 0; // SPA 427
|
constexpr uint16 SKILLATK_PROC_CHANCE = 0; // SPA 427
|
||||||
constexpr uint16 SKILLPROC_SKILL = 1; // SPA 427
|
constexpr uint16 SKILLATK_PROC_SKILL = 1; // SPA 427
|
||||||
constexpr uint16 SKILLPROC_SPELL_ID = 2; // SPA 427
|
constexpr uint16 SKILLATK_PROC_SPELL_ID = 2; // SPA 427
|
||||||
constexpr uint16 SLAYUNDEAD_RATE_MOD = 0; // SPA 219
|
constexpr uint16 SLAYUNDEAD_RATE_MOD = 0; // SPA 219
|
||||||
constexpr uint16 SLAYUNDEAD_DMG_MOD = 1; // SPA 219
|
constexpr uint16 SLAYUNDEAD_DMG_MOD = 1; // SPA 219
|
||||||
constexpr uint16 DOUBLE_RIPOSTE_CHANCE = 0; // SPA 223
|
constexpr uint16 DOUBLE_RIPOSTE_CHANCE = 0; // SPA 223
|
||||||
@ -688,14 +688,18 @@ namespace SBIndex {
|
|||||||
constexpr uint16 REFLECT_CHANCE = 0; // SPA 158
|
constexpr uint16 REFLECT_CHANCE = 0; // SPA 158
|
||||||
constexpr uint16 REFLECT_RESISTANCE_MOD = 1; // SPA 158
|
constexpr uint16 REFLECT_RESISTANCE_MOD = 1; // SPA 158
|
||||||
constexpr uint16 REFLECT_DMG_EFFECTIVENESS = 2; // 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
|
typedef struct
|
||||||
{
|
{
|
||||||
uint16 spellID;
|
int32 spellID;
|
||||||
uint16 chance;
|
uint16 chance;
|
||||||
uint16 base_spellID;
|
int32 base_spellID;
|
||||||
int level_override;
|
int level_override;
|
||||||
uint32 proc_reuse_time;
|
uint32 proc_reuse_time;
|
||||||
} tProc;
|
} 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)
|
void Mob::TriggerDefensiveProcs(Mob *on, uint16 hand, bool FromSkillProc, int damage)
|
||||||
{
|
{
|
||||||
if (!on)
|
if (!on) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FromSkillProc)
|
if (!FromSkillProc) {
|
||||||
on->TryDefensiveProc(this, hand);
|
on->TryDefensiveProc(this, hand);
|
||||||
|
}
|
||||||
|
|
||||||
//Defensive Skill Procs
|
//Defensive Skill Procs
|
||||||
if (damage < 0 && damage >= -4) {
|
if (damage < 0 && damage >= -4) {
|
||||||
uint16 skillinuse = 0;
|
EQ::skills::SkillType skillinuse = EQ::skills::SkillBlock;
|
||||||
switch (damage) {
|
switch (damage) {
|
||||||
case (-1):
|
case (-1):
|
||||||
skillinuse = EQ::skills::SkillBlock;
|
skillinuse = EQ::skills::SkillBlock;
|
||||||
@ -4240,11 +4242,13 @@ void Mob::TriggerDefensiveProcs(Mob *on, uint16 hand, bool FromSkillProc, int da
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (on->HasSkillProcs())
|
if (on->HasSkillProcs()) {
|
||||||
on->TrySkillProc(this, skillinuse, 0, false, hand, true);
|
on->TrySkillProc(this, skillinuse, 0, false, hand, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (on->HasSkillProcSuccess())
|
if (on && on->HasSkillProcSuccess()) {
|
||||||
on->TrySkillProc(this, skillinuse, 0, true, hand, true);
|
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) {
|
switch (ItemType) {
|
||||||
case EQ::item::ItemType1HSlash:
|
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 Mob::GetWeaponSpeedbyHand(uint16 hand) {
|
||||||
|
|
||||||
uint16 weapon_speed = 0;
|
uint16 weapon_speed = 0;
|
||||||
|
|||||||
@ -701,7 +701,7 @@ public:
|
|||||||
static uint32 RandomTimer(int min, int max);
|
static uint32 RandomTimer(int min, int max);
|
||||||
static uint8 GetDefaultGender(uint16 in_race, uint8 in_gender = 0xFF);
|
static uint8 GetDefaultGender(uint16 in_race, uint8 in_gender = 0xFF);
|
||||||
static bool IsPlayerRace(uint16 in_race);
|
static bool IsPlayerRace(uint16 in_race);
|
||||||
uint16 GetSkillByItemType(int ItemType);
|
EQ::skills::SkillType GetSkillByItemType(int ItemType);
|
||||||
uint8 GetItemTypeBySkill(EQ::skills::SkillType skill);
|
uint8 GetItemTypeBySkill(EQ::skills::SkillType skill);
|
||||||
virtual void MakePet(uint16 spell_id, const char* pettype, const char *petname = nullptr);
|
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);
|
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 IsTargetedFocusEffect(int focus_type);
|
||||||
bool HasPersistDeathIllusion(int32 spell_id);
|
bool HasPersistDeathIllusion(int32 spell_id);
|
||||||
|
|
||||||
|
|
||||||
bool TryDoubleMeleeRoundEffect();
|
bool TryDoubleMeleeRoundEffect();
|
||||||
bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; }
|
bool GetUseDoubleMeleeRoundDmgBonus() const { return use_double_melee_round_dmg_bonus; }
|
||||||
inline void SetUseDoubleMeleeRoundDmgBonus(bool val) { use_double_melee_round_dmg_bonus = val; }
|
inline void SetUseDoubleMeleeRoundDmgBonus(bool val) { use_double_melee_round_dmg_bonus = val; }
|
||||||
@ -1446,13 +1447,13 @@ protected:
|
|||||||
bool spawned;
|
bool spawned;
|
||||||
void CalcSpellBonuses(StatBonuses* newbon);
|
void CalcSpellBonuses(StatBonuses* newbon);
|
||||||
virtual void CalcBonuses();
|
virtual void CalcBonuses();
|
||||||
void TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); // hand = SlotCharm?
|
void TrySkillProc(Mob *on, EQ::skills::SkillType skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false); // hand = SlotCharm?
|
||||||
bool PassLimitToSkill(uint16 spell_id, uint16 skill);
|
bool PassLimitToSkill(EQ::skills::SkillType skill, int32 spell_id, int proc_type, int aa_id=0);
|
||||||
bool PassLimitClass(uint32 Classes_, uint16 Class_);
|
bool PassLimitClass(uint32 Classes_, uint16 Class_);
|
||||||
void TryDefensiveProc(Mob *on, uint16 hand = EQ::invslot::slotPrimary);
|
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 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 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);
|
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 GetProcChances(float ProcBonus, uint16 hand = EQ::invslot::slotPrimary);
|
||||||
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 hand = EQ::invslot::slotPrimary, Mob *on = nullptr);
|
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:
|
case SE_WeaponProc:
|
||||||
// We need to reapply buff based procs
|
// We need to reapply buff based procs
|
||||||
// We need to do this here so suspended pets also regain their 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;
|
break;
|
||||||
case SE_DefensiveProc:
|
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;
|
break;
|
||||||
case SE_RangedProc:
|
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;
|
break;
|
||||||
case SE_Charm:
|
case SE_Charm:
|
||||||
case SE_Rune:
|
case SE_Rune:
|
||||||
|
|||||||
@ -196,12 +196,12 @@ void Mob::DoSpecialAttackDamage(Mob *who, EQ::skills::SkillType skill, int32 bas
|
|||||||
DoAttack(who, my_hit);
|
DoAttack(who, my_hit);
|
||||||
|
|
||||||
who->AddToHateList(this, hate, 0);
|
who->AddToHateList(this, hate, 0);
|
||||||
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SKILL] == skill &&
|
if (my_hit.damage_done > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SKILL] == skill &&
|
||||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID])) {
|
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID])) {
|
||||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
|
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] / 1000.0f;
|
||||||
if (zone->random.Roll(chance))
|
if (zone->random.Roll(chance))
|
||||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], who, EQ::spells::CastingSlot::Item, 0, -1,
|
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID], who, EQ::spells::CastingSlot::Item, 0, -1,
|
||||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty);
|
spells[aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
who->Damage(this, my_hit.damage_done, SPELL_UNKNOWN, skill, false);
|
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())
|
if (HasDied())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (HasSkillProcs())
|
if (HasSkillProcs()) {
|
||||||
TrySkillProc(who, skill, ReuseTime * 1000);
|
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);
|
TrySkillProc(who, skill, ReuseTime * 1000, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should probably refactor this to take the struct not the packet
|
// 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 *_RangeWeapon = nullptr;
|
||||||
const EQ::ItemInstance *_Ammo = 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,
|
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)
|
if (_Ammo && _Ammo->GetItem() && _Ammo->GetItem()->ID == ammo_id)
|
||||||
Ammo = _Ammo;
|
Ammo = _Ammo;
|
||||||
else
|
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);
|
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
|
// Weapon Proc
|
||||||
if (RangeWeapon && other && !other->HasDied())
|
if (RangeWeapon && other && !other->HasDied()) {
|
||||||
TryWeaponProc(RangeWeapon, other, EQ::invslot::slotRange);
|
TryCombatProcs(RangeWeapon, other, EQ::invslot::slotRange);
|
||||||
|
}
|
||||||
|
|
||||||
// Ammo Proc
|
// Ammo Proc, do not try spell procs if from ammo.
|
||||||
if (ammo_lost)
|
if (last_ammo_used) {
|
||||||
TryWeaponProc(nullptr, ammo_lost, other, EQ::invslot::slotRange);
|
TryWeaponProc(nullptr, last_ammo_used, other, EQ::invslot::slotRange);
|
||||||
else if (Ammo && other && !other->HasDied())
|
}
|
||||||
TryWeaponProc(Ammo, 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 (HasSkillProcs() && other && !other->HasDied()) {
|
||||||
if (ReuseTime)
|
if (ReuseTime) {
|
||||||
TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime);
|
TrySkillProc(other, EQ::skills::SkillArchery, ReuseTime);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
TrySkillProc(other, EQ::skills::SkillArchery, 0, false, EQ::invslot::slotRange);
|
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())
|
if (Ammo && Ammo->GetItem())
|
||||||
ProjectileAtk[slot].ammo_id = Ammo->GetItem()->ID;
|
ProjectileAtk[slot].ammo_id = Ammo->GetItem()->ID;
|
||||||
|
|
||||||
ProjectileAtk[slot].ammo_slot = 0;
|
ProjectileAtk[slot].ammo_slot = AmmoSlot;
|
||||||
ProjectileAtk[slot].skill = skillInUse;
|
ProjectileAtk[slot].skill = skillInUse;
|
||||||
ProjectileAtk[slot].speed_mod = speed;
|
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);
|
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
|
//try proc on hits and misses
|
||||||
if(other && !other->HasDied())
|
if (other && !other->HasDied()) {
|
||||||
TrySpellProc(nullptr, (const EQ::ItemData*)nullptr, other, EQ::invslot::slotRange);
|
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);
|
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
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DoThrowingAttackDmg(other, RangeWeapon, item);
|
DoThrowingAttackDmg(other, RangeWeapon, item, 0, 0, 0, 0, 0,ammo_slot);
|
||||||
|
|
||||||
// Consume Ammo, unless Ammo Consumption is disabled
|
// Consume Ammo, unless Ammo Consumption is disabled
|
||||||
if (RuleB(Combat, ThrowingConsumesAmmo)) {
|
if (RuleB(Combat, ThrowingConsumesAmmo)) {
|
||||||
@ -1378,8 +1387,8 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQ::ItemInstance *RangeWeapon, c
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EQ::ItemInstance *_RangeWeapon = nullptr;
|
const EQ::ItemInstance *m_RangeWeapon = nullptr;//throwing weapon
|
||||||
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,
|
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 {
|
} else {
|
||||||
if (!RangeWeapon && range_id) {
|
if (!RangeWeapon && range_id) {
|
||||||
if (IsClient()) {
|
if (IsClient()) {
|
||||||
_RangeWeapon = CastToClient()->m_inv[AmmoSlot];
|
m_RangeWeapon = CastToClient()->m_inv[AmmoSlot];
|
||||||
if (_RangeWeapon && _RangeWeapon->GetItem() &&
|
|
||||||
_RangeWeapon->GetItem()->ID != range_id)
|
if (m_RangeWeapon && m_RangeWeapon->GetItem() && m_RangeWeapon->GetItem()->ID == range_id) {
|
||||||
RangeWeapon = _RangeWeapon;
|
RangeWeapon = m_RangeWeapon;
|
||||||
else
|
}
|
||||||
ammo_lost = database.GetItem(range_id);
|
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;
|
int WDmg = 0;
|
||||||
|
|
||||||
if (!weapon_damage) {
|
if (!weapon_damage) {
|
||||||
if (IsClient() && RangeWeapon)
|
if (IsClient() && RangeWeapon) {
|
||||||
WDmg = GetWeaponDamage(other, RangeWeapon);
|
WDmg = GetWeaponDamage(other, RangeWeapon);
|
||||||
else if (AmmoItem)
|
}
|
||||||
|
else if (AmmoItem) {
|
||||||
WDmg = GetWeaponDamage(other, AmmoItem);
|
WDmg = GetWeaponDamage(other, AmmoItem);
|
||||||
|
}
|
||||||
|
|
||||||
if (LaunchProjectile) {
|
if (LaunchProjectile) {
|
||||||
TryProjectileAttack(other, AmmoItem, EQ::skills::SkillThrowing, WDmg, RangeWeapon,
|
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;
|
WDmg = weapon_damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focus) // From FcBaseEffects
|
if (focus) { // no longer used, keep for quests
|
||||||
WDmg += WDmg * focus / 100;
|
WDmg += WDmg * focus / 100;
|
||||||
|
}
|
||||||
|
|
||||||
int TotalDmg = 0;
|
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);
|
other->Damage(this, TotalDmg, SPELL_UNKNOWN, EQ::skills::SkillThrowing);
|
||||||
|
|
||||||
if (TotalDmg > 0 && HasSkillProcSuccess() && other && !other->HasDied()) {
|
if (other && !other->HasDied()) {
|
||||||
if (ReuseTime)
|
TryCombatProcs(RangeWeapon, other, EQ::invslot::slotRange, last_ammo_used);
|
||||||
TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime);
|
|
||||||
else
|
|
||||||
TrySkillProc(other, EQ::skills::SkillThrowing, 0, true, EQ::invslot::slotRange);
|
|
||||||
}
|
}
|
||||||
// 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 (HasSkillProcs() && other && !other->HasDied()) {
|
||||||
if (ReuseTime)
|
if (ReuseTime) {
|
||||||
TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime);
|
TrySkillProc(other, EQ::skills::SkillThrowing, ReuseTime);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
TrySkillProc(other, EQ::skills::SkillThrowing, 0, false, EQ::invslot::slotRange);
|
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()) {
|
if (IsClient()) {
|
||||||
CastToClient()->CheckIncreaseSkill(EQ::skills::SkillThrowing, GetTarget());
|
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();
|
Mob *hate_top = who->GetHateMost();
|
||||||
|
|
||||||
int level_difference = GetLevel() - who->GetLevel();
|
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.
|
// Support for how taunt worked pre 2000 on LIVE - Can not taunt NPC over your level.
|
||||||
if ((RuleB(Combat, TauntOverLevel) == false) && (level_difference < 0) ||
|
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) {
|
if ((hate_top && hate_top->GetHPRatio() >= 20) || hate_top == nullptr || chance_bonus) {
|
||||||
// SE_Taunt this is flat chance
|
// SE_Taunt this is flat chance
|
||||||
if (chance_bonus) {
|
if (chance_bonus) {
|
||||||
Success = zone->random.Roll(chance_bonus);
|
success = zone->random.Roll(chance_bonus);
|
||||||
} else {
|
} else {
|
||||||
float tauntchance = 50.0f;
|
float tauntchance = 50.0f;
|
||||||
|
|
||||||
@ -2012,14 +2025,14 @@ void Mob::Taunt(NPC *who, bool always_succeed, int chance_bonus, bool FromSpell,
|
|||||||
|
|
||||||
tauntchance /= 100.0f;
|
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) {
|
if (hate_top && hate_top != this) {
|
||||||
int newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1 + bonus_hate;
|
int newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1 + bonus_hate;
|
||||||
who->CastToNPC()->AddToHateList(this, newhate);
|
who->CastToNPC()->AddToHateList(this, newhate);
|
||||||
Success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
who->CastToNPC()->AddToHateList(this, 12);
|
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);
|
MessageString(Chat::SpellFailure, FAILED_TAUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasSkillProcs())
|
if (HasSkillProcs()) {
|
||||||
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000);
|
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
if (Success && HasSkillProcSuccess())
|
if (success && HasSkillProcSuccess()) {
|
||||||
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000, true);
|
TrySkillProc(who, EQ::skills::SkillTaunt, TauntReuseTime * 1000, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::InstillDoubt(Mob *who) {
|
void Mob::InstillDoubt(Mob *who) {
|
||||||
@ -2061,6 +2076,7 @@ void Mob::InstillDoubt(Mob *who) {
|
|||||||
|
|
||||||
//I think this formula needs work
|
//I think this formula needs work
|
||||||
int value = 0;
|
int value = 0;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
//user's bonus
|
//user's bonus
|
||||||
value += GetSkill(EQ::skills::SkillIntimidation) + GetCHA() / 4;
|
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
|
//cast fear on them... should prolly be a different spell
|
||||||
//and should be un-resistable.
|
//and should be un-resistable.
|
||||||
SpellOnTarget(229, who, 0, true, -2000);
|
SpellOnTarget(229, who, 0, true, -2000);
|
||||||
|
success = true;
|
||||||
//is there a success message?
|
//is there a success message?
|
||||||
} else {
|
} else {
|
||||||
MessageString(Chat::LightBlue,NOT_SCARING);
|
MessageString(Chat::LightBlue,NOT_SCARING);
|
||||||
@ -2083,6 +2100,14 @@ void Mob::InstillDoubt(Mob *who) {
|
|||||||
entity_list.AEAttack(target, 50);
|
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)
|
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);
|
other->AddToHateList(this, hate, 0);
|
||||||
if (damage > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SKILL] == skillinuse &&
|
if (damage > 0 && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] && aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SKILL] == skillinuse &&
|
||||||
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID])) {
|
IsValidSpell(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID])) {
|
||||||
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLPROC_CHANCE] / 1000.0f;
|
float chance = aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_CHANCE] / 1000.0f;
|
||||||
if (zone->random.Roll(chance))
|
if (zone->random.Roll(chance))
|
||||||
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
SpellFinished(aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID], other, EQ::spells::CastingSlot::Item, 0, -1,
|
||||||
spells[aabonuses.SkillAttackProc[SBIndex::SKILLPROC_SPELL_ID]].resist_difficulty);
|
spells[aabonuses.SkillAttackProc[SBIndex::SKILLATK_PROC_SPELL_ID]].resist_difficulty);
|
||||||
}
|
}
|
||||||
|
|
||||||
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
|
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse);
|
||||||
@ -2241,11 +2266,13 @@ void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQ::skills::Sk
|
|||||||
if (HasDied())
|
if (HasDied())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (CanSkillProc && HasSkillProcs())
|
if (CanSkillProc && HasSkillProcs()) {
|
||||||
TrySkillProc(other, skillinuse, ReuseTime);
|
TrySkillProc(other, skillinuse, ReuseTime);
|
||||||
|
}
|
||||||
|
|
||||||
if (CanSkillProc && (damage > 0) && HasSkillProcSuccess())
|
if (CanSkillProc && (damage > 0) && HasSkillProcSuccess()) {
|
||||||
TrySkillProc(other, skillinuse, ReuseTime, true);
|
TrySkillProc(other, skillinuse, ReuseTime, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::CanDoSpecialAttack(Mob *other) {
|
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
|
#ifdef SPELL_EFFECT_SPAM
|
||||||
snprintf(effect_desc, _EDLEN, "Weapon Proc: %s (id %d)", spells[effect_value].name, procid);
|
snprintf(effect_desc, _EDLEN, "Weapon Proc: %s (id %d)", spells[effect_value].name, procid);
|
||||||
#endif
|
#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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1831,7 +1831,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
#ifdef SPELL_EFFECT_SPAM
|
#ifdef SPELL_EFFECT_SPAM
|
||||||
snprintf(effect_desc, _EDLEN, "Ranged Proc: %+i", effect_value);
|
snprintf(effect_desc, _EDLEN, "Ranged Proc: %+i", effect_value);
|
||||||
#endif
|
#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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1841,7 +1841,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
#ifdef SPELL_EFFECT_SPAM
|
#ifdef SPELL_EFFECT_SPAM
|
||||||
snprintf(effect_desc, _EDLEN, "Defensive Proc: %s (id %d)", spells[effect_value].name, procid);
|
snprintf(effect_desc, _EDLEN, "Defensive Proc: %s (id %d)", spells[effect_value].name, procid);
|
||||||
#endif
|
#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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3156,7 +3156,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
case SE_LimitSpellClass:
|
case SE_LimitSpellClass:
|
||||||
case SE_Sanctuary:
|
case SE_Sanctuary:
|
||||||
case SE_PetMeleeMitigation:
|
case SE_PetMeleeMitigation:
|
||||||
case SE_SkillProc:
|
case SE_SkillProcAttempt:
|
||||||
case SE_SkillProcSuccess:
|
case SE_SkillProcSuccess:
|
||||||
case SE_SpellResistReduction:
|
case SE_SpellResistReduction:
|
||||||
case SE_Duration_HP_Pct:
|
case SE_Duration_HP_Pct:
|
||||||
@ -8518,6 +8518,87 @@ bool Mob::PassCharmTargetRestriction(Mob *target) {
|
|||||||
return true;
|
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)
|
bool Mob::CanFocusUseRandomEffectivenessByType(focusType type)
|
||||||
{
|
{
|
||||||
switch (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++) {
|
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_spellid[i] == base_spell_id) {
|
||||||
if (spell_proclimit_timer[i].Enabled()) {
|
if (spell_proclimit_timer[i].Enabled()) {
|
||||||
if (spell_proclimit_timer[i].GetRemainingTime() > 0) {
|
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_spellid[i] == base_spell_id) {
|
||||||
if (ranged_proclimit_timer[i].Enabled()) {
|
if (ranged_proclimit_timer[i].Enabled()) {
|
||||||
if (ranged_proclimit_timer[i].GetRemainingTime() > 0) {
|
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_spellid[i] == base_spell_id) {
|
||||||
if (def_proclimit_timer[i].Enabled()) {
|
if (def_proclimit_timer[i].Enabled()) {
|
||||||
if (def_proclimit_timer[i].GetRemainingTime() > 0) {
|
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++) {
|
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) {
|
if (!spell_proclimit_spellid[i] && !is_set) {
|
||||||
spell_proclimit_spellid[i] = base_spell_id;
|
spell_proclimit_spellid[i] = base_spell_id;
|
||||||
spell_proclimit_timer[i].SetTimer(proc_reuse_time);
|
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) {
|
if (!ranged_proclimit_spellid[i] && !is_set) {
|
||||||
ranged_proclimit_spellid[i] = base_spell_id;
|
ranged_proclimit_spellid[i] = base_spell_id;
|
||||||
ranged_proclimit_timer[i].SetTimer(proc_reuse_time);
|
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) {
|
if (!def_proclimit_spellid[i] && !is_set) {
|
||||||
def_proclimit_spellid[i] = base_spell_id;
|
def_proclimit_spellid[i] = base_spell_id;
|
||||||
def_proclimit_timer[i].SetTimer(proc_reuse_time);
|
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
|
// +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);
|
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)
|
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;
|
auto over_cap = ac - softcap;
|
||||||
ac = softcap + (over_cap * returns);
|
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;
|
return ac;
|
||||||
@ -1384,7 +1378,6 @@ bool Mob::TuneCheckHitChance(Mob* other, DamageHitInfo &hit, int avoidance_overr
|
|||||||
|
|
||||||
Mob *attacker = other;
|
Mob *attacker = other;
|
||||||
Mob *defender = this;
|
Mob *defender = this;
|
||||||
//Shout("CheckHitChance(%s) attacked by %s", defender->GetName(), attacker->GetName());
|
|
||||||
|
|
||||||
if (defender->IsClient() && defender->CastToClient()->IsSitting())
|
if (defender->IsClient() && defender->CastToClient()->IsSitting())
|
||||||
return true;
|
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.)
|
// 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 tohit_roll = zone->random.Roll0(accuracy);
|
||||||
int avoid_roll = zone->random.Roll0(avoidance);
|
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
|
// tie breaker? Don't want to be biased any one way
|
||||||
if (tohit_roll == avoid_roll)
|
if (tohit_roll == avoid_roll)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user