Merge pull request #167 from KayenEQ/Development

Development
This commit is contained in:
Michael Cook 2014-07-08 21:18:53 -04:00
commit fc721b8ec8
17 changed files with 612 additions and 306 deletions

View File

@ -1,5 +1,17 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50) EQEMu Changelog (Started on Sept 24, 2003 15:50)
------------------------------------------------------- -------------------------------------------------------
== 07/5/2014 ==
Kayen: Updated SE_Sanctuary - Adjust way hate lowering effect worked to be more accurate
Kayen: Updated SE_SympatheticProc - Revised proc rate formula to be accurate to live.
Sympathetic foci on items with proc rate mod will now benefit from that modifier.
Sympathetic foci can now be placed on AA's (This should always be slot1 in the AA)
Kayen: Implemented SE_IllusionPersistence- Allows illusions to last until you die or the illusion is forcibly removed.
Kayen: Added rule 'PreNerftBardAEDot' for SE_BardAEDot to allow it to once again do damage to moving targets. (Set to true)
Kayen: Completely revised SE_SkillProc, SE_LimitToSkill, SE_SkillProcSuccess to overall just work better and more accurately, AA support.
Required SQL: utils/sql/git/required/2014_07_04_AA_Update.sql
== 07/2/2014 == == 07/2/2014 ==
Kayen: Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self. Kayen: Implemented SE_Sanctuary - Places caster at bottom hate list, effect fades if caster cast spell on targets other than self.
Kayen: Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end. Kayen: Implemented SE_ResourceTap - Coverts a percent of dmg from dmg spells(DD/DoT) to hp/mana/end.

View File

@ -310,6 +310,7 @@ RULE_INT ( Spells, FRProjectileItem_SOF, 80684) // Item id for SOF clients for F
RULE_INT ( Spells, FRProjectileItem_NPC, 80684) // Item id for NPC Fire 'spell projectile'. RULE_INT ( Spells, FRProjectileItem_NPC, 80684) // Item id for NPC Fire 'spell projectile'.
RULE_BOOL ( Spells, UseLiveSpellProjectileGFX, false) // Use spell projectile graphics set in the spells_new table (player_1). Server must be using UF+ spell file. RULE_BOOL ( Spells, UseLiveSpellProjectileGFX, false) // Use spell projectile graphics set in the spells_new table (player_1). Server must be using UF+ spell file.
RULE_BOOL ( Spells, FocusCombatProcs, false) //Allow all combat procs to receive focus effects. RULE_BOOL ( Spells, FocusCombatProcs, false) //Allow all combat procs to receive focus effects.
RULE_BOOL ( Spells, PreNerfBardAEDoT, false) //Allow bard AOE dots to damage targets when moving.
RULE_CATEGORY_END() RULE_CATEGORY_END()
RULE_CATEGORY( Combat ) RULE_CATEGORY( Combat )

View File

@ -37,6 +37,8 @@
#define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2) #define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2)
#define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists. #define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists.
#define MaxLimitInclude 16 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects #define MaxLimitInclude 16 //Number(x 0.5) of focus Limiters that have inclusive checks used when calcing focus effects
#define MAX_SKILL_PROCS 4 //Number of spells to check skill procs from. (This is arbitrary) [Single spell can have multiple proc checks]
const int Z_AGGRO=10; const int Z_AGGRO=10;
@ -385,7 +387,7 @@ typedef enum {
#define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live. #define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live.
//#define SE_FreePet 236 // not used //#define SE_FreePet 236 // not used
#define SE_GivePetGroupTarget 237 // implemented[AA] - (Pet Affinity) #define SE_GivePetGroupTarget 237 // implemented[AA] - (Pet Affinity)
//#define SE_IllusionPersistence 238 // *not implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed. #define SE_IllusionPersistence 238 // implemented - lends persistence to your illusionary disguises, causing them to last until you die or the illusion is forcibly removed.
//#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you. //#define SE_FeignedCastOnChance 239 // *not implemented as bonus - ability gives you an increasing chance for your feigned deaths to not be revealed by spells cast upon you.
//#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.] //#define SE_StringUnbreakable 240 // not used [Likely related to above - you become immune to feign breaking on a resisted spell and have a good chance of feigning through a spell that successfully lands upon you.]
#define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet. #define SE_ImprovedReclaimEnergy 241 // implemented - increase the amount of mana returned to you when reclaiming your pet.
@ -576,7 +578,7 @@ typedef enum {
//#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_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_LimitToSkill 428 // implemented - limits what skills will effect a skill proc
#define SE_SkillProc2 429 // implemented - chance to proc when using a skill (most have hit limits) #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
//#define SE_ExpandMaxActiveTrophyBen 432 // not used //#define SE_ExpandMaxActiveTrophyBen 432 // not used

View File

@ -0,0 +1,6 @@
-- AA Permanent Illusion
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('158', '1', '238', '1', '0');
-- AA Sanctuary
INSERT INTO `altadv_vars` (`skill_id`, `name`, `cost`, `max_level`, `hotkey_sid`, `hotkey_sid2`, `title_sid`, `desc_sid`, `type`, `spellid`, `prereq_skill`, `prereq_minpoints`, `spell_type`, `spell_refresh`, `classes`, `berserker`, `class_type`, `cost_inc`, `aa_expansion`, `special_category`, `sof_type`, `sof_cost_inc`, `sof_max_level`, `sof_next_skill`, `clientver`, `account_time_required`, `sof_current_level`,`sof_next_id`,`level_inc`) VALUES ('1209', 'Sanctuary', '12', '1', '1209', '4294967295', '1209', '1209', '3', '5912', '0', '0', '14', '4320', '4', '0', '70', '0', '8', '4294967295', '3', '0', '1', '1209', '1', '0', '0', '0', '0');
INSERT INTO `aa_actions` (`aaid`, `rank`, `reuse_time`, `spell_id`, `target`, `nonspell_action`, `nonspell_mana`, `nonspell_duration`, `redux_aa`, `redux_rate`, `redux_aa2`, `redux_rate2`) VALUES ('1209', '0', '4320', '5912', '1', '0', '0', '0', '0', '0', '0', '0');

View File

@ -1359,8 +1359,11 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
MeleeLifeTap(damage); MeleeLifeTap(damage);
if (damage > 0) if (damage > 0){
CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess); CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess);
if (HasSkillProcSuccess() && other && other->GetHP() > 0)
TrySkillProc(other, skillinuse, 0, true, Hand);
}
//break invis when you attack //break invis when you attack
if(invisible) { if(invisible) {
@ -2018,9 +2021,12 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
if (!GetTarget()) if (!GetTarget())
return true; //We killed them return true; //We killed them
if(!bRiposte && other->GetHP() > 0 ) { if(!bRiposte && other && other->GetHP() > 0) {
TryWeaponProc(nullptr, weapon, other, Hand); //no weapon TryWeaponProc(nullptr, weapon, other, Hand); //no weapon
TrySpellProc(nullptr, weapon, other, Hand); TrySpellProc(nullptr, weapon, other, Hand);
if (damage > 0 && HasSkillProcSuccess())
TrySkillProc(other, skillinuse, 0, true, Hand);
} }
TriggerDefensiveProcs(nullptr, other, Hand, damage); TriggerDefensiveProcs(nullptr, other, Hand, damage);
@ -3426,9 +3432,20 @@ bool Mob::HasDefensiveProcs() const
bool Mob::HasSkillProcs() const bool Mob::HasSkillProcs() const
{ {
for (int i = 0; i < MAX_PROCS; i++)
if (SkillProcs[i].spellID != SPELL_UNKNOWN) for(int i = 0; i < MAX_SKILL_PROCS; i++){
if (spellbonuses.SkillProc[i] || itembonuses.SkillProc[i] || aabonuses.SkillProc[i])
return true; return true;
}
return false;
}
bool Mob::HasSkillProcSuccess() const
{
for(int i = 0; i < MAX_SKILL_PROCS; i++){
if (spellbonuses.SkillProcSuccess[i] || itembonuses.SkillProcSuccess[i] || aabonuses.SkillProcSuccess[i])
return true;
}
return false; return false;
} }
@ -3911,22 +3928,7 @@ float Mob::GetProcChances(float ProcBonus, uint16 weapon_speed, uint16 hand)
int mydex = GetDEX(); int mydex = GetDEX();
float ProcChance = 0.0f; float ProcChance = 0.0f;
switch (hand) { weapon_speed = GetWeaponSpeedbyHand(hand);
case 13:
weapon_speed = attack_timer.GetDuration();
break;
case 14:
weapon_speed = attack_dw_timer.GetDuration();
break;
case 11:
weapon_speed = ranged_timer.GetDuration();
break;
}
//calculate the weapon speed in ms, so we can use the rule to compare against.
// fast as a client can swing, so should be the floor of the proc chance
if (weapon_speed < RuleI(Combat, MinHastedDelay))
weapon_speed = RuleI(Combat, MinHastedDelay);
if (RuleB(Combat, AdjustProcPerMinute)) { if (RuleB(Combat, AdjustProcPerMinute)) {
ProcChance = (static_cast<float>(weapon_speed) * ProcChance = (static_cast<float>(weapon_speed) *
@ -3948,25 +3950,10 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 w
ProcBonus = 0; ProcBonus = 0;
ProcChance = 0; ProcChance = 0;
switch(hand){ weapon_speed = GetWeaponSpeedbyHand(hand);
case 13:
weapon_speed = attack_timer.GetDuration();
break;
case 14:
weapon_speed = attack_dw_timer.GetDuration();
break;
case 11:
return 0;
break;
}
//calculate the weapon speed in ms, so we can use the rule to compare against. ProcChance = (static_cast<float>(weapon_speed) * RuleR(Combat, AvgDefProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
//weapon_speed = ((int)(weapon_speed*(100.0f+attack_speed)*PermaHaste)); ProcBonus += static_cast<float>(myagi) * RuleR(Combat, DefProcPerMinAgiContrib) / 100.0f;
if(weapon_speed < RuleI(Combat, MinHastedDelay)) // fast as a client can swing, so should be the floor of the proc chance
weapon_speed = RuleI(Combat, MinHastedDelay);
ProcChance = ((float)weapon_speed * RuleR(Combat, AvgDefProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
ProcBonus += float(myagi) * RuleR(Combat, DefProcPerMinAgiContrib) / 100.0f;
ProcChance = ProcChance + (ProcChance * ProcBonus); ProcChance = ProcChance + (ProcChance * ProcBonus);
mlog(COMBAT__PROCS, "Defensive Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus); mlog(COMBAT__PROCS, "Defensive Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus);
@ -3981,13 +3968,9 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam
return; return;
} }
bool bSkillProc = HasSkillProcs();
bool bDefensiveProc = HasDefensiveProcs(); bool bDefensiveProc = HasDefensiveProcs();
if (!bDefensiveProc && !bSkillProc) if (!bDefensiveProc)
return;
if (!bDefensiveProc && (bSkillProc && damage >= 0))
return; return;
float ProcChance, ProcBonus; float ProcChance, ProcBonus;
@ -4000,30 +3983,15 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam
if (bDefensiveProc){ if (bDefensiveProc){
for (int i = 0; i < MAX_PROCS; i++) { for (int i = 0; i < MAX_PROCS; i++) {
if (DefensiveProcs[i].spellID != SPELL_UNKNOWN) { if (IsValidSpell(DefensiveProcs[i].spellID)) {
int chance = ProcChance * (DefensiveProcs[i].chance); float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance)/100.0f);
if ((MakeRandomInt(0, 100) < chance)) { if ((MakeRandomFloat(0, 1) <= 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);
} }
} }
} }
} }
if (bSkillProc && damage < 0){
if (damage == -1)
TrySkillProc(on, SkillBlock, ProcChance);
if (damage == -2)
TrySkillProc(on, SkillParry, ProcChance);
if (damage == -3)
TrySkillProc(on, SkillRiposte, ProcChance);
if (damage == -4)
TrySkillProc(on, SkillDodge, ProcChance);
}
} }
void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) { void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
@ -4059,6 +4027,7 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand) void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand)
{ {
if (!weapon) if (!weapon)
return; return;
uint16 skillinuse = 28; uint16 skillinuse = 28;
@ -4135,8 +4104,6 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on
} }
} }
// TODO: Powersource procs // TODO: Powersource procs
if (HasSkillProcs())
TrySkillProc(on, skillinuse, ProcChance);
return; return;
} }
@ -4217,6 +4184,14 @@ void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on,
} }
} }
if (HasSkillProcs() && hand != 11){ //We check ranged skill procs within the attack functions.
uint16 skillinuse = 28;
if (weapon)
skillinuse = GetSkillByItemType(weapon->ItemType);
TrySkillProc(on, skillinuse, 0, false, hand);
}
return; return;
} }
@ -4560,7 +4535,7 @@ uint16 Mob::GetDamageTable(SkillUseTypes skillinuse)
} }
} }
void Mob::TrySkillProc(Mob *on, uint16 skill, float chance) void Mob::TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success, uint16 hand, bool IsDefensive)
{ {
if (!on) { if (!on) {
@ -4569,19 +4544,176 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, float chance)
return; return;
} }
for (int i = 0; i < MAX_PROCS; i++) { if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill])
if (SkillProcs[i].spellID != SPELL_UNKNOWN){ return;
if (PassLimitToSkill(SkillProcs[i].base_spellID,skill)){
int ProcChance = chance * (float)SkillProcs[i].chance; /*Allow one proc from each (Spell/Item/AA)
if ((MakeRandomInt(0, 100) < ProcChance)) { Kayen: Due to limited avialability of effects on live it is too difficult
ExecWeaponProc(nullptr, SkillProcs[i].spellID, on); to confirm how they stack at this time, will adjust formula when more data is avialablle to test.*/
CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, SkillProcs[i].base_spellID); bool CanProc = true;
uint16 base_spell_id = 0;
uint16 proc_spell_id = 0;
float ProcMod = 0;
float chance = 0;
if (IsDefensive)
chance = on->GetSkillProcChances(ReuseTime, hand);
else
chance = GetSkillProcChances(ReuseTime, hand);
if (spellbonuses.LimitToSkill[skill]){
for(int e = 0; e < MAX_SKILL_PROCS; e++){
if (CanProc &&
(!Success && spellbonuses.SkillProc[e] && IsValidSpell(spellbonuses.SkillProc[e]))
|| (Success && spellbonuses.SkillProcSuccess[e] && IsValidSpell(spellbonuses.SkillProcSuccess[e]))) {
base_spell_id = spellbonuses.SkillProc[e];
base_spell_id = 0;
ProcMod = 0;
for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[base_spell_id].effectid[i] == SE_SkillProc) {
proc_spell_id = spells[base_spell_id].base[i];
ProcMod = static_cast<float>(spells[base_spell_id].base2[i]);
}
else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].effectid[i] <= HIGHEST_SKILL) {
if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) {
float final_chance = chance * (ProcMod / 100.0f);
if (MakeRandomFloat(0, 1) <= final_chance) {
ExecWeaponProc(nullptr, proc_spell_id, on);
CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, base_spell_id);
CanProc = false;
break;
}
}
}
else {
proc_spell_id = 0;
ProcMod = 0;
} }
} }
} }
} }
} }
if (itembonuses.LimitToSkill[skill]){
CanProc = true;
for(int e = 0; e < MAX_SKILL_PROCS; e++){
if (CanProc &&
(!Success && itembonuses.SkillProc[e] && IsValidSpell(itembonuses.SkillProc[e]))
|| (Success && itembonuses.SkillProcSuccess[e] && IsValidSpell(itembonuses.SkillProcSuccess[e]))) {
base_spell_id = itembonuses.SkillProc[e];
base_spell_id = 0;
ProcMod = 0;
for (int i = 0; i < EFFECT_COUNT; i++) {
if (spells[base_spell_id].effectid[i] == SE_SkillProc) {
proc_spell_id = spells[base_spell_id].base[i];
ProcMod = static_cast<float>(spells[base_spell_id].base2[i]);
}
else if (spells[base_spell_id].effectid[i] == SE_LimitToSkill && spells[base_spell_id].effectid[i] <= HIGHEST_SKILL) {
if (CanProc && spells[base_spell_id].base[i] == skill && IsValidSpell(proc_spell_id)) {
float final_chance = chance * (ProcMod / 100.0f);
if (MakeRandomFloat(0, 1) <= final_chance) {
ExecWeaponProc(nullptr, proc_spell_id, on);
CanProc = false;
break;
}
}
}
else {
proc_spell_id = 0;
ProcMod = 0;
}
}
}
}
}
if (IsClient() && aabonuses.LimitToSkill[skill]){
CanProc = true;
uint32 effect = 0;
int32 base1 = 0;
int32 base2 = 0;
uint32 slot = 0;
for(int e = 0; e < MAX_SKILL_PROCS; e++){
if (CanProc &&
(!Success && aabonuses.SkillProc[e])
|| (Success && aabonuses.SkillProcSuccess[e])){
int aaid = aabonuses.SkillProc[e];
base_spell_id = 0;
ProcMod = 0;
std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aaid);
if(find_iter == aa_effects.end())
break;
for (std::map<uint32, AA_Ability>::const_iterator iter = aa_effects[aaid].begin(); iter != aa_effects[aaid].end(); ++iter) {
effect = iter->second.skill_id;
base1 = iter->second.base1;
base2 = iter->second.base2;
slot = iter->second.slot;
if (effect == SE_SkillProc) {
proc_spell_id = base1;
ProcMod = static_cast<float>(base2);
}
else if (effect == SE_LimitToSkill && effect <= HIGHEST_SKILL) {
if (CanProc && base1 == skill && IsValidSpell(proc_spell_id)) {
float final_chance = chance * (ProcMod / 100.0f);
if (MakeRandomFloat(0, 1) <= final_chance) {
ExecWeaponProc(nullptr, proc_spell_id, on);
CanProc = false;
break;
}
}
}
else {
proc_spell_id = 0;
ProcMod = 0;
}
}
}
}
}
}
float Mob::GetSkillProcChances(uint16 ReuseTime, uint16 hand) {
uint16 weapon_speed;
float ProcChance = 0;
if (!ReuseTime && hand) {
weapon_speed = GetWeaponSpeedbyHand(hand);
ProcChance = static_cast<float>(weapon_speed) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
if (hand != 13)
ProcChance /= 2;
}
else
ProcChance = static_cast<float>(ReuseTime) * (RuleR(Combat, AvgProcsPerMinute) / 60000.0f);
return ProcChance;
}
bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) { bool Mob::TryRootFadeByDamage(int buffslot, Mob* attacker) {
/*Dev Quote 2010: http://forums.station.sony.com/eq/posts/list.m?topic_id=161443 /*Dev Quote 2010: http://forums.station.sony.com/eq/posts/list.m?topic_id=161443

View File

@ -1329,6 +1329,45 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
break; break;
} }
case SE_IllusionPersistence:
newbon->IllusionPersistence = true;
break;
case SE_LimitToSkill:{
if (base1 <= HIGHEST_SKILL)
newbon->LimitToSkill[base1] = true;
break;
}
case SE_SkillProc:{
for(int e = 0; e < MAX_SKILL_PROCS; e++)
{
if(newbon->SkillProc[e] && newbon->SkillProc[e] == aaid)
break; //Do not use the same aa id more than once.
else if(!newbon->SkillProc[e]){
newbon->SkillProc[e] = aaid;
break;
}
}
break;
}
case SE_SkillProcSuccess:{
for(int e = 0; e < MAX_SKILL_PROCS; e++)
{
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid)
break; //Do not use the same spell id more than once.
else if(!newbon->SkillProcSuccess[e]){
newbon->SkillProcSuccess[e] = aaid;
break;
}
}
break;
}
} }
} }
} }
@ -2876,6 +2915,47 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
break; break;
} }
case SE_IllusionPersistence:
newbon->IllusionPersistence = true;
break;
case SE_LimitToSkill:{
if (effect_value <= HIGHEST_SKILL){
newbon->LimitToSkill[effect_value] = true;
}
break;
}
case SE_SkillProc:{
for(int e = 0; e < MAX_SKILL_PROCS; e++)
{
if(newbon->SkillProc[e] && newbon->SkillProc[e] == spell_id)
break; //Do not use the same spell id more than once.
else if(!newbon->SkillProc[e]){
newbon->SkillProc[e] = spell_id;
break;
}
}
break;
}
case SE_SkillProcSuccess:{
for(int e = 0; e < MAX_SKILL_PROCS; e++)
{
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == spell_id)
break; //Do not use the same spell id more than once.
else if(!newbon->SkillProcSuccess[e]){
newbon->SkillProcSuccess[e] = spell_id;
break;
}
}
break;
}
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table //Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) { if (IsAISpellEffect) {
@ -4356,6 +4436,17 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
aabonuses.FactionModPct = effect_value; aabonuses.FactionModPct = effect_value;
break; break;
case SE_MeleeVulnerability:
spellbonuses.MeleeVulnerability = effect_value;
itembonuses.MeleeVulnerability = effect_value;
aabonuses.MeleeVulnerability = effect_value;
break;
case SE_IllusionPersistence:
spellbonuses.IllusionPersistence = effect_value;
itembonuses.IllusionPersistence = effect_value;
aabonuses.IllusionPersistence = effect_value;
break;
} }
} }
} }

View File

@ -3292,7 +3292,7 @@ bool Bot::CheckBotDoubleAttack(bool tripleAttack) {
return false; return false;
} }
void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte) void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime)
{ {
if (!CanDoSpecialAttack(other)) if (!CanDoSpecialAttack(other))
return; return;
@ -3396,10 +3396,11 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
other->Stun(100); other->Stun(100);
} }
if (CanSkillProc && HasSkillProcs()){ if (CanSkillProc && HasSkillProcs())
float chance = 10.0f*RuleR(Combat, AvgProcsPerMinute)/60000.0f; TrySkillProc(other, skillinuse, ReuseTime);
TrySkillProc(other, skillinuse, chance);
} if (CanSkillProc && (damage > 0) && HasSkillProcSuccess())
TrySkillProc(other, skillinuse, ReuseTime, true);
} }
void Bot::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) { void Bot::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg) {
@ -7641,10 +7642,8 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
{ {
if(bottype == BotfocusSympatheticProc) if(bottype == BotfocusSympatheticProc)
{ {
float ProcChance, ProcBonus;
int16 ProcRateMod = focus_spell.base[i]; //Baseline is 100 for most Sympathetic foci float ProcChance = GetSympatheticProcChances(spell_id, focus_spell.base[i]);
int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time);
GetSympatheticProcChances(ProcBonus, ProcChance, cast_time, ProcRateMod);
if(MakeRandomFloat(0, 1) <= ProcChance) if(MakeRandomFloat(0, 1) <= ProcChance)
value = focus_id; value = focus_id;
@ -8104,10 +8103,11 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
//who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC.
} }
if (HasSkillProcs()){ if (HasSkillProcs())
float chance = (float)ReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f; TrySkillProc(who, skill, ReuseTime*1000);
TrySkillProc(who, skill, chance);
} if (max_damage > 0 && HasSkillProcSuccess())
TrySkillProc(who, skill, ReuseTime*1000, true);
if(max_damage == -3 && !(who->GetHP() <= 0)) if(max_damage == -3 && !(who->GetHP() <= 0))
DoRiposte(who); DoRiposte(who);

View File

@ -185,7 +185,7 @@ public:
virtual void RogueAssassinate(Mob* other); virtual void RogueAssassinate(Mob* other);
virtual void DoClassAttacks(Mob *target, bool IsRiposte=false); virtual void DoClassAttacks(Mob *target, bool IsRiposte=false);
virtual bool TryHeadShot(Mob* defender, SkillUseTypes skillInUse); virtual bool TryHeadShot(Mob* defender, SkillUseTypes skillInUse);
virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false); virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false, int ReuseTime =0);
virtual void ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg); virtual void ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg);
bool CanDoSpecialAttack(Mob *other); bool CanDoSpecialAttack(Mob *other);
virtual int32 CheckAggroAmount(uint16 spellid); virtual int32 CheckAggroAmount(uint16 spellid);

View File

@ -776,7 +776,10 @@ public:
int GetSpentAA() { return m_pp.aapoints_spent; } int GetSpentAA() { return m_pp.aapoints_spent; }
void RefundAA(); void RefundAA();
void IncrementAA(int aa_id); void IncrementAA(int aa_id);
int32 GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2);
int32 GetAAEffectid(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, true, false,false); }
int32 GetAABase1(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, true,false); }
int32 GetAABase2(uint32 aa_ID, uint32 slot_id) { return GetAAEffectDataBySlot(aa_ID, slot_id, false, false,true); }
int16 acmod(); int16 acmod();
// Item methods // Item methods

View File

@ -9490,13 +9490,6 @@ void Client::CompleteConnect()
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid); AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid);
break; break;
} }
case SE_SkillProc2:
case SE_SkillProc:
{
AddSkillProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid);
break;
}
} }
} }
} }

View File

@ -375,6 +375,9 @@ struct StatBonuses {
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.
int16 FactionModPct; // Modifies amount of faction gained. int16 FactionModPct; // Modifies amount of faction gained.
int16 MeleeVulnerability; // Weakness/mitigation to melee damage int16 MeleeVulnerability; // Weakness/mitigation to melee damage
bool LimitToSkill[HIGHEST_SKILL+2]; // Determines if we need to search for a skill proc.
uint16 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs.
uint16 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success.
// AAs // AAs
int8 Packrat; //weight reduction for items, 1 point = 10% int8 Packrat; //weight reduction for items, 1 point = 10%
@ -431,7 +434,7 @@ struct StatBonuses {
uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg
uint8 AssassinateLevel; // Max Level Assassinate will be effective at. uint8 AssassinateLevel; // Max Level Assassinate will be effective at.
int32 PetMeleeMitigation; // Add AC to owner's pet. int32 PetMeleeMitigation; // Add AC to owner's pet.
bool IllusionPersistence; // Causes illusions not to fade.
}; };
typedef struct typedef struct

View File

@ -308,6 +308,16 @@ Mob *HateList::GetTop(Mob *center)
} }
} }
if (cur->ent->Sanctuary()) {
if(hate == -1)
{
top = cur->ent;
hate = 1;
}
++iterator;
continue;
}
if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){ if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){
if(hate == -1) if(hate == -1)
{ {

View File

@ -2761,6 +2761,14 @@ bool Mob::DivineAura() const
return false; return false;
} }
bool Mob::Sanctuary() const
{
if (spellbonuses.Sanctuary)
return true;
return false;
}
int16 Mob::GetResist(uint8 type) const int16 Mob::GetResist(uint8 type) const
{ {
if (IsNPC()) if (IsNPC())
@ -3042,6 +3050,34 @@ void Mob::TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand, in
return; return;
on->TryDefensiveProc(weapon, this, hand, damage); on->TryDefensiveProc(weapon, this, hand, damage);
//Defensive Skill Procs
if (damage < 0 && damage >= -4) {
uint16 skillinuse = 0;
switch (damage) {
case (-1):
skillinuse = SkillBlock;
break;
case (-2):
skillinuse = SkillParry;
break;
case (-3):
skillinuse = SkillRiposte;
break;
case (-4):
skillinuse = SkillDodge;
break;
}
if (on->HasSkillProcs())
on->TrySkillProc(this, skillinuse, 0, false, hand, true);
if (on->HasSkillProcSuccess())
on->TrySkillProc(this, skillinuse, 0, true, hand, true);
}
} }
void Mob::SetDeltas(float dx, float dy, float dz, float dh) { void Mob::SetDeltas(float dx, float dy, float dz, float dh) {
@ -4706,6 +4742,28 @@ bool Mob::PassLimitToSkill(uint16 spell_id, uint16 skill) {
return false; return false;
} }
uint16 Mob::GetWeaponSpeedbyHand(uint16 hand) {
uint16 weapon_speed = 0;
switch (hand) {
case 13:
weapon_speed = attack_timer.GetDuration();
break;
case 14:
weapon_speed = attack_dw_timer.GetDuration();
break;
case 11:
weapon_speed = ranged_timer.GetDuration();
break;
}
if (weapon_speed < RuleI(Combat, MinHastedDelay))
weapon_speed = RuleI(Combat, MinHastedDelay);
return weapon_speed;
}
int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) { int8 Mob::GetDecayEffectValue(uint16 spell_id, uint16 spelleffect) {
if (!IsValidSpell(spell_id)) if (!IsValidSpell(spell_id))

View File

@ -506,9 +506,8 @@ public:
bool AddDefensiveProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool AddDefensiveProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
bool RemoveDefensiveProc(uint16 spell_id, bool bAll = false); bool RemoveDefensiveProc(uint16 spell_id, bool bAll = false);
bool HasDefensiveProcs() const; bool HasDefensiveProcs() const;
bool AddSkillProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
bool RemoveSkillProc(uint16 spell_id, bool bAll = false);
bool HasSkillProcs() const; bool HasSkillProcs() const;
bool HasSkillProcSuccess() const;
bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN); bool AddProcToWeapon(uint16 spell_id, bool bPerma = false, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false); bool RemoveProcFromWeapon(uint16 spell_id, bool bAll = false);
bool HasProcs() const; bool HasProcs() const;
@ -700,9 +699,9 @@ public:
int32 ReduceAllDamage(int32 damage); int32 ReduceAllDamage(int32 damage);
virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false, bool CanAvoid=true); virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false, bool CanAvoid=true);
virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0); virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0, int ReuseTime=0);
virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false); virtual void DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false, int ReuseTime=0);
virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0); virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0, int ReuseTime=0);
bool CanDoSpecialAttack(Mob *other); bool CanDoSpecialAttack(Mob *other);
bool Flurry(ExtraAttackOptions *opts); bool Flurry(ExtraAttackOptions *opts);
bool Rampage(ExtraAttackOptions *opts); bool Rampage(ExtraAttackOptions *opts);
@ -820,6 +819,7 @@ public:
void SetNextIncHPEvent( int inchpevent ); void SetNextIncHPEvent( int inchpevent );
bool DivineAura() const; bool DivineAura() const;
bool Sanctuary() const;
bool HasNPCSpecialAtk(const char* parse); bool HasNPCSpecialAtk(const char* parse);
int GetSpecialAbility(int ability); int GetSpecialAbility(int ability);
@ -986,7 +986,7 @@ protected:
bool focused; bool focused;
void CalcSpellBonuses(StatBonuses* newbon); void CalcSpellBonuses(StatBonuses* newbon);
virtual void CalcBonuses(); virtual void CalcBonuses();
void TrySkillProc(Mob *on, uint16 skill, float chance); void TrySkillProc(Mob *on, uint16 skill, uint16 ReuseTime, bool Success = false, uint16 hand = 0, bool IsDefensive = false);
bool PassLimitToSkill(uint16 spell_id, uint16 skill); bool PassLimitToSkill(uint16 spell_id, uint16 skill);
bool PassLimitClass(uint32 Classes_, uint16 Class_); bool PassLimitClass(uint32 Classes_, uint16 Class_);
void TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand = 13, int damage=0); void TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand = 13, int damage=0);
@ -998,6 +998,8 @@ protected:
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13); virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13);
virtual float GetSpecialProcChances(uint16 hand); virtual float GetSpecialProcChances(uint16 hand);
virtual float GetAssassinateProcChances(uint16 ReuseTime); virtual float GetAssassinateProcChances(uint16 ReuseTime);
virtual float GetSkillProcChances(uint16 ReuseTime, uint16 hand = 0);
uint16 GetWeaponSpeedbyHand(uint16 hand);
int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item); int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item);
int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr); int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr);
int GetKickDamage(); int GetKickDamage();
@ -1009,7 +1011,7 @@ protected:
Map::Vertex UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached); Map::Vertex UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
void PrintRoute(); void PrintRoute();
virtual float GetSympatheticProcChances(float &ProcBonus, float &ProcChance, int32 cast_time, int16 ProcRateMod); virtual float GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate = 0);
enum {MAX_PROCS = 4}; enum {MAX_PROCS = 4};
tProc PermaProcs[MAX_PROCS]; tProc PermaProcs[MAX_PROCS];

View File

@ -171,10 +171,11 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
//who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC. //who->Stun(100); Kayen: This effect does not stun on live, it only moves the NPC.
} }
if (HasSkillProcs()){ if (HasSkillProcs())
float chance = (float)ReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f; TrySkillProc(who, skill, ReuseTime*1000);
TrySkillProc(who, skill, chance);
} if (max_damage > 0 && HasSkillProcSuccess())
TrySkillProc(who, skill, ReuseTime*1000, true);
if(max_damage == -3 && !who->HasDied()) if(max_damage == -3 && !who->HasDied())
DoRiposte(who); DoRiposte(who);
@ -847,7 +848,7 @@ void Client::RangedAttack(Mob* other, bool CanDoubleAttack) {
} }
} }
void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus) void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const ItemInst* Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime)
{ {
if (!CanDoSpecialAttack(other)) if (!CanDoSpecialAttack(other))
return; return;
@ -874,6 +875,9 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
else else
WDmg = weapon_damage; WDmg = weapon_damage;
if (focus) //From FcBaseEffects
WDmg += WDmg*focus/100;
if((WDmg > 0) || (ADmg > 0)) if((WDmg > 0) || (ADmg > 0))
{ {
if(WDmg < 0) if(WDmg < 0)
@ -948,7 +952,6 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
other->MeleeMitigation(this, TotalDmg, minDmg); other->MeleeMitigation(this, TotalDmg, minDmg);
if(TotalDmg > 0) if(TotalDmg > 0)
{ {
TotalDmg += TotalDmg*focus/100;
ApplyMeleeDamageBonus(SkillArchery, TotalDmg); ApplyMeleeDamageBonus(SkillArchery, TotalDmg);
TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillArchery); TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillArchery);
TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillArchery) / 100) + GetSkillDmgAmt(SkillArchery); TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillArchery) / 100) + GetSkillDmgAmt(SkillArchery);
@ -968,19 +971,32 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery); other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillArchery);
if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && other && !other->HasDied()){
if (ReuseTime)
TrySkillProc(other, SkillArchery, ReuseTime);
else
TrySkillProc(other, SkillArchery, 0, true, 11);
}
} }
//try proc on hits and misses //try proc on hits and misses
if((RangeWeapon != nullptr) && GetTarget() && other && (other->GetHP() > -10)) if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied())
{ {
TryWeaponProc(RangeWeapon, other, 11); TryWeaponProc(RangeWeapon, other, 11);
} }
//Arrow procs because why not? //Arrow procs because why not?
if((Ammo != NULL) && GetTarget() && other && (other->GetHP() > -10)) if((Ammo != NULL) && GetTarget() && other && !other->HasDied())
{ {
TryWeaponProc(Ammo, other, 11); TryWeaponProc(Ammo, other, 11);
} }
if (HasSkillProcs() && GetTarget() && other && !other->HasDied()){
if (ReuseTime)
TrySkillProc(other, SkillArchery, ReuseTime);
else
TrySkillProc(other, SkillArchery, 0, false, 11);
}
} }
void NPC::RangedAttack(Mob* other) void NPC::RangedAttack(Mob* other)
@ -1253,7 +1269,7 @@ void Client::ThrowingAttack(Mob* other, bool CanDoubleAttack) { //old was 51
} }
} }
void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus) void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item_Struct* item, uint16 weapon_damage, int16 chance_mod,int16 focus, int ReuseTime)
{ {
if (!CanDoSpecialAttack(other)) if (!CanDoSpecialAttack(other))
return; return;
@ -1271,6 +1287,9 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
else else
WDmg = weapon_damage; WDmg = weapon_damage;
if (focus) //From FcBaseEffects
WDmg += WDmg*focus/100;
int32 TotalDmg = 0; int32 TotalDmg = 0;
uint32 Assassinate_Dmg = 0; uint32 Assassinate_Dmg = 0;
@ -1294,7 +1313,6 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
other->MeleeMitigation(this, TotalDmg, minDmg); other->MeleeMitigation(this, TotalDmg, minDmg);
if(TotalDmg > 0) if(TotalDmg > 0)
{ {
TotalDmg += TotalDmg*focus/100;
ApplyMeleeDamageBonus(SkillThrowing, TotalDmg); ApplyMeleeDamageBonus(SkillThrowing, TotalDmg);
TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillThrowing); TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillThrowing);
TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillThrowing) / 100) + GetSkillDmgAmt(SkillThrowing); TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillThrowing) / 100) + GetSkillDmgAmt(SkillThrowing);
@ -1309,10 +1327,25 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
TotalDmg = -5; TotalDmg = -5;
other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillThrowing); other->Damage(this, TotalDmg, SPELL_UNKNOWN, SkillThrowing);
if (TotalDmg > 0 && HasSkillProcSuccess() && GetTarget() && other && !other->HasDied()){
if (ReuseTime)
TrySkillProc(other, SkillThrowing, ReuseTime);
else
TrySkillProc(other, SkillThrowing, 0, true, 11);
}
} }
if((RangeWeapon != nullptr) && GetTarget() && other && (other->GetHP() > -10)) if((RangeWeapon != nullptr) && GetTarget() && other && (other->GetHP() > -10))
TryWeaponProc(RangeWeapon, other, 11); TryWeaponProc(RangeWeapon, other, 11);
if (HasSkillProcs() && GetTarget() && other && !other->HasDied()){
if (ReuseTime)
TrySkillProc(other, SkillThrowing, ReuseTime);
else
TrySkillProc(other, SkillThrowing, 0, false, 11);
}
} }
void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skillInUse) { void Mob::SendItemAnimation(Mob *to, const Item_Struct *item, SkillUseTypes skillInUse) {
@ -1891,6 +1924,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
Mob *hate_top = who->GetHateMost(); Mob *hate_top = who->GetHateMost();
float level_difference = GetLevel() - who->GetLevel(); float level_difference = GetLevel() - who->GetLevel();
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) || who->GetSpecialAbility(IMMUNE_TAUNT)){ if ((RuleB(Combat,TauntOverLevel) == false) && (level_difference < 0) || who->GetSpecialAbility(IMMUNE_TAUNT)){
@ -1940,6 +1974,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
if (hate_top && hate_top != this){ if (hate_top && hate_top != this){
newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1; newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1;
who->CastToNPC()->AddToHateList(this, newhate); who->CastToNPC()->AddToHateList(this, newhate);
Success = true;
} }
else else
who->CastToNPC()->AddToHateList(this,12); who->CastToNPC()->AddToHateList(this,12);
@ -1955,10 +1990,12 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
else else
Message_StringID(MT_SpellFailure,FAILED_TAUNT); Message_StringID(MT_SpellFailure,FAILED_TAUNT);
if (HasSkillProcs()){ if (HasSkillProcs())
float chance = (float)TauntReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f; TrySkillProc(who, SkillTaunt, TauntReuseTime*1000);
TrySkillProc(who, SkillTaunt, chance);
}
if (Success && HasSkillProcSuccess())
TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true);
} }
@ -2045,20 +2082,7 @@ float Mob::GetSpecialProcChances(uint16 hand)
float ProcChance = 0.0f; float ProcChance = 0.0f;
float ProcBonus = 0.0f; float ProcBonus = 0.0f;
switch (hand) { weapon_speed = GetWeaponSpeedbyHand(hand);
case 13:
weapon_speed = attack_timer.GetDuration();
break;
case 14:
weapon_speed = attack_dw_timer.GetDuration();
break;
case 11:
weapon_speed = ranged_timer.GetDuration();
break;
}
if (weapon_speed < RuleI(Combat, MinHastedDelay))
weapon_speed = RuleI(Combat, MinHastedDelay);
if (RuleB(Combat, AdjustSpecialProcPerMinute)) { if (RuleB(Combat, AdjustSpecialProcPerMinute)) {
ProcChance = (static_cast<float>(weapon_speed) * ProcChance = (static_cast<float>(weapon_speed) *
@ -2138,7 +2162,7 @@ float Mob::GetAssassinateProcChances(uint16 ReuseTime)
return ProcChance; return ProcChance;
} }
void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte) void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime)
{ {
if (!CanDoSpecialAttack(other)) if (!CanDoSpecialAttack(other))
return; return;
@ -2155,6 +2179,9 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
if(weapon_damage > 0){ if(weapon_damage > 0){
if (focus) //From FcBaseEffects
weapon_damage += weapon_damage*focus/100;
if(GetClass() == BERSERKER){ if(GetClass() == BERSERKER){
int bonus = 3 + GetLevel()/10; int bonus = 3 + GetLevel()/10;
weapon_damage = weapon_damage * (100+bonus) / 100; weapon_damage = weapon_damage * (100+bonus) / 100;
@ -2190,7 +2217,6 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
other->AvoidDamage(this, damage, CanRiposte); other->AvoidDamage(this, damage, CanRiposte);
other->MeleeMitigation(this, damage, min_hit); other->MeleeMitigation(this, damage, min_hit);
if(damage > 0) { if(damage > 0) {
damage += damage*focus/100;
ApplyMeleeDamageBonus(skillinuse, damage); ApplyMeleeDamageBonus(skillinuse, damage);
damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse); damage += other->GetFcDamageAmtIncoming(this, 0, true, skillinuse);
damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse); damage += (itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse);
@ -2244,10 +2270,11 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff); SpellFinished(904, other, 10, 0, -1, spells[904].ResistDiff);
} }
if (CanSkillProc && HasSkillProcs()){ if (CanSkillProc && HasSkillProcs())
float chance = 10.0f*RuleR(Combat, AvgProcsPerMinute)/60000.0f; TrySkillProc(other, skillinuse, ReuseTime);
TrySkillProc(other, skillinuse, chance);
} if (CanSkillProc && (damage > 0) && HasSkillProcSuccess())
TrySkillProc(other, skillinuse, ReuseTime, true);
} }
bool Mob::CanDoSpecialAttack(Mob *other) bool Mob::CanDoSpecialAttack(Mob *other)

View File

@ -1430,7 +1430,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
for(int x = 0; x < 7; x++){ for(int x = 0; x < 7; x++){
SendWearChange(x); SendWearChange(x);
} }
if(caster && caster->GetAA(aaPermanentIllusion)) if(caster && (caster->spellbonuses.IllusionPersistence || caster->aabonuses.IllusionPersistence
|| caster->itembonuses.IllusionPersistence))
buffs[buffslot].persistant_buff = 1; buffs[buffslot].persistant_buff = 1;
else else
buffs[buffslot].persistant_buff = 0; buffs[buffslot].persistant_buff = 0;
@ -1772,20 +1773,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
break; break;
} }
case SE_SkillProc2:
case SE_SkillProc:
{
uint16 procid = GetProcID(spell_id, i);
#ifdef SPELL_EFFECT_SPAM
snprintf(effect_desc, _EDLEN, "Weapon Proc: %s (id %d)", spells[effect_value].name, procid);
#endif
if(spells[spell_id].base2[i] == 0)
AddSkillProc(procid, 100, spell_id);
else
AddSkillProc(procid, spells[spell_id].base2[i]+100, spell_id);
break;
}
case SE_NegateAttacks: case SE_NegateAttacks:
{ {
#ifdef SPELL_EFFECT_SPAM #ifdef SPELL_EFFECT_SPAM
@ -2256,6 +2243,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
*Max is lower value then Weapon base, possibly min hit vs Weapon Damage range ie. MakeRandInt(max,base) *Max is lower value then Weapon base, possibly min hit vs Weapon Damage range ie. MakeRandInt(max,base)
*/ */
int16 focus = 0; int16 focus = 0;
int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time;
if(caster->IsClient()) if(caster->IsClient())
focus = caster->CastToClient()->GetFocusEffect(focusFcBaseEffects, spell_id); focus = caster->CastToClient()->GetFocusEffect(focusFcBaseEffects, spell_id);
@ -2263,15 +2251,15 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
switch(spells[spell_id].skill) switch(spells[spell_id].skill)
{ {
case SkillThrowing: case SkillThrowing:
caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i], focus); caster->DoThrowingAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i], focus, ReuseTime);
break; break;
case SkillArchery: case SkillArchery:
caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i],focus); caster->DoArcheryAttackDmg(this, nullptr, nullptr, spells[spell_id].base[i],spells[spell_id].base2[i],focus,ReuseTime);
break; break;
default: default:
caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base[i], spells[spell_id].skill, spells[spell_id].base2[i], focus); caster->DoMeleeSkillAttackDmg(this, spells[spell_id].base[i], spells[spell_id].skill, spells[spell_id].base2[i], focus, ReuseTime);
break; break;
} }
break; break;
@ -2329,7 +2317,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if (buffslot >= 0) if (buffslot >= 0)
break; break;
//This effect does no damage if target is moving. //This effect does no damage if target is moving.
if (IsMoving()) if (!RuleB(Spells, PreNerfBardAEDoT) && IsMoving())
break; break;
// for offensive spells check if we have a spell rune on // for offensive spells check if we have a spell rune on
@ -2735,22 +2723,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
break; break;
} }
case SE_Sanctuary:
{
std::list<NPC*> npc_list;
entity_list.GetNPCList(npc_list);
for(std::list<NPC*>::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) {
NPC* npc = *itr;
if (npc && npc->CheckAggro(this))
npc->SetHate(caster, 1);
}
break;
}
// Handled Elsewhere // Handled Elsewhere
case SE_ImmuneFleeing: case SE_ImmuneFleeing:
case SE_NegateSpellEffect: case SE_NegateSpellEffect:
@ -2984,6 +2956,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
case SE_AssassinateLevel: case SE_AssassinateLevel:
case SE_FactionModPct: case SE_FactionModPct:
case SE_LimitSpellClass: case SE_LimitSpellClass:
case SE_Sanctuary:
case SE_PetMeleeMitigation:
case SE_SkillProc:
case SE_SkillProcSuccess:
{ {
break; break;
} }
@ -3403,7 +3379,7 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
{ {
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster); effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster);
if (IsMoving() || invulnerable || /*effect_value > 0 ||*/ DivineAura()) if ((!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) || invulnerable || /*effect_value > 0 ||*/ DivineAura())
break; break;
if(effect_value < 0) { if(effect_value < 0) {
@ -3630,21 +3606,6 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
break; break;
} }
case SE_Sanctuary:
{
std::list<NPC*> npc_list;
entity_list.GetNPCList(npc_list);
for(std::list<NPC*>::iterator itr = npc_list.begin(); itr != npc_list.end(); ++itr) {
NPC* npc = *itr;
if (npc && npc->CheckAggro(this))
npc->SetHate(caster, 1);
}
break;
}
default: default:
{ {
@ -3712,14 +3673,6 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
break; break;
} }
case SE_SkillProc2:
case SE_SkillProc:
{
uint16 procid = GetProcID(buffs[slot].spellid, i);
RemoveSkillProc(procid);
break;
}
case SE_DefensiveProc: case SE_DefensiveProc:
{ {
uint16 procid = GetProcID(buffs[slot].spellid, i); uint16 procid = GetProcID(buffs[slot].spellid, i);
@ -4084,39 +4037,41 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
CalcBonuses(); CalcBonuses();
} }
/* No longer used. int32 Client::GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2)
int16 Client::CalcAAFocusEffect(focusType type, uint16 focus_spell, uint16 spell_id)
{ {
uint32 slots = 0; int32 aa_effects_data[3] = { 0 };
uint32 aa_AA = 0; uint32 effect = 0;
uint32 aa_value = 0; int32 base1 = 0;
int32 base2 = 0;
uint32 slot = 0;
int32 value = 0;
// Iterate through all of the client's AAs std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aa_ID);
for (int i = 0; i < MAX_PP_AA_ARRAY; i++) if(find_iter == aa_effects.end())
return 0;
for (std::map<uint32, AA_Ability>::const_iterator iter = aa_effects[aa_ID].begin(); iter != aa_effects[aa_ID].end(); ++iter)
{ {
aa_AA = this->aa[i]->AA; effect = iter->second.skill_id;
aa_value = this->aa[i]->value; base1 = iter->second.base1;
if (aa_AA > 0 || aa_value > 0) base2 = iter->second.base2;
{ slot = iter->second.slot;
slots = zone->GetTotalAALevels(aa_AA);
if (slots > 0) if (slot && slot == slot_id) {
for(int j = 1;j <= slots; j++)
{ if (GetEffect)
switch (aa_effects[aa_AA][j].skill_id) return effect;
{
case SE_TriggerOnCast: if (GetBase1)
// If focus_spell matches the spell listed in the DB, load these restrictions return base1;
if(type == focusTriggerOnCast && focus_spell == aa_effects[aa_AA][j].base1)
value = CalcAAFocus(type, aa_AA, spell_id); if (GetBase2)
break; return base2;
} }
} }
return 0;
} }
}
return value;
}
*/
int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id) int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
@ -4496,8 +4451,10 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
value = base1; value = base1;
break; break;
//Note if using these as AA, make sure this is first focus used.
case SE_SympatheticProc: case SE_SympatheticProc:
//No AA support at this time. if(type == focusSympatheticProc)
value = base2;
break; break;
case SE_FcDamageAmt: case SE_FcDamageAmt:
@ -4962,16 +4919,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
case SE_SympatheticProc: case SE_SympatheticProc:
if(type == focusSympatheticProc) { if(type == focusSympatheticProc) {
float ProcChance, ProcBonus;
int16 ProcRateMod = focus_spell.base[i]; //Baseline is 100 for most Sympathetic foci
int32 cast_time = GetActSpellCasttime(spell_id, spells[spell_id].cast_time);
GetSympatheticProcChances(ProcBonus, ProcChance, cast_time, ProcRateMod);
if(MakeRandomFloat(0, 1) <= ProcChance)
value = focus_id; value = focus_id;
else
value = 0;
} }
break; break;
@ -5089,8 +5037,8 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
return 0; return 0;
uint16 proc_spellid = 0; uint16 proc_spellid = 0;
uint8 SizeProcList = 0;
uint8 MAX_SYMPATHETIC = 10; uint8 MAX_SYMPATHETIC = 10;
float ProcChance = 0.0f;
std::vector<int> SympatheticProcList; std::vector<int> SympatheticProcList;
@ -5101,7 +5049,7 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
for(int x=0; x<=21; x++) for(int x=0; x<=21; x++)
{ {
if (SizeProcList > MAX_SYMPATHETIC) if (SympatheticProcList.size() > MAX_SYMPATHETIC)
continue; continue;
TempItem = nullptr; TempItem = nullptr;
@ -5109,20 +5057,22 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
if (!ins) if (!ins)
continue; continue;
TempItem = ins->GetItem(); TempItem = ins->GetItem();
if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) { if (TempItem && TempItem->Focus.Effect > 0 && IsValidSpell(TempItem->Focus.Effect)) {
proc_spellid = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id); proc_spellid = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id);
if (proc_spellid > 0) if (IsValidSpell(proc_spellid)){
{
ProcChance = GetSympatheticProcChances(spell_id, spells[TempItem->Focus.Effect].base[0], TempItem->ProcRate);
if(MakeRandomFloat(0, 1) <= ProcChance)
SympatheticProcList.push_back(proc_spellid); SympatheticProcList.push_back(proc_spellid);
SizeProcList = SympatheticProcList.size();
} }
} }
for(int y = 0; y < MAX_AUGMENT_SLOTS; ++y) for(int y = 0; y < MAX_AUGMENT_SLOTS; ++y)
{ {
if (SizeProcList > MAX_SYMPATHETIC) if (SympatheticProcList.size() > MAX_SYMPATHETIC)
continue; continue;
ItemInst *aug = nullptr; ItemInst *aug = nullptr;
@ -5130,14 +5080,16 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
if(aug) if(aug)
{ {
const Item_Struct* TempItemAug = aug->GetItem(); const Item_Struct* TempItemAug = aug->GetItem();
if (TempItemAug && TempItemAug->Focus.Effect > 0 && TempItemAug->Focus.Effect != SPELL_UNKNOWN) { if (TempItemAug && TempItemAug->Focus.Effect > 0 && IsValidSpell(TempItemAug->Focus.Effect)) {
proc_spellid = CalcFocusEffect(type, TempItemAug->Focus.Effect, spell_id); proc_spellid = CalcFocusEffect(type, TempItemAug->Focus.Effect, spell_id);
if (proc_spellid > 0) if (IsValidSpell(proc_spellid)){
{
ProcChance = GetSympatheticProcChances(spell_id, spells[TempItem->Focus.Effect].base[0], TempItemAug->ProcRate);
if(MakeRandomFloat(0, 1) <= ProcChance)
SympatheticProcList.push_back(proc_spellid); SympatheticProcList.push_back(proc_spellid);
SizeProcList = SympatheticProcList.size();
} }
} }
} }
@ -5152,26 +5104,57 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
uint32 buff_max = GetMaxTotalSlots(); uint32 buff_max = GetMaxTotalSlots();
for (buff_slot = 0; buff_slot < buff_max; buff_slot++) { for (buff_slot = 0; buff_slot < buff_max; buff_slot++) {
if (SizeProcList > MAX_SYMPATHETIC) if (SympatheticProcList.size() > MAX_SYMPATHETIC)
continue; continue;
focusspellid = buffs[buff_slot].spellid; focusspellid = buffs[buff_slot].spellid;
if (focusspellid == 0 || focusspellid >= SPDAT_RECORDS) if (IsValidSpell(focusspellid))
continue; continue;
proc_spellid = CalcFocusEffect(type, focusspellid, spell_id); proc_spellid = CalcFocusEffect(type, focusspellid, spell_id);
if (proc_spellid > 0) if (IsValidSpell(proc_spellid)){
{
ProcChance = GetSympatheticProcChances(spell_id, spells[focusspellid].base[0]);
if(MakeRandomFloat(0, 1) <= ProcChance)
SympatheticProcList.push_back(proc_spellid); SympatheticProcList.push_back(proc_spellid);
SizeProcList = SympatheticProcList.size();
} }
} }
} }
if (SizeProcList > 0) /*Note: At present, ff designing custom AA to have a sympathetic proc effect, only use one focus
effect within the aa_effects data for each AA*[No live AA's use this effect to my knowledge]*/
if (aabonuses.FocusEffects[type]){
uint32 aa_AA = 0;
uint32 aa_value = 0;
for (int i = 0; i < MAX_PP_AA_ARRAY; i++)
{ {
uint8 random = MakeRandomInt(0, SizeProcList-1); aa_AA = this->aa[i]->AA;
aa_value = this->aa[i]->value;
if (aa_AA < 1 || aa_value < 1)
continue;
if (SympatheticProcList.size() > MAX_SYMPATHETIC)
continue;
proc_spellid = CalcAAFocus(type, aa_AA, spell_id);
if (IsValidSpell(proc_spellid)){
ProcChance = GetSympatheticProcChances(spell_id, GetAABase1(aa_AA, 1));
if(MakeRandomFloat(0, 1) <= ProcChance)
SympatheticProcList.push_back(proc_spellid);
}
}
}
if (SympatheticProcList.size() > 0)
{
uint8 random = MakeRandomInt(0, SympatheticProcList.size()-1);
int FinalSympatheticProc = SympatheticProcList[random]; int FinalSympatheticProc = SympatheticProcList[random];
SympatheticProcList.clear(); SympatheticProcList.clear();
return FinalSympatheticProc; return FinalSympatheticProc;
@ -5674,15 +5657,29 @@ bool Mob::AffectedBySpellExcludingSlot(int slot, int effect)
return false; return false;
} }
float Mob::GetSympatheticProcChances(float &ProcBonus, float &ProcChance, int32 cast_time, int16 ProcRateMod) { float Mob::GetSympatheticProcChances(uint16 spell_id, int16 ProcRateMod, int32 ItemProcRate) {
ProcChance = 0; float ProcChance = 0.0f;
int32 total_cast_time = 0;
float cast_time_mod = 0.0f;
ProcRateMod -= 100;
if (spells[spell_id].recast_time >= spells[spell_id].recovery_time)
total_cast_time = spells[spell_id].recast_time + spells[spell_id].cast_time;
else
total_cast_time = spells[spell_id].recovery_time + spells[spell_id].cast_time;
if (total_cast_time > 0 && total_cast_time <= 2500)
cast_time_mod = 0.25f;
else if (total_cast_time > 2500 && total_cast_time < 7000)
cast_time_mod = 0.167*((static_cast<float>(total_cast_time) - 1000.0f)/1000.0f);
else
cast_time_mod = static_cast<float>(total_cast_time) / 7000.0f;
ProcChance = (RuleR(Casting, AvgSpellProcsPerMinute)/100.0f) * (static_cast<float>(100.0f + ProcRateMod) / 10.0f)
* cast_time_mod * (static_cast<float>(100.0f + ItemProcRate)/100.0f);
if(cast_time > 0)
{
ProcChance = ((float)cast_time * RuleR(Casting, AvgSpellProcsPerMinute) / 60000.0f);
ProcChance = ProcChance * (float)(ProcRateMod/100);
}
return ProcChance; return ProcChance;
} }

View File

@ -5103,37 +5103,6 @@ bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll)
return true; return true;
} }
bool Mob::AddSkillProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id)
{
if(spell_id == SPELL_UNKNOWN)
return(false);
int i;
for (i = 0; i < MAX_PROCS; i++) {
if (SkillProcs[i].spellID == SPELL_UNKNOWN) {
SkillProcs[i].spellID = spell_id;
SkillProcs[i].chance = iChance;
SkillProcs[i].base_spellID = base_spell_id;
mlog(SPELLS__PROCS, "Added spell-granted skill proc spell %d with chance %d to slot %d", spell_id, iChance, i);
return true;
}
}
return false;
}
bool Mob::RemoveSkillProc(uint16 spell_id, bool bAll)
{
for (int i = 0; i < MAX_PROCS; i++) {
if (bAll || SkillProcs[i].spellID == spell_id) {
SkillProcs[i].spellID = SPELL_UNKNOWN;
SkillProcs[i].chance = 0;
SkillProcs[i].base_spellID = SPELL_UNKNOWN;
mlog(SPELLS__PROCS, "Removed Skill proc %d from slot %d", spell_id, i);
}
}
return true;
}
bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id) bool Mob::AddRangedProc(uint16 spell_id, uint16 iChance, uint16 base_spell_id)
{ {
if(spell_id == SPELL_UNKNOWN) if(spell_id == SPELL_UNKNOWN)