Implemented SE_Assassinate, SE_AssassinateLevel - Defines assassinate damage and level requirements.

Revised Assassinate mechanic so damage now receives all backstab bonuses, proc chance can be set to either (lives new Proc Per minute
system, or flat chance based on dex (formula updated). Assassinate can now proc from THROW if behind target, various other adjustments.

Required SQL for AA updates
This commit is contained in:
KayenEQ 2014-06-29 23:26:22 -04:00
parent 8a92fada5a
commit 70f10782b0
6 changed files with 157 additions and 147 deletions

View File

@ -12,8 +12,11 @@ Kayen: Update SE_AETaunt - Base value will now determine AE taunt range (This wi
Kayen: Udpated SE_ReclaimPet - Correct forumla for mana returned to properly return 75% of actual pet spell mana cost. Kayen: Udpated SE_ReclaimPet - Correct forumla for mana returned to properly return 75% of actual pet spell mana cost.
Kayen: Implemented SE_ImprovedReclaimEnergy - Modifies % mana returned from SE_ReclaimPet. Kayen: Implemented SE_ImprovedReclaimEnergy - Modifies % mana returned from SE_ReclaimPet.
Kayen: Implemented SE_HeadShot, SE_HeadShotLevel - Defines headshot damage and level requirements. Kayen: Implemented SE_HeadShot, SE_HeadShotLevel - Defines headshot damage and level requirements.
Revised HeadShot mechanic so damage now recieves all archery bonuses, proc chance can be set to either (lives new Proc Per minute Revised HeadShot mechanic so damage now receives all archery bonuses, proc chance can be set to either (lives new Proc Per minute
system, or flat chance based on dex (formula updated). system, or flat chance based on dex (formula updated).
Kayen: Implemented SE_Assassinate, SE_AssassinateLevel - Defines assassinate damage and level requirements.
Revised Assassinate mechanic so damage now receives all backstab bonuses, proc chance can be set to either (lives new Proc Per minute
system, or flat chance based on dex (formula updated). Assassinate can now proc from THROW if behind target, various other adjustments.
Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql Required SQL: utils/sql/git/required/2014_06_25_AA_Update.sql
Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql Optional SQL: utils/sql/git/optiional/2014_06_29_HeadShotRules.sql

View File

@ -13,5 +13,11 @@ INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '1', '217', '0', '32000'); INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '1', '217', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '2', '346', '46', '0'); INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '2', '346', '46', '0');
-- spells_new update -- AA Anatomy (Rogue Assassinate)
ALTER TABLE `spells_new` CHANGE `field175` `numhits_type` INT(11) NOT NULL DEFAULT '0'; 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 ('1604', 'Anatomy', '5', '3', '4294967295', '4294967295', '1604', '1604', '1', '4294967295', '0', '0', '0', '0', '512', '0', '60', '1', '10', '4294967295', '3', '0', '3', '1604', '1', '0', '0', '0', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '2', '345', '48', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '2', '345', '51', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '2', '345', '53', '0');

View File

@ -1296,6 +1296,22 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
break; break;
} }
case SE_Assassinate:
{
if(newbon->Assassinate[1] < base2){
newbon->Assassinate[0] = base1;
newbon->Assassinate[1] = base2;
}
break;
}
case SE_AssassinateLevel:
{
if(newbon->AssassinateLevel < base1)
newbon->AssassinateLevel = base1;
break;
}
} }
} }
} }

View File

@ -423,9 +423,9 @@ struct StatBonuses {
int8 IncreaseChanceMemwipe; // increases chance to memory wipe int8 IncreaseChanceMemwipe; // increases chance to memory wipe
int8 CriticalMend; // chance critical monk mend int8 CriticalMend; // chance critical monk mend
int16 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy int16 ImprovedReclaimEnergy; // Modifies amount of mana returned from reclaim energy
int32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg uint32 HeadShot[2]; // Headshot AA (Massive dmg vs humaniod w/ archery) 0= ? 1= Dmg
uint8 HSLevel; // Max Level Headshot will be effective at. uint8 HSLevel; // Max Level Headshot will be effective at.
int32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg uint32 Assassinate[2]; // Assassinate AA (Massive dmg vs humaniod w/ assassinate) 0= ? 1= Dmg
uint8 AssassinateLevel; // Max Level Assassinate will be effective at. uint8 AssassinateLevel; // Max Level Assassinate will be effective at.
}; };

View File

@ -142,6 +142,7 @@ public:
void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage); void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage);
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse); virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
uint32 TryHeadShot(Mob* defender, SkillUseTypes skillInUse); uint32 TryHeadShot(Mob* defender, SkillUseTypes skillInUse);
uint32 TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime);
virtual void DoRiposte(Mob* defender); virtual void DoRiposte(Mob* defender);
void ApplyMeleeDamageBonus(uint16 skill, int32 &damage); void ApplyMeleeDamageBonus(uint16 skill, int32 &damage);
virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr); virtual void MeleeMitigation(Mob *attacker, int32 &damage, int32 minhit, ExtraAttackOptions *opts = nullptr);
@ -694,7 +695,7 @@ public:
int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker); int32 AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTic, Mob* attacker);
int32 ReduceAllDamage(int32 damage); int32 ReduceAllDamage(int32 damage);
virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false); virtual void DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage = 1, int32 hate_override = -1, int ReuseTime = 10, bool HitChance=false, bool CanAvoid=true);
virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0); virtual void DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const Item_Struct* item=nullptr, uint16 weapon_damage=0, int16 chance_mod=0,int16 focus=0);
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);
virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0); virtual void DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon=nullptr, const ItemInst* Ammo=nullptr, uint16 weapon_damage=0, int16 chance_mod=0, int16 focus=0);
@ -991,7 +992,8 @@ protected:
void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on); void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on);
virtual float GetProcChances(float ProcBonus, uint16 weapon_speed = 30, uint16 hand = 13); virtual float GetProcChances(float ProcBonus, uint16 weapon_speed = 30, uint16 hand = 13);
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13); virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13);
virtual float GetSpecialProcChances(uint16 hand = 13); virtual float GetSpecialProcChances(uint16 hand);
virtual float GetAssassinateProcChances(uint16 ReuseTime);
int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item); int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item);
int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr); int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr);
int GetKickDamage(); int GetKickDamage();

View File

@ -100,7 +100,8 @@ void Mob::ApplySpecialAttackMod(SkillUseTypes skill, int32 &dmg, int32 &mindmg)
} }
} }
void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime, bool HitChance) { void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage, int32 min_damage, int32 hate_override,int ReuseTime,
bool HitChance, bool CanAvoid) {
//this really should go through the same code as normal melee damage to //this really should go through the same code as normal melee damage to
//pick up all the special behavior there //pick up all the special behavior there
@ -135,7 +136,9 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&' if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&'
CanRiposte = false; CanRiposte = false;
who->AvoidDamage(this, max_damage, CanRiposte); if (CanAvoid)
who->AvoidDamage(this, max_damage, CanRiposte);
who->MeleeMitigation(this, max_damage, min_damage); who->MeleeMitigation(this, max_damage, min_damage);
if(max_damage > 0) { if(max_damage > 0) {
@ -373,8 +376,8 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
if (ca_atk->m_atk != 100 || ca_atk->m_skill != SkillBackstab) { if (ca_atk->m_atk != 100 || ca_atk->m_skill != SkillBackstab) {
break; break;
} }
TryBackstab(GetTarget(), ReuseTime);
ReuseTime = BackstabReuseTime-1 - skill_reduction; ReuseTime = BackstabReuseTime-1 - skill_reduction;
TryBackstab(GetTarget(), ReuseTime);
break; break;
} }
default: default:
@ -527,64 +530,47 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
if (FrontalBSChance && (FrontalBSChance > MakeRandomInt(0, 100))) if (FrontalBSChance && (FrontalBSChance > MakeRandomInt(0, 100)))
bCanFrontalBS = true; bCanFrontalBS = true;
} }
if (bIsBehind || bCanFrontalBS){ // Player is behind other OR can do Frontal Backstab if (bIsBehind || bCanFrontalBS){ // Player is behind other OR can do Frontal Backstab
if (bCanFrontalBS) { if (bCanFrontalBS)
CastToClient()->Message(0,"Your fierce attack is executed with such grace, your target did not see it coming!"); CastToClient()->Message(0,"Your fierce attack is executed with such grace, your target did not see it coming!");
}
RogueBackstab(other,false,ReuseTime);
if (level > 54) {
// solar - chance to assassinate if(IsClient() && CastToClient()->CheckDoubleAttack(false))
int chance = 10 + (GetDEX()/10) + (itembonuses.HeroicDEX/10); //18.5% chance at 85 dex 40% chance at 300 dex {
if( if(other->GetHP() > 0)
level >= 60 && // player is 60 or higher RogueBackstab(other,false,ReuseTime);
other->GetLevel() <= 45 && // mob 45 or under
!other->CastToNPC()->IsEngaged() && // not aggro
other->GetHP()<=32000
&& other->IsNPC()
&& MakeRandomFloat(0, 99) < chance // chance
) {
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName());
if(IsClient())
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
RogueAssassinate(other);
}
else {
RogueBackstab(other);
if (level > 54) {
float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max
// Check for double attack with main hand assuming maxed DA Skill (MS)
if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
{ RogueBackstab(other,false,ReuseTime);
if(other->GetHP() > 0)
RogueBackstab(other,false,ReuseTime);
if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
RogueBackstab(other,false,ReuseTime);
}
} }
if(IsClient())
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
} }
if(IsClient())
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
} }
//Live AA - Chaotic Backstab //Live AA - Chaotic Backstab
else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) { else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) {
//we can stab from any angle, we do min damage though. //we can stab from any angle, we do min damage though.
RogueBackstab(other, true); RogueBackstab(other, true, ReuseTime);
if (level > 54) { if (level > 54) {
float DoubleAttackProbability = (GetSkill(SkillDoubleAttack) + GetLevel()) / 500.0f; // 62.4 max
if(IsClient())
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
// Check for double attack with main hand assuming maxed DA Skill (MS) // Check for double attack with main hand assuming maxed DA Skill (MS)
if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA if(IsClient() && CastToClient()->CheckDoubleAttack(false))
if(other->GetHP() > 0) if(other->GetHP() > 0)
RogueBackstab(other,true, ReuseTime); RogueBackstab(other,true, ReuseTime);
if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100)) if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
RogueBackstab(other,false,ReuseTime); RogueBackstab(other,false,ReuseTime);
} }
if(IsClient())
CastToClient()->CheckIncreaseSkill(SkillBackstab, other, 10);
} }
else { //We do a single regular attack if we attack from the front without chaotic stab else { //We do a single regular attack if we attack from the front without chaotic stab
Attack(other, 13); Attack(other, 13);
@ -594,6 +580,9 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
//heko: backstab //heko: backstab
void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime) void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
{ {
if (!other)
return;
int32 ndamage = 0; int32 ndamage = 0;
int32 max_hit = 0; int32 max_hit = 0;
int32 min_hit = 0; int32 min_hit = 0;
@ -668,12 +657,20 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
} }
ndamage = mod_backstab_damage(ndamage); ndamage = mod_backstab_damage(ndamage);
uint32 Assassinate_Dmg = 0;
Assassinate_Dmg = TryAssassinate(other, SkillBackstab, ReuseTime);
if (Assassinate_Dmg) {
ndamage = Assassinate_Dmg;
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName());
}
DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime); DoSpecialAttackDamage(other, SkillBackstab, ndamage, min_hit, hate, ReuseTime, false, false);
DoAnim(animPiercing); DoAnim(animPiercing);
} }
// solar - assassinate // solar - assassinate [Kayen: No longer used for regular assassinate 6-29-14]
void Mob::RogueAssassinate(Mob* other) void Mob::RogueAssassinate(Mob* other)
{ {
//can you dodge, parry, etc.. an assassinate?? //can you dodge, parry, etc.. an assassinate??
@ -1276,13 +1273,24 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
int32 TotalDmg = 0; int32 TotalDmg = 0;
uint32 Assassinate_Dmg = 0;
if (GetClass() == ROGUE && (BehindMob(other, GetX(), GetY())))
Assassinate_Dmg = TryAssassinate(other, SkillThrowing, ranged_timer.GetDuration());
if(WDmg > 0) if(WDmg > 0)
{ {
int minDmg = 1; int minDmg = 1;
uint16 MaxDmg = GetThrownDamage(WDmg, TotalDmg, minDmg); uint16 MaxDmg = GetThrownDamage(WDmg, TotalDmg, minDmg);
if (Assassinate_Dmg) {
TotalDmg = Assassinate_Dmg;
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, ASSASSINATES, GetName());
}
mlog(COMBAT__RANGED, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg); mlog(COMBAT__RANGED, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg);
other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks. if (!Assassinate_Dmg)
other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks.
other->MeleeMitigation(this, TotalDmg, minDmg); other->MeleeMitigation(this, TotalDmg, minDmg);
if(TotalDmg > 0) if(TotalDmg > 0)
{ {
@ -1866,92 +1874,6 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
} }
} }
/*
void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
if (who == nullptr)
return;
if(DivineAura())
return;
if(!CombatRange(who))
return;
if(!always_succeed && IsClient())
CastToClient()->CheckIncreaseSkill(TAUNT, who, 10);
int level = GetLevel();
Mob *hate_top = who->GetHateMost();
// Check to see if we're already at the top of the target's hate list
// a mob will not be taunted if its target's health is below 20%
if ((hate_top != this)
&& (who->GetLevel() < level)
&& (hate_top == nullptr || hate_top->GetHPRatio() >= 20) ) {
int32 newhate, tauntvalue;
float tauntchance;
if(always_succeed) {
tauntchance = 101;
} else {
// no idea how taunt success is actually calculated
// TODO: chance for level 50+ mobs should be lower
int level_difference = level - who->GetLevel();
if (level_difference <= 5) {
tauntchance = 25.0; // minimum
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
if (tauntchance > 65.0)
tauntchance = 65.0;
}
else if (level_difference <= 10) {
tauntchance = 30.0; // minimum
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
if (tauntchance > 85.0)
tauntchance = 85.0;
}
else if (level_difference <= 15) {
tauntchance = 40.0; // minimum
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
if (tauntchance > 90.0)
tauntchance = 90.0;
}
else {
tauntchance = 50.0; // minimum
tauntchance += tauntchance * (float)GetSkill(TAUNT) / 200.0; // skill modifier
if (tauntchance > 95.0)
tauntchance = 95.0;
}
}
if (chance_bonus)
tauntchance = tauntchance + (tauntchance*chance_bonus/100.0f);
if (tauntchance > MakeRandomFloat(0, 100)) {
// this is the max additional hate added per succesfull taunt
tauntvalue = (MakeRandomInt(2, 4) * level);
//tauntvalue = (int32) ((float)level * 10.0 * (float)rand()/(float)RAND_MAX + 1);
// new hate: find diff of player's hate and whoever's at top of list, add that plus tauntvalue to players hate
newhate = who->GetNPCHate(hate_top) - who->GetNPCHate(this) + tauntvalue;
// add the hate
who->CastToNPC()->AddToHateList(this, newhate);
}
else{
//generate at least some hate reguardless of the outcome.
who->CastToNPC()->AddToHateList(this, (MakeRandomInt(2, 4)*level));
}
}
//generate at least some hate reguardless of the outcome.
who->CastToNPC()->AddToHateList(this, (MakeRandomInt(2, 4)*level));
if (HasSkillProcs()){
float chance = (float)TauntReuseTime*RuleR(Combat, AvgProcsPerMinute)/60000.0f;
TrySkillProc(who, TAUNT, chance);
}
}
*/
void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) { void Mob::Taunt(NPC* who, bool always_succeed, float chance_bonus) {
if (who == nullptr) if (who == nullptr)
@ -2089,9 +2011,10 @@ void Mob::InstillDoubt(Mob *who) {
uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) { uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
//Only works on YOUR target. //Only works on YOUR target.
if(defender && (skillInUse == SkillArchery) && (GetTarget() == defender)) { if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient()
&& (skillInUse == SkillArchery) && (GetTarget() == defender)) {
int32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1]; uint32 HeadShot_Dmg = aabonuses.HeadShot[1] + spellbonuses.HeadShot[1] + itembonuses.HeadShot[1];
uint8 HeadShot_Level = 0; //Get Highest Headshot Level uint8 HeadShot_Level = 0; //Get Highest Headshot Level
HeadShot_Level = aabonuses.HSLevel; HeadShot_Level = aabonuses.HSLevel;
@ -2100,14 +2023,11 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
else if (HeadShot_Level < itembonuses.HSLevel) else if (HeadShot_Level < itembonuses.HSLevel)
HeadShot_Level = itembonuses.HSLevel; HeadShot_Level = itembonuses.HSLevel;
if(HeadShot_Dmg && defender->GetBodyType() == BT_Humanoid) { if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){
if(HeadShot_Level && (defender->GetLevel() <= HeadShot_Level) && !defender->IsClient()){
float ProcChance = GetSpecialProcChances(11); float ProcChance = GetSpecialProcChances(11);
if(ProcChance > MakeRandomFloat(0,1)) if(ProcChance > MakeRandomFloat(0,1))
return HeadShot_Dmg; return HeadShot_Dmg;
}
} }
} }
@ -2119,7 +2039,7 @@ float Mob::GetSpecialProcChances(uint16 hand)
int mydex = GetDEX(); int mydex = GetDEX();
if (mydex > 255) if (mydex > 255)
mydex = 255; mydex = 255;
uint16 weapon_speed; uint16 weapon_speed;
float ProcChance = 0.0f; float ProcChance = 0.0f;
@ -2155,6 +2075,69 @@ float Mob::GetSpecialProcChances(uint16 hand)
return ProcChance; return ProcChance;
} }
uint32 Mob::TryAssassinate(Mob* defender, SkillUseTypes skillInUse, uint16 ReuseTime) {
if(defender && (defender->GetBodyType() == BT_Humanoid) && !defender->IsClient() &&
(skillInUse == SkillBackstab || skillInUse == SkillThrowing)) {
uint32 Assassinate_Dmg = aabonuses.Assassinate[1] + spellbonuses.Assassinate[1] + itembonuses.Assassinate[1];
uint8 Assassinate_Level = 0; //Get Highest Headshot Level
Assassinate_Level = aabonuses.AssassinateLevel;
if (Assassinate_Level < spellbonuses.AssassinateLevel)
Assassinate_Level = spellbonuses.AssassinateLevel;
else if (Assassinate_Level < itembonuses.AssassinateLevel)
Assassinate_Level = itembonuses.AssassinateLevel;
if (GetLevel() >= 60){ //Innate Assassinate Ability if client as no bonuses.
if (!Assassinate_Level)
Assassinate_Level = 45;
if (!Assassinate_Dmg)
Assassinate_Dmg = 32000;
}
if(Assassinate_Dmg && Assassinate_Level && (defender->GetLevel() <= Assassinate_Level)){
float ProcChance = 0.0f;
if (skillInUse == SkillThrowing)
ProcChance = GetSpecialProcChances(11);
else
ProcChance = GetAssassinateProcChances(ReuseTime);
if(ProcChance > MakeRandomFloat(0,1))
return Assassinate_Dmg;
}
}
return 0;
}
float Mob::GetAssassinateProcChances(uint16 ReuseTime)
{
int mydex = GetDEX();
if (mydex > 255)
mydex = 255;
float ProcChance = 0.0f;
float ProcBonus = 0.0f;
if (RuleB(Combat, AdjustSpecialProcPerMinute)) {
ProcChance = (static_cast<float>(ReuseTime*1000) *
RuleR(Combat, AvgSpecialProcsPerMinute) / 60000.0f);
ProcBonus += (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
ProcChance += ProcChance * ProcBonus / 100.0f;
} else {
/*Kayen: Unable to find data on old proc rate of assassinate, no idea if our formula is real or made up.*/
ProcChance = (10 + (static_cast<float>(mydex/10) + static_cast<float>(itembonuses.HeroicDEX /10)))/100.0f;
}
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)
{ {
if (!CanDoSpecialAttack(other)) if (!CanDoSpecialAttack(other))