mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-16 01:01:30 +00:00
Merge pull request #292 from KayenEQ/Development
Updated swarm pet AI to be consistent with live.
This commit is contained in:
commit
d7e05de556
@ -66,6 +66,21 @@ Akkadius: World will now check the db_update.pl script on bootup, if the db_upda
|
||||
|
||||
== 11/15/2014 ==
|
||||
Uleat(Natedog): A better fix for OP_ShopPlayerBuy - doesn't cause the issues that I introduced
|
||||
Kayen: Implemented NPC Special Ability 41 'Allow To Tank', gives NPC opportunity to take aggro over a client in melee range.
|
||||
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.
|
||||
|
||||
@ -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 )
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//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()){
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -133,7 +133,8 @@ enum {
|
||||
ALLOW_BENEFICIAL = 38,
|
||||
DISABLE_MELEE = 39,
|
||||
NPC_CHASE_DISTANCE = 40,
|
||||
MAX_SPECIAL_ATTACK = 41
|
||||
ALLOW_TO_TANK = 41,
|
||||
MAX_SPECIAL_ATTACK = 42
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -403,6 +403,13 @@ Mob *HateList::GetTop(Mob *center)
|
||||
}
|
||||
}
|
||||
|
||||
if (!isTopClientType) {
|
||||
if (top->GetSpecialAbility(ALLOW_TO_TANK)){
|
||||
isTopClientType = true;
|
||||
topClientTypeInRange = top;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isTopClientType)
|
||||
return topClientTypeInRange ? topClientTypeInRange : nullptr;
|
||||
|
||||
|
||||
@ -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());
|
||||
|
||||
11
zone/mob.h
11
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
|
||||
|
||||
114
zone/npc.cpp
114
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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, target=nullptr, sticktarg=0,)");
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -3956,7 +3971,10 @@ XS(XS_Mob_CastSpell)
|
||||
resist_adjust = (int16)SvIV(ST(6));
|
||||
}
|
||||
|
||||
THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, &resist_adjust);
|
||||
if (resist_adjust == 0)//If you do not pass resist adjust as nullptr it will ignore the spells default resist adjust
|
||||
THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0);
|
||||
else
|
||||
THIS->CastSpell(spell_id, target_id, slot, casttime, mana_cost, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0, 0, &resist_adjust);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@ -8433,7 +8451,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, "$$;$$$$$$");
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@ -3349,6 +3339,12 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
sprintf(temp1, "%d", spell_id);
|
||||
parse->EventNPC(EVENT_CAST_ON, spelltar->CastToNPC(), this, temp1, 0);
|
||||
}
|
||||
else if (spelltar->IsClient())
|
||||
{
|
||||
char temp1[100];
|
||||
sprintf(temp1, "%d", spell_id);
|
||||
parse->EventPlayer(EVENT_CAST_ON, spelltar->CastToClient(),temp1, 0);
|
||||
}
|
||||
|
||||
mod_spell_cast(spell_id, spelltar, reflect, use_resist_adjust, resist_adjust, isproc);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user