mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 17:51:28 +00:00
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). Updated perl quest function: MakeTempPet(Tspell_id, name=nullptr, duration=0, target=nullptr, sticktarg=0) 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
This commit is contained in:
parent
30922afd08
commit
94231b62a3
@ -1,6 +1,22 @@
|
|||||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
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 ==
|
== 11/14/2014 ==
|
||||||
Secrets: Identified object size and solidtype as flags. Exported them as functions to Perl.
|
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
|
demonstar55: Don't use the hack for charms that doesn't work on RoF
|
||||||
|
|||||||
@ -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_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, 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, 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_END()
|
||||||
|
|
||||||
RULE_CATEGORY( Combat )
|
RULE_CATEGORY( Combat )
|
||||||
|
|||||||
1
utils/sql/git/optional/2014_11_15_SwarmPetTargetLock.sql
Normal file
1
utils/sql/git/optional/2014_11_15_SwarmPetTargetLock.sql
Normal file
@ -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.');
|
||||||
30
zone/aa.cpp
30
zone/aa.cpp
@ -542,10 +542,7 @@ void Client::HandleAAAction(aaID activate) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) {
|
||||||
//Originally written by Branks
|
|
||||||
//functionality rewritten by Father Nitwit
|
|
||||||
void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override) {
|
|
||||||
|
|
||||||
//It might not be a bad idea to put these into the database, eventually..
|
//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.count = 1;
|
||||||
pet.duration = 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)
|
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,
|
static const float swarm_pet_y[MAX_SWARM_PETS] = { 5, 5, -5, -5,
|
||||||
10, 10, -10, -10,
|
10, 10, -10, -10,
|
||||||
8, 8, -8, -8 };
|
8, 8, -8, -8 };
|
||||||
TempPets(true);
|
|
||||||
|
|
||||||
while(summon_count > 0) {
|
while(summon_count > 0) {
|
||||||
int pet_duration = pet.duration;
|
int pet_duration = pet.duration;
|
||||||
if(duration_override > 0)
|
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],
|
GetX()+swarm_pet_x[summon_count], GetY()+swarm_pet_y[summon_count],
|
||||||
GetZ(), GetHeading(), FlyMode3);
|
GetZ(), GetHeading(), FlyMode3);
|
||||||
|
|
||||||
if((spell_id == 6882) || (spell_id == 6884))
|
if (followme)
|
||||||
npca->SetFollowID(GetID());
|
npca->SetFollowID(GetID());
|
||||||
|
|
||||||
if(!npca->GetSwarmInfo()){
|
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"
|
//give the pets somebody to "love"
|
||||||
if(targ != nullptr){
|
if(targ != nullptr){
|
||||||
npca->AddToHateList(targ, 1000, 1000);
|
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
|
//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);
|
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;
|
AA_SwarmPet pet;
|
||||||
pet.count = 1;
|
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,
|
static const float swarm_pet_y[MAX_SWARM_PETS] = { 5, 5, -5, -5,
|
||||||
10, 10, -10, -10,
|
10, 10, -10, -10,
|
||||||
8, 8, -8, -8 };
|
8, 8, -8, -8 };
|
||||||
TempPets(true);
|
|
||||||
|
|
||||||
while(summon_count > 0) {
|
while(summon_count > 0) {
|
||||||
int pet_duration = pet.duration;
|
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],
|
GetX()+swarm_pet_x[summon_count], GetY()+swarm_pet_y[summon_count],
|
||||||
GetZ(), GetHeading(), FlyMode3);
|
GetZ(), GetHeading(), FlyMode3);
|
||||||
|
|
||||||
|
if (followme)
|
||||||
|
npca->SetFollowID(GetID());
|
||||||
|
|
||||||
if(!npca->GetSwarmInfo()){
|
if(!npca->GetSwarmInfo()){
|
||||||
AA_SwarmPetInfo* nSI = new AA_SwarmPetInfo;
|
AA_SwarmPetInfo* nSI = new AA_SwarmPetInfo;
|
||||||
npca->SetSwarmInfo(nSI);
|
npca->SetSwarmInfo(nSI);
|
||||||
@ -736,7 +736,11 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
|
|||||||
//give the pets somebody to "love"
|
//give the pets somebody to "love"
|
||||||
if(targ != nullptr){
|
if(targ != nullptr){
|
||||||
npca->AddToHateList(targ, 1000, 1000);
|
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
|
//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_texture1 = 0;
|
||||||
make_npc->d_meele_texture2 = 0;
|
make_npc->d_meele_texture2 = 0;
|
||||||
|
|
||||||
TempPets(true);
|
|
||||||
|
|
||||||
NPC* npca = new NPC(make_npc, 0, GetX(), GetY(), GetZ(), GetHeading(), FlyMode3);
|
NPC* npca = new NPC(make_npc, 0, GetX(), GetY(), GetZ(), GetHeading(), FlyMode3);
|
||||||
|
|
||||||
if(!npca->GetSwarmInfo()){
|
if(!npca->GetSwarmInfo()){
|
||||||
|
|||||||
@ -2062,6 +2062,13 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
|
|||||||
}
|
}
|
||||||
SetHP(0);
|
SetHP(0);
|
||||||
SetPet(0);
|
SetPet(0);
|
||||||
|
|
||||||
|
if (GetSwarmOwner()){
|
||||||
|
Mob* owner = entity_list.GetMobID(GetSwarmOwner());
|
||||||
|
if (owner)
|
||||||
|
owner->SetTempPetCount(owner->GetTempPetCount() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
Mob* killer = GetHateDamageTop(this);
|
Mob* killer = GetHateDamageTop(this);
|
||||||
|
|
||||||
entity_list.RemoveFromTargets(this, p_depop);
|
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))
|
if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO))
|
||||||
myowner->hate_list.Add(other, 0, 0, bFrenzy);
|
myowner->hate_list.Add(other, 0, 0, bFrenzy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (other->GetTempPetCount())
|
||||||
|
entity_list.AddTempPetsToHateList(other, this, bFrenzy);
|
||||||
|
|
||||||
if (!wasengaged) {
|
if (!wasengaged) {
|
||||||
if(IsNPC() && other->IsClient() && other->CastToClient())
|
if(IsNPC() && other->IsClient() && other->CastToClient())
|
||||||
parse->EventNPC(EVENT_AGGRO, this->CastToNPC(), other, "", 0);
|
parse->EventNPC(EVENT_AGGRO, this->CastToNPC(), other, "", 0);
|
||||||
|
|||||||
@ -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_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 };
|
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) {
|
while(summon_count > 0) {
|
||||||
NPCType *npc_dup = nullptr;
|
NPCType *npc_dup = nullptr;
|
||||||
|
|||||||
@ -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,
|
bool Entity::CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z,
|
||||||
float trg_x, float trg_y, float trg_z, float perwalk)
|
float trg_x, float trg_y, float trg_z, float perwalk)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -251,6 +251,8 @@ public:
|
|||||||
void RemoveAllLocalities();
|
void RemoveAllLocalities();
|
||||||
void RemoveAllRaids();
|
void RemoveAllRaids();
|
||||||
void DestroyTempPets(Mob *owner);
|
void DestroyTempPets(Mob *owner);
|
||||||
|
int16 CountTempPets(Mob *owner);
|
||||||
|
void AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy = false);
|
||||||
Entity *GetEntityMob(uint16 id);
|
Entity *GetEntityMob(uint16 id);
|
||||||
Entity *GetEntityMerc(uint16 id);
|
Entity *GetEntityMerc(uint16 id);
|
||||||
Entity *GetEntityDoor(uint16 id);
|
Entity *GetEntityDoor(uint16 id);
|
||||||
|
|||||||
@ -362,7 +362,8 @@ Mob::Mob(const char* in_name,
|
|||||||
nexthpevent = -1;
|
nexthpevent = -1;
|
||||||
nextinchpevent = -1;
|
nextinchpevent = -1;
|
||||||
|
|
||||||
TempPets(false);
|
hasTempPet = false;
|
||||||
|
count_TempPet = 0;
|
||||||
|
|
||||||
m_is_running = false;
|
m_is_running = false;
|
||||||
|
|
||||||
@ -423,7 +424,7 @@ Mob::~Mob()
|
|||||||
delete trade;
|
delete trade;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(HadTempPets()){
|
if(HasTempPetsActive()){
|
||||||
entity_list.DestroyTempPets(this);
|
entity_list.DestroyTempPets(this);
|
||||||
}
|
}
|
||||||
entity_list.UnMarkNPC(GetID());
|
entity_list.UnMarkNPC(GetID());
|
||||||
|
|||||||
11
zone/mob.h
11
zone/mob.h
@ -575,8 +575,8 @@ public:
|
|||||||
virtual void UnStun();
|
virtual void UnStun();
|
||||||
inline void Silence(bool newval) { silenced = newval; }
|
inline void Silence(bool newval) { silenced = newval; }
|
||||||
inline void Amnesia(bool newval) { amnesiad = 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 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 = 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 WakeTheDead(uint16 spell_id, Mob *target, uint32 duration);
|
||||||
void Spin();
|
void Spin();
|
||||||
void Kill();
|
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 HasOwner() { if(GetOwnerID()==0){return false;} return( entity_list.GetMob(GetOwnerID()) != 0); }
|
||||||
inline virtual bool IsPet() { return(HasOwner() && !IsMerc()); }
|
inline virtual bool IsPet() { return(HasOwner() && !IsMerc()); }
|
||||||
inline bool HasPet() const { if(GetPetID()==0){return false;} return (entity_list.GetMob(GetPetID()) != 0);}
|
inline bool HasPet() const { if(GetPetID()==0){return false;} return (entity_list.GetMob(GetPetID()) != 0);}
|
||||||
bool HadTempPets() const { return(hasTempPet); }
|
inline bool HasTempPetsActive() const { return(hasTempPet); }
|
||||||
void TempPets(bool i) { hasTempPet = i; }
|
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; }
|
bool HasPetAffinity() { if (aabonuses.GivePetGroupTarget || itembonuses.GivePetGroupTarget || spellbonuses.GivePetGroupTarget) return true; return false; }
|
||||||
inline bool IsPetOwnerClient() const { return pet_owner_client; }
|
inline bool IsPetOwnerClient() const { return pet_owner_client; }
|
||||||
inline void SetPetOwnerClient(bool value) { pet_owner_client = value; }
|
inline void SetPetOwnerClient(bool value) { pet_owner_client = value; }
|
||||||
@ -1232,6 +1234,7 @@ protected:
|
|||||||
//temppet
|
//temppet
|
||||||
bool hasTempPet;
|
bool hasTempPet;
|
||||||
bool _IsTempPet;
|
bool _IsTempPet;
|
||||||
|
int16 count_TempPet;
|
||||||
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
bool pet_owner_client; //Flags regular and pets as belonging to a client
|
||||||
|
|
||||||
EGNode *_egnode; //the EG node we are in
|
EGNode *_egnode; //the EG node we are in
|
||||||
|
|||||||
110
zone/npc.cpp
110
zone/npc.cpp
@ -405,8 +405,8 @@ void NPC::SetTarget(Mob* mob) {
|
|||||||
if(mob == GetTarget()) //dont bother if they are allready our target
|
if(mob == GetTarget()) //dont bother if they are allready our target
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//our target is already set, do not turn from the course, unless our current target is dead.
|
//This is not the default behavior for swarm pets, must be specified from quest functions or rules value.
|
||||||
if(GetSwarmInfo() && GetTarget() && (GetTarget()->GetHP() > 0)) {
|
if(GetSwarmInfo() && GetSwarmInfo()->target && GetTarget() && (GetTarget()->GetHP() > 0)) {
|
||||||
Mob *targ = entity_list.GetMob(GetSwarmInfo()->target);
|
Mob *targ = entity_list.GetMob(GetSwarmInfo()->target);
|
||||||
if(targ != mob){
|
if(targ != mob){
|
||||||
return;
|
return;
|
||||||
@ -1841,60 +1841,53 @@ bool Mob::HasNPCSpecialAtk(const char* parse) {
|
|||||||
void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||||
{
|
{
|
||||||
Mob::FillSpawnStruct(ns, 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.
|
//Basic settings to make sure swarm pets work properly.
|
||||||
if (GetSwarmOwner()) {
|
if (GetSwarmOwner()) {
|
||||||
Client *c = entity_list.GetClientByID(GetSwarmOwner());
|
|
||||||
if(c) {
|
Mob *m = entity_list.GetMobID(GetSwarmOwner());
|
||||||
SetAllowBeneficial(1); //Allow client cast swarm pets to be heal/buffed.
|
|
||||||
SetPetOwnerClient(true);
|
if(m->IsClient()) {
|
||||||
//This is a hack to allow CLIENT swarm pets NOT to be targeted with F8. Warning: Will turn name 'Yellow'!
|
SetPetOwnerClient(true); //Simple flag to determine if pet belongs to a client
|
||||||
if (RuleB(Pets, SwarmPetNotTargetableWithHotKey))
|
SetAllowBeneficial(1);//Allow temp pets to receive buffs and heals if owner is client.
|
||||||
ns->spawn.IsMercenary = 1;
|
//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.
|
//NPC cast swarm pets should still be targetable with F8.
|
||||||
else
|
else
|
||||||
ns->spawn.IsMercenary = 0;
|
ns->spawn.IsMercenary = 0;
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Not recommended if using above (However, this will work better on older clients).
|
else if(GetOwnerID()) {
|
||||||
if (RuleB(Pets, UnTargetableSwarmPet)) {
|
ns->spawn.is_pet = 1;
|
||||||
if(GetOwnerID() || GetSwarmOwner()) {
|
if (!IsCharmed() && GetOwnerID()) {
|
||||||
ns->spawn.is_pet = 1;
|
Client *c = entity_list.GetClientByID(GetOwnerID());
|
||||||
if (!IsCharmed() && GetOwnerID()) {
|
if(c){
|
||||||
Client *c = entity_list.GetClientByID(GetOwnerID());
|
SetPetOwnerClient(true);
|
||||||
if(c){
|
sprintf(ns->spawn.lastName, "%s's Pet", c->GetName());
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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)
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -243,6 +243,8 @@ public:
|
|||||||
uint32 GetSwarmOwner();
|
uint32 GetSwarmOwner();
|
||||||
uint32 GetSwarmTarget();
|
uint32 GetSwarmTarget();
|
||||||
void SetSwarmTarget(int target_id = 0);
|
void SetSwarmTarget(int target_id = 0);
|
||||||
|
void DepopSwarmPets();
|
||||||
|
void PetOnSpawn(NewSpawn_Struct* ns);
|
||||||
|
|
||||||
void SignalNPC(int _signal_id);
|
void SignalNPC(int _signal_id);
|
||||||
|
|
||||||
|
|||||||
@ -1517,14 +1517,15 @@ XS(XS_Mob_MakeTempPet); /* prototype to pass -Wmissing-prototypes */
|
|||||||
XS(XS_Mob_MakeTempPet)
|
XS(XS_Mob_MakeTempPet)
|
||||||
{
|
{
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
if (items < 2 || items > 5)
|
if (items < 2 || items > 6)
|
||||||
Perl_croak(aTHX_ "Usage: Mob::MakeTempPet(THIS, spell_id, name=nullptr, duration=0, target=nullptr)");
|
Perl_croak(aTHX_ "Usage: Mob::MakeTempPet(THIS, spell_id, name=nullptr, duration=0, target=nullptr, sticktarg=0)");
|
||||||
{
|
{
|
||||||
Mob * THIS;
|
Mob * THIS;
|
||||||
uint16 spell_id = (uint16)SvUV(ST(1));
|
uint16 spell_id = (uint16)SvUV(ST(1));
|
||||||
char * name;
|
char * name;
|
||||||
uint32 duration;
|
uint32 duration;
|
||||||
Mob * target;
|
Mob * target;
|
||||||
|
bool sticktarg;
|
||||||
|
|
||||||
if (sv_derived_from(ST(0), "Mob")) {
|
if (sv_derived_from(ST(0), "Mob")) {
|
||||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
@ -1554,7 +1555,13 @@ XS(XS_Mob_MakeTempPet)
|
|||||||
else
|
else
|
||||||
Perl_croak(aTHX_ "owner is not of type Mob");
|
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;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
@ -1563,15 +1570,16 @@ XS(XS_Mob_TypesTempPet); /* prototype to pass -Wmissing-prototypes */
|
|||||||
XS(XS_Mob_TypesTempPet)
|
XS(XS_Mob_TypesTempPet)
|
||||||
{
|
{
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
if (items < 2 || items > 6)
|
if (items < 2 || items > 7)
|
||||||
Perl_croak(aTHX_ "Usage: Mob::TypesTempPet(THIS, typesid, name=nullptr, duration=0, target=nullptr, follow=0)");
|
Perl_croak(aTHX_ "Usage: Mob::TypesTempPet(THIS, typesid, name=nullptr, duration=0, follow=0, sticktarg=0, target=nullptr)");
|
||||||
{
|
{
|
||||||
Mob * THIS;
|
Mob * THIS;
|
||||||
uint32 typesid = (uint32)SvUV(ST(1));
|
uint32 typesid = (uint32)SvUV(ST(1));
|
||||||
char * name;
|
char * name;
|
||||||
uint32 duration;
|
uint32 duration;
|
||||||
Mob * target;
|
|
||||||
bool follow;
|
bool follow;
|
||||||
|
Mob * target;
|
||||||
|
bool sticktarg;
|
||||||
|
|
||||||
if (sv_derived_from(ST(0), "Mob")) {
|
if (sv_derived_from(ST(0), "Mob")) {
|
||||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
@ -1593,21 +1601,28 @@ XS(XS_Mob_TypesTempPet)
|
|||||||
duration = (uint32)SvUV(ST(3));
|
duration = (uint32)SvUV(ST(3));
|
||||||
|
|
||||||
if (items < 5)
|
if (items < 5)
|
||||||
|
follow = true;
|
||||||
|
else {
|
||||||
|
follow = (bool)SvTRUE(ST(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items < 6)
|
||||||
target = nullptr;
|
target = nullptr;
|
||||||
else if (sv_derived_from(ST(4), "Mob")) {
|
else if (sv_derived_from(ST(5), "Mob")) {
|
||||||
IV tmp = SvIV((SV*)SvRV(ST(4)));
|
IV tmp = SvIV((SV*)SvRV(ST(5)));
|
||||||
target = INT2PTR(Mob *,tmp);
|
target = INT2PTR(Mob *,tmp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Perl_croak(aTHX_ "target is not of type Mob");
|
Perl_croak(aTHX_ "target is not of type Mob");
|
||||||
|
|
||||||
if (items < 6)
|
|
||||||
follow = false;
|
if (items < 7)
|
||||||
|
sticktarg = false;
|
||||||
else {
|
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;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
@ -8433,7 +8448,8 @@ XS(boot_Mob)
|
|||||||
newXSproto(strcpy(buf, "SetRace"), XS_Mob_SetRace, file, "$$");
|
newXSproto(strcpy(buf, "SetRace"), XS_Mob_SetRace, file, "$$");
|
||||||
newXSproto(strcpy(buf, "SetGender"), XS_Mob_SetGender, file, "$$");
|
newXSproto(strcpy(buf, "SetGender"), XS_Mob_SetGender, file, "$$");
|
||||||
newXSproto(strcpy(buf, "SendIllusion"), XS_Mob_SendIllusion, 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, "QuestReward"), XS_Mob_QuestReward, file, "$$;$$$");
|
||||||
newXSproto(strcpy(buf, "CameraEffect"), XS_Mob_CameraEffect, file, "$$;$$$");
|
newXSproto(strcpy(buf, "CameraEffect"), XS_Mob_CameraEffect, file, "$$;$$$");
|
||||||
newXSproto(strcpy(buf, "SpellEffect"), XS_Mob_SpellEffect, file, "$$;$$$$$$");
|
newXSproto(strcpy(buf, "SpellEffect"), XS_Mob_SpellEffect, file, "$$;$$$$$$");
|
||||||
|
|||||||
@ -122,17 +122,7 @@ void Mob::SpellProcess()
|
|||||||
void NPC::SpellProcess()
|
void NPC::SpellProcess()
|
||||||
{
|
{
|
||||||
Mob::SpellProcess();
|
Mob::SpellProcess();
|
||||||
|
DepopSwarmPets();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user