mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 09:31:30 +00:00
Reworked activated avoidance skills based on dev quotes
This commit is contained in:
parent
80c2d9d68d
commit
49e9c9ee34
@ -1,5 +1,10 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
== 7/4/2015 ==
|
||||||
|
mackal: Reworked the activated avoidace skills (riposte, dodge, etc) based on dev quotes
|
||||||
|
This also fixes the order things are checked (avoidance skills, THEN hit/miss)
|
||||||
|
Also riposte immunity from the increase riposte chance spell effect.
|
||||||
|
|
||||||
== 7/2/2015 ==
|
== 7/2/2015 ==
|
||||||
KLS/Demonstar55: AA system has been rewritten fixing a ton of bugs and extending functionality while making it easier to create new AA points.
|
KLS/Demonstar55: AA system has been rewritten fixing a ton of bugs and extending functionality while making it easier to create new AA points.
|
||||||
KLS/Demonstar55: New tables are needed and so older data will need to be migrated to the new system.
|
KLS/Demonstar55: New tables are needed and so older data will need to be migrated to the new system.
|
||||||
|
|||||||
346
zone/attack.cpp
346
zone/attack.cpp
@ -341,7 +341,7 @@ bool Mob::CheckHitChance(Mob* other, SkillUseTypes skillinuse, int Hand, int16 c
|
|||||||
return(tohit_roll <= chancetohit);
|
return(tohit_roll <= chancetohit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
bool Mob::AvoidDamage(Mob *other, int32 &damage, int hand)
|
||||||
{
|
{
|
||||||
/* called when a mob is attacked, does the checks to see if it's a hit
|
/* called when a mob is attacked, does the checks to see if it's a hit
|
||||||
* and does other mitigation checks. 'this' is the mob being attacked.
|
* and does other mitigation checks. 'this' is the mob being attacked.
|
||||||
@ -353,22 +353,32 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
* -4 - dodge
|
* -4 - dodge
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
float skill;
|
|
||||||
float bonus;
|
/* Order according to current (SoF+?) dev quotes:
|
||||||
float RollTable[4] = {0,0,0,0};
|
* https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3261772
|
||||||
float roll;
|
* https://forums.daybreakgames.com/eq/index.php?threads/test-update-06-10-15.223510/page-2#post-3268227
|
||||||
|
* Riposte 50, hDEX, must have weapon/fists, doesn't work on archery/throwing
|
||||||
|
* Block 25, hDEX, works on archery/throwing, behind block done here if back to attacker base1 is chance
|
||||||
|
* Parry 45, hDEX, doesn't work on throwing/archery, must be facing target
|
||||||
|
* Dodge 45, hAGI, works on archery/throwing, monks can dodge attacks from behind
|
||||||
|
* Shield Block, rand base1
|
||||||
|
* Staff Block, rand base1
|
||||||
|
* regular strike through
|
||||||
|
* avoiding the attack (CheckHitChance)
|
||||||
|
* As soon as one succeeds, none of the rest are checked
|
||||||
|
*
|
||||||
|
* Formula (all int math)
|
||||||
|
* (posted for parry, assume rest at the same)
|
||||||
|
* Chance = (((SKILL + 100) + [((SKILL+100) * SPA(175).Base1) / 100]) / 45) + [(hDex / 25) - min([hDex / 25], hStrikethrough)].
|
||||||
|
* hStrikethrough is a mob stat that was added to counter the bonuses of heroic stats
|
||||||
|
* Number rolled against 100, if the chance is greater than 100 it happens 100% of time
|
||||||
|
*
|
||||||
|
* Things with 10k accuracy mods can be avoided with these skills qq
|
||||||
|
*/
|
||||||
Mob *attacker = other;
|
Mob *attacker = other;
|
||||||
Mob *defender = this;
|
Mob *defender = this;
|
||||||
|
|
||||||
//garunteed hit
|
bool InFront = attacker->InFrontMob(this, attacker->GetX(), attacker->GetY());
|
||||||
bool ghit = false;
|
|
||||||
if((attacker->aabonuses.MeleeSkillCheck + attacker->spellbonuses.MeleeSkillCheck + attacker->itembonuses.MeleeSkillCheck) > 500)
|
|
||||||
ghit = true;
|
|
||||||
|
|
||||||
bool InFront = false;
|
|
||||||
|
|
||||||
if (attacker->InFrontMob(this, attacker->GetX(), attacker->GetY()))
|
|
||||||
InFront = true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This special ability adds a negative modifer to the defenders riposte/block/parry/chance
|
This special ability adds a negative modifer to the defenders riposte/block/parry/chance
|
||||||
@ -384,7 +394,6 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
int counter_dodge = 0;
|
int counter_dodge = 0;
|
||||||
|
|
||||||
if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)) {
|
if (attacker->GetSpecialAbility(COUNTER_AVOID_DAMAGE)) {
|
||||||
|
|
||||||
counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0);
|
counter_all = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 0);
|
||||||
counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 1);
|
counter_riposte = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 1);
|
||||||
counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2);
|
counter_block = attacker->GetSpecialAbilityParam(COUNTER_AVOID_DAMAGE, 2);
|
||||||
@ -400,31 +409,37 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
// riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo
|
||||||
// riposte
|
bool ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance;
|
||||||
/////////////////////////////////////////////////////////
|
// Need to check if we have something in MainHand to actually attack with (or fists)
|
||||||
float riposte_chance = 0.0f;
|
if (hand != MainRange && CanThisClassRiposte() && InFront && !ImmuneRipo) {
|
||||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && InFront)
|
if (IsClient())
|
||||||
{
|
|
||||||
riposte_chance = (100.0f + static_cast<float>(aabonuses.RiposteChance + spellbonuses.RiposteChance +
|
|
||||||
itembonuses.RiposteChance - counter_riposte - counter_all)) / 100.0f;
|
|
||||||
skill = GetSkill(SkillRiposte);
|
|
||||||
if (IsClient()) {
|
|
||||||
CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
|
CastToClient()->CheckIncreaseSkill(SkillRiposte, other, -10);
|
||||||
|
// check auto discs ... I guess aa/items too :P
|
||||||
|
if (spellbonuses.RiposteChance == 10000 || aabonuses.RiposteChance == 10000 || itembonuses.RiposteChance == 10000) {
|
||||||
|
damage = -3;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
int chance = GetSkill(SkillRiposte) + 100;
|
||||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
chance += (chance * (aabonuses.RiposteChance + spellbonuses.RiposteChance + itembonuses.RiposteChance)) / 100;
|
||||||
bonus = 2.0 + skill/60.0 + (GetDEX()/200);
|
chance /= 50;
|
||||||
bonus *= riposte_chance;
|
chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter
|
||||||
bonus = mod_riposte_chance(bonus, attacker);
|
if (counter_riposte || counter_all) {
|
||||||
RollTable[0] = bonus + (itembonuses.HeroicDEX / 25); // 25 heroic = 1%, applies to ripo, parry, block
|
float counter = (counter_riposte + counter_all) / 100.0f;
|
||||||
|
chance -= chance * counter;
|
||||||
|
}
|
||||||
|
// AA Slippery Attacks
|
||||||
|
if (hand == MainSecondary) {
|
||||||
|
int slip = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail;
|
||||||
|
chance += chance * slip / 100;
|
||||||
|
}
|
||||||
|
if (chance > 0 && zone->random.Roll(chance)) { // could be <0 from offhand stuff
|
||||||
|
damage = -3;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
|
||||||
// block
|
// block
|
||||||
///////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool bBlockFromRear = false;
|
bool bBlockFromRear = false;
|
||||||
|
|
||||||
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
// a successful roll on this does not mean a successful block is forthcoming. only that a chance to block
|
||||||
@ -435,101 +450,100 @@ bool Mob::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte)
|
|||||||
if (BlockBehindChance && zone->random.Roll(BlockBehindChance))
|
if (BlockBehindChance && zone->random.Roll(BlockBehindChance))
|
||||||
bBlockFromRear = true;
|
bBlockFromRear = true;
|
||||||
|
|
||||||
float block_chance = 0.0f;
|
if (CanThisClassBlock() && (InFront || bBlockFromRear)) {
|
||||||
if (damage > 0 && CanThisClassBlock() && (InFront || bBlockFromRear)) {
|
if (IsClient())
|
||||||
block_chance = (100.0f + static_cast<float>(aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance +
|
|
||||||
itembonuses.IncreaseBlockChance - counter_block - counter_all)) / 100.0f;
|
|
||||||
skill = CastToClient()->GetSkill(SkillBlock);
|
|
||||||
if (IsClient()) {
|
|
||||||
CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10);
|
CastToClient()->CheckIncreaseSkill(SkillBlock, other, -10);
|
||||||
|
// check auto discs ... I guess aa/items too :P
|
||||||
|
if (spellbonuses.IncreaseBlockChance == 10000 || aabonuses.IncreaseBlockChance == 10000 ||
|
||||||
|
itembonuses.IncreaseBlockChance == 10000) {
|
||||||
|
damage = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int chance = GetSkill(SkillBlock) + 100;
|
||||||
|
chance += (chance * (aabonuses.IncreaseBlockChance + spellbonuses.IncreaseBlockChance + itembonuses.IncreaseBlockChance)) / 100;
|
||||||
|
chance /= 25;
|
||||||
|
chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter
|
||||||
|
if (counter_block || counter_all) {
|
||||||
|
float counter = (counter_block + counter_all) / 100.0f;
|
||||||
|
chance -= chance * counter;
|
||||||
|
}
|
||||||
|
if (zone->random.Roll(chance)) {
|
||||||
|
damage = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
// parry
|
||||||
bonus = 2.0 + skill/35.0 + (GetDEX()/200);
|
if (CanThisClassParry() && InFront && hand != MainRange) {
|
||||||
bonus = mod_block_chance(bonus, attacker);
|
if (IsClient())
|
||||||
RollTable[1] = RollTable[0] + (bonus * block_chance);
|
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
||||||
|
// check auto discs ... I guess aa/items too :P
|
||||||
|
if (spellbonuses.ParryChance == 10000 || aabonuses.ParryChance == 10000 || itembonuses.ParryChance == 10000) {
|
||||||
|
damage = -2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int chance = GetSkill(SkillParry) + 100;
|
||||||
|
chance += (chance * (aabonuses.ParryChance + spellbonuses.ParryChance + itembonuses.ParryChance)) / 100;
|
||||||
|
chance /= 45;
|
||||||
|
chance += itembonuses.HeroicDEX / 25; // live has "heroic strickthrough" here to counter
|
||||||
|
if (counter_parry || counter_all) {
|
||||||
|
float counter = (counter_parry + counter_all) / 100.0f;
|
||||||
|
chance -= chance * counter;
|
||||||
|
}
|
||||||
|
if (zone->random.Roll(chance)) {
|
||||||
|
damage = -2;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
|
||||||
RollTable[1] = RollTable[0];
|
// dodge
|
||||||
|
if (CanThisClassDodge() && (InFront || GetClass() == MONK) ) {
|
||||||
|
if (IsClient())
|
||||||
|
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
||||||
|
// check auto discs ... I guess aa/items too :P
|
||||||
|
if (spellbonuses.DodgeChance == 10000 || aabonuses.DodgeChance == 10000 || itembonuses.DodgeChance == 10000) {
|
||||||
|
damage = -4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int chance = GetSkill(SkillDodge) + 100;
|
||||||
|
chance += (chance * (aabonuses.DodgeChance + spellbonuses.DodgeChance + itembonuses.DodgeChance)) / 100;
|
||||||
|
chance /= 45;
|
||||||
|
chance += itembonuses.HeroicAGI / 25; // live has "heroic strickthrough" here to counter
|
||||||
|
if (counter_dodge || counter_all) {
|
||||||
|
float counter = (counter_dodge + counter_all) / 100.0f;
|
||||||
|
chance -= chance * counter;
|
||||||
|
}
|
||||||
|
if (zone->random.Roll(chance)) {
|
||||||
|
damage = -4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try Shield Block OR TwoHandBluntBlockCheck
|
// Try Shield Block OR TwoHandBluntBlockCheck
|
||||||
if(damage > 0 && HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear))
|
if (HasShieldEquiped() && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock) && (InFront || bBlockFromRear)) {
|
||||||
RollTable[1] += static_cast<float>(aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock - counter_block - counter_all);
|
int chance = aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock;
|
||||||
|
if (counter_block || counter_all) {
|
||||||
else if(damage > 0 && HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear))
|
float counter = (counter_block + counter_all) / 100.0f;
|
||||||
RollTable[1] += static_cast<float>(aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock - counter_block - counter_all);
|
chance -= chance * counter;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
// parry
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
float parry_chance = 0.0f;
|
|
||||||
if (damage > 0 && CanThisClassParry() && InFront){
|
|
||||||
parry_chance = (100.0f + static_cast<float>(aabonuses.ParryChance + itembonuses.ParryChance +
|
|
||||||
itembonuses.ParryChance - counter_parry - counter_all)) / 100.0f;
|
|
||||||
skill = CastToClient()->GetSkill(SkillParry);
|
|
||||||
if (IsClient()) {
|
|
||||||
CastToClient()->CheckIncreaseSkill(SkillParry, other, -10);
|
|
||||||
}
|
}
|
||||||
|
if (zone->random.Roll(chance)) {
|
||||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
|
||||||
bonus = 2.0 + skill/60.0 + (GetDEX()/200);
|
|
||||||
bonus *= parry_chance;
|
|
||||||
bonus = mod_parry_chance(bonus, attacker);
|
|
||||||
RollTable[2] = RollTable[1] + bonus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
RollTable[2] = RollTable[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
// dodge
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
float dodge_chance = 0.0f;
|
|
||||||
if (damage > 0 && CanThisClassDodge() && InFront){
|
|
||||||
|
|
||||||
dodge_chance = (100.0f + static_cast<float>(aabonuses.DodgeChance + spellbonuses.DodgeChance +
|
|
||||||
itembonuses.DodgeChance - counter_dodge - counter_all)) / 100.0f;
|
|
||||||
|
|
||||||
skill = CastToClient()->GetSkill(SkillDodge);
|
|
||||||
if (IsClient()) {
|
|
||||||
CastToClient()->CheckIncreaseSkill(SkillDodge, other, -10);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ghit) { //if they are not using a garunteed hit discipline
|
|
||||||
bonus = 2.0 + skill/60.0 + (GetAGI()/200);
|
|
||||||
bonus *= dodge_chance;
|
|
||||||
//DCBOOMKAR
|
|
||||||
bonus = mod_dodge_chance(bonus, attacker);
|
|
||||||
RollTable[3] = RollTable[2] + bonus - (itembonuses.HeroicDEX / 25) + (itembonuses.HeroicAGI / 25);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
RollTable[3] = RollTable[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(damage > 0){
|
|
||||||
roll = zone->random.Real(0,100);
|
|
||||||
if(roll <= RollTable[0]){
|
|
||||||
damage = -3;
|
|
||||||
}
|
|
||||||
else if(roll <= RollTable[1]){
|
|
||||||
damage = -1;
|
damage = -1;
|
||||||
}
|
|
||||||
else if(roll <= RollTable[2]){
|
|
||||||
damage = -2;
|
|
||||||
}
|
|
||||||
else if(roll <= RollTable[3]){
|
|
||||||
damage = -4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all avoidances: %d", damage);
|
|
||||||
|
|
||||||
if (damage < 0)
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasTwoHandBluntEquiped() && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock) && (InFront || bBlockFromRear)) {
|
||||||
|
int chance = aabonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock;
|
||||||
|
if (counter_block || counter_all) {
|
||||||
|
float counter = (counter_block + counter_all) / 100.0f;
|
||||||
|
chance -= chance * counter;
|
||||||
|
}
|
||||||
|
if (zone->random.Roll(chance)) {
|
||||||
|
damage = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1286,6 +1300,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this effect is actually a min cap that happens after the final damage is calculated
|
||||||
min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100;
|
min_hit += min_hit * GetMeleeMinDamageMod_SE(skillinuse) / 100;
|
||||||
|
|
||||||
if(max_hit < min_hit)
|
if(max_hit < min_hit)
|
||||||
@ -1312,61 +1327,40 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check to see if we hit..
|
//check to see if we hit..
|
||||||
if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
if (other->AvoidDamage(this, damage, Hand)) {
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0.");
|
if (!bRiposte && !IsStrikethrough) {
|
||||||
damage = 0;
|
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
||||||
} else { //we hit, try to avoid it
|
if(strike_through && zone->random.Roll(strike_through)) {
|
||||||
other->AvoidDamage(this, damage);
|
|
||||||
other->MeleeMitigation(this, damage, min_hit, opts);
|
|
||||||
if(damage > 0)
|
|
||||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
//riposte
|
|
||||||
bool slippery_attack = false; // Part of hack to allow riposte to become a miss, but still allow a Strikethrough chance (like on Live)
|
|
||||||
if (damage == -3) {
|
|
||||||
if (bRiposte) return false;
|
|
||||||
else {
|
|
||||||
if (Hand == MainSecondary) {// Do we even have it & was attack with mainhand? If not, don't bother with other calculations
|
|
||||||
//Live AA - SlipperyAttacks
|
|
||||||
//This spell effect most likely directly modifies the actual riposte chance when using offhand attack.
|
|
||||||
int32 OffhandRiposteFail = aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail;
|
|
||||||
OffhandRiposteFail *= -1; //Live uses a negative value for this.
|
|
||||||
|
|
||||||
if (OffhandRiposteFail &&
|
|
||||||
(OffhandRiposteFail > 99 || zone->random.Roll(OffhandRiposteFail))) {
|
|
||||||
damage = 0; // Counts as a miss
|
|
||||||
slippery_attack = true;
|
|
||||||
} else
|
|
||||||
DoRiposte(other);
|
|
||||||
if (IsDead()) return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
DoRiposte(other);
|
|
||||||
if (IsDead()) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((damage < 0) || slippery_attack) && !bRiposte && !IsStrikethrough) { // Hack to still allow Strikethrough chance w/ Slippery Attacks AA
|
|
||||||
int32 bonusStrikeThrough = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
|
||||||
|
|
||||||
if(bonusStrikeThrough && zone->random.Roll(bonusStrikeThrough)) {
|
|
||||||
Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses!
|
Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses!
|
||||||
Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit
|
Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// I'm pretty sure you can riposte a riposte
|
||||||
|
if (damage == -3 && !bRiposte) {
|
||||||
|
DoRiposte(other);
|
||||||
|
if (IsDead())
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
Log.Out(Logs::Detail, Logs::Combat, "Avoided damage with code %d", damage);
|
||||||
|
} else {
|
||||||
|
if (other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
||||||
|
other->MeleeMitigation(this, damage, min_hit, opts);
|
||||||
|
if (damage > 0)
|
||||||
|
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||||
|
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage);
|
||||||
|
} else {
|
||||||
|
Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0.");
|
||||||
|
damage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
damage = -5;
|
damage = -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same.
|
// Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same.
|
||||||
// If we are this far, this means we are atleast making a swing.
|
// If we are this far, this means we are atleast making a swing.
|
||||||
|
|
||||||
if (!bRiposte) // Ripostes never generate any aggro.
|
|
||||||
other->AddToHateList(this, hate);
|
other->AddToHateList(this, hate);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
@ -1912,21 +1906,18 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
|||||||
hit_chance_bonus += opts->hit_chance;
|
hit_chance_bonus += opts->hit_chance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
if (other->AvoidDamage(this, damage, Hand)) {
|
||||||
damage = 0; //miss
|
if (!bRiposte && damage == -3)
|
||||||
} else { //hit, check for damage avoidance
|
DoRiposte(other);
|
||||||
other->AvoidDamage(this, damage);
|
} else {
|
||||||
|
if (other->CheckHitChance(this, skillinuse, Hand, hit_chance_bonus)) {
|
||||||
other->MeleeMitigation(this, damage, min_dmg+eleBane, opts);
|
other->MeleeMitigation(this, damage, min_dmg+eleBane, opts);
|
||||||
if(damage > 0) {
|
|
||||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||||
|
} else {
|
||||||
|
damage = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Generating hate %d towards %s", hate, GetName());
|
|
||||||
// now add done damage to the hate list
|
|
||||||
if(damage > 0)
|
|
||||||
other->AddToHateList(this, hate);
|
other->AddToHateList(this, hate);
|
||||||
else
|
|
||||||
other->AddToHateList(this, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage against %s: %d", other->GetName(), damage);
|
Log.Out(Logs::Detail, Logs::Combat, "Final damage against %s: %d", other->GetName(), damage);
|
||||||
@ -1939,12 +1930,6 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
|||||||
else
|
else
|
||||||
damage = -5;
|
damage = -5;
|
||||||
|
|
||||||
//cant riposte a riposte
|
|
||||||
if (bRiposte && damage == -3) {
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Riposte of riposte canceled.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(GetHP() > 0 && !other->HasDied()) {
|
if(GetHP() > 0 && !other->HasDied()) {
|
||||||
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, false); // Not avoidable client already had thier chance to Avoid
|
other->Damage(this, damage, SPELL_UNKNOWN, skillinuse, false); // Not avoidable client already had thier chance to Avoid
|
||||||
} else
|
} else
|
||||||
@ -1974,11 +1959,6 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
|||||||
if(GetHP() > 0 && !other->HasDied())
|
if(GetHP() > 0 && !other->HasDied())
|
||||||
TriggerDefensiveProcs(nullptr, other, Hand, damage);
|
TriggerDefensiveProcs(nullptr, other, Hand, damage);
|
||||||
|
|
||||||
// now check ripostes
|
|
||||||
if (damage == -3) { // riposting
|
|
||||||
DoRiposte(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (damage > 0)
|
if (damage > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
239
zone/bot.cpp
239
zone/bot.cpp
@ -2192,10 +2192,14 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
|||||||
else
|
else
|
||||||
damage = zone->random.Int(min_hit, max_hit);
|
damage = zone->random.Int(min_hit, max_hit);
|
||||||
|
|
||||||
if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod))
|
if (other->AvoidDamage(this, damage, CanRiposte ? MainRange : MainPrimary)) { // MainRange excludes ripo, primary doesn't have any extra behavior
|
||||||
damage = 0;
|
if (damage == -3) {
|
||||||
else {
|
DoRiposte(other);
|
||||||
other->AvoidDamage(this, damage, CanRiposte);
|
if (HasDied())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (other->CheckHitChance(this, skillinuse, Hand, chance_mod)) {
|
||||||
other->MeleeMitigation(this, damage, min_hit);
|
other->MeleeMitigation(this, damage, min_hit);
|
||||||
if (damage > 0) {
|
if (damage > 0) {
|
||||||
damage += damage*focus/100;
|
damage += damage*focus/100;
|
||||||
@ -2204,12 +2208,9 @@ void Bot::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
|||||||
damage += ((itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse));
|
damage += ((itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse));
|
||||||
TryCriticalHit(other, skillinuse, damage, nullptr);
|
TryCriticalHit(other, skillinuse, damage, nullptr);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
damage = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (damage == -3) {
|
|
||||||
DoRiposte(other);
|
|
||||||
if (HasDied())
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -4813,69 +4814,37 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
//check to see if we hit..
|
//check to see if we hit..
|
||||||
if(!other->CheckHitChance(other, skillinuse, Hand)) {
|
if (other->AvoidDamage(this, damage, Hand)) {
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Attack missed. Damage set to 0.");
|
if (!FromRiposte && !IsStrikethrough) {
|
||||||
damage = 0;
|
int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough;
|
||||||
other->AddToHateList(this, 0);
|
if(strike_through && zone->random.Roll(strike_through)) {
|
||||||
} else { //we hit, try to avoid it
|
|
||||||
other->AvoidDamage(this, damage);
|
|
||||||
other->MeleeMitigation(this, damage, min_hit, opts);
|
|
||||||
if(damage > 0) {
|
|
||||||
ApplyMeleeDamageBonus(skillinuse, damage);
|
|
||||||
damage += ((itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse));
|
|
||||||
TryCriticalHit(other, skillinuse, damage, opts);
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Generating hate %d towards %s", hate, GetCleanName());
|
|
||||||
// now add done damage to the hate list
|
|
||||||
//other->AddToHateList(this, hate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
other->AddToHateList(this, 0);
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage);
|
|
||||||
}
|
|
||||||
|
|
||||||
//riposte
|
|
||||||
bool slippery_attack = false; // Part of hack to allow riposte to become a miss, but still allow a Strikethrough chance (like on Live)
|
|
||||||
if (damage == -3) {
|
|
||||||
if (FromRiposte)
|
|
||||||
return false;
|
|
||||||
else {
|
|
||||||
if (Hand == MainSecondary) {// Do we even have it & was attack with mainhand? If not, don't bother with other calculations
|
|
||||||
//Live AA - SlipperyAttacks
|
|
||||||
//This spell effect most likely directly modifies the actual riposte chance when using offhand attack.
|
|
||||||
int32 OffhandRiposteFail = (aabonuses.OffhandRiposteFail + itembonuses.OffhandRiposteFail + spellbonuses.OffhandRiposteFail);
|
|
||||||
OffhandRiposteFail *= -1; //Live uses a negative value for this.
|
|
||||||
|
|
||||||
if (OffhandRiposteFail &&
|
|
||||||
(OffhandRiposteFail > 99 || (zone->random.Int(0, 100) < OffhandRiposteFail))) {
|
|
||||||
damage = 0; // Counts as a miss
|
|
||||||
slippery_attack = true;
|
|
||||||
} else
|
|
||||||
DoRiposte(other);
|
|
||||||
if (GetHP() < 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
DoRiposte(other);
|
|
||||||
if (GetHP() < 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((damage < 0) || slippery_attack) && !FromRiposte && !IsStrikethrough) { // Hack to still allow Strikethrough chance w/ Slippery Attacks AA
|
|
||||||
int32 bonusStrikeThrough = (itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough);
|
|
||||||
if(bonusStrikeThrough && (zone->random.Int(0, 100) < bonusStrikeThrough)) {
|
|
||||||
Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses!
|
Message_StringID(MT_StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses!
|
||||||
Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit
|
Attack(other, Hand, false, true); // Strikethrough only gives another attempted hit
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (damage == -3 && !FromRiposte) {
|
||||||
|
DoRiposte(other);
|
||||||
|
if (HasDied())
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (other->CheckHitChance(this, skillinuse, Hand)) {
|
||||||
|
other->MeleeMitigation(this, damage, min_hit, opts);
|
||||||
|
ApplyMeleeDamageBonus(skillinuse, damage);
|
||||||
|
damage += ((itembonuses.HeroicSTR / 10) + (damage * other->GetSkillDmgTaken(skillinuse) / 100) + GetSkillDmgAmt(skillinuse));
|
||||||
|
TryCriticalHit(other, skillinuse, damage, opts);
|
||||||
|
} else {
|
||||||
|
damage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all reductions: %d", damage);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
damage = -5;
|
damage = -5;
|
||||||
|
|
||||||
// Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same.
|
// Hate Generation is on a per swing basis, regardless of a hit, miss, or block, its always the same.
|
||||||
// If we are this far, this means we are atleast making a swing.
|
// If we are this far, this means we are atleast making a swing.
|
||||||
if (!FromRiposte)
|
|
||||||
other->AddToHateList(this, hate);
|
other->AddToHateList(this, hate);
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
@ -5771,132 +5740,6 @@ float Bot::GetProcChances(float ProcBonus, uint16 hand) {
|
|||||||
return ProcChance;
|
return ProcChance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::AvoidDamage(Mob* other, int32 &damage, bool CanRiposte) {
|
|
||||||
if(GetAppearance() == eaDead)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
float skill = 0;
|
|
||||||
float bonus = 0;
|
|
||||||
float RollTable[4] = {0,0,0,0};
|
|
||||||
float roll = 0;
|
|
||||||
Mob *attacker = other;
|
|
||||||
Mob *defender = this;
|
|
||||||
|
|
||||||
bool ghit = false;
|
|
||||||
if((attacker->GetSpellBonuses().MeleeSkillCheck + attacker->GetItemBonuses().MeleeSkillCheck) > 500)
|
|
||||||
ghit = true;
|
|
||||||
|
|
||||||
if (IsEnraged() && !other->BehindMob(this, other->GetX(), other->GetY())) {
|
|
||||||
damage = -3;
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "I am enraged, riposting frontal attack.");
|
|
||||||
}
|
|
||||||
|
|
||||||
float riposte_chance = 0.0f;
|
|
||||||
if (CanRiposte && damage > 0 && CanThisClassRiposte() && !other->BehindMob(this, other->GetX(), other->GetY())) {
|
|
||||||
riposte_chance = ((100.0f + (float)defender->GetAABonuses().RiposteChance + (float)defender->GetSpellBonuses().RiposteChance + (float)defender->GetItemBonuses().RiposteChance) / 100.0f);
|
|
||||||
skill = GetSkill(SkillRiposte);
|
|
||||||
if (!ghit) {
|
|
||||||
bonus = (2.0 + skill / 60.0 + (GetDEX() / 200));
|
|
||||||
bonus *= riposte_chance;
|
|
||||||
RollTable[0] = (bonus + (itembonuses.HeroicDEX / 25));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bBlockFromRear = false;
|
|
||||||
bool bShieldBlockFromRear = false;
|
|
||||||
if (this->IsBot()) {
|
|
||||||
int aaChance = 0;
|
|
||||||
int BlockBehindChance = (aabonuses.BlockBehind + spellbonuses.BlockBehind + itembonuses.BlockBehind);
|
|
||||||
if (BlockBehindChance && (BlockBehindChance > zone->random.Int(1, 100))){
|
|
||||||
bBlockFromRear = true;
|
|
||||||
if (spellbonuses.BlockBehind || itembonuses.BlockBehind)
|
|
||||||
bShieldBlockFromRear = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float block_chance = 0.0f;
|
|
||||||
if (damage > 0 && CanThisClassBlock() && (!other->BehindMob(this, other->GetX(), other->GetY()) || bBlockFromRear)) {
|
|
||||||
block_chance = ((100.0f + (float)spellbonuses.IncreaseBlockChance + (float)itembonuses.IncreaseBlockChance) / 100.0f);
|
|
||||||
skill = GetSkill(SkillBlock);
|
|
||||||
if (!ghit) {
|
|
||||||
bonus = (2.0 + skill / 35.0 + (GetDEX() / 200));
|
|
||||||
RollTable[1] = (RollTable[0] + (bonus * block_chance) - riposte_chance);
|
|
||||||
block_chance *= bonus;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
RollTable[1] = RollTable[0];
|
|
||||||
|
|
||||||
if(damage > 0 && (aabonuses.ShieldBlock || spellbonuses.ShieldBlock || itembonuses.ShieldBlock)
|
|
||||||
&& (!other->BehindMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
|
||||||
bool equiped = GetBotItem(MainSecondary);
|
|
||||||
if(equiped) {
|
|
||||||
uint8 shield = GetBotItem(MainSecondary)->GetItem()->ItemType;
|
|
||||||
float bonusShieldBlock = 0.0f;
|
|
||||||
if(shield == ItemTypeShield) {
|
|
||||||
bonusShieldBlock = (aabonuses.ShieldBlock + spellbonuses.ShieldBlock + itembonuses.ShieldBlock);
|
|
||||||
RollTable[1] = (RollTable[0] + bonusShieldBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(damage > 0 && (aabonuses.TwoHandBluntBlock || spellbonuses.TwoHandBluntBlock || itembonuses.TwoHandBluntBlock)
|
|
||||||
&& (!other->BehindMob(this, other->GetX(), other->GetY()) || bShieldBlockFromRear)) {
|
|
||||||
bool equiped2 = GetBotItem(MainPrimary);
|
|
||||||
if(equiped2) {
|
|
||||||
uint8 TwoHandBlunt = GetBotItem(MainPrimary)->GetItem()->ItemType;
|
|
||||||
float bonusStaffBlock = 0.0f;
|
|
||||||
if(TwoHandBlunt == ItemType2HBlunt) {
|
|
||||||
bonusStaffBlock = (aabonuses.TwoHandBluntBlock + spellbonuses.TwoHandBluntBlock + itembonuses.TwoHandBluntBlock);
|
|
||||||
RollTable[1] = (RollTable[0] + bonusStaffBlock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float parry_chance = 0.0f;
|
|
||||||
if (damage > 0 && CanThisClassParry() && !other->BehindMob(this, other->GetX(), other->GetY())) {
|
|
||||||
parry_chance = ((100.0f + (float)defender->GetSpellBonuses().ParryChance + (float)defender->GetItemBonuses().ParryChance) / 100.0f);
|
|
||||||
skill = GetSkill(SkillParry);
|
|
||||||
if (!ghit) {
|
|
||||||
bonus = (2.0 + skill / 60.0 + (GetDEX() / 200));
|
|
||||||
bonus *= parry_chance;
|
|
||||||
RollTable[2] = (RollTable[1] + bonus - block_chance);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
RollTable[2] = (RollTable[1] - block_chance);
|
|
||||||
|
|
||||||
float dodge_chance = 0.0f;
|
|
||||||
if (damage > 0 && CanThisClassDodge() && !other->BehindMob(this, other->GetX(), other->GetY())) {
|
|
||||||
dodge_chance = ((100.0f + (float)defender->GetSpellBonuses().DodgeChance + (float)defender->GetItemBonuses().DodgeChance) / 100.0f);
|
|
||||||
skill = GetSkill(SkillDodge);
|
|
||||||
if (!ghit) {
|
|
||||||
bonus = (2.0 + skill / 60.0 + (GetAGI() / 200));
|
|
||||||
bonus *= dodge_chance;
|
|
||||||
RollTable[3] = (RollTable[2] + bonus - (itembonuses.HeroicDEX / 25) + (itembonuses.HeroicAGI / 25) - parry_chance);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RollTable[3] = (RollTable[2] - (itembonuses.HeroicDEX / 25) + (itembonuses.HeroicAGI / 25) - parry_chance);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(damage > 0) {
|
|
||||||
roll = zone->random.Real(0,100);
|
|
||||||
if(roll <= RollTable[0])
|
|
||||||
damage = -3;
|
|
||||||
else if(roll <= RollTable[1])
|
|
||||||
damage = -1;
|
|
||||||
else if(roll <= RollTable[2])
|
|
||||||
damage = -2;
|
|
||||||
else if(roll <= RollTable[3])
|
|
||||||
damage = -4;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Final damage after all avoidances: %d", damage);
|
|
||||||
|
|
||||||
if (damage < 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Bot::GetMonkHandToHandDamage(void) {
|
int Bot::GetMonkHandToHandDamage(void) {
|
||||||
static int damage[66] = {
|
static int damage[66] = {
|
||||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
||||||
@ -5986,25 +5829,24 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
min_damage += (min_damage * GetMeleeMinDamageMod_SE(skill) / 100);
|
min_damage += (min_damage * GetMeleeMinDamageMod_SE(skill) / 100);
|
||||||
if(HitChance && !who->CheckHitChance(this, skill, MainPrimary))
|
int hand = MainPrimary;
|
||||||
max_damage = 0;
|
|
||||||
else {
|
|
||||||
bool CanRiposte = true;
|
|
||||||
if (skill == SkillThrowing || skill == SkillArchery)
|
if (skill == SkillThrowing || skill == SkillArchery)
|
||||||
CanRiposte = false;
|
hand = MainRange;
|
||||||
|
if (who->AvoidDamage(this, max_damage, hand)) {
|
||||||
who->AvoidDamage(this, max_damage, CanRiposte);
|
if (max_damage == -3)
|
||||||
|
DoRiposte(who);
|
||||||
|
} else {
|
||||||
|
if (HitChance || who->CheckHitChance(this, skill, MainPrimary)) {
|
||||||
who->MeleeMitigation(this, max_damage, min_damage);
|
who->MeleeMitigation(this, max_damage, min_damage);
|
||||||
|
|
||||||
if(max_damage > 0) {
|
|
||||||
ApplyMeleeDamageBonus(skill, max_damage);
|
ApplyMeleeDamageBonus(skill, max_damage);
|
||||||
max_damage += who->GetFcDamageAmtIncoming(this, 0, true, skill);
|
max_damage += who->GetFcDamageAmtIncoming(this, 0, true, skill);
|
||||||
max_damage += ((itembonuses.HeroicSTR / 10) + (max_damage * who->GetSkillDmgTaken(skill) / 100) + GetSkillDmgAmt(skill));
|
max_damage += ((itembonuses.HeroicSTR / 10) + (max_damage * who->GetSkillDmgTaken(skill) / 100) + GetSkillDmgAmt(skill));
|
||||||
TryCriticalHit(who, skill, max_damage);
|
TryCriticalHit(who, skill, max_damage);
|
||||||
|
} else {
|
||||||
|
max_damage = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_damage >= 0)
|
|
||||||
who->AddToHateList(this, hate);
|
who->AddToHateList(this, hate);
|
||||||
|
|
||||||
who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false);
|
who->Damage(this, max_damage, SPELL_UNKNOWN, skill, false);
|
||||||
@ -6030,9 +5872,6 @@ void Bot::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
|||||||
|
|
||||||
if (max_damage > 0 && HasSkillProcSuccess())
|
if (max_damage > 0 && HasSkillProcSuccess())
|
||||||
TrySkillProc(who, skill, (ReuseTime * 1000), true);
|
TrySkillProc(who, skill, (ReuseTime * 1000), true);
|
||||||
|
|
||||||
if(max_damage == -3 && !(who->GetHP() <= 0))
|
|
||||||
DoRiposte(who);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::TryBackstab(Mob *other, int ReuseTime) {
|
void Bot::TryBackstab(Mob *other, int ReuseTime) {
|
||||||
|
|||||||
@ -169,7 +169,6 @@ public:
|
|||||||
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
|
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
|
||||||
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
|
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
|
||||||
virtual float GetProcChances(float ProcBonus, uint16 hand);
|
virtual float GetProcChances(float ProcBonus, uint16 hand);
|
||||||
virtual bool AvoidDamage(Mob* other, int32 &damage, bool CanRiposte);
|
|
||||||
virtual int GetMonkHandToHandDamage(void);
|
virtual int GetMonkHandToHandDamage(void);
|
||||||
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
|
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
|
||||||
virtual void DoRiposte(Mob* defender);
|
virtual void DoRiposte(Mob* defender);
|
||||||
|
|||||||
@ -149,7 +149,7 @@ public:
|
|||||||
int MonkSpecialAttack(Mob* other, uint8 skill_used);
|
int MonkSpecialAttack(Mob* other, uint8 skill_used);
|
||||||
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
|
virtual void TryBackstab(Mob *other,int ReuseTime = 10);
|
||||||
void TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary, int damage = 0);
|
void TriggerDefensiveProcs(const ItemInst* weapon, Mob *on, uint16 hand = MainPrimary, int damage = 0);
|
||||||
virtual bool AvoidDamage(Mob* attacker, int32 &damage, bool CanRiposte = true);
|
bool AvoidDamage(Mob* attacker, int32 &damage, int hand);
|
||||||
virtual bool CheckHitChance(Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod = 0);
|
virtual bool CheckHitChance(Mob* attacker, SkillUseTypes skillinuse, int Hand, int16 chance_mod = 0);
|
||||||
virtual void TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts = nullptr);
|
virtual void TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttackOptions *opts = nullptr);
|
||||||
void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage);
|
void TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage);
|
||||||
|
|||||||
@ -130,22 +130,19 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
|||||||
|
|
||||||
min_damage += min_damage * GetMeleeMinDamageMod_SE(skill) / 100;
|
min_damage += min_damage * GetMeleeMinDamageMod_SE(skill) / 100;
|
||||||
|
|
||||||
if(HitChance && !who->CheckHitChance(this, skill, MainPrimary))
|
int hand = MainPrimary; // Avoid checks hand for throwing/archery exclusion, primary should work for most
|
||||||
max_damage = 0;
|
if (skill == SkillThrowing || skill == SkillArchery)
|
||||||
|
hand = MainRange;
|
||||||
else{
|
if (who->AvoidDamage(this, max_damage, hand)) {
|
||||||
bool CanRiposte = true;
|
if (max_damage == -3)
|
||||||
if(skill == SkillThrowing || skill == SkillArchery) // changed from '&&'
|
DoRiposte(who);
|
||||||
CanRiposte = false;
|
} else {
|
||||||
|
if (HitChance || who->CheckHitChance(this, skill, MainPrimary)) {
|
||||||
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)
|
|
||||||
CommonOutgoingHitSuccess(who, max_damage, skill);
|
CommonOutgoingHitSuccess(who, max_damage, skill);
|
||||||
|
} else {
|
||||||
|
max_damage = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
who->AddToHateList(this, hate, 0, false);
|
who->AddToHateList(this, hate, 0, false);
|
||||||
@ -168,8 +165,6 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
|
|||||||
if (max_damage > 0 && HasSkillProcSuccess())
|
if (max_damage > 0 && HasSkillProcSuccess())
|
||||||
TrySkillProc(who, skill, ReuseTime*1000, true);
|
TrySkillProc(who, skill, ReuseTime*1000, true);
|
||||||
|
|
||||||
if(max_damage == -3 && !who->HasDied())
|
|
||||||
DoRiposte(who);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -972,7 +967,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!HeadShot)
|
if (!HeadShot)
|
||||||
other->AvoidDamage(this, TotalDmg, false);
|
other->AvoidDamage(this, TotalDmg, MainRange);
|
||||||
|
|
||||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||||
if(TotalDmg > 0){
|
if(TotalDmg > 0){
|
||||||
@ -1305,7 +1300,7 @@ void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 cha
|
|||||||
|
|
||||||
TotalDmg += TotalDmg * damage_mod / 100;
|
TotalDmg += TotalDmg * damage_mod / 100;
|
||||||
|
|
||||||
other->AvoidDamage(this, TotalDmg, false);
|
other->AvoidDamage(this, TotalDmg, MainRange);
|
||||||
other->MeleeMitigation(this, TotalDmg, MinDmg);
|
other->MeleeMitigation(this, TotalDmg, MinDmg);
|
||||||
|
|
||||||
if (TotalDmg > 0)
|
if (TotalDmg > 0)
|
||||||
@ -1539,7 +1534,7 @@ void Mob::DoThrowingAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
|
|||||||
|
|
||||||
Log.Out(Logs::Detail, Logs::Combat, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg);
|
Log.Out(Logs::Detail, Logs::Combat, "Item DMG %d. Max Damage %d. Hit for damage %d", WDmg, MaxDmg, TotalDmg);
|
||||||
if (!Assassinate_Dmg)
|
if (!Assassinate_Dmg)
|
||||||
other->AvoidDamage(this, TotalDmg, false); //CanRiposte=false - Can not riposte throw attacks.
|
other->AvoidDamage(this, TotalDmg, MainRange);
|
||||||
|
|
||||||
other->MeleeMitigation(this, TotalDmg, minDmg);
|
other->MeleeMitigation(this, TotalDmg, minDmg);
|
||||||
if(TotalDmg > 0)
|
if(TotalDmg > 0)
|
||||||
@ -2411,27 +2406,26 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
|
|||||||
else
|
else
|
||||||
damage = zone->random.Int(min_hit, max_hit);
|
damage = zone->random.Int(min_hit, max_hit);
|
||||||
|
|
||||||
if(!other->CheckHitChance(this, skillinuse, Hand, chance_mod)) {
|
if (other->AvoidDamage(this, damage, CanRiposte ? MainRange : MainPrimary)) { // MainRange excludes ripo, primary doesn't have any extra behavior
|
||||||
damage = 0;
|
|
||||||
} else {
|
|
||||||
other->AvoidDamage(this, damage, CanRiposte);
|
|
||||||
other->MeleeMitigation(this, damage, min_hit);
|
|
||||||
if(damage > 0)
|
|
||||||
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (damage == -3) {
|
if (damage == -3) {
|
||||||
DoRiposte(other);
|
DoRiposte(other);
|
||||||
if (HasDied())
|
if (HasDied())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (other->CheckHitChance(this, skillinuse, Hand, chance_mod)) {
|
||||||
|
other->MeleeMitigation(this, damage, min_hit);
|
||||||
|
CommonOutgoingHitSuccess(other, damage, skillinuse);
|
||||||
|
} else {
|
||||||
|
damage = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
damage = -5;
|
damage = -5;
|
||||||
|
|
||||||
other->AddToHateList(this, hate);
|
|
||||||
|
|
||||||
bool CanSkillProc = true;
|
bool CanSkillProc = true;
|
||||||
if (skillinuse == SkillOffense){ //Hack to allow damage to display.
|
if (skillinuse == SkillOffense){ //Hack to allow damage to display.
|
||||||
skillinuse = SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message.
|
skillinuse = SkillTigerClaw; //'strike' your opponent - Arbitrary choice for message.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user