Merge branch 'master' into RunQueryToDatabaseQuery_database

Conflicts:
	changelog.txt
	common/spdat.h
	zone/attack.cpp
	zone/bonuses.cpp
	zone/common.h
	zone/mob.h
	zone/special_attacks.cpp
	zone/spell_effects.cpp
This commit is contained in:
Arthur Ice
2014-07-10 14:15:05 -07:00
19 changed files with 641 additions and 317 deletions
+204 -72
View File
@@ -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) {
+92 -1
View File
@@ -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;
}
}
}
+13 -13
View File
@@ -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);
+1 -1
View File
@@ -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);
+4 -1
View File
@@ -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
-7
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);
break;
}
case SE_SkillProc2:
case SE_SkillProc:
{
AddSkillProc(GetProcID(buffs[j1].spellid, x1), 100+spells[buffs[j1].spellid].base2[x1],buffs[j1].spellid);
break;
}
}
}
}
+4 -1
View File
@@ -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
+10
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(hate == -1)
{
+50 -8
View File
@@ -2753,14 +2753,6 @@ void Mob::Warp( float x, float y, float z )
SendPosition();
}
bool Mob::DivineAura() const
{
if (spellbonuses.DivineAura)
return true;
return false;
}
int16 Mob::GetResist(uint8 type) const
{
if (IsNPC())
@@ -3042,6 +3034,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 +4726,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))
+10 -8
View File
@@ -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);
@@ -819,7 +818,8 @@ public:
inline int& GetNextIncHPEvent() { return nextinchpevent; }
void SetNextIncHPEvent( int inchpevent );
bool DivineAura() const;
inline bool DivineAura() const { return spellbonuses.DivineAura; }
inline bool Sanctuary() const { return spellbonuses.Sanctuary; }
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];
+66 -39
View File
@@ -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) *
@@ -2066,7 +2090,7 @@ float Mob::GetSpecialProcChances(uint16 hand)
ProcBonus += static_cast<float>(mydex/35) + static_cast<float>(itembonuses.HeroicDEX / 25);
ProcChance += ProcChance * ProcBonus / 100.0f;
} else {
/*PRE 2014 CHANGE Dev Quote - "Elidroth SOE:Proc chance is a function of your base hardcapped Dexterity / 35 + Heroic Dexterity / 25.
/*PRE 2014 CHANGE Dev Quote - "Elidroth SOE:Proc chance is a function of your base hardcapped Dexterity / 35 + Heroic Dexterity / 25.”
Kayen: Most reports suggest a ~ 6% chance to Headshot which consistent with above.*/
ProcChance = (static_cast<float>(mydex/35) + static_cast<float>(itembonuses.HeroicDEX / 25))/100.0f;
@@ -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)
+129 -132
View File
@@ -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)
{
-31
View File
@@ -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)