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
committed by Arthur Ice
parent 25c20f0629
commit 2afa08e361
6 changed files with 157 additions and 147 deletions
+123 -140
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
//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 '&&'
CanRiposte = false;
who->AvoidDamage(this, max_damage, CanRiposte);
if (CanAvoid)
who->AvoidDamage(this, max_damage, CanRiposte);
who->MeleeMitigation(this, max_damage, min_damage);
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) {
break;
}
TryBackstab(GetTarget(), ReuseTime);
ReuseTime = BackstabReuseTime-1 - skill_reduction;
TryBackstab(GetTarget(), ReuseTime);
break;
}
default:
@@ -527,64 +530,47 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
if (FrontalBSChance && (FrontalBSChance > MakeRandomInt(0, 100)))
bCanFrontalBS = true;
}
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!");
}
RogueBackstab(other,false,ReuseTime);
if (level > 54) {
// solar - chance to assassinate
int chance = 10 + (GetDEX()/10) + (itembonuses.HeroicDEX/10); //18.5% chance at 85 dex 40% chance at 300 dex
if(
level >= 60 && // player is 60 or higher
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(IsClient() && CastToClient()->CheckDoubleAttack(false))
{
if(other->GetHP() > 0)
RogueBackstab(other,false,ReuseTime);
if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA
{
if(other->GetHP() > 0)
RogueBackstab(other,false,ReuseTime);
if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
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
else if(aabonuses.FrontalBackstabMinDmg || itembonuses.FrontalBackstabMinDmg || spellbonuses.FrontalBackstabMinDmg) {
//we can stab from any angle, we do min damage though.
RogueBackstab(other, true);
RogueBackstab(other, true, ReuseTime);
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)
if(MakeRandomFloat(0, 1) < DoubleAttackProbability) // Max 62.4 % chance of DA
if(IsClient() && CastToClient()->CheckDoubleAttack(false))
if(other->GetHP() > 0)
RogueBackstab(other,true, ReuseTime);
if (tripleChance && other->GetHP() > 0 && tripleChance > MakeRandomInt(0, 100))
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
Attack(other, 13);
@@ -594,6 +580,9 @@ void Mob::TryBackstab(Mob *other, int ReuseTime) {
//heko: backstab
void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
{
if (!other)
return;
int32 ndamage = 0;
int32 max_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);
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);
}
// solar - assassinate
// solar - assassinate [Kayen: No longer used for regular assassinate 6-29-14]
void Mob::RogueAssassinate(Mob* other)
{
//can you dodge, parry, etc.. an assassinate??
@@ -1276,13 +1273,24 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
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)
{
int minDmg = 1;
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);
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);
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) {
if (who == nullptr)
@@ -2089,9 +2011,10 @@ void Mob::InstillDoubt(Mob *who) {
uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
//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
HeadShot_Level = aabonuses.HSLevel;
@@ -2100,14 +2023,11 @@ uint32 Mob::TryHeadShot(Mob* defender, SkillUseTypes skillInUse) {
else if (HeadShot_Level < itembonuses.HSLevel)
HeadShot_Level = itembonuses.HSLevel;
if(HeadShot_Dmg && defender->GetBodyType() == BT_Humanoid) {
if(HeadShot_Level && (defender->GetLevel() <= HeadShot_Level) && !defender->IsClient()){
if(HeadShot_Dmg && HeadShot_Level && (defender->GetLevel() <= HeadShot_Level)){
float ProcChance = GetSpecialProcChances(11);
if(ProcChance > MakeRandomFloat(0,1))
return HeadShot_Dmg;
}
float ProcChance = GetSpecialProcChances(11);
if(ProcChance > MakeRandomFloat(0,1))
return HeadShot_Dmg;
}
}
@@ -2119,7 +2039,7 @@ float Mob::GetSpecialProcChances(uint16 hand)
int mydex = GetDEX();
if (mydex > 255)
mydex = 255;
mydex = 255;
uint16 weapon_speed;
float ProcChance = 0.0f;
@@ -2155,6 +2075,69 @@ float Mob::GetSpecialProcChances(uint16 hand)
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)
{
if (!CanDoSpecialAttack(other))