mirror of
https://github.com/EQEmu/Server.git
synced 2026-03-12 03:52:35 +00:00
[Bug Fix] Rampage Number of Hits Limit (#3929)
* [Bug Fix] Rampage Number of Hits Limit Rampage should Hit 1-2 times (Primary / Secondary) should not be Triple/Quadable * requested name convention changes
This commit is contained in:
parent
1b5b22eeca
commit
d0e069f4f8
@ -6446,10 +6446,11 @@ bool Client::CheckDualWield()
|
|||||||
return zone->random.Int(1, 375) <= chance;
|
return zone->random.Int(1, 375) <= chance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts, bool rampage)
|
||||||
{
|
{
|
||||||
if (!target)
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (RuleB(Combat, UseLiveCombatRounds)) {
|
if (RuleB(Combat, UseLiveCombatRounds)) {
|
||||||
// A "quad" on live really is just a successful dual wield where both double attack
|
// A "quad" on live really is just a successful dual wield where both double attack
|
||||||
@ -6459,8 +6460,9 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
|||||||
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
||||||
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
||||||
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
|
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
|
||||||
if (chance && zone->random.Roll(chance))
|
if (chance && zone->random.Roll(chance)) {
|
||||||
Flurry(nullptr);
|
Flurry(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -6468,16 +6470,14 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
|||||||
|
|
||||||
if (IsNPC()) {
|
if (IsNPC()) {
|
||||||
int16 n_atk = CastToNPC()->GetNumberOfAttacks();
|
int16 n_atk = CastToNPC()->GetNumberOfAttacks();
|
||||||
if (n_atk <= 1) {
|
if (n_atk <= 1 || rampage) {
|
||||||
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
for (int i = 0; i < n_atk; ++i) {
|
for (int i = 0; i < n_atk; ++i) {
|
||||||
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
Attack(target, EQ::invslot::slotPrimary, false, false, false, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6503,10 +6503,12 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts, bool rampage)
|
||||||
{
|
{
|
||||||
if (!target)
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Mobs will only dual wield w/ the flag or have a secondary weapon
|
// Mobs will only dual wield w/ the flag or have a secondary weapon
|
||||||
// For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true
|
// For now, SPECATK_QUAD means innate DW when Combat:UseLiveCombatRounds is true
|
||||||
if ((GetSpecialAbility(SPECATK_INNATE_DW) ||
|
if ((GetSpecialAbility(SPECATK_INNATE_DW) ||
|
||||||
@ -6514,13 +6516,14 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts)
|
|||||||
GetEquippedItemFromTextureSlot(EQ::textures::weaponSecondary) != 0) {
|
GetEquippedItemFromTextureSlot(EQ::textures::weaponSecondary) != 0) {
|
||||||
if (CheckDualWield()) {
|
if (CheckDualWield()) {
|
||||||
Attack(target, EQ::invslot::slotSecondary, false, false, false, opts);
|
Attack(target, EQ::invslot::slotSecondary, false, false, false, opts);
|
||||||
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack()) {
|
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack() && !rampage) {
|
||||||
Attack(target, EQ::invslot::slotSecondary, false, false, false, opts);
|
Attack(target, EQ::invslot::slotSecondary, false, false, false, opts);
|
||||||
|
|
||||||
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()) {
|
||||||
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
|
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
|
||||||
if (chance && zone->random.Roll(chance))
|
if (chance && zone->random.Roll(chance)) {
|
||||||
Flurry(nullptr);
|
Flurry(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
zone/mob.h
13
zone/mob.h
@ -260,16 +260,17 @@ public:
|
|||||||
void CommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
void CommonOutgoingHitSuccess(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *opts = nullptr);
|
||||||
bool HasDied();
|
bool HasDied();
|
||||||
virtual bool CheckDualWield();
|
virtual bool CheckDualWield();
|
||||||
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
void DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, bool rampage = false);
|
||||||
void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr);
|
void DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, bool rampage = false);
|
||||||
virtual bool CheckDoubleAttack();
|
virtual bool CheckDoubleAttack();
|
||||||
// inline process for places where we need to do them outside of the AI_Process
|
// inline process for places where we need to do them outside of the AI_Process
|
||||||
void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr)
|
void ProcessAttackRounds(Mob *target, ExtraAttackOptions *opts = nullptr, bool rampage = false)
|
||||||
{
|
{
|
||||||
if (target) {
|
if (target) {
|
||||||
DoMainHandAttackRounds(target, opts);
|
DoMainHandAttackRounds(target, opts, rampage);
|
||||||
if (CanThisClassDualWield())
|
if (CanThisClassDualWield()) {
|
||||||
DoOffHandAttackRounds(target, opts);
|
DoOffHandAttackRounds(target, opts, rampage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2098,16 +2098,22 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
|
|||||||
} else {
|
} else {
|
||||||
entity_list.MessageCloseString(this, true, 200, Chat::NPCRampage, NPC_RAMPAGE, GetCleanName());
|
entity_list.MessageCloseString(this, true, 200, Chat::NPCRampage, NPC_RAMPAGE, GetCleanName());
|
||||||
}
|
}
|
||||||
|
|
||||||
int rampage_targets = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1);
|
int rampage_targets = GetSpecialAbilityParam(SPECATK_RAMPAGE, 1);
|
||||||
if (rampage_targets == 0) // if set to 0 or not set in the DB
|
|
||||||
|
if (rampage_targets == 0) { // if set to 0 or not set in the DB
|
||||||
rampage_targets = RuleI(Combat, DefaultRampageTargets);
|
rampage_targets = RuleI(Combat, DefaultRampageTargets);
|
||||||
if (rampage_targets > RuleI(Combat, MaxRampageTargets))
|
}
|
||||||
|
|
||||||
|
if (rampage_targets > RuleI(Combat, MaxRampageTargets)) {
|
||||||
rampage_targets = RuleI(Combat, MaxRampageTargets);
|
rampage_targets = RuleI(Combat, MaxRampageTargets);
|
||||||
|
}
|
||||||
|
|
||||||
m_specialattacks = eSpecialAttacks::Rampage;
|
m_specialattacks = eSpecialAttacks::Rampage;
|
||||||
for (int i = 0; i < RampageArray.size(); i++) {
|
for (int i = 0; i < RampageArray.size(); i++) {
|
||||||
if (index_hit >= rampage_targets)
|
if (index_hit >= rampage_targets) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// range is important
|
// range is important
|
||||||
Mob *m_target = entity_list.GetMob(RampageArray[i]);
|
Mob *m_target = entity_list.GetMob(RampageArray[i]);
|
||||||
if (m_target) {
|
if (m_target) {
|
||||||
@ -2122,7 +2128,7 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DistanceSquaredNoZ(GetPosition(), m_target->GetPosition()) <= NPC_RAMPAGE_RANGE2) {
|
if (DistanceSquaredNoZ(GetPosition(), m_target->GetPosition()) <= NPC_RAMPAGE_RANGE2) {
|
||||||
ProcessAttackRounds(m_target, opts);
|
ProcessAttackRounds(m_target, opts, true);
|
||||||
index_hit++;
|
index_hit++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2130,20 +2136,22 @@ bool Mob::Rampage(ExtraAttackOptions *opts)
|
|||||||
|
|
||||||
if (RuleB(Combat, RampageHitsTarget)) {
|
if (RuleB(Combat, RampageHitsTarget)) {
|
||||||
if (index_hit < rampage_targets)
|
if (index_hit < rampage_targets)
|
||||||
ProcessAttackRounds(GetTarget(), opts);
|
ProcessAttackRounds(GetTarget(), opts, true);
|
||||||
} else { // let's do correct behavior here, if they set above rule we can assume they want non-live like behavior
|
} else { // let's do correct behavior here, if they set above rule we can assume they want non-live like behavior
|
||||||
if (index_hit < rampage_targets) {
|
if (index_hit < rampage_targets) {
|
||||||
// so we go over in reverse order and skip range check
|
// so we go over in reverse order and skip range check
|
||||||
// lets do it this way to still support non-live-like >1 rampage targets
|
// lets do it this way to still support non-live-like >1 rampage targets
|
||||||
// likely live is just a fall through of the last valid mob
|
// likely live is just a fall through of the last valid mob
|
||||||
for (auto i = RampageArray.crbegin(); i != RampageArray.crend(); ++i) {
|
for (auto i = RampageArray.crbegin(); i != RampageArray.crend(); ++i) {
|
||||||
if (index_hit >= rampage_targets)
|
if (index_hit >= rampage_targets) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
auto m_target = entity_list.GetMob(*i);
|
auto m_target = entity_list.GetMob(*i);
|
||||||
if (m_target) {
|
if (m_target) {
|
||||||
if (m_target == GetTarget())
|
if (m_target == GetTarget()) {
|
||||||
continue;
|
continue;
|
||||||
ProcessAttackRounds(m_target, opts);
|
}
|
||||||
|
ProcessAttackRounds(m_target, opts, true);
|
||||||
index_hit++;
|
index_hit++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user