diff --git a/changelog.txt b/changelog.txt index 506c4d2ff..566cb393b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,22 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 11/15/2014 == +Kayen: Updated swarm pet AI to be consistent with live. + +*OLD AI: Swarm pet would lock on to target until target died, then depop as soon as target died. + +*NEW AI: Swarm pet will attack cast on target, NOT perma locked it can change targets if attacked +by something else that generate more hate. When target dies swarm pet will follow owner, if owner is +attacked by something else the swarm pet will attack it (until duration timer despawns the pet). + +Kayen: Updated perl quest function: MakeTempPet(Tspell_id, name=nullptr, duration=0, target=nullptr, sticktarg=0) +Kayen: Implemented perl quest function: Mob::TypesTempPet(npctypesid, name=nullptr, duration=0, follow=0, target=nullptr, sticktarg=0) +Note: 'sticktarg' field will cause the swarm pet to use the OLD AI + +Rule to use OLD AI only - default is disabled. +Optional SQL: utils/sql/git/optional/2014_11_15_SwarmPetTargetLock.sql + == 11/14/2014 == Secrets: Identified object size and solidtype as flags. Exported them as functions to Perl. demonstar55: Don't use the hack for charms that doesn't work on RoF diff --git a/common/ruletypes.h b/common/ruletypes.h index 129e0ed61..1d266a269 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -324,6 +324,7 @@ RULE_INT ( Spells, AI_IdleNoSpellMaxRecast, 2000) // AI spell recast time(MS) ch RULE_INT ( Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others. RULE_BOOL ( Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false) RULE_BOOL ( Spells, Jun182014HundredHandsRevamp, false) // this should be true for if you import a spell file newer than June 18, 2014 +RULE_BOOL ( Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning. RULE_CATEGORY_END() RULE_CATEGORY( Combat ) diff --git a/utils/sql/git/optional/2014_11_15_SwarmPetTargetLock.sql b/utils/sql/git/optional/2014_11_15_SwarmPetTargetLock.sql new file mode 100644 index 000000000..f2c11ae45 --- /dev/null +++ b/utils/sql/git/optional/2014_11_15_SwarmPetTargetLock.sql @@ -0,0 +1 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Spells:SwarmPetTargetLock', 'false', 'Use old method of swarm pet AI, where they lock onto a set target then depop when target is dead.'); diff --git a/zone/aa.cpp b/zone/aa.cpp index 321439aa2..3a3101746 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -542,10 +542,7 @@ void Client::HandleAAAction(aaID activate) { } } - -//Originally written by Branks -//functionality rewritten by Father Nitwit -void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override) { +void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) { //It might not be a bad idea to put these into the database, eventually.. @@ -563,7 +560,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u pet.count = 1; pet.duration = 1; - for(int x = 0; x < 12; x++) + for(int x = 0; x < MAX_SWARM_PETS; x++) { if(spells[spell_id].effectid[x] == SE_TemporaryPets) { @@ -607,8 +604,6 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u static const float swarm_pet_y[MAX_SWARM_PETS] = { 5, 5, -5, -5, 10, 10, -10, -10, 8, 8, -8, -8 }; - TempPets(true); - while(summon_count > 0) { int pet_duration = pet.duration; if(duration_override > 0) @@ -628,7 +623,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u GetX()+swarm_pet_x[summon_count], GetY()+swarm_pet_y[summon_count], GetZ(), GetHeading(), FlyMode3); - if((spell_id == 6882) || (spell_id == 6884)) + if (followme) npca->SetFollowID(GetID()); if(!npca->GetSwarmInfo()){ @@ -646,7 +641,10 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u //give the pets somebody to "love" if(targ != nullptr){ npca->AddToHateList(targ, 1000, 1000); - npca->GetSwarmInfo()->target = targ->GetID(); + if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) + npca->GetSwarmInfo()->target = targ->GetID(); + else + npca->GetSwarmInfo()->target = 0; } //we allocated a new NPC type object, give the NPC ownership of that memory @@ -662,7 +660,7 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u targ->AddToHateList(this, 1, 0); } -void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_override, uint32 duration_override, bool followme) { +void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) { AA_SwarmPet pet; pet.count = 1; @@ -700,7 +698,6 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid static const float swarm_pet_y[MAX_SWARM_PETS] = { 5, 5, -5, -5, 10, 10, -10, -10, 8, 8, -8, -8 }; - TempPets(true); while(summon_count > 0) { int pet_duration = pet.duration; @@ -721,6 +718,9 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid GetX()+swarm_pet_x[summon_count], GetY()+swarm_pet_y[summon_count], GetZ(), GetHeading(), FlyMode3); + if (followme) + npca->SetFollowID(GetID()); + if(!npca->GetSwarmInfo()){ AA_SwarmPetInfo* nSI = new AA_SwarmPetInfo; npca->SetSwarmInfo(nSI); @@ -736,7 +736,11 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid //give the pets somebody to "love" if(targ != nullptr){ npca->AddToHateList(targ, 1000, 1000); - npca->GetSwarmInfo()->target = targ->GetID(); + + if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) + npca->GetSwarmInfo()->target = targ->GetID(); + else + npca->GetSwarmInfo()->target = 0; } //we allocated a new NPC type object, give the NPC ownership of that memory @@ -895,8 +899,6 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration) make_npc->d_meele_texture1 = 0; make_npc->d_meele_texture2 = 0; - TempPets(true); - NPC* npca = new NPC(make_npc, 0, GetX(), GetY(), GetZ(), GetHeading(), FlyMode3); if(!npca->GetSwarmInfo()){ diff --git a/zone/attack.cpp b/zone/attack.cpp index 44bffce62..569466f68 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2062,6 +2062,13 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack } SetHP(0); SetPet(0); + + if (GetSwarmOwner()){ + Mob* owner = entity_list.GetMobID(GetSwarmOwner()); + if (owner) + owner->SetTempPetCount(owner->GetTempPetCount() - 1); + } + Mob* killer = GetHateDamageTop(this); entity_list.RemoveFromTargets(this, p_depop); @@ -2535,6 +2542,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO)) myowner->hate_list.Add(other, 0, 0, bFrenzy); } + + if (other->GetTempPetCount()) + entity_list.AddTempPetsToHateList(other, this, bFrenzy); + if (!wasengaged) { if(IsNPC() && other->IsClient() && other->CastToClient()) parse->EventNPC(EVENT_AGGRO, this->CastToNPC(), other, "", 0); diff --git a/zone/client.cpp b/zone/client.cpp index a8a3f6f8d..cfc686707 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6264,7 +6264,6 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid static const float swarm_pet_x[MAX_SWARM_PETS] = { 5, -5, 5, -5, 10, -10, 10, -10, 8, -8, 8, -8 }; static const float swarm_pet_y[MAX_SWARM_PETS] = { 5, 5, -5, -5, 10, 10, -10, -10, 8, 8, -8, -8 }; - TempPets(true); while(summon_count > 0) { NPCType *npc_dup = nullptr; diff --git a/zone/entity.cpp b/zone/entity.cpp index 76b9eb8d4..eeebfa88d 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -3622,6 +3622,42 @@ void EntityList::DestroyTempPets(Mob *owner) } } +int16 EntityList::CountTempPets(Mob *owner) +{ + int16 count = 0; + auto it = npc_list.begin(); + while (it != npc_list.end()) { + NPC* n = it->second; + if (n->GetSwarmInfo()) { + if (n->GetSwarmInfo()->owner_id == owner->GetID()) { + count++; + } + } + ++it; + } + + owner->SetTempPetCount(count); + + return count; +} + +void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy) +{ + if (!other || !owner) + return; + + auto it = npc_list.begin(); + while (it != npc_list.end()) { + NPC* n = it->second; + if (n->GetSwarmInfo()) { + if (n->GetSwarmInfo()->owner_id == owner->GetID()) { + n->CastToNPC()->hate_list.Add(other, 0, 0, bFrenzy); + } + } + ++it; + } +} + bool Entity::CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk) { diff --git a/zone/entity.h b/zone/entity.h index 2e6990231..486f1d49f 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -251,6 +251,8 @@ public: void RemoveAllLocalities(); void RemoveAllRaids(); void DestroyTempPets(Mob *owner); + int16 CountTempPets(Mob *owner); + void AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy = false); Entity *GetEntityMob(uint16 id); Entity *GetEntityMerc(uint16 id); Entity *GetEntityDoor(uint16 id); diff --git a/zone/mob.cpp b/zone/mob.cpp index b0dac9dff..a7d141b30 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -362,7 +362,8 @@ Mob::Mob(const char* in_name, nexthpevent = -1; nextinchpevent = -1; - TempPets(false); + hasTempPet = false; + count_TempPet = 0; m_is_running = false; @@ -423,7 +424,7 @@ Mob::~Mob() delete trade; } - if(HadTempPets()){ + if(HasTempPetsActive()){ entity_list.DestroyTempPets(this); } entity_list.UnMarkNPC(GetID()); diff --git a/zone/mob.h b/zone/mob.h index 7bd873d98..a4dd2d665 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -575,8 +575,8 @@ public: virtual void UnStun(); inline void Silence(bool newval) { silenced = newval; } inline void Amnesia(bool newval) { amnesiad = newval; } - void TemporaryPets(uint16 spell_id, Mob *target, const char *name_override = nullptr, uint32 duration_override = 0); - void TypesTemporaryPets(uint32 typesid, Mob *target, const char *name_override = nullptr, uint32 duration_override = 0, bool followme = false); + void TemporaryPets(uint16 spell_id, Mob *target, const char *name_override = nullptr, uint32 duration_override = 0, bool followme=true, bool sticktarg=false); + void TypesTemporaryPets(uint32 typesid, Mob *target, const char *name_override = nullptr, uint32 duration_override = 0, bool followme=true, bool sticktarg=false); void WakeTheDead(uint16 spell_id, Mob *target, uint32 duration); void Spin(); void Kill(); @@ -673,8 +673,10 @@ public: inline virtual bool HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); } inline virtual bool IsPet() { return(HasOwner() && !IsMerc()); } inline bool HasPet() const { if(GetPetID()==0){return false;} return (entity_list.GetMob(GetPetID()) != 0);} - bool HadTempPets() const { return(hasTempPet); } - void TempPets(bool i) { hasTempPet = i; } + inline bool HasTempPetsActive() const { return(hasTempPet); } + inline void SetTempPetsActive(bool i) { hasTempPet = i; } + inline int16 GetTempPetCount() const { return count_TempPet; } + inline void SetTempPetCount(int16 i) { count_TempPet = i; } bool HasPetAffinity() { if (aabonuses.GivePetGroupTarget || itembonuses.GivePetGroupTarget || spellbonuses.GivePetGroupTarget) return true; return false; } inline bool IsPetOwnerClient() const { return pet_owner_client; } inline void SetPetOwnerClient(bool value) { pet_owner_client = value; } @@ -1232,6 +1234,7 @@ protected: //temppet bool hasTempPet; bool _IsTempPet; + int16 count_TempPet; bool pet_owner_client; //Flags regular and pets as belonging to a client EGNode *_egnode; //the EG node we are in diff --git a/zone/npc.cpp b/zone/npc.cpp index 699f81384..d1bdee979 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -405,8 +405,8 @@ void NPC::SetTarget(Mob* mob) { if(mob == GetTarget()) //dont bother if they are allready our target return; - //our target is already set, do not turn from the course, unless our current target is dead. - if(GetSwarmInfo() && GetTarget() && (GetTarget()->GetHP() > 0)) { + //This is not the default behavior for swarm pets, must be specified from quest functions or rules value. + if(GetSwarmInfo() && GetSwarmInfo()->target && GetTarget() && (GetTarget()->GetHP() > 0)) { Mob *targ = entity_list.GetMob(GetSwarmInfo()->target); if(targ != mob){ return; @@ -1841,60 +1841,53 @@ bool Mob::HasNPCSpecialAtk(const char* parse) { void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho) { Mob::FillSpawnStruct(ns, ForWho); + PetOnSpawn(ns); + ns->spawn.is_npc = 1; +} +void NPC::PetOnSpawn(NewSpawn_Struct* ns) +{ //Basic settings to make sure swarm pets work properly. if (GetSwarmOwner()) { - Client *c = entity_list.GetClientByID(GetSwarmOwner()); - if(c) { - SetAllowBeneficial(1); //Allow client cast swarm pets to be heal/buffed. - SetPetOwnerClient(true); - //This is a hack to allow CLIENT swarm pets NOT to be targeted with F8. Warning: Will turn name 'Yellow'! - if (RuleB(Pets, SwarmPetNotTargetableWithHotKey)) - ns->spawn.IsMercenary = 1; + + Mob *m = entity_list.GetMobID(GetSwarmOwner()); + + if(m->IsClient()) { + SetPetOwnerClient(true); //Simple flag to determine if pet belongs to a client + SetAllowBeneficial(1);//Allow temp pets to receive buffs and heals if owner is client. + //This is a hack to allow CLIENT swarm pets NOT to be targeted with F8. Warning: Will turn name 'Yellow'! + if (RuleB(Pets, SwarmPetNotTargetableWithHotKey)) + ns->spawn.IsMercenary = 1; } //NPC cast swarm pets should still be targetable with F8. - else - ns->spawn.IsMercenary = 0; - } + else + ns->spawn.IsMercenary = 0; - //Not recommended if using above (However, this will work better on older clients). - if (RuleB(Pets, UnTargetableSwarmPet)) { - if(GetOwnerID() || GetSwarmOwner()) { - ns->spawn.is_pet = 1; - if (!IsCharmed() && GetOwnerID()) { - Client *c = entity_list.GetClientByID(GetOwnerID()); - if(c){ - SetPetOwnerClient(true); - sprintf(ns->spawn.lastName, "%s's Pet", c->GetName()); - } - } - else if (GetSwarmOwner()) { - ns->spawn.bodytype = 11; - if(!IsCharmed()) - { - Client *c = entity_list.GetClientByID(GetSwarmOwner()); - if(c){ - SetPetOwnerClient(true); - sprintf(ns->spawn.lastName, "%s's Pet", c->GetName()); - } - } + SetTempPet(true); //Simple mob flag for checking if temp pet + m->SetTempPetsActive(true); //Neccessary fail safe flag set if mob ever had a swarm pet to ensure they are removed. + m->SetTempPetCount(m->GetTempPetCount() + 1); + + //Not recommended if using above (However, this will work better on older clients). + if (RuleB(Pets, UnTargetableSwarmPet)) { + ns->spawn.bodytype = 11; + if(!IsCharmed() && m->IsClient()) + sprintf(ns->spawn.lastName, "%s's Pet", m->GetName()); + } + } + + else if(GetOwnerID()) { + ns->spawn.is_pet = 1; + if (!IsCharmed() && GetOwnerID()) { + Client *c = entity_list.GetClientByID(GetOwnerID()); + if(c){ + SetPetOwnerClient(true); + sprintf(ns->spawn.lastName, "%s's Pet", c->GetName()); } } - } else { - if(GetOwnerID()) { - ns->spawn.is_pet = 1; - if (!IsCharmed() && GetOwnerID()) { - Client *c = entity_list.GetClientByID(GetOwnerID()); - if(c){ - SetPetOwnerClient(true); - sprintf(ns->spawn.lastName, "%s's Pet", c->GetName()); - } - } - } else - ns->spawn.is_pet = 0; - } + } - ns->spawn.is_npc = 1; + else + ns->spawn.is_pet = 0; } void NPC::SetLevel(uint8 in_level, bool command) @@ -2417,3 +2410,30 @@ void NPC::DoQuestPause(Mob *other) { } } + +void NPC::DepopSwarmPets() +{ + if (GetSwarmInfo()) { + if (GetSwarmInfo()->duration->Check(false)){ + Mob* owner = entity_list.GetMobID(GetSwarmInfo()->owner_id); + if (owner) + owner->SetTempPetCount(owner->GetTempPetCount() - 1); + + Depop(); + return; + } + + //This is only used for optional quest or rule derived behavior now if you force a temp pet on a specific target. + if (GetSwarmInfo()->target) { + Mob *targMob = entity_list.GetMob(GetSwarmInfo()->target); + if(!targMob || (targMob && targMob->IsCorpse())){ + Mob* owner = entity_list.GetMobID(GetSwarmInfo()->owner_id); + if (owner) + owner->SetTempPetCount(owner->GetTempPetCount() - 1); + + Depop(); + return; + } + } + } +} \ No newline at end of file diff --git a/zone/npc.h b/zone/npc.h index c24c97200..71e6596ad 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -243,6 +243,8 @@ public: uint32 GetSwarmOwner(); uint32 GetSwarmTarget(); void SetSwarmTarget(int target_id = 0); + void DepopSwarmPets(); + void PetOnSpawn(NewSpawn_Struct* ns); void SignalNPC(int _signal_id); diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index b34cbb6c3..10e94f47e 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -1517,14 +1517,15 @@ XS(XS_Mob_MakeTempPet); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_MakeTempPet) { dXSARGS; - if (items < 2 || items > 5) - Perl_croak(aTHX_ "Usage: Mob::MakeTempPet(THIS, spell_id, name=nullptr, duration=0, target=nullptr)"); + if (items < 2 || items > 6) + Perl_croak(aTHX_ "Usage: Mob::MakeTempPet(THIS, spell_id, name=nullptr, duration=0, target=nullptr, sticktarg=0)"); { Mob * THIS; uint16 spell_id = (uint16)SvUV(ST(1)); char * name; uint32 duration; Mob * target; + bool sticktarg; if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -1554,7 +1555,13 @@ XS(XS_Mob_MakeTempPet) else Perl_croak(aTHX_ "owner is not of type Mob"); - THIS->TemporaryPets(spell_id, target, name, duration); + if (items < 6) + sticktarg = false; + else { + sticktarg = (bool)SvTRUE(ST(5)); + } + + THIS->TemporaryPets(spell_id, target, name, duration, true, sticktarg); } XSRETURN_EMPTY; } @@ -1563,15 +1570,16 @@ XS(XS_Mob_TypesTempPet); /* prototype to pass -Wmissing-prototypes */ XS(XS_Mob_TypesTempPet) { dXSARGS; - if (items < 2 || items > 6) - Perl_croak(aTHX_ "Usage: Mob::TypesTempPet(THIS, typesid, name=nullptr, duration=0, target=nullptr, follow=0)"); + if (items < 2 || items > 7) + Perl_croak(aTHX_ "Usage: Mob::TypesTempPet(THIS, typesid, name=nullptr, duration=0, follow=0, sticktarg=0, target=nullptr)"); { Mob * THIS; uint32 typesid = (uint32)SvUV(ST(1)); char * name; uint32 duration; - Mob * target; bool follow; + Mob * target; + bool sticktarg; if (sv_derived_from(ST(0), "Mob")) { IV tmp = SvIV((SV*)SvRV(ST(0))); @@ -1593,21 +1601,28 @@ XS(XS_Mob_TypesTempPet) duration = (uint32)SvUV(ST(3)); if (items < 5) + follow = true; + else { + follow = (bool)SvTRUE(ST(4)); + } + + if (items < 6) target = nullptr; - else if (sv_derived_from(ST(4), "Mob")) { - IV tmp = SvIV((SV*)SvRV(ST(4))); + else if (sv_derived_from(ST(5), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(5))); target = INT2PTR(Mob *,tmp); } else Perl_croak(aTHX_ "target is not of type Mob"); - if (items < 6) - follow = false; + + if (items < 7) + sticktarg = false; else { - follow = (bool)SvTRUE(ST(5)); + sticktarg = (bool)SvTRUE(ST(6)); } - THIS->TypesTemporaryPets(typesid, target, name, duration, follow); + THIS->TypesTemporaryPets(typesid, target, name, duration, follow, sticktarg); } XSRETURN_EMPTY; } @@ -8433,7 +8448,8 @@ XS(boot_Mob) newXSproto(strcpy(buf, "SetRace"), XS_Mob_SetRace, file, "$$"); newXSproto(strcpy(buf, "SetGender"), XS_Mob_SetGender, file, "$$"); newXSproto(strcpy(buf, "SendIllusion"), XS_Mob_SendIllusion, file, "$$;$$$$$$$$$$$$"); - newXSproto(strcpy(buf, "MakeTempPet"), XS_Mob_MakeTempPet, file, "$$;$$$"); + newXSproto(strcpy(buf, "MakeTempPet"), XS_Mob_MakeTempPet, file, "$$;$$$$"); + newXSproto(strcpy(buf, "TypesTempPet"), XS_Mob_TypesTempPet, file, "$$;$$$$$"); newXSproto(strcpy(buf, "QuestReward"), XS_Mob_QuestReward, file, "$$;$$$"); newXSproto(strcpy(buf, "CameraEffect"), XS_Mob_CameraEffect, file, "$$;$$$"); newXSproto(strcpy(buf, "SpellEffect"), XS_Mob_SpellEffect, file, "$$;$$$$$$"); diff --git a/zone/spells.cpp b/zone/spells.cpp index 6c6119831..52fabb6ff 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -122,17 +122,7 @@ void Mob::SpellProcess() void NPC::SpellProcess() { Mob::SpellProcess(); - - if (GetSwarmInfo()) { - if (GetSwarmInfo()->duration->Check(false)) - Depop(); - - Mob *targMob = entity_list.GetMob(GetSwarmInfo()->target); - if (GetSwarmInfo()->target != 0) { - if(!targMob || (targMob && targMob->IsCorpse())) - Depop(); - } - } + DepopSwarmPets(); } ///////////////////////////////////////////////////////////////////////////////