diff --git a/zone/loottables.cpp b/zone/loottables.cpp index 957889874..46eda9989 100644 --- a/zone/loottables.cpp +++ b/zone/loottables.cpp @@ -400,6 +400,16 @@ void NPC::AddLootDrop( item->trivial_max_level = loot_drop.trivial_max_level; item->equip_slot = EQ::invslot::SLOT_INVALID; + + // unsure if required to equip, YOLO for now + if (item2->ItemType == EQ::item::ItemTypeBow) { + SetBowEquipped(true); + } + + if (item2->ItemType == EQ::item::ItemTypeArrow) { + SetArrowEquipped(true); + } + if (loot_drop.equip_item > 0) { uint8 eslot = 0xFF; char newid[20]; diff --git a/zone/mob.h b/zone/mob.h index a71d92e23..eda57ca3c 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -480,6 +480,11 @@ public: bool HasTwoHanderEquipped() { return has_twohanderequipped; } void SetTwoHanderEquipped(bool val) { has_twohanderequipped = val; } bool HasDualWeaponsEquiped() const { return has_duelweaponsequiped; } + bool HasBowEquipped() const { return has_bowequipped; } + void SetBowEquipped(bool val) { has_bowequipped = val; } + bool HasArrowEquipped() const { return has_arrowequipped; } + void SetArrowEquipped(bool val) { has_arrowequipped = val; } + bool HasBowAndArrowEquipped() const { return HasBowEquipped() && HasArrowEquipped(); } inline void SetDuelWeaponsEquiped(bool val) { has_duelweaponsequiped = val; } bool CanFacestab() { return can_facestab; } void SetFacestab(bool val) { can_facestab = val; } @@ -1655,6 +1660,8 @@ protected: bool has_twohandbluntequiped; bool has_twohanderequipped; bool has_duelweaponsequiped; + bool has_bowequipped = false; + bool has_arrowequipped = false; bool use_double_melee_round_dmg_bonus; bool can_facestab; bool has_numhits; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index b42fd0341..80c7da5fb 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1336,9 +1336,11 @@ void Mob::AI_Process() { // See if we can summon the mob to us if (!HateSummon()) { + //could not summon them, check ranged... - if (GetSpecialAbility(SPECATK_RANGED_ATK)) + if (GetSpecialAbility(SPECATK_RANGED_ATK) || HasBowAndArrowEquipped()) { doranged = true; + } // Now pursue // TODO: Check here for another person on hate list with close hate value diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index e545ace88..0c2df7d71 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -1153,52 +1153,52 @@ float Mob::GetRangeDistTargetSizeMod(Mob* other) return (mod + 2.0f); //Add 2.0f as buffer to prevent any chance of failures, client enforce range check regardless. } -void NPC::RangedAttack(Mob* other) +void NPC::RangedAttack(Mob *other) { if (!other) return; - //make sure the attack and ranged timers are up - //if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow - if((attack_timer.Enabled() && !attack_timer.Check(false)) || (ranged_timer.Enabled() && !ranged_timer.Check())){ - LogCombat("Archery canceled. Timer not up. Attack [{}], ranged [{}]", attack_timer.GetRemainingTime(), ranged_timer.GetRemainingTime()); + // make sure the attack and ranged timers are up + // if the ranged timer is disabled, then they have no ranged weapon and shouldent be attacking anyhow + if ((attack_timer.Enabled() && !attack_timer.Check(false)) || + (ranged_timer.Enabled() && !ranged_timer.Check())) { + LogCombat("Archery canceled. Timer not up. Attack [{}], ranged [{}]", attack_timer.GetRemainingTime(), + ranged_timer.GetRemainingTime()); return; } - if(!CheckLosFN(other)) + if (!HasBowAndArrowEquipped() && !GetSpecialAbility(SPECATK_RANGED_ATK)) return; - int attacks = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0); - attacks = attacks > 0 ? attacks : 1; - for(int i = 0; i < attacks; ++i) { + if (!CheckLosFN(other)) + return; - if(!GetSpecialAbility(SPECATK_RANGED_ATK)) + int attacks = 1; + float min_range = static_cast(RuleI(Combat, MinRangedAttackDist)); + float max_range = 250.0f; // needs to be longer than 200(most spells) + + if (GetSpecialAbility(SPECATK_RANGED_ATK)) { + int temp_attacks = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 0); + attacks = temp_attacks > 0 ? temp_attacks : 1; + + int temp_min_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 4); // Min Range of NPC attack + int temp_max_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 1); // Max Range of NPC attack + if (temp_max_range) + max_range = static_cast(temp_max_range); + if (temp_min_range) + min_range = static_cast(temp_min_range); + } + + max_range *= max_range; + min_range *= min_range; + + for (int i = 0; i < attacks; ++i) { + if (DistanceSquared(m_Position, other->GetPosition()) > max_range) + return; + else if (DistanceSquared(m_Position, other->GetPosition()) < min_range) return; - int sa_min_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 4); //Min Range of NPC attack - int sa_max_range = GetSpecialAbilityParam(SPECATK_RANGED_ATK, 1); //Max Range of NPC attack - - float min_range = static_cast(RuleI(Combat, MinRangedAttackDist)); - float max_range = 250; // needs to be longer than 200(most spells) - - if (sa_max_range) - max_range = static_cast(sa_max_range); - - if (sa_min_range) - min_range = static_cast(sa_min_range); - - max_range *= max_range; - if(DistanceSquared(m_Position, other->GetPosition()) > max_range) - return; - else if(DistanceSquared(m_Position, other->GetPosition()) < (min_range * min_range)) - return; - - if(!other || !IsAttackAllowed(other) || - IsCasting() || - DivineAura() || - IsStunned() || - IsFeared() || - IsMezzed() || - (GetAppearance() == eaDead)){ + if (!other || !IsAttackAllowed(other) || IsCasting() || DivineAura() || IsStunned() || IsFeared() || + IsMezzed() || (GetAppearance() == eaDead)) { return; }