mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 09:31:30 +00:00
commit
fc721b8ec8
@ -1,5 +1,17 @@
|
||||
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 ==
|
||||
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.
|
||||
|
||||
@ -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_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, PreNerfBardAEDoT, false) //Allow bard AOE dots to damage targets when moving.
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY( Combat )
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
#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 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;
|
||||
|
||||
@ -385,7 +387,7 @@ typedef enum {
|
||||
#define SE_ChannelChanceSpells 235 // implemented[AA] - chance to channel from SPELLS *No longer used on live.
|
||||
//#define SE_FreePet 236 // not used
|
||||
#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_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.
|
||||
@ -576,7 +578,7 @@ typedef enum {
|
||||
//#define SE_IncreaseExtTargetWindow 426 // *not implmented[AA] - increases the capacity of your extended target window
|
||||
#define SE_SkillProc 427 // implemented - chance to proc when using a skill(ie taunt)
|
||||
#define SE_LimitToSkill 428 // implemented - limits what skills will effect a skill proc
|
||||
#define SE_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_PostEffectData 431 // *not implemented - Fear of the Dark(27641) - Alters vision
|
||||
//#define SE_ExpandMaxActiveTrophyBen 432 // not used
|
||||
|
||||
6
utils/sql/git/required/2014_07_04_AA_Updates.sql
Normal file
6
utils/sql/git/required/2014_07_04_AA_Updates.sql
Normal 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');
|
||||
276
zone/attack.cpp
276
zone/attack.cpp
@ -1359,8 +1359,11 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
||||
|
||||
MeleeLifeTap(damage);
|
||||
|
||||
if (damage > 0)
|
||||
if (damage > 0){
|
||||
CheckNumHitsRemaining(NUMHIT_OutgoingHitSuccess);
|
||||
if (HasSkillProcSuccess() && other && other->GetHP() > 0)
|
||||
TrySkillProc(other, skillinuse, 0, true, Hand);
|
||||
}
|
||||
|
||||
//break invis when you attack
|
||||
if(invisible) {
|
||||
@ -2018,9 +2021,12 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
if (!GetTarget())
|
||||
return true; //We killed them
|
||||
|
||||
if(!bRiposte && other->GetHP() > 0 ) {
|
||||
if(!bRiposte && other && other->GetHP() > 0) {
|
||||
TryWeaponProc(nullptr, weapon, other, Hand); //no weapon
|
||||
TrySpellProc(nullptr, weapon, other, Hand);
|
||||
|
||||
if (damage > 0 && HasSkillProcSuccess())
|
||||
TrySkillProc(other, skillinuse, 0, true, Hand);
|
||||
}
|
||||
|
||||
TriggerDefensiveProcs(nullptr, other, Hand, damage);
|
||||
@ -3426,9 +3432,20 @@ bool Mob::HasDefensiveProcs() 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 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;
|
||||
}
|
||||
|
||||
@ -3911,22 +3928,7 @@ float Mob::GetProcChances(float ProcBonus, uint16 weapon_speed, uint16 hand)
|
||||
int mydex = GetDEX();
|
||||
float ProcChance = 0.0f;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//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);
|
||||
weapon_speed = GetWeaponSpeedbyHand(hand);
|
||||
|
||||
if (RuleB(Combat, AdjustProcPerMinute)) {
|
||||
ProcChance = (static_cast<float>(weapon_speed) *
|
||||
@ -3948,25 +3950,10 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 w
|
||||
ProcBonus = 0;
|
||||
ProcChance = 0;
|
||||
|
||||
switch(hand){
|
||||
case 13:
|
||||
weapon_speed = attack_timer.GetDuration();
|
||||
break;
|
||||
case 14:
|
||||
weapon_speed = attack_dw_timer.GetDuration();
|
||||
break;
|
||||
case 11:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
weapon_speed = GetWeaponSpeedbyHand(hand);
|
||||
|
||||
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
||||
//weapon_speed = ((int)(weapon_speed*(100.0f+attack_speed)*PermaHaste));
|
||||
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 = (static_cast<float>(weapon_speed) * RuleR(Combat, AvgDefProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
||||
ProcBonus += static_cast<float>(myagi) * RuleR(Combat, DefProcPerMinAgiContrib) / 100.0f;
|
||||
ProcChance = ProcChance + (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;
|
||||
}
|
||||
|
||||
bool bSkillProc = HasSkillProcs();
|
||||
bool bDefensiveProc = HasDefensiveProcs();
|
||||
|
||||
if (!bDefensiveProc && !bSkillProc)
|
||||
return;
|
||||
|
||||
if (!bDefensiveProc && (bSkillProc && damage >= 0))
|
||||
if (!bDefensiveProc)
|
||||
return;
|
||||
|
||||
float ProcChance, ProcBonus;
|
||||
@ -4000,30 +3983,15 @@ void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand, int dam
|
||||
|
||||
if (bDefensiveProc){
|
||||
for (int i = 0; i < MAX_PROCS; i++) {
|
||||
if (DefensiveProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
int chance = ProcChance * (DefensiveProcs[i].chance);
|
||||
if ((MakeRandomInt(0, 100) < chance)) {
|
||||
if (IsValidSpell(DefensiveProcs[i].spellID)) {
|
||||
float chance = ProcChance * (static_cast<float>(DefensiveProcs[i].chance)/100.0f);
|
||||
if ((MakeRandomFloat(0, 1) <= chance)) {
|
||||
ExecWeaponProc(nullptr, DefensiveProcs[i].spellID, on);
|
||||
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) {
|
||||
@ -4032,7 +4000,7 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
|
||||
LogFile->write(EQEMuLog::Error, "A null Mob object was passed to Mob::TryWeaponProc for evaluation!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!IsAttackAllowed(on)) {
|
||||
mlog(COMBAT__PROCS, "Preventing procing off of unattackable things.");
|
||||
return;
|
||||
@ -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)
|
||||
{
|
||||
|
||||
if (!weapon)
|
||||
return;
|
||||
uint16 skillinuse = 28;
|
||||
@ -4135,8 +4104,6 @@ void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on
|
||||
}
|
||||
}
|
||||
// TODO: Powersource procs
|
||||
if (HasSkillProcs())
|
||||
TrySkillProc(on, skillinuse, ProcChance);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
@ -4569,17 +4544,174 @@ void Mob::TrySkillProc(Mob *on, uint16 skill, float chance)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_PROCS; i++) {
|
||||
if (SkillProcs[i].spellID != SPELL_UNKNOWN){
|
||||
if (PassLimitToSkill(SkillProcs[i].base_spellID,skill)){
|
||||
int ProcChance = chance * (float)SkillProcs[i].chance;
|
||||
if ((MakeRandomInt(0, 100) < ProcChance)) {
|
||||
ExecWeaponProc(nullptr, SkillProcs[i].spellID, on);
|
||||
CheckNumHitsRemaining(NUMHIT_OffensiveSpellProcs,0, SkillProcs[i].base_spellID);
|
||||
if (!spellbonuses.LimitToSkill[skill] && !itembonuses.LimitToSkill[skill] && !aabonuses.LimitToSkill[skill])
|
||||
return;
|
||||
|
||||
/*Allow one proc from each (Spell/Item/AA)
|
||||
Kayen: Due to limited avialability of effects on live it is too difficult
|
||||
to confirm how they stack at this time, will adjust formula when more data is avialablle to test.*/
|
||||
bool CanProc = true;
|
||||
|
||||
uint16 base_spell_id = 0;
|
||||
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) {
|
||||
|
||||
@ -637,7 +637,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
continue;
|
||||
|
||||
_log(AA__BONUSES, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName());
|
||||
|
||||
|
||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||
if (focus)
|
||||
{
|
||||
@ -1329,6 +1329,45 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
if (IsAISpellEffect) {
|
||||
|
||||
@ -4356,6 +4436,17 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.FactionModPct = effect_value;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
26
zone/bot.cpp
26
zone/bot.cpp
@ -3292,7 +3292,7 @@ bool Bot::CheckBotDoubleAttack(bool tripleAttack) {
|
||||
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))
|
||||
return;
|
||||
@ -3396,10 +3396,11 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
other->Stun(100);
|
||||
}
|
||||
|
||||
if (CanSkillProc && HasSkillProcs()){
|
||||
float chance = 10.0f*RuleR(Combat, AvgProcsPerMinute)/60000.0f;
|
||||
TrySkillProc(other, skillinuse, chance);
|
||||
}
|
||||
if (CanSkillProc && HasSkillProcs())
|
||||
TrySkillProc(other, skillinuse, ReuseTime);
|
||||
|
||||
if (CanSkillProc && (damage > 0) && HasSkillProcSuccess())
|
||||
TrySkillProc(other, skillinuse, ReuseTime, true);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
float ProcChance = GetSympatheticProcChances(spell_id, focus_spell.base[i]);
|
||||
|
||||
if(MakeRandomFloat(0, 1) <= ProcChance)
|
||||
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.
|
||||
}
|
||||
|
||||
if (HasSkillProcs()){
|
||||
float chance = (float)ReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f;
|
||||
TrySkillProc(who, skill, chance);
|
||||
}
|
||||
if (HasSkillProcs())
|
||||
TrySkillProc(who, skill, ReuseTime*1000);
|
||||
|
||||
if (max_damage > 0 && HasSkillProcSuccess())
|
||||
TrySkillProc(who, skill, ReuseTime*1000, true);
|
||||
|
||||
if(max_damage == -3 && !(who->GetHP() <= 0))
|
||||
DoRiposte(who);
|
||||
|
||||
@ -185,7 +185,7 @@ public:
|
||||
virtual void RogueAssassinate(Mob* other);
|
||||
virtual void DoClassAttacks(Mob *target, bool IsRiposte=false);
|
||||
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);
|
||||
bool CanDoSpecialAttack(Mob *other);
|
||||
virtual int32 CheckAggroAmount(uint16 spellid);
|
||||
|
||||
@ -776,7 +776,10 @@ public:
|
||||
int GetSpentAA() { return m_pp.aapoints_spent; }
|
||||
void RefundAA();
|
||||
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();
|
||||
|
||||
// Item methods
|
||||
|
||||
@ -9490,13 +9490,6 @@ void Client::CompleteConnect()
|
||||
AddRangedProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid);
|
||||
break;
|
||||
}
|
||||
case SE_SkillProc2:
|
||||
case SE_SkillProc:
|
||||
{
|
||||
AddSkillProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -375,6 +375,9 @@ struct StatBonuses {
|
||||
bool Sanctuary; // Sanctuary effect, lowers place on hate list until cast on others.
|
||||
int16 FactionModPct; // Modifies amount of faction gained.
|
||||
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
|
||||
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
|
||||
uint8 AssassinateLevel; // Max Level Assassinate will be effective at.
|
||||
int32 PetMeleeMitigation; // Add AC to owner's pet.
|
||||
|
||||
bool IllusionPersistence; // Causes illusions not to fade.
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
||||
@ -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(hate == -1)
|
||||
{
|
||||
|
||||
58
zone/mob.cpp
58
zone/mob.cpp
@ -2761,6 +2761,14 @@ bool Mob::DivineAura() const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mob::Sanctuary() const
|
||||
{
|
||||
if (spellbonuses.Sanctuary)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int16 Mob::GetResist(uint8 type) const
|
||||
{
|
||||
if (IsNPC())
|
||||
@ -3042,6 +3050,34 @@ void Mob::TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand, in
|
||||
return;
|
||||
|
||||
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) {
|
||||
@ -4706,6 +4742,28 @@ bool Mob::PassLimitToSkill(uint16 spell_id, uint16 skill) {
|
||||
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) {
|
||||
|
||||
if (!IsValidSpell(spell_id))
|
||||
|
||||
16
zone/mob.h
16
zone/mob.h
@ -506,9 +506,8 @@ public:
|
||||
bool AddDefensiveProc(uint16 spell_id, uint16 iChance = 3, uint16 base_spell_id = SPELL_UNKNOWN);
|
||||
bool RemoveDefensiveProc(uint16 spell_id, bool bAll = false);
|
||||
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 HasSkillProcSuccess() const;
|
||||
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 HasProcs() const;
|
||||
@ -700,9 +699,9 @@ public:
|
||||
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 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 DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes skillinuse, int16 chance_mod=0, int16 focus=0, bool CanRiposte=false);
|
||||
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 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, 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, int ReuseTime=0);
|
||||
bool CanDoSpecialAttack(Mob *other);
|
||||
bool Flurry(ExtraAttackOptions *opts);
|
||||
bool Rampage(ExtraAttackOptions *opts);
|
||||
@ -820,6 +819,7 @@ public:
|
||||
void SetNextIncHPEvent( int inchpevent );
|
||||
|
||||
bool DivineAura() const;
|
||||
bool Sanctuary() const;
|
||||
|
||||
bool HasNPCSpecialAtk(const char* parse);
|
||||
int GetSpecialAbility(int ability);
|
||||
@ -986,7 +986,7 @@ protected:
|
||||
bool focused;
|
||||
void CalcSpellBonuses(StatBonuses* newbon);
|
||||
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 PassLimitClass(uint32 Classes_, uint16 Class_);
|
||||
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 GetSpecialProcChances(uint16 hand);
|
||||
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 ItemInst *weapon_item, uint32 *hate = nullptr);
|
||||
int GetKickDamage();
|
||||
@ -1009,7 +1011,7 @@ protected:
|
||||
Map::Vertex UpdatePath(float ToX, float ToY, float ToZ, float Speed, bool &WaypointChange, bool &NodeReached);
|
||||
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};
|
||||
tProc PermaProcs[MAX_PROCS];
|
||||
|
||||
@ -171,11 +171,12 @@ 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.
|
||||
}
|
||||
|
||||
if (HasSkillProcs()){
|
||||
float chance = (float)ReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f;
|
||||
TrySkillProc(who, skill, chance);
|
||||
}
|
||||
|
||||
if (HasSkillProcs())
|
||||
TrySkillProc(who, skill, ReuseTime*1000);
|
||||
|
||||
if (max_damage > 0 && HasSkillProcSuccess())
|
||||
TrySkillProc(who, skill, ReuseTime*1000, true);
|
||||
|
||||
if(max_damage == -3 && !who->HasDied())
|
||||
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))
|
||||
return;
|
||||
@ -874,6 +875,9 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
else
|
||||
WDmg = weapon_damage;
|
||||
|
||||
if (focus) //From FcBaseEffects
|
||||
WDmg += WDmg*focus/100;
|
||||
|
||||
if((WDmg > 0) || (ADmg > 0))
|
||||
{
|
||||
if(WDmg < 0)
|
||||
@ -948,7 +952,6 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||
if(TotalDmg > 0)
|
||||
{
|
||||
TotalDmg += TotalDmg*focus/100;
|
||||
ApplyMeleeDamageBonus(SkillArchery, TotalDmg);
|
||||
TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, SkillArchery);
|
||||
TotalDmg += (itembonuses.HeroicDEX / 10) + (TotalDmg * other->GetSkillDmgTaken(SkillArchery) / 100) + GetSkillDmgAmt(SkillArchery);
|
||||
@ -967,20 +970,33 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Item
|
||||
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FATAL_BOW_SHOT, GetName());
|
||||
|
||||
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
|
||||
if((RangeWeapon != nullptr) && GetTarget() && other && (other->GetHP() > -10))
|
||||
if((RangeWeapon != nullptr) && GetTarget() && other && !other->HasDied())
|
||||
{
|
||||
TryWeaponProc(RangeWeapon, other, 11);
|
||||
}
|
||||
|
||||
//Arrow procs because why not?
|
||||
if((Ammo != NULL) && GetTarget() && other && (other->GetHP() > -10))
|
||||
if((Ammo != NULL) && GetTarget() && other && !other->HasDied())
|
||||
{
|
||||
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)
|
||||
@ -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))
|
||||
return;
|
||||
@ -1268,9 +1284,12 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
|
||||
if (!weapon_damage && item != nullptr)
|
||||
WDmg = GetWeaponDamage(other, item);
|
||||
else
|
||||
else
|
||||
WDmg = weapon_damage;
|
||||
|
||||
if (focus) //From FcBaseEffects
|
||||
WDmg += WDmg*focus/100;
|
||||
|
||||
int32 TotalDmg = 0;
|
||||
|
||||
uint32 Assassinate_Dmg = 0;
|
||||
@ -1294,7 +1313,6 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||
if(TotalDmg > 0)
|
||||
{
|
||||
TotalDmg += TotalDmg*focus/100;
|
||||
ApplyMeleeDamageBonus(SkillThrowing, TotalDmg);
|
||||
TotalDmg += other->GetFcDamageAmtIncoming(this, 0, true, 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;
|
||||
|
||||
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))
|
||||
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) {
|
||||
@ -1891,6 +1924,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
Mob *hate_top = who->GetHateMost();
|
||||
|
||||
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.
|
||||
if ((RuleB(Combat,TauntOverLevel) == false) && (level_difference < 0) || who->GetSpecialAbility(IMMUNE_TAUNT)){
|
||||
@ -1903,7 +1937,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
|
||||
int32 newhate = 0;
|
||||
float tauntchance = 50.0f;
|
||||
|
||||
|
||||
if(always_succeed)
|
||||
tauntchance = 101.0f;
|
||||
|
||||
@ -1940,6 +1974,7 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
if (hate_top && hate_top != this){
|
||||
newhate = (who->GetNPCHate(hate_top) - who->GetNPCHate(this)) + 1;
|
||||
who->CastToNPC()->AddToHateList(this, newhate);
|
||||
Success = true;
|
||||
}
|
||||
else
|
||||
who->CastToNPC()->AddToHateList(this,12);
|
||||
@ -1955,10 +1990,12 @@ void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
|
||||
else
|
||||
Message_StringID(MT_SpellFailure,FAILED_TAUNT);
|
||||
|
||||
if (HasSkillProcs()){
|
||||
float chance = (float)TauntReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f;
|
||||
TrySkillProc(who, SkillTaunt, chance);
|
||||
}
|
||||
if (HasSkillProcs())
|
||||
TrySkillProc(who, SkillTaunt, TauntReuseTime*1000);
|
||||
|
||||
|
||||
if (Success && HasSkillProcSuccess())
|
||||
TrySkillProc(who, SkillTaunt, TauntReuseTime*1000, true);
|
||||
}
|
||||
|
||||
|
||||
@ -2045,20 +2082,7 @@ float Mob::GetSpecialProcChances(uint16 hand)
|
||||
float ProcChance = 0.0f;
|
||||
float ProcBonus = 0.0f;
|
||||
|
||||
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);
|
||||
weapon_speed = GetWeaponSpeedbyHand(hand);
|
||||
|
||||
if (RuleB(Combat, AdjustSpecialProcPerMinute)) {
|
||||
ProcChance = (static_cast<float>(weapon_speed) *
|
||||
@ -2138,7 +2162,7 @@ float Mob::GetAssassinateProcChances(uint16 ReuseTime)
|
||||
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))
|
||||
return;
|
||||
@ -2155,6 +2179,9 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
||||
|
||||
if(weapon_damage > 0){
|
||||
|
||||
if (focus) //From FcBaseEffects
|
||||
weapon_damage += weapon_damage*focus/100;
|
||||
|
||||
if(GetClass() == BERSERKER){
|
||||
int bonus = 3 + GetLevel()/10;
|
||||
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->MeleeMitigation(this, damage, min_hit);
|
||||
if(damage > 0) {
|
||||
damage += damage*focus/100;
|
||||
ApplyMeleeDamageBonus(skillinuse, damage);
|
||||
damage += other->GetFcDamageAmtIncoming(this, 0, true, 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);
|
||||
}
|
||||
|
||||
if (CanSkillProc && HasSkillProcs()){
|
||||
float chance = 10.0f*RuleR(Combat, AvgProcsPerMinute)/60000.0f;
|
||||
TrySkillProc(other, skillinuse, chance);
|
||||
}
|
||||
if (CanSkillProc && HasSkillProcs())
|
||||
TrySkillProc(other, skillinuse, ReuseTime);
|
||||
|
||||
if (CanSkillProc && (damage > 0) && HasSkillProcSuccess())
|
||||
TrySkillProc(other, skillinuse, ReuseTime, true);
|
||||
}
|
||||
|
||||
bool Mob::CanDoSpecialAttack(Mob *other)
|
||||
|
||||
@ -1430,7 +1430,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
for(int x = 0; x < 7; x++){
|
||||
SendWearChange(x);
|
||||
}
|
||||
if(caster && caster->GetAA(aaPermanentIllusion))
|
||||
if(caster && (caster->spellbonuses.IllusionPersistence || caster->aabonuses.IllusionPersistence
|
||||
|| caster->itembonuses.IllusionPersistence))
|
||||
buffs[buffslot].persistant_buff = 1;
|
||||
else
|
||||
buffs[buffslot].persistant_buff = 0;
|
||||
@ -1772,20 +1773,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
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:
|
||||
{
|
||||
#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)
|
||||
*/
|
||||
int16 focus = 0;
|
||||
int ReuseTime = spells[spell_id].recast_time + spells[spell_id].recovery_time;
|
||||
|
||||
if(caster->IsClient())
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
@ -2329,7 +2317,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
if (buffslot >= 0)
|
||||
break;
|
||||
//This effect does no damage if target is moving.
|
||||
if (IsMoving())
|
||||
if (!RuleB(Spells, PreNerfBardAEDoT) && IsMoving())
|
||||
break;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
case SE_ImmuneFleeing:
|
||||
case SE_NegateSpellEffect:
|
||||
@ -2984,6 +2956,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_AssassinateLevel:
|
||||
case SE_FactionModPct:
|
||||
case SE_LimitSpellClass:
|
||||
case SE_Sanctuary:
|
||||
case SE_PetMeleeMitigation:
|
||||
case SE_SkillProc:
|
||||
case SE_SkillProcSuccess:
|
||||
{
|
||||
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);
|
||||
|
||||
if (IsMoving() || invulnerable || /*effect_value > 0 ||*/ DivineAura())
|
||||
if ((!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) || invulnerable || /*effect_value > 0 ||*/ DivineAura())
|
||||
break;
|
||||
|
||||
if(effect_value < 0) {
|
||||
@ -3630,21 +3606,6 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
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:
|
||||
{
|
||||
@ -3712,14 +3673,6 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SkillProc2:
|
||||
case SE_SkillProc:
|
||||
{
|
||||
uint16 procid = GetProcID(buffs[slot].spellid, i);
|
||||
RemoveSkillProc(procid);
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DefensiveProc:
|
||||
{
|
||||
uint16 procid = GetProcID(buffs[slot].spellid, i);
|
||||
@ -4084,39 +4037,41 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
CalcBonuses();
|
||||
}
|
||||
|
||||
/* No longer used.
|
||||
int16 Client::CalcAAFocusEffect(focusType type, uint16 focus_spell, uint16 spell_id)
|
||||
int32 Client::GetAAEffectDataBySlot(uint32 aa_ID, uint32 slot_id, bool GetEffect, bool GetBase1, bool GetBase2)
|
||||
{
|
||||
uint32 slots = 0;
|
||||
uint32 aa_AA = 0;
|
||||
uint32 aa_value = 0;
|
||||
int32 aa_effects_data[3] = { 0 };
|
||||
uint32 effect = 0;
|
||||
int32 base1 = 0;
|
||||
int32 base2 = 0;
|
||||
uint32 slot = 0;
|
||||
|
||||
int32 value = 0;
|
||||
// Iterate through all of the client's AAs
|
||||
for (int i = 0; i < MAX_PP_AA_ARRAY; i++)
|
||||
|
||||
std::map<uint32, std::map<uint32, AA_Ability> >::const_iterator find_iter = aa_effects.find(aa_ID);
|
||||
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;
|
||||
aa_value = this->aa[i]->value;
|
||||
if (aa_AA > 0 || aa_value > 0)
|
||||
{
|
||||
slots = zone->GetTotalAALevels(aa_AA);
|
||||
if (slots > 0)
|
||||
for(int j = 1;j <= slots; j++)
|
||||
{
|
||||
switch (aa_effects[aa_AA][j].skill_id)
|
||||
{
|
||||
case SE_TriggerOnCast:
|
||||
// If focus_spell matches the spell listed in the DB, load these restrictions
|
||||
if(type == focusTriggerOnCast && focus_spell == aa_effects[aa_AA][j].base1)
|
||||
value = CalcAAFocus(type, aa_AA, spell_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
effect = iter->second.skill_id;
|
||||
base1 = iter->second.base1;
|
||||
base2 = iter->second.base2;
|
||||
slot = iter->second.slot;
|
||||
|
||||
if (slot && slot == slot_id) {
|
||||
|
||||
if (GetEffect)
|
||||
return effect;
|
||||
|
||||
if (GetBase1)
|
||||
return base1;
|
||||
|
||||
if (GetBase2)
|
||||
return base2;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
@ -4496,9 +4451,11 @@ int16 Client::CalcAAFocus(focusType type, uint32 aa_ID, uint16 spell_id)
|
||||
value = base1;
|
||||
break;
|
||||
|
||||
case SE_SympatheticProc:
|
||||
//No AA support at this time.
|
||||
break;
|
||||
//Note if using these as AA, make sure this is first focus used.
|
||||
case SE_SympatheticProc:
|
||||
if(type == focusSympatheticProc)
|
||||
value = base2;
|
||||
break;
|
||||
|
||||
case SE_FcDamageAmt:
|
||||
if(type == focusFcDamageAmt)
|
||||
@ -4962,16 +4919,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
|
||||
case SE_SympatheticProc:
|
||||
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;
|
||||
|
||||
else
|
||||
value = 0;
|
||||
value = focus_id;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -5089,8 +5037,8 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
return 0;
|
||||
|
||||
uint16 proc_spellid = 0;
|
||||
uint8 SizeProcList = 0;
|
||||
uint8 MAX_SYMPATHETIC = 10;
|
||||
float ProcChance = 0.0f;
|
||||
|
||||
std::vector<int> SympatheticProcList;
|
||||
|
||||
@ -5101,7 +5049,7 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
|
||||
for(int x=0; x<=21; x++)
|
||||
{
|
||||
if (SizeProcList > MAX_SYMPATHETIC)
|
||||
if (SympatheticProcList.size() > MAX_SYMPATHETIC)
|
||||
continue;
|
||||
|
||||
TempItem = nullptr;
|
||||
@ -5109,20 +5057,22 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
if (!ins)
|
||||
continue;
|
||||
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 (IsValidSpell(proc_spellid)){
|
||||
|
||||
if (proc_spellid > 0)
|
||||
{
|
||||
SympatheticProcList.push_back(proc_spellid);
|
||||
SizeProcList = SympatheticProcList.size();
|
||||
}
|
||||
ProcChance = GetSympatheticProcChances(spell_id, spells[TempItem->Focus.Effect].base[0], TempItem->ProcRate);
|
||||
|
||||
if(MakeRandomFloat(0, 1) <= ProcChance)
|
||||
SympatheticProcList.push_back(proc_spellid);
|
||||
}
|
||||
}
|
||||
|
||||
for(int y = 0; y < MAX_AUGMENT_SLOTS; ++y)
|
||||
{
|
||||
if (SizeProcList > MAX_SYMPATHETIC)
|
||||
if (SympatheticProcList.size() > MAX_SYMPATHETIC)
|
||||
continue;
|
||||
|
||||
ItemInst *aug = nullptr;
|
||||
@ -5130,14 +5080,16 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
if(aug)
|
||||
{
|
||||
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);
|
||||
|
||||
if (proc_spellid > 0)
|
||||
{
|
||||
SympatheticProcList.push_back(proc_spellid);
|
||||
SizeProcList = SympatheticProcList.size();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5152,26 +5104,57 @@ int16 Client::GetSympatheticFocusEffect(focusType type, uint16 spell_id) {
|
||||
uint32 buff_max = GetMaxTotalSlots();
|
||||
for (buff_slot = 0; buff_slot < buff_max; buff_slot++) {
|
||||
|
||||
if (SizeProcList > MAX_SYMPATHETIC)
|
||||
if (SympatheticProcList.size() > MAX_SYMPATHETIC)
|
||||
continue;
|
||||
|
||||
focusspellid = buffs[buff_slot].spellid;
|
||||
if (focusspellid == 0 || focusspellid >= SPDAT_RECORDS)
|
||||
if (IsValidSpell(focusspellid))
|
||||
continue;
|
||||
|
||||
proc_spellid = CalcFocusEffect(type, focusspellid, spell_id);
|
||||
|
||||
if (proc_spellid > 0)
|
||||
{
|
||||
SympatheticProcList.push_back(proc_spellid);
|
||||
SizeProcList = SympatheticProcList.size();
|
||||
}
|
||||
if (IsValidSpell(proc_spellid)){
|
||||
|
||||
ProcChance = GetSympatheticProcChances(spell_id, spells[focusspellid].base[0]);
|
||||
|
||||
if(MakeRandomFloat(0, 1) <= ProcChance)
|
||||
SympatheticProcList.push_back(proc_spellid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
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, SizeProcList-1);
|
||||
uint8 random = MakeRandomInt(0, SympatheticProcList.size()-1);
|
||||
int FinalSympatheticProc = SympatheticProcList[random];
|
||||
SympatheticProcList.clear();
|
||||
return FinalSympatheticProc;
|
||||
@ -5674,17 +5657,31 @@ bool Mob::AffectedBySpellExcludingSlot(int slot, int effect)
|
||||
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(cast_time > 0)
|
||||
{
|
||||
ProcChance = ((float)cast_time * RuleR(Casting, AvgSpellProcsPerMinute) / 60000.0f);
|
||||
ProcChance = ProcChance * (float)(ProcRateMod/100);
|
||||
}
|
||||
return ProcChance;
|
||||
}
|
||||
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);
|
||||
|
||||
return ProcChance;
|
||||
}
|
||||
|
||||
bool Mob::DoHPToManaCovert(uint16 mana_cost)
|
||||
{
|
||||
|
||||
@ -5103,37 +5103,6 @@ bool Mob::RemoveDefensiveProc(uint16 spell_id, bool bAll)
|
||||
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)
|
||||
{
|
||||
if(spell_id == SPELL_UNKNOWN)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user