I've honestly never touched the eqemu codebase before, so everything is still entirely foreign to me.
I'm confident in most of the logic here other than how I attempt to grab the weapon(s) equipped by the pet. Random shot in the dark, untested, likely won't work. But, I can't test this right now.
Code:
diff --git a/zone/attack.cpp b/zone/attack.cpp
index 85ee29e..003acb3 100644
--- a/zone/attack.cpp
+++ b/zone/attack.cpp
@@ -4586,17 +4586,6 @@ void NPC::SetAttackTimer()
attack_timer.SetAtTrigger(4000, true);
Timer *TimerToUse = nullptr;
- int hhe = itembonuses.HundredHands + spellbonuses.HundredHands;
-
- // Technically NPCs should do some logic for weapons, but the effect is minimal
- // What they do is take the lower of their set delay and the weapon's
- // ex. Mob's delay set to 20, weapon set to 19, delay 19
- // Mob's delay set to 20, weapon set to 21, delay 20
- int speed = 0;
- if (RuleB(Spells, Jun182014HundredHandsRevamp))
- speed = static_cast<int>(((attack_delay / haste_mod) + ((hhe / 1000.0f) * (attack_delay / haste_mod))) * 100);
- else
- speed = static_cast<int>(((attack_delay / haste_mod) + ((hhe / 100.0f) * attack_delay)) * 100);
for (int i = MainRange; i <= MainSecondary; i++) {
//pick a timer
@@ -4609,6 +4598,13 @@ void NPC::SetAttackTimer()
else //invalid slot (hands will always hit this)
continue;
+ const Item_Struct *ItemToUse = nullptr;
+
+ //find our item
+ ServerLootItem_Struct* item_data = GetItem(i);
+ if (item_data)
+ ItemToUse = database.GetItem(item_data->item_id);
+
//special offhand stuff
if (i == MainSecondary) {
// SPECATK_QUAD is uncheesable
@@ -4618,6 +4614,50 @@ void NPC::SetAttackTimer()
}
}
+ //see if we have a valid weapon
+ if (ItemToUse != nullptr) {
+ //check type and damage/delay
+ if (ItemToUse->ItemClass != ItemClassCommon
+ || ItemToUse->Damage == 0
+ || ItemToUse->Delay == 0) {
+ //no weapon
+ ItemToUse = nullptr;
+ }
+ // Check to see if skill is valid
+ else if ((ItemToUse->ItemType > ItemTypeLargeThrowing) &&
+ (ItemToUse->ItemType != ItemTypeMartial) &&
+ (ItemToUse->ItemType != ItemType2HPiercing)) {
+ //no weapon
+ ItemToUse = nullptr;
+ }
+ }
+
+ int hhe = itembonuses.HundredHands + spellbonuses.HundredHands;
+
+ // Client pets do some logic for weapons, but the effect is minimal
+ // What they do is take the lower of their set delay and the weapon's
+ // ex. Pet's delay set to 20, weapon set to 19, delay 19
+ // Pet's delay set to 20, weapon set to 21, delay 20
+ int speed = 0;
+ int delay = 100 * attack_delay;
+
+ // Only apply the weapon-based delay modifications to Client pets. Otherwise,
+ // this change would affect all NPCs and their pets
+ bool clientpet = false;
+ if ((IsPet() || IsTempPet()) && IsPetOwnerClient())
+ clientpet = true;
+
+ // Apply weapon delay only if it's faster than the pet's default attack_delay
+ if (clientpet && (ItemToUse != nullptr) && (ItemToUse->Delay < attack_delay))
+ delay = 100 * ItemToUse->Delay;
+
+ speed = delay / haste_mod;
+
+ if (RuleB(Spells, Jun182014HundredHandsRevamp))
+ speed = static_cast<int>(speed + ((hhe / 1000.0f) * speed));
+ else
+ speed = static_cast<int>(speed + ((hhe / 100.0f) * delay));
+
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
}
}
It at least compiles, but that means little. If you care to give 'er a whirl, let me know. I may be able to test this tonight.