diff --git a/common/ruletypes.h b/common/ruletypes.h index 056b568ed..e7817f4bb 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -508,7 +508,7 @@ RULE_INT(Combat, SneakPullAssistRange, 400, "Modified range of assist for sneak RULE_BOOL(Combat, Classic2HBAnimation, false, "2HB will use the 2 hand piercing animation instead of the overhead slashing animation") RULE_BOOL(Combat, ArcheryConsumesAmmo, true, "Set to false to disable Archery Ammo Consumption") RULE_BOOL(Combat, ThrowingConsumesAmmo, true, "Set to false to disable Throwing Ammo Consumption") -RULE_BOOL(Combat, ImmuneToEnrageFromRiposteSpellEffect, true, "Set to false to disable SPA 173 SE_RiposteChance from making those with the effect on them immune to enrage") +RULE_BOOL(Combat, UseLiveRiposteMechanics, false, "Set to true to disable SPA 173 SE_RiposteChance from making those with the effect on them immune to enrage, can longer riposte from a riposte.") RULE_CATEGORY_END() RULE_CATEGORY(NPC) diff --git a/zone/attack.cpp b/zone/attack.cpp index 683ea78b5..4392e983f 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -433,9 +433,20 @@ bool Mob::AvoidDamage(Mob *other, DamageHitInfo &hit) // riposte -- it may seem crazy, but if the attacker has SPA 173 on them, they are immune to Ripo bool ImmuneRipo = false; - if (RuleB(Combat, ImmuneToEnrageFromRiposteSpellEffect)) { + if (!RuleB(Combat, UseLiveRiposteMechanics)) { ImmuneRipo = attacker->aabonuses.RiposteChance || attacker->spellbonuses.RiposteChance || attacker->itembonuses.RiposteChance || attacker->IsEnraged(); } + /* + Live Riposte Mechanics (~Kayen updated 1/22) + -Ripostes can not trigger another riposte. (Ie. Riposte from defender can't then trigger the attacker to riposte) + -Ripostes can not be 'avoided', only hit or miss. + -Attacker with SPA 173 is not immune to riposte. The defender can riposte against the attackers melee hits. + + Legacy Riposte Mechanics + -Ripostes can trigger another riposte + -Attacker with SPA 173 is immune to riposte + -Attacker that is enraged is immune to riposte + */ // Need to check if we have something in MainHand to actually attack with (or fists) if (hit.hand != EQ::invslot::slotRange && (CanThisClassRiposte() || IsEnraged()) && InFront && !ImmuneRipo) { @@ -1373,25 +1384,27 @@ int Client::DoDamageCaps(int base_damage) // other is the defender, this is the attacker //SYNC WITH: tune.cpp, mob.h TuneDoAttack -void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts) +void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts, bool FromRiposte) { if (!other) return; LogCombat("[{}]::DoAttack vs [{}] base [{}] min [{}] offense [{}] tohit [{}] skill [{}]", GetName(), other->GetName(), hit.base_damage, hit.min_damage, hit.offense, hit.tohit, hit.skill); - // check to see if we hit.. - if (other->AvoidDamage(this, hit)) { + if (!RuleB(Combat, UseLiveRiposteMechanics)) { + FromRiposte = false; + } + + // check to see if we hit.. + if (!FromRiposte && other->AvoidDamage(this, hit)) { int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; if (strike_through && zone->random.Roll(strike_through)) { MessageString(Chat::StrikeThrough, STRIKETHROUGH_STRING); // You strike through your opponents defenses! hit.damage_done = 1; // set to one, we will check this to continue } - // I'm pretty sure you can riposte a riposte if (hit.damage_done == DMG_RIPOSTED) { DoRiposte(other); - //if (IsDead()) return; } LogCombat("Avoided/strikethrough damage with code [{}]", hit.damage_done); @@ -1574,7 +1587,7 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus); - DoAttack(other, my_hit, opts); + DoAttack(other, my_hit, opts, bRiposte); } else { my_hit.damage_done = DMG_INVULNERABLE; @@ -2166,7 +2179,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool my_hit.offense = offense(my_hit.skill); my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus); - DoAttack(other, my_hit, opts); + DoAttack(other, my_hit, opts, bRiposte); other->AddToHateList(this, hate); @@ -4822,6 +4835,7 @@ void Mob::DoRiposte(Mob *defender) } defender->Attack(this, EQ::invslot::slotPrimary, true); + if (HasDied()) return; diff --git a/zone/bot.cpp b/zone/bot.cpp index 031282051..c2b6b2d59 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -4906,7 +4906,7 @@ bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, b my_hit.tohit = GetTotalToHit(my_hit.skill, hit_chance_bonus); - DoAttack(other, my_hit, opts); + DoAttack(other, my_hit, opts, FromRiposte); LogCombat("Final damage after all reductions: [{}]", my_hit.damage_done); } else { diff --git a/zone/mob.h b/zone/mob.h index edd3ac36a..16bce03b3 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -195,7 +195,7 @@ public: // 13 = Primary (default), 14 = secondary virtual bool Attack(Mob* other, int Hand = EQ::invslot::slotPrimary, bool FromRiposte = false, bool IsStrikethrough = false, bool IsFromSpell = false, ExtraAttackOptions *opts = nullptr) = 0; - void DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr); + void DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr, bool FromRiposte = false); int MonkSpecialAttack(Mob* other, uint8 skill_used); virtual void TryBackstab(Mob *other,int ReuseTime = 10); bool AvoidDamage(Mob *attacker, DamageHitInfo &hit);