Fix for two possible crash points in NPC::Death()

This commit is contained in:
Uleat 2016-03-01 16:55:31 -05:00
parent 66b62303e4
commit 141d6e3e8b

View File

@ -1874,34 +1874,36 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack
} }
} }
bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attack_skill) { bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attack_skill)
Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killer_mob->GetName(), damage, spell, attack_skill); {
Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d",
((killer_mob) ? (killer_mob->GetName()) : ("[nullptr]")), damage, spell, attack_skill);
Mob *oos = nullptr; Mob *oos = nullptr;
if (killer_mob) { if (killer_mob) {
oos = killer_mob->GetOwnerOrSelf(); oos = killer_mob->GetOwnerOrSelf();
char buffer[48] = { 0 }; char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill)); snprintf(buffer, 47, "%d %d %d %d", killer_mob->GetID(), damage, spell, static_cast<int>(attack_skill));
if(parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0)
{ if (parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0) {
if (GetHP() < 0) { if (GetHP() < 0) {
SetHP(0); SetHP(0);
} }
return false; return false;
} }
if(killer_mob && killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { if (killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20] = { 0 }; char val1[20] = { 0 };
entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE, entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE,
killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1)); killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
} }
} else { }
else {
char buffer[48] = { 0 }; char buffer[48] = { 0 };
snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast<int>(attack_skill)); snprintf(buffer, 47, "%d %d %d %d", 0, damage, spell, static_cast<int>(attack_skill));
if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0)
{ if (parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0) {
if (GetHP() < 0) { if (GetHP() < 0) {
SetHP(0); SetHP(0);
} }
@ -1909,11 +1911,11 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
} }
} }
if (IsEngaged()) if (IsEngaged()) {
{
zone->DelAggroMob(); zone->DelAggroMob();
Log.Out(Logs::Detail, Logs::Attack, "%s Mobs currently Aggro %i", __FUNCTION__, zone->MobsAggroCount()); Log.Out(Logs::Detail, Logs::Attack, "%s Mobs currently Aggro %i", __FUNCTION__, zone->MobsAggroCount());
} }
SetHP(0); SetHP(0);
SetPet(0); SetPet(0);
@ -1945,16 +1947,14 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
app->priority = 6; app->priority = 6;
entity_list.QueueClients(killer_mob, app, false); entity_list.QueueClients(killer_mob, app, false);
safe_delete(app);
if (respawn2) { if (respawn2) {
respawn2->DeathReset(1); respawn2->DeathReset(1);
} }
if (killer_mob) { if (killer_mob && GetClass() != LDON_TREASURE)
if(GetClass() != LDON_TREASURE)
hate_list.AddEntToHateList(killer_mob, damage); hate_list.AddEntToHateList(killer_mob, damage);
}
safe_delete(app);
Mob *give_exp = hate_list.GetDamageTopOnHateList(this); Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
@ -1979,17 +1979,13 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
} }
if (give_exp && give_exp->IsTempPet() && give_exp->IsPetOwnerClient()) { if (give_exp && give_exp->IsTempPet() && give_exp->IsPetOwnerClient()) {
if (give_exp->IsNPC() && give_exp->CastToNPC()->GetSwarmOwner()) { if (give_exp->IsNPC() && give_exp->CastToNPC()->GetSwarmOwner()) {
Mob* temp_owner = nullptr; Mob* temp_owner = entity_list.GetMobID(give_exp->CastToNPC()->GetSwarmOwner());
temp_owner = entity_list.GetMobID(give_exp->CastToNPC()->GetSwarmOwner());
if (temp_owner) if (temp_owner)
give_exp = temp_owner; give_exp = temp_owner;
} }
} }
int PlayerCount = 0; // QueryServ Player Counting int PlayerCount = 0; // QueryServ Player Counting
Client *give_exp_client = nullptr; Client *give_exp_client = nullptr;
@ -2001,21 +1997,21 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
hate_list.DoFactionHits(GetNPCFactionID()); hate_list.DoFactionHits(GetNPCFactionID());
bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE); bool IsLdonTreasure = (this->GetClass() == LDON_TREASURE);
if (give_exp_client && !IsCorpse())
{ if (give_exp_client && !IsCorpse()) {
Group *kg = entity_list.GetGroupByClient(give_exp_client); Group *kg = entity_list.GetGroupByClient(give_exp_client);
Raid *kr = entity_list.GetRaidByClient(give_exp_client); Raid *kr = entity_list.GetRaidByClient(give_exp_client);
int32 finalxp = EXP_FORMULA; int32 finalxp = EXP_FORMULA;
finalxp = give_exp_client->mod_client_xp(finalxp, this); finalxp = give_exp_client->mod_client_xp(finalxp, this);
if(kr) if (kr) {
{
if (!IsLdonTreasure && MerchantType == 0) { if (!IsLdonTreasure && MerchantType == 0) {
kr->SplitExp((finalxp), this); kr->SplitExp((finalxp), this);
if (killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName()))) if (killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName())))
killer_mob->TrySpellOnKill(killed_level, spell); killer_mob->TrySpellOnKill(killed_level, spell);
} }
/* Send the EVENT_KILLED_MERIT event for all raid members */ /* Send the EVENT_KILLED_MERIT event for all raid members */
for (int i = 0; i < MAX_RAID_MEMBERS; i++) { for (int i = 0; i < MAX_RAID_MEMBERS; i++) {
if (kr->members[i].member != nullptr && kr->members[i].member->IsClient()) { // If Group Member is Client if (kr->members[i].member != nullptr && kr->members[i].member->IsClient()) { // If Group Member is Client
@ -2054,13 +2050,13 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
// End QueryServ Logging // End QueryServ Logging
} }
else if (give_exp_client->IsGrouped() && kg != nullptr) else if (give_exp_client->IsGrouped() && kg != nullptr) {
{
if (!IsLdonTreasure && MerchantType == 0) { if (!IsLdonTreasure && MerchantType == 0) {
kg->SplitExp((finalxp), this); kg->SplitExp((finalxp), this);
if (killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName()))) if (killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName())))
killer_mob->TrySpellOnKill(killed_level, spell); killer_mob->TrySpellOnKill(killed_level, spell);
} }
/* Send the EVENT_KILLED_MERIT event and update kill tasks /* Send the EVENT_KILLED_MERIT event and update kill tasks
* for all group members */ * for all group members */
for (int i = 0; i < MAX_GROUP_MEMBERS; i++) { for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
@ -2100,20 +2096,18 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
} }
// End QueryServ Logging // End QueryServ Logging
} }
else else {
{
if (!IsLdonTreasure && MerchantType == 0) { if (!IsLdonTreasure && MerchantType == 0) {
int conlevel = give_exp->GetLevelCon(GetLevel()); int conlevel = give_exp->GetLevelCon(GetLevel());
if (conlevel != CON_GREEN) if (conlevel != CON_GREEN) {
{ if (!GetOwner() || (GetOwner() && !GetOwner()->IsClient())) {
if(!GetOwner() || (GetOwner() && !GetOwner()->IsClient()))
{
give_exp_client->AddEXP((finalxp), conlevel); give_exp_client->AddEXP((finalxp), conlevel);
if (killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID())) if (killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID()))
killer_mob->TrySpellOnKill(killed_level, spell); killer_mob->TrySpellOnKill(killed_level, spell);
} }
} }
} }
/* Send the EVENT_KILLED_MERIT event */ /* Send the EVENT_KILLED_MERIT event */
parse->EventNPC(EVENT_KILLED_MERIT, this, give_exp_client, "killed", 0); parse->EventNPC(EVENT_KILLED_MERIT, this, give_exp_client, "killed", 0);
@ -2147,14 +2141,14 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
&& MerchantType == 0 && killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) || && MerchantType == 0 && killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient()))) (killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
{ {
if(killer != 0) if (killer != 0) {
{
if (killer->GetOwner() != 0 && killer->GetOwner()->IsClient()) if (killer->GetOwner() != 0 && killer->GetOwner()->IsClient())
killer = killer->GetOwner(); killer = killer->GetOwner();
if(!killer->CastToClient()->GetGM() && killer->IsClient()) if (killer->IsClient() && !killer->CastToClient()->GetGM())
this->CheckMinMaxLevel(killer); this->CheckMinMaxLevel(killer);
} }
entity_list.RemoveFromAutoXTargets(this); entity_list.RemoveFromAutoXTargets(this);
uint16 emoteid = this->GetEmoteID(); uint16 emoteid = this->GetEmoteID();
Corpse* corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata, level>54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS) : RuleI(NPC, MinorNPCCorpseDecayTimeMS)); Corpse* corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata, level>54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS) : RuleI(NPC, MinorNPCCorpseDecayTimeMS));
@ -2164,6 +2158,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
entity_list.UnMarkNPC(GetID()); entity_list.UnMarkNPC(GetID());
entity_list.RemoveNPC(GetID()); entity_list.RemoveNPC(GetID());
this->SetID(0); this->SetID(0);
if (killer != 0 && emoteid != 0) if (killer != 0 && emoteid != 0)
corpse->CastToNPC()->DoNPCEmote(AFTERDEATH, emoteid); corpse->CastToNPC()->DoNPCEmote(AFTERDEATH, emoteid);
if (killer != 0 && killer->IsClient()) { if (killer != 0 && killer->IsClient()) {
@ -2182,10 +2177,8 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
Raid* r = entity_list.GetRaidByClient(killer->CastToClient()); Raid* r = entity_list.GetRaidByClient(killer->CastToClient());
if (r) { if (r) {
int i = 0; int i = 0;
for(int x = 0; x < MAX_RAID_MEMBERS; x++) for (int x = 0; x < MAX_RAID_MEMBERS; x++) {
{ switch (r->GetLootType()) {
switch(r->GetLootType())
{
case 0: case 0:
case 1: case 1:
if (r->members[x].member && r->members[x].IsRaidLeader) { if (r->members[x].member && r->members[x].IsRaidLeader) {
@ -2210,8 +2203,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
} }
break; break;
case 4: case 4:
if(r->members[x].member) if (r->members[x].member) {
{
corpse->AllowPlayerLoot(r->members[x].member, i); corpse->AllowPlayerLoot(r->members[x].member, i);
i++; i++;
} }
@ -2222,28 +2214,24 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
} }
} }
if(zone && zone->adv_data) if (zone && zone->adv_data) {
{
ServerZoneAdventureDataReply_Struct *sr = (ServerZoneAdventureDataReply_Struct*)zone->adv_data; ServerZoneAdventureDataReply_Struct *sr = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
if(sr->type == Adventure_Kill) if (sr->type == Adventure_Kill) {
{
zone->DoAdventureCountIncrease(); zone->DoAdventureCountIncrease();
} }
else if(sr->type == Adventure_Assassinate) else if (sr->type == Adventure_Assassinate) {
{ if (sr->data_id == GetNPCTypeID()) {
if(sr->data_id == GetNPCTypeID())
{
zone->DoAdventureCountIncrease(); zone->DoAdventureCountIncrease();
} }
else else {
{
zone->DoAdventureAssassinationCountIncrease(); zone->DoAdventureAssassinationCountIncrease();
} }
} }
} }
} }
else else {
entity_list.RemoveFromXTargets(this); entity_list.RemoveFromXTargets(this);
}
// Parse quests even if we're killed by an NPC // Parse quests even if we're killed by an NPC
if (oos) { if (oos) {
@ -2252,8 +2240,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
uint16 emoteid = this->GetEmoteID(); uint16 emoteid = this->GetEmoteID();
if (emoteid != 0) if (emoteid != 0)
this->DoNPCEmote(ONDEATH, emoteid); this->DoNPCEmote(ONDEATH, emoteid);
if(oos->IsNPC()) if (oos->IsNPC()) {
{
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0); parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
uint16 emoteid = oos->GetEmoteID(); uint16 emoteid = oos->GetEmoteID();
if (emoteid != 0) if (emoteid != 0)
@ -2264,6 +2251,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attac
WipeHateList(); WipeHateList();
p_depop = true; p_depop = true;
if (killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted if (killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted
killer_mob->SetTarget(nullptr); //via AE effects and such.. killer_mob->SetTarget(nullptr); //via AE effects and such..