diff --git a/common/spdat.h b/common/spdat.h index edbbcc01e..d2b7dff04 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -168,6 +168,7 @@ #define SPELL_ILLUSION_TREE 601 #define SPELL_ILLUSION_FEMALE 1731 #define SPELL_ILLUSION_MALE 1732 +#define SPELL_UNSUMMON_SELF 892 //spellgroup ids #define SPELLGROUP_FRENZIED_BURNOUT 2754 diff --git a/zone/aa.cpp b/zone/aa.cpp index 857b5e495..a72bf2d7e 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -151,10 +151,14 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u //give the pets somebody to "love" if (targ != nullptr) { swarm_pet_npc->AddToHateList(targ, 1000, 1000); - if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) + if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) { swarm_pet_npc->GetSwarmInfo()->target = targ->GetID(); - else + swarm_pet_npc->SetPetTargetLockID(targ->GetID()); + swarm_pet_npc->SetSpecialAbility(IMMUNE_AGGRO, 1); + } + else { swarm_pet_npc->GetSwarmInfo()->target = 0; + } } //we allocated a new NPC type object, give the NPC ownership of that memory @@ -255,10 +259,14 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid if(targ != nullptr){ swarm_pet_npc->AddToHateList(targ, 1000, 1000); - if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) + if (RuleB(Spells, SwarmPetTargetLock) || sticktarg) { swarm_pet_npc->GetSwarmInfo()->target = targ->GetID(); - else + swarm_pet_npc->SetPetTargetLockID(targ->GetID()); + swarm_pet_npc->SetSpecialAbility(IMMUNE_AGGRO, 1); + } + else { swarm_pet_npc->GetSwarmInfo()->target = 0; + } } //we allocated a new NPC type object, give the NPC ownership of that memory diff --git a/zone/npc.cpp b/zone/npc.cpp index 110c652e4..a10713d06 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -509,12 +509,8 @@ void NPC::SetTarget(Mob* mob) { if(mob == GetTarget()) //dont bother if they are allready our target return; - //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; - } + if (GetPetTargetLockID()) { + TryDepopTargetLockedPets(mob); } if (mob) { @@ -847,6 +843,10 @@ bool NPC::Process() SpellProcess(); + if (swarm_timer.Check()) { + DepopSwarmPets(); + } + if (mob_close_scan_timer.Check()) { entity_list.ScanCloseMobs(close_mobs, this, IsMoving()); } @@ -3091,28 +3091,6 @@ void NPC::DepopSwarmPets() Depop(); return; } - - 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; - } - } - } - - if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()){ - - Mob *targMob = entity_list.GetMob(GetPetTargetLockID()); - - if(!targMob || (targMob && targMob->IsCorpse())){ - Kill(); - return; - } } } diff --git a/zone/npc.h b/zone/npc.h index 084a3df8a..d3578f1d2 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -260,6 +260,7 @@ public: uint32 GetSwarmTarget(); void SetSwarmTarget(int target_id = 0); void DepopSwarmPets(); + void TryDepopTargetLockedPets(Mob* current_target); void PetOnSpawn(NewSpawn_Struct* ns); void SignalNPC(int _signal_id); diff --git a/zone/pets.cpp b/zone/pets.cpp index 3b83df1e8..1b3a7e3ec 100644 --- a/zone/pets.cpp +++ b/zone/pets.cpp @@ -387,20 +387,64 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower, SetPetID(npc->GetID()); // We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet - if (record.petcontrol == petTargetLock) { - Mob* target = GetTarget(); + Mob* m_target = GetTarget(); - if (target){ - npc->AddToHateList(target, 1); - npc->SetPetTargetLockID(target->GetID()); + bool activiate_pet = false; + if (m_target && m_target->GetID() != GetID()) { + + if (spells[spell_id].target_type == ST_Self) { + float distance = CalculateDistance(m_target->GetX(), m_target->GetY(), m_target->GetZ()); + if (distance <= 200) { //Live distance on targetlock pets that self cast. No message is given if not in range. + activiate_pet = true; + } + } + else { + activiate_pet = true; + } + } + + if (activiate_pet){ + npc->AddToHateList(m_target, 1); + npc->SetPetTargetLockID(m_target->GetID()); npc->SetSpecialAbility(IMMUNE_AGGRO, 1); } - else - npc->Kill(); //On live casts spell 892 Unsummon (Kayen - Too limiting to use that for emu since pet can have more than 20k HP) + else { + npc->CastSpell(SPELL_UNSUMMON_SELF, npc->GetID()); //Live like behavior, damages self for 20K + if (!npc->HasDied()) { + npc->Kill(); //Ensure pet dies if over 20k HP. + } + } } } + +void NPC::TryDepopTargetLockedPets(Mob* current_target) { + + if (!current_target || (current_target && (current_target->GetID() != GetPetTargetLockID()) || current_target->IsCorpse())) { + + //Use when swarmpets are set to auto lock from quest or rule + if (GetSwarmInfo() && GetSwarmInfo()->target) { + Mob* owner = entity_list.GetMobID(GetSwarmInfo()->owner_id); + if (owner) { + owner->SetTempPetCount(owner->GetTempPetCount() - 1); + } + Depop(); + return; + } + //Use when pets are given petype 5 + if (IsPet() && GetPetType() == petTargetLock && GetPetTargetLockID()) { + CastSpell(SPELL_UNSUMMON_SELF, GetID()); //Live like behavior, damages self for 20K + if (!HasDied()) { + Kill(); //Ensure pet dies if over 20k HP. + } + return; + } + } +} + + + /* This is why the pets ghost - pets were being spawned too far away from its npc owner and some into walls or objects (+10), this sometimes creates the "ghost" effect. I changed to +2 (as close as I could get while it still looked good). I also noticed this can happen if an NPC is spawned on the same spot of another or in a related bad spot.*/ diff --git a/zone/spells.cpp b/zone/spells.cpp index b6d10a3a9..44f1cd8e7 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -136,9 +136,6 @@ void Mob::SpellProcess() void NPC::SpellProcess() { Mob::SpellProcess(); - if (swarm_timer.Check()) { - DepopSwarmPets(); - } } ///////////////////////////////////////////////////////////////////////////////