diff --git a/common/spdat.h b/common/spdat.h index 9358bde69..d8b1bd188 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -26,6 +26,7 @@ #define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit //some spell IDs which will prolly change, but are needed +#define SPELL_LIFEBURN 2755 #define SPELL_LEECH_TOUCH 2766 #define SPELL_LAY_ON_HANDS 87 #define SPELL_HARM_TOUCH 88 @@ -998,7 +999,7 @@ typedef enum { #define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage) #define SE_Flurry 279 // implemented #define SE_PetFlurry 280 // implemented[AA] -#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance +#define SE_FeignedMinion 281 // implemented, ability allows you to instruct your pet to feign death via the '/pet feign' command, base: succeed chance, limit: none, max: none, Note: Only implemented as an AA. #define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent. #define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk //#define SE_LoHSetHeal 284 // not used diff --git a/zone/aggro.cpp b/zone/aggro.cpp index ba217960e..3d706efde 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -1402,45 +1402,62 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib return std::max(0, AggroAmount); } -void Mob::AddFeignMemory(Client* attacker) { - if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) +void Mob::AddFeignMemory(Mob* attacker) { + if (feign_memory_list.empty() && AI_feign_remember_timer != nullptr) { AI_feign_remember_timer->Start(AIfeignremember_delay); - feign_memory_list.insert(attacker->CharacterID()); + } + + if (attacker) { + feign_memory_list.insert(attacker->GetID()); + } } -void Mob::RemoveFromFeignMemory(Client* attacker) { - feign_memory_list.erase(attacker->CharacterID()); - if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr) +void Mob::RemoveFromFeignMemory(Mob* attacker) { + + if (!attacker) { + return; + } + + feign_memory_list.erase(attacker->GetID()); + if (feign_memory_list.empty() && AI_feign_remember_timer != nullptr) { AI_feign_remember_timer->Disable(); + } if(feign_memory_list.empty()) { minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AI_feign_remember_timer != nullptr) + if (AI_feign_remember_timer != nullptr) { AI_feign_remember_timer->Disable(); + } } } void Mob::ClearFeignMemory() { - auto RememberedCharID = feign_memory_list.begin(); - while (RememberedCharID != feign_memory_list.end()) + auto remembered_feigned_mobid = feign_memory_list.begin(); + while (remembered_feigned_mobid != feign_memory_list.end()) { - Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID); - if(remember_client != nullptr) //Still in zone - remember_client->RemoveXTarget(this, false); - ++RememberedCharID; + Mob* remembered_mob = entity_list.GetMob(*remembered_feigned_mobid); + if (remembered_mob->IsClient() && remembered_mob != nullptr) { //Still in zone + remembered_mob->CastToClient()->RemoveXTarget(this, false); + } + ++remembered_feigned_mobid; } feign_memory_list.clear(); minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin); maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax); - if(AI_feign_remember_timer != nullptr) + if (AI_feign_remember_timer != nullptr) { AI_feign_remember_timer->Disable(); + } } -bool Mob::IsOnFeignMemory(Client *attacker) const +bool Mob::IsOnFeignMemory(Mob *attacker) const { - return feign_memory_list.find(attacker->CharacterID()) != feign_memory_list.end(); + if (!attacker) { + return 0; + } + + return feign_memory_list.find(attacker->GetID()) != feign_memory_list.end(); } bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) { diff --git a/zone/attack.cpp b/zone/attack.cpp index 5fec09739..ff9f85264 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2813,7 +2813,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic); - if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other->CastToClient())) + if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other)) other->CastToClient()->AddAutoXTarget(this); #ifdef BOTS diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 04ab98239..4cb4047e9 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -1571,8 +1571,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon) break; case SE_FeignedMinion: - if (newbon->FeignedMinionChance < base_value) + if (newbon->FeignedMinionChance < base_value) { newbon->FeignedMinionChance = base_value; + } + newbon->PetCommands[PET_FEIGN] = true; break; case SE_AdditionalAura: diff --git a/zone/client.cpp b/zone/client.cpp index 397a26c88..62ffafd17 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -145,7 +145,6 @@ Client::Client(EQStreamInterface* ieqs) global_channel_timer(1000), fishing_timer(8000), endupkeep_timer(1000), - forget_timer(0), autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000), client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)), client_zone_wide_full_position_update_timer(5 * 60 * 1000), @@ -186,7 +185,6 @@ Client::Client(EQStreamInterface* ieqs) character_id = 0; conn_state = NoPacketsReceived; client_data_loaded = false; - feigned = false; berserk = false; dead = false; eqs = ieqs; @@ -2677,22 +2675,6 @@ void Client::MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing, uint32 re safe_delete(outapp); } -void Client::SetFeigned(bool in_feigned) { - if (in_feigned) - { - if(RuleB(Character, FeignKillsPet)) - { - SetPet(0); - } - SetHorseId(0); - entity_list.ClearFeignAggro(this); - forget_timer.Start(FeignMemoryDuration); - } else { - forget_timer.Disable(); - } - feigned=in_feigned; - } - void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQ::ItemData* item, bool buying) { if(!player || !merchant || !item) diff --git a/zone/client.h b/zone/client.h index 3254e9899..2ba96bd30 100644 --- a/zone/client.h +++ b/zone/client.h @@ -835,9 +835,6 @@ public: inline uint8 GetBecomeNPCLevel() const { return npclevel; } inline void SetBecomeNPC(bool flag) { npcflag = flag; } inline void SetBecomeNPCLevel(uint8 level) { npclevel = level; } - void SetFeigned(bool in_feigned); - /// this cures timing issues cuz dead animation isn't done but server side feigning is? - inline bool GetFeigned() const { return(feigned); } EQStreamInterface* Connection() { return eqs; } #ifdef PACKET_PROFILER void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); } @@ -1850,7 +1847,6 @@ private: Timer global_channel_timer; Timer fishing_timer; Timer endupkeep_timer; - Timer forget_timer; // our 2 min everybody forgets you timer Timer autosave_timer; Timer client_scan_npc_aggro_timer; Timer client_zone_wide_full_position_update_timer; @@ -1890,7 +1886,6 @@ private: bool npcflag; uint8 npclevel; - bool feigned; bool bZoning; bool tgb; bool instalog; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 3c6801e8c..cad61cdf3 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -10255,6 +10255,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { + mypet->SetFeigned(false); if (mypet->IsPetStop()) { mypet->SetPetStop(false); SetPetCommandState(PET_BUTTON_STOP, 0); @@ -10301,6 +10302,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) { + mypet->SetFeigned(false); if (mypet->IsPetStop()) { mypet->SetPetStop(false); SetPetCommandState(PET_BUTTON_STOP, 0); @@ -10376,6 +10378,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsNPC()) { // Set Sit button to unpressed - send stand anim/end hpregen + mypet->SetFeigned(false); SetPetCommandState(PET_BUTTON_SIT, 0); mypet->SendAppearancePacket(AT_Anim, ANIM_STAND); @@ -10396,6 +10399,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); mypet->SayString(this, Chat::PetResponse, PET_FOLLOWING); mypet->SetPetOrder(SPO_Follow); @@ -10443,6 +10447,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); mypet->SayString(this, Chat::PetResponse, PET_GUARDME_STRING); mypet->SetPetOrder(SPO_Follow); @@ -10463,12 +10468,14 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { if (mypet->GetPetOrder() == SPO_Sit) { + mypet->SetFeigned(false); mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); mypet->SetPetOrder(SPO_Follow); mypet->SendAppearancePacket(AT_Anim, ANIM_STAND); } else { + mypet->SetFeigned(false); mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); mypet->SetPetOrder(SPO_Sit); mypet->SetRunAnimSpeed(0); @@ -10483,6 +10490,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); SetPetCommandState(PET_BUTTON_SIT, 0); mypet->SetPetOrder(SPO_Follow); @@ -10494,6 +10502,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) { + mypet->SetFeigned(false); mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING); SetPetCommandState(PET_BUTTON_SIT, 1); mypet->SetPetOrder(SPO_Sit); @@ -10687,6 +10696,38 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) } break; } + + case PET_FEIGN: { + if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) { + if (mypet->IsFeared()) + break; + + int pet_fd_chance = aabonuses.FeignedMinionChance; + if (zone->random.Int(0, 99) > pet_fd_chance) { + mypet->SetFeigned(false); + entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, mypet->GetCleanName()); + } + else { + bool immune_aggro = GetSpecialAbility(IMMUNE_AGGRO); + mypet->SetSpecialAbility(IMMUNE_AGGRO, 1); + mypet->WipeHateList(); + mypet->SetPetOrder(SPO_FeignDeath); + mypet->SetRunAnimSpeed(0); + mypet->StopNavigation(); + mypet->SendAppearancePacket(AT_Anim, ANIM_DEATH); + mypet->SetFeigned(true); + mypet->SetTarget(nullptr); + if (!mypet->UseBardSpellLogic()) { + mypet->InterruptSpell(); + } + + if (!immune_aggro) { + mypet->SetSpecialAbility(IMMUNE_AGGRO, 0); + } + } + } + break; + } case PET_STOP: { if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF @@ -10694,7 +10735,6 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsPetStop()) { mypet->SetPetStop(false); } else { - mypet->SetPetStop(true); mypet->StopNavigation(); mypet->SetTarget(nullptr); if (mypet->IsPetRegroup()) { diff --git a/zone/entity.cpp b/zone/entity.cpp index 7e66929e3..0179b3c54 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -1515,10 +1515,10 @@ void EntityList::RemoveFromTargets(Mob *mob, bool RemoveFromXTargets) continue; if (RemoveFromXTargets) { - if (m->IsClient() && (mob->CheckAggro(m) || mob->IsOnFeignMemory(m->CastToClient()))) + if (m->IsClient() && (mob->CheckAggro(m) || mob->IsOnFeignMemory(m))) m->CastToClient()->RemoveXTarget(mob, false); // FadingMemories calls this function passing the client. - else if (mob->IsClient() && (m->CheckAggro(mob) || m->IsOnFeignMemory(mob->CastToClient()))) + else if (mob->IsClient() && (m->CheckAggro(mob) || m->IsOnFeignMemory(mob))) mob->CastToClient()->RemoveXTarget(m, false); } @@ -3488,7 +3488,7 @@ void EntityList::ClearFeignAggro(Mob *targ) auto it = npc_list.begin(); while (it != npc_list.end()) { // add Feign Memory check because sometimes weird stuff happens - if (it->second->CheckAggro(targ) || (targ->IsClient() && it->second->IsOnFeignMemory(targ->CastToClient()))) { + if (it->second->CheckAggro(targ) || (targ->IsClient() && it->second->IsOnFeignMemory(targ))) { if (it->second->GetSpecialAbility(IMMUNE_FEIGN_DEATH)) { ++it; continue; @@ -3514,22 +3514,31 @@ void EntityList::ClearFeignAggro(Mob *targ) it->second->RemoveFromHateList(targ); if (targ->IsClient()) { - if (it->second->GetLevel() >= 35 && zone->random.Roll(60)) - it->second->AddFeignMemory(targ->CastToClient()); - else + if (it->second->GetLevel() >= 35 && zone->random.Roll(60)) { + it->second->AddFeignMemory(targ); + } + else { targ->CastToClient()->RemoveXTarget(it->second, false); + } + } + else if (targ->IsPet()){ + if (it->second->GetLevel() >= 35 && zone->random.Roll(60)) { + it->second->AddFeignMemory(targ); + } } } ++it; } } -void EntityList::ClearZoneFeignAggro(Client *targ) +void EntityList::ClearZoneFeignAggro(Mob *targ) { auto it = npc_list.begin(); while (it != npc_list.end()) { it->second->RemoveFromFeignMemory(targ); - targ->CastToClient()->RemoveXTarget(it->second, false); + if (targ && targ->IsClient()) { + targ->CastToClient()->RemoveXTarget(it->second, false); + } ++it; } } diff --git a/zone/entity.h b/zone/entity.h index 0984932fe..542f95845 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -455,7 +455,7 @@ public: void ClearAggro(Mob* targ); void ClearWaterAggro(Mob* targ); void ClearFeignAggro(Mob* targ); - void ClearZoneFeignAggro(Client* targ); + void ClearZoneFeignAggro(Mob* targ); void AggroZone(Mob* who, uint32 hate = 0); bool Fighting(Mob* targ); diff --git a/zone/mob.cpp b/zone/mob.cpp index 87b315612..f1aebb7f2 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -109,6 +109,7 @@ Mob::Mob( stunned_timer(0), spun_timer(0), bardsong_timer(6000), + forget_timer(0), gravity_timer(1000), viral_timer(0), m_FearWalkTarget(-999999.0f, -999999.0f, -999999.0f), @@ -282,6 +283,8 @@ Mob::Mob( InitializeBuffSlots(); + feigned = false; + // clear the proc arrays for (int j = 0; j < MAX_PROCS; j++) { PermaProcs[j].spellID = SPELL_UNKNOWN; @@ -6505,6 +6508,24 @@ void Mob::ShieldAbilityClearVariables() } } +void Mob::SetFeigned(bool in_feigned) { + + if (in_feigned) { + if (IsClient()) { + if (RuleB(Character, FeignKillsPet)){ + SetPet(0); + } + CastToClient()->SetHorseId(0); + } + entity_list.ClearFeignAggro(this); + forget_timer.Start(FeignMemoryDuration); + } + else { + forget_timer.Disable(); + } + feigned = in_feigned; +} + #ifdef BOTS bool Mob::JoinHealRotationTargetPool(std::shared_ptr* heal_rotation) { diff --git a/zone/mob.h b/zone/mob.h index 34c991177..50ad8af58 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -71,7 +71,7 @@ class Mob : public Entity { public: enum CLIENT_CONN_STATUS { CLIENT_CONNECTING, CLIENT_CONNECTED, CLIENT_LINKDEAD, CLIENT_KICKED, DISCONNECTED, CLIENT_ERROR, CLIENT_CONNECTINGALL }; - enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard }; + enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard, SPO_FeignDeath }; struct SpecialAbility { SpecialAbility() { @@ -670,10 +670,10 @@ public: bool HateSummon(); void FaceTarget(Mob* mob_to_face = 0); void WipeHateList(); - void AddFeignMemory(Client* attacker); - void RemoveFromFeignMemory(Client* attacker); + void AddFeignMemory(Mob* attacker); + void RemoveFromFeignMemory(Mob* attacker); void ClearFeignMemory(); - bool IsOnFeignMemory(Client *attacker) const; + bool IsOnFeignMemory(Mob *attacker) const; void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); } std::list& GetHateList() { return hate_list.GetHateList(); } std::list GetHateListByDistance(int distance = 0) { return hate_list.GetHateListByDistance(distance); } @@ -1296,6 +1296,10 @@ public: bool CanOpenDoors() const; void SetCanOpenDoors(bool can_open); + void SetFeigned(bool in_feigned); + /// this cures timing issues cuz dead animation isn't done but server side feigning is? + inline bool GetFeigned() const { return(feigned); } + void DeleteBucket(std::string bucket_name); std::string GetBucket(std::string bucket_name); std::string GetBucketExpires(std::string bucket_name); @@ -1720,6 +1724,9 @@ protected: AuraMgr aura_mgr; AuraMgr trap_mgr; + bool feigned; + Timer forget_timer; // our 2 min everybody forgets you timer + bool m_can_open_doors; MobMovementManager *mMovementManager; @@ -1727,7 +1734,7 @@ protected: private: void _StopSong(); //this is not what you think it is Mob* target; - + #ifdef BOTS std::shared_ptr m_target_of_heal_rotation; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 1a071cd06..1d7d9c317 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -838,20 +838,21 @@ void Client::AI_Process() else { if(AI_feign_remember_timer->Check()) { - std::set::iterator RememberedCharID; - RememberedCharID = feign_memory_list.begin(); - while (RememberedCharID != feign_memory_list.end()) { - Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID); - if (remember_client == nullptr) { + std::set::iterator remembered_feigned_mobid; + remembered_feigned_mobid = feign_memory_list.begin(); + while (remembered_feigned_mobid != feign_memory_list.end()) { + + Mob* remembered_mob = entity_list.GetMob(*remembered_feigned_mobid); + if (remembered_mob == nullptr || remembered_mob->IsCorpse()) { //they are gone now... - RememberedCharID = feign_memory_list.erase(RememberedCharID); - } else if (!remember_client->GetFeigned()) { - AddToHateList(remember_client->CastToMob(),1); - RememberedCharID = feign_memory_list.erase(RememberedCharID); + remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid); + } else if (!remembered_mob->GetFeigned()) { + AddToHateList(remembered_mob,1); + remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid); break; } else { //they are still feigned, carry on... - ++RememberedCharID; + ++remembered_feigned_mobid; } } } @@ -1373,22 +1374,22 @@ void Mob::AI_Process() { // 6/14/06 // Improved Feign Death Memory // check to see if any of our previous feigned targets have gotten up. - std::set::iterator RememberedCharID; - RememberedCharID = feign_memory_list.begin(); - while (RememberedCharID != feign_memory_list.end()) { - Client *remember_client = entity_list.GetClientByCharID(*RememberedCharID); - if (remember_client == nullptr) { + std::set::iterator remembered_feigned_mobid; + remembered_feigned_mobid = feign_memory_list.begin(); + while (remembered_feigned_mobid != feign_memory_list.end()) { + Mob *remembered_mob = entity_list.GetMob(*remembered_feigned_mobid); + if (remembered_mob == nullptr || remembered_mob->IsCorpse()) { //they are gone now... - RememberedCharID = feign_memory_list.erase(RememberedCharID); + remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid); } - else if (!remember_client->GetFeigned()) { - AddToHateList(remember_client->CastToMob(), 1); - RememberedCharID = feign_memory_list.erase(RememberedCharID); + else if (!remembered_mob->GetFeigned()) { + AddToHateList(remembered_mob, 1); + remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid); break; } else { //they are still feigned, carry on... - ++RememberedCharID; + ++remembered_feigned_mobid; } } } @@ -1485,6 +1486,10 @@ void Mob::AI_Process() { } break; } + case SPO_FeignDeath: { + SetAppearance(eaDead, false); + break; + } } if (IsPetRegroup()) { return; @@ -1557,6 +1562,11 @@ void Mob::AI_Process() { } } + if (forget_timer.Check()) { + forget_timer.Disable(); + entity_list.ClearZoneFeignAggro(this); + } + //Do Ranged attack here if (doranged) { RangedAttack(target); diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index c49662802..c9d76de7a 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -1557,18 +1557,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove #ifdef SPELL_EFFECT_SPAM snprintf(effect_desc, _EDLEN, "Feign Death"); #endif - //todo, look up spell ID in DB - if(spell_id == 2488) //Dook- Lifeburn fix + if(spell_id == SPELL_LIFEBURN) //Dook- Lifeburn fix break; if(IsClient()) { CastToClient()->SetHorseId(0); // dismount if have horse if (zone->random.Int(0, 99) > spells[spell_id].base_value[i]) { - CastToClient()->SetFeigned(false); + SetFeigned(false); entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, GetName()); } else { - CastToClient()->SetFeigned(true); + SetFeigned(true); } } break;