mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
[Bug Fix] Fix NPC After Death Emotes (#4021)
* [Bug Fix] Fix NPC After Death Emotes - `DoNPCEmote` was being called on the corpse, not the NPC, so it wasn't working for some reason despite it working for years. - Cleaned up some other logic and variable names in `NPC::Death` while I was in there. * Update attack.cpp * Update npc.cpp * Update attack.cpp * Update attack.cpp
This commit is contained in:
parent
1cb72642ac
commit
a1f2a21c99
468
zone/attack.cpp
468
zone/attack.cpp
@ -1818,9 +1818,8 @@ bool Client::Death(Mob* killerMob, int64 damage, uint16 spell, EQ::skills::Skill
|
||||
parse->EventNPC(EVENT_SLAY, killerMob->CastToNPC(), this, "", 0);
|
||||
}
|
||||
|
||||
const uint32 emote_id = killerMob->GetEmoteID();
|
||||
if (emote_id) {
|
||||
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emote_id, this);
|
||||
if (emoteid) {
|
||||
killerMob->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledPC, emoteid, this);
|
||||
}
|
||||
|
||||
killerMob->TrySpellOnKill(killed_level, spell);
|
||||
@ -2376,10 +2375,15 @@ void NPC::Damage(Mob* other, int64 damage, uint16 spell_id, EQ::skills::SkillTyp
|
||||
|
||||
bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillType attack_skill)
|
||||
{
|
||||
LogCombat("Fatal blow dealt by [{}] with [{}] damage, spell [{}], skill [{}]",
|
||||
((killer_mob) ? (killer_mob->GetName()) : ("[nullptr]")), damage, spell, attack_skill);
|
||||
LogCombat(
|
||||
"Fatal blow dealt by [{}] with [{}] damage, spell [{}], skill [{}]",
|
||||
(killer_mob ? killer_mob->GetName() : "[nullptr]"),
|
||||
damage,
|
||||
spell,
|
||||
attack_skill
|
||||
);
|
||||
|
||||
Mob *oos = killer_mob ? killer_mob->GetOwnerOrSelf() : nullptr;
|
||||
Mob* owner_or_self = killer_mob ? killer_mob->GetOwnerOrSelf() : nullptr;
|
||||
|
||||
if (IsNPC()) {
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH)) {
|
||||
@ -2391,7 +2395,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
static_cast<int>(attack_skill)
|
||||
);
|
||||
|
||||
if (parse->EventNPC(EVENT_DEATH, this, oos, export_string, 0) != 0) {
|
||||
if (parse->EventNPC(EVENT_DEATH, this, owner_or_self, export_string, 0) != 0) {
|
||||
if (GetHP() < 0) {
|
||||
SetHP(0);
|
||||
}
|
||||
@ -2408,7 +2412,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
spell,
|
||||
static_cast<int>(attack_skill)
|
||||
);
|
||||
if (parse->EventBot(EVENT_DEATH, CastToBot(), oos, export_string, 0) != 0) {
|
||||
if (parse->EventBot(EVENT_DEATH, CastToBot(), owner_or_self, export_string, 0) != 0) {
|
||||
if (GetHP() < 0) {
|
||||
SetHP(0);
|
||||
}
|
||||
@ -2435,7 +2439,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
if (IsEngaged()) {
|
||||
zone->DelAggroMob();
|
||||
Log(Logs::Detail, Logs::Attack, "%s Mobs currently Aggro %i", __FUNCTION__, zone->MobsAggroCount());
|
||||
LogAttackDetail("{} Mob{} currently aggroed.", zone->MobsAggroCount(), zone->MobsAggroCount() != 1 ? "s" : "");
|
||||
}
|
||||
|
||||
ShieldAbilityClearVariables();
|
||||
@ -2444,45 +2448,52 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
SetPet(0);
|
||||
|
||||
if (GetSwarmOwner()) {
|
||||
auto* owner = entity_list.GetMobID(GetSwarmOwner());
|
||||
Mob* owner = entity_list.GetMobID(GetSwarmOwner());
|
||||
if (owner) {
|
||||
owner->SetTempPetCount(owner->GetTempPetCount() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
auto* killer = GetHateDamageTop(this);
|
||||
|
||||
entity_list.RemoveFromTargets(this, p_depop);
|
||||
|
||||
if (p_depop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto illusion_spell_id = spellbonuses.Illusion;
|
||||
const int illusion_spell_id = spellbonuses.Illusion;
|
||||
|
||||
HasAISpellEffects = false;
|
||||
|
||||
BuffFadeAll();
|
||||
const auto killed_level = GetLevel();
|
||||
|
||||
const uint8 killed_level = GetLevel();
|
||||
|
||||
if (GetClass() == Class::LDoNTreasure) { // open chest
|
||||
auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct));
|
||||
Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer;
|
||||
anim->spawnid = GetID();
|
||||
anim->action = 0x0F;
|
||||
anim->speed = 10;
|
||||
|
||||
auto a = (Animation_Struct*) outapp->pBuffer;
|
||||
|
||||
a->spawnid = GetID();
|
||||
a->action = 0x0F;
|
||||
a->speed = 10;
|
||||
|
||||
entity_list.QueueCloseClients(this, outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
auto app = new EQApplicationPacket(OP_Death, sizeof(Death_Struct));
|
||||
auto* d = (Death_Struct*) app->pBuffer;
|
||||
d->spawn_id = GetID();
|
||||
d->killer_id = killer_mob ? killer_mob->GetID() : 0;
|
||||
d->bindzoneid = 0;
|
||||
d->spell_id = 0xffffffff; // Sending spell was causing extra DoT land msg
|
||||
|
||||
auto d = (Death_Struct*) app->pBuffer;
|
||||
|
||||
d->spawn_id = GetID();
|
||||
d->killer_id = killer_mob ? killer_mob->GetID() : 0;
|
||||
d->bindzoneid = 0;
|
||||
d->spell_id = UINT32_MAX;
|
||||
d->attack_skill = SkillDamageTypes[attack_skill];
|
||||
d->damage = damage;
|
||||
d->damage = damage;
|
||||
|
||||
app->priority = 6;
|
||||
|
||||
entity_list.QueueClients(killer_mob, app, false);
|
||||
|
||||
safe_delete(app);
|
||||
@ -2495,24 +2506,37 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
hate_list.AddEntToHateList(killer_mob, damage);
|
||||
}
|
||||
|
||||
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
|
||||
Mob* give_exp = hate_list.GetDamageTopOnHateList(this);
|
||||
|
||||
if (give_exp) {
|
||||
give_exp = killer;
|
||||
give_exp = killer_mob;
|
||||
}
|
||||
|
||||
if (give_exp && give_exp->HasOwner()) {
|
||||
bool ownerInGroup = false;
|
||||
if ((give_exp->HasGroup() && give_exp->GetGroup()->IsGroupMember(give_exp->GetUltimateOwner()))
|
||||
|| (give_exp->IsPet() && (give_exp->GetOwner()->IsClient()
|
||||
|| (give_exp->GetOwner()->HasGroup() && give_exp->GetOwner()->GetGroup()->IsGroupMember(give_exp->GetOwner()->GetUltimateOwner()))))
|
||||
) {
|
||||
ownerInGroup = true;
|
||||
bool owner_in_group = false;
|
||||
|
||||
if (
|
||||
(
|
||||
give_exp->HasGroup() &&
|
||||
give_exp->GetGroup()->IsGroupMember(give_exp->GetUltimateOwner())
|
||||
) ||
|
||||
(
|
||||
give_exp->IsPet() &&
|
||||
(
|
||||
give_exp->GetOwner()->IsClient() ||
|
||||
(
|
||||
give_exp->GetOwner()->HasGroup() &&
|
||||
give_exp->GetOwner()->GetGroup()->IsGroupMember(give_exp->GetOwner()->GetUltimateOwner())
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
owner_in_group = true;
|
||||
}
|
||||
|
||||
give_exp = give_exp->GetUltimateOwner();
|
||||
|
||||
if (!RuleB(Bots, BotGroupXP) && !ownerInGroup) {
|
||||
if (!RuleB(Bots, BotGroupXP) && !owner_in_group) {
|
||||
give_exp = nullptr;
|
||||
}
|
||||
}
|
||||
@ -2526,9 +2550,9 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
}
|
||||
}
|
||||
|
||||
int PlayerCount = 0; // QueryServ Player Counting
|
||||
int player_count = 0; // QueryServ Player Counting
|
||||
|
||||
Client *give_exp_client = nullptr;
|
||||
Client* give_exp_client = nullptr;
|
||||
if (give_exp && give_exp->IsClient()) {
|
||||
give_exp_client = give_exp->CastToClient();
|
||||
}
|
||||
@ -2538,13 +2562,13 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
hate_list.DoFactionHits(GetNPCFactionID(), GetPrimaryFaction(), GetFactionAmount());
|
||||
}
|
||||
|
||||
bool IsLdonTreasure = (GetClass() == Class::LDoNTreasure);
|
||||
const bool is_ldon_treasure = GetClass() == Class::LDoNTreasure;
|
||||
|
||||
if (give_exp_client && !IsCorpse()) {
|
||||
Group *kg = entity_list.GetGroupByClient(give_exp_client);
|
||||
Raid *kr = entity_list.GetRaidByClient(give_exp_client);
|
||||
Group* killer_group = entity_list.GetGroupByClient(give_exp_client);
|
||||
Raid* killer_raid = entity_list.GetRaidByClient(give_exp_client);
|
||||
|
||||
int64 finalxp = give_exp_client->GetExperienceForKill(this);
|
||||
int64 final_exp = give_exp_client->GetExperienceForKill(this);
|
||||
|
||||
// handle task credit on behalf of the killer
|
||||
if (RuleB(TaskSystem, EnableTaskSystem)) {
|
||||
@ -2556,75 +2580,98 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
task_manager->HandleUpdateTasksOnKill(give_exp_client, this);
|
||||
}
|
||||
|
||||
if (kr) {
|
||||
if (!IsLdonTreasure && MerchantType == 0) {
|
||||
kr->SplitExp((finalxp), this);
|
||||
if (killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName())))
|
||||
if (killer_raid) {
|
||||
if (!is_ldon_treasure && MerchantType == 0) {
|
||||
killer_raid->SplitExp(final_exp, this);
|
||||
|
||||
if (
|
||||
killer_mob &&
|
||||
(
|
||||
killer_raid->IsRaidMember(killer_mob->GetName()) ||
|
||||
killer_raid->IsRaidMember(killer_mob->GetUltimateOwner()->GetName())
|
||||
)
|
||||
) {
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the EVENT_KILLED_MERIT event for all raid members */
|
||||
for (const auto& m : kr->members) {
|
||||
for (const auto& m : killer_raid->members) {
|
||||
if (m.is_bot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.member && m.member->IsClient()) { // If Group Member is Client
|
||||
Client *c = m.member;
|
||||
if (m.member) {
|
||||
m.member->RecordKilledNPCEvent(this);
|
||||
|
||||
c->RecordKilledNPCEvent(this);
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, c, "killed", 0);
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, m.member, "killed", 0);
|
||||
}
|
||||
|
||||
if (RuleB(NPC, EnableMeritBasedFaction)) {
|
||||
c->SetFactionLevel(c->CharacterID(), GetNPCFactionID(), c->GetBaseClass(), c->GetBaseRace(), c->GetDeity());
|
||||
m.member->SetFactionLevel(
|
||||
m.member->CharacterID(),
|
||||
GetNPCFactionID(),
|
||||
m.member->GetBaseClass(),
|
||||
m.member->GetBaseRace(),
|
||||
m.member->GetDeity()
|
||||
);
|
||||
}
|
||||
|
||||
PlayerCount++;
|
||||
player_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// QueryServ Logging - Raid Kills
|
||||
if (RuleB(QueryServ, PlayerLogNPCKills)) {
|
||||
auto pack =
|
||||
new ServerPacket(ServerOP_QSPlayerLogNPCKills,
|
||||
sizeof(QSPlayerLogNPCKill_Struct) +
|
||||
(sizeof(QSPlayerLogNPCKillsPlayers_Struct) * PlayerCount));
|
||||
PlayerCount = 0;
|
||||
QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer;
|
||||
QS->s1.NPCID = GetNPCTypeID();
|
||||
auto pack = new ServerPacket(
|
||||
ServerOP_QSPlayerLogNPCKills,
|
||||
sizeof(QSPlayerLogNPCKill_Struct) +
|
||||
(sizeof(QSPlayerLogNPCKillsPlayers_Struct) * player_count)
|
||||
);
|
||||
|
||||
player_count = 0;
|
||||
|
||||
auto QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer;
|
||||
|
||||
QS->s1.NPCID = GetNPCTypeID();
|
||||
QS->s1.ZoneID = GetZoneID();
|
||||
QS->s1.Type = 2; // Raid Fight
|
||||
for (const auto& m : kr->members) {
|
||||
QS->s1.Type = 2; // Raid Fight
|
||||
|
||||
for (const auto& m : killer_raid->members) {
|
||||
if (m.is_bot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m.member && m.member->IsClient()) { // If Group Member is Client
|
||||
Client *c = m.member;
|
||||
QS->Chars[PlayerCount].char_id = c->CharacterID();
|
||||
PlayerCount++;
|
||||
if (m.member && m.member->IsClient()) {
|
||||
QS->Chars[player_count].char_id = m.member->CastToClient()->CharacterID();
|
||||
player_count++;
|
||||
}
|
||||
}
|
||||
worldserver.SendPacket(pack); // Send Packet to World
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
// End QueryServ Logging
|
||||
} else if (give_exp_client->IsGrouped() && killer_group) {
|
||||
if (!is_ldon_treasure && MerchantType == 0) {
|
||||
killer_group->SplitExp(final_exp, this);
|
||||
|
||||
}
|
||||
else if (give_exp_client->IsGrouped() && kg != nullptr) {
|
||||
if (!IsLdonTreasure && MerchantType == 0) {
|
||||
kg->SplitExp((finalxp), this);
|
||||
if (killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName())))
|
||||
if (
|
||||
killer_mob &&
|
||||
(
|
||||
killer_group->IsGroupMember(killer_mob->GetName()) ||
|
||||
killer_group->IsGroupMember(killer_mob->GetUltimateOwner()->GetName())
|
||||
)
|
||||
) {
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the EVENT_KILLED_MERIT event and update kill tasks
|
||||
* for all group members */
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (kg->members[i] != nullptr && kg->members[i]->IsClient()) { // If Group Member is Client
|
||||
Client *c = kg->members[i]->CastToClient();
|
||||
for (const auto& m : killer_group->members) {
|
||||
if (m && m->IsClient()) {
|
||||
Client* c = m->CastToClient();
|
||||
|
||||
c->RecordKilledNPCEvent(this);
|
||||
|
||||
@ -2632,70 +2679,101 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, c, "killed", 0);
|
||||
}
|
||||
|
||||
if (RuleB(NPC, EnableMeritBasedFaction))
|
||||
c->SetFactionLevel(c->CharacterID(), GetNPCFactionID(), c->GetBaseClass(), c->GetBaseRace(), c->GetDeity());
|
||||
if (RuleB(NPC, EnableMeritBasedFaction)) {
|
||||
c->SetFactionLevel(
|
||||
c->CharacterID(),
|
||||
GetNPCFactionID(),
|
||||
c->GetBaseClass(),
|
||||
c->GetBaseRace(),
|
||||
c->GetDeity()
|
||||
);
|
||||
}
|
||||
|
||||
PlayerCount++;
|
||||
player_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// QueryServ Logging - Group Kills
|
||||
if (RuleB(QueryServ, PlayerLogNPCKills)) {
|
||||
auto pack =
|
||||
new ServerPacket(ServerOP_QSPlayerLogNPCKills,
|
||||
sizeof(QSPlayerLogNPCKill_Struct) +
|
||||
(sizeof(QSPlayerLogNPCKillsPlayers_Struct) * PlayerCount));
|
||||
PlayerCount = 0;
|
||||
QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer;
|
||||
QS->s1.NPCID = GetNPCTypeID();
|
||||
auto pack = new ServerPacket(
|
||||
ServerOP_QSPlayerLogNPCKills,
|
||||
sizeof(QSPlayerLogNPCKill_Struct) +
|
||||
(sizeof(QSPlayerLogNPCKillsPlayers_Struct) * player_count)
|
||||
);
|
||||
|
||||
player_count = 0;
|
||||
|
||||
auto QS = (QSPlayerLogNPCKill_Struct*) pack->pBuffer;
|
||||
|
||||
QS->s1.NPCID = GetNPCTypeID();
|
||||
QS->s1.ZoneID = GetZoneID();
|
||||
QS->s1.Type = 1; // Group Fight
|
||||
for (int i = 0; i < MAX_GROUP_MEMBERS; i++) {
|
||||
if (kg->members[i] != nullptr && kg->members[i]->IsClient()) { // If Group Member is Client
|
||||
Client *c = kg->members[i]->CastToClient();
|
||||
QS->Chars[PlayerCount].char_id = c->CharacterID();
|
||||
PlayerCount++;
|
||||
QS->s1.Type = 1; // Group Fight
|
||||
|
||||
for (const auto& m : killer_group->members) {
|
||||
if (m && m->IsClient()) {
|
||||
QS->Chars[player_count].char_id = m->CastToClient()->CharacterID();
|
||||
player_count++;
|
||||
}
|
||||
}
|
||||
worldserver.SendPacket(pack); // Send Packet to World
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
// End QueryServ Logging
|
||||
}
|
||||
else {
|
||||
if (!IsLdonTreasure && MerchantType == 0) {
|
||||
int conlevel = give_exp->GetLevelCon(GetLevel());
|
||||
if (conlevel != CON_GRAY) {
|
||||
} else {
|
||||
if (!is_ldon_treasure && !MerchantType) {
|
||||
const uint32 con_level = give_exp->GetLevelCon(GetLevel());
|
||||
|
||||
if (con_level != CON_GRAY) {
|
||||
if (!GetOwner() || (GetOwner() && !GetOwner()->IsClient())) {
|
||||
give_exp_client->AddEXP((finalxp), conlevel);
|
||||
if (killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID()))
|
||||
give_exp_client->AddEXP(final_exp, con_level);
|
||||
|
||||
if (
|
||||
killer_mob &&
|
||||
(
|
||||
killer_mob->GetID() == give_exp_client->GetID() ||
|
||||
killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID()
|
||||
)
|
||||
) {
|
||||
killer_mob->TrySpellOnKill(killed_level, spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the EVENT_KILLED_MERIT event */
|
||||
give_exp_client->RecordKilledNPCEvent(this);
|
||||
|
||||
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
|
||||
parse->EventNPC(EVENT_KILLED_MERIT, this, give_exp_client, "killed", 0);
|
||||
}
|
||||
|
||||
if (RuleB(NPC, EnableMeritBasedFaction))
|
||||
give_exp_client->SetFactionLevel(give_exp_client->CharacterID(), GetNPCFactionID(), give_exp_client->GetBaseClass(),
|
||||
give_exp_client->GetBaseRace(), give_exp_client->GetDeity());
|
||||
if (RuleB(NPC, EnableMeritBasedFaction)) {
|
||||
give_exp_client->SetFactionLevel(
|
||||
give_exp_client->CharacterID(),
|
||||
GetNPCFactionID(),
|
||||
give_exp_client->GetBaseClass(),
|
||||
give_exp_client->GetBaseRace(),
|
||||
give_exp_client->GetDeity()
|
||||
);
|
||||
}
|
||||
|
||||
// QueryServ Logging - Solo
|
||||
if (RuleB(QueryServ, PlayerLogNPCKills)) {
|
||||
auto pack = new ServerPacket(ServerOP_QSPlayerLogNPCKills,
|
||||
auto pack = new ServerPacket(
|
||||
ServerOP_QSPlayerLogNPCKills,
|
||||
sizeof(QSPlayerLogNPCKill_Struct) +
|
||||
(sizeof(QSPlayerLogNPCKillsPlayers_Struct) * 1));
|
||||
QSPlayerLogNPCKill_Struct* QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer;
|
||||
QS->s1.NPCID = GetNPCTypeID();
|
||||
QS->s1.ZoneID = GetZoneID();
|
||||
QS->s1.Type = 0; // Solo Fight
|
||||
Client *c = give_exp_client;
|
||||
QS->Chars[0].char_id = c->CharacterID();
|
||||
PlayerCount++;
|
||||
(sizeof(QSPlayerLogNPCKillsPlayers_Struct) * 1)
|
||||
);
|
||||
|
||||
auto QS = (QSPlayerLogNPCKill_Struct*)pack->pBuffer;
|
||||
|
||||
QS->s1.NPCID = GetNPCTypeID();
|
||||
QS->s1.ZoneID = GetZoneID();
|
||||
QS->s1.Type = 0; // Solo Fight
|
||||
QS->Chars[0].char_id = give_exp_client->CharacterID();
|
||||
|
||||
player_count++;
|
||||
|
||||
worldserver.SendPacket(pack); // Send Packet to World
|
||||
safe_delete(pack);
|
||||
}
|
||||
@ -2703,32 +2781,68 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
}
|
||||
}
|
||||
|
||||
bool allow_merchant_corpse = RuleB(Merchant, AllowCorpse);
|
||||
bool is_merchant = (class_ == Class::Merchant || class_ == Class::AdventureMerchant || MerchantType != 0);
|
||||
const bool allow_merchant_corpse = RuleB(Merchant, AllowCorpse);
|
||||
const bool is_merchant = (class_ == Class::Merchant || class_ == Class::AdventureMerchant || MerchantType != 0);
|
||||
|
||||
Corpse* corpse = nullptr;
|
||||
|
||||
const uint16 entity_id = GetID();
|
||||
|
||||
if (!HasOwner() && !IsMerc() && !GetSwarmInfo() && (!is_merchant || allow_merchant_corpse) &&
|
||||
((killer && (killer->IsClient() || (killer->HasOwner() && killer->GetUltimateOwner()->IsClient()) ||
|
||||
(killer->IsNPC() && killer->CastToNPC()->GetSwarmInfo() && killer->CastToNPC()->GetSwarmInfo()->GetOwner() && killer->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient())))
|
||||
|| (killer_mob && IsLdonTreasure)))
|
||||
{
|
||||
if (killer != 0) {
|
||||
if (killer->GetOwner() != 0 && killer->GetOwner()->IsClient())
|
||||
killer = killer->GetOwner();
|
||||
if (
|
||||
!HasOwner() &&
|
||||
!IsMerc() &&
|
||||
!GetSwarmInfo() &&
|
||||
(!is_merchant || allow_merchant_corpse) &&
|
||||
(
|
||||
(
|
||||
killer_mob &&
|
||||
(
|
||||
killer_mob->IsClient() ||
|
||||
(
|
||||
killer_mob->HasOwner() &&
|
||||
killer_mob->GetUltimateOwner()->IsClient()
|
||||
) ||
|
||||
(
|
||||
killer_mob->IsNPC() &&
|
||||
killer_mob->CastToNPC()->GetSwarmInfo() &&
|
||||
killer_mob->CastToNPC()->GetSwarmInfo()->GetOwner() &&
|
||||
killer_mob->CastToNPC()->GetSwarmInfo()->GetOwner()->IsClient()
|
||||
)
|
||||
)
|
||||
) ||
|
||||
(
|
||||
killer_mob && is_ldon_treasure
|
||||
)
|
||||
)
|
||||
) {
|
||||
if (killer_mob) {
|
||||
if (killer_mob->GetOwner() != 0 && killer_mob->GetOwner()->IsClient()) {
|
||||
killer_mob = killer_mob->GetOwner();
|
||||
}
|
||||
|
||||
if (killer->IsClient() && !killer->CastToClient()->GetGM())
|
||||
CheckTrivialMinMaxLevelDrop(killer);
|
||||
if (killer_mob->IsClient() && !killer_mob->CastToClient()->GetGM()) {
|
||||
CheckTrivialMinMaxLevelDrop(killer_mob);
|
||||
}
|
||||
}
|
||||
|
||||
entity_list.RemoveFromAutoXTargets(this);
|
||||
|
||||
const uint32 emote_id = GetEmoteID();
|
||||
corpse = new Corpse(this, &itemlist, GetNPCTypeID(), &NPCTypedata,
|
||||
level > 54 ? RuleI(NPC, MajorNPCCorpseDecayTimeMS)
|
||||
: RuleI(NPC, MinorNPCCorpseDecayTimeMS));
|
||||
corpse = new Corpse(
|
||||
this,
|
||||
&itemlist,
|
||||
GetNPCTypeID(),
|
||||
&NPCTypedata,
|
||||
(
|
||||
level > 54 ?
|
||||
RuleI(NPC, MajorNPCCorpseDecayTimeMS) :
|
||||
RuleI(NPC, MinorNPCCorpseDecayTimeMS)
|
||||
)
|
||||
);
|
||||
|
||||
if (killer_mob && emoteid) {
|
||||
DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emoteid, killer_mob);
|
||||
}
|
||||
|
||||
entity_list.LimitRemoveNPC(this);
|
||||
entity_list.AddCorpse(corpse, GetID());
|
||||
|
||||
@ -2740,25 +2854,27 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
SetID(0);
|
||||
ApplyIllusionToCorpse(illusion_spell_id, corpse);
|
||||
|
||||
if (killer != 0 && emote_id)
|
||||
corpse->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::AfterDeath, emote_id, killer);
|
||||
if (killer != 0 && killer->IsClient()) {
|
||||
corpse->AllowPlayerLoot(killer, 0);
|
||||
if (killer->IsGrouped()) {
|
||||
Group* group = entity_list.GetGroupByClient(killer->CastToClient());
|
||||
if (group != 0) {
|
||||
for (int i = 0; i<6; i++) { // Doesnt work right, needs work
|
||||
if (group->members[i] != nullptr) {
|
||||
corpse->AllowPlayerLoot(group->members[i], i);
|
||||
if (killer_mob && killer_mob->IsClient()) {
|
||||
corpse->AllowPlayerLoot(killer_mob, 0);
|
||||
if (killer_mob->IsGrouped()) {
|
||||
Group* g = entity_list.GetGroupByClient(killer_mob->CastToClient());
|
||||
if (g) {
|
||||
uint8 slot_id = 0;
|
||||
|
||||
for (const auto &m : g->members) {
|
||||
if (m) {
|
||||
corpse->AllowPlayerLoot(m, slot_id);
|
||||
}
|
||||
|
||||
slot_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (killer->IsRaidGrouped()) {
|
||||
Raid* r = entity_list.GetRaidByClient(killer->CastToClient());
|
||||
} else if (killer_mob->IsRaidGrouped()) {
|
||||
Raid* r = entity_list.GetRaidByClient(killer_mob->CastToClient());
|
||||
if (r) {
|
||||
int i = 0;
|
||||
for (const auto& m : r->members) {
|
||||
uint8 slot_id = 0;
|
||||
|
||||
for (const auto &m : r->members) {
|
||||
if (m.is_bot) {
|
||||
continue;
|
||||
}
|
||||
@ -2766,77 +2882,71 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
switch (r->GetLootType()) {
|
||||
case RaidLootType::LeaderOnly:
|
||||
if (m.member && m.is_raid_leader) {
|
||||
corpse->AllowPlayerLoot(m.member, i);
|
||||
i++;
|
||||
corpse->AllowPlayerLoot(m.member, slot_id);
|
||||
slot_id++;
|
||||
}
|
||||
break;
|
||||
case RaidLootType::LeaderAndGroupLeadersOnly:
|
||||
if (m.member && (m.is_raid_leader || m.is_group_leader)) {
|
||||
corpse->AllowPlayerLoot(m.member, i);
|
||||
i++;
|
||||
corpse->AllowPlayerLoot(m.member, slot_id);
|
||||
slot_id++;
|
||||
}
|
||||
break;
|
||||
case RaidLootType::LeaderSelected:
|
||||
if (m.member && m.is_looter) {
|
||||
corpse->AllowPlayerLoot(m.member, i);
|
||||
i++;
|
||||
corpse->AllowPlayerLoot(m.member, slot_id);
|
||||
slot_id++;
|
||||
}
|
||||
break;
|
||||
case RaidLootType::EntireRaid:
|
||||
default:
|
||||
if (m.member) {
|
||||
corpse->AllowPlayerLoot(m.member, i);
|
||||
i++;
|
||||
corpse->AllowPlayerLoot(m.member, slot_id);
|
||||
slot_id++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (killer_mob && IsLdonTreasure) {
|
||||
auto u_owner = killer_mob->GetUltimateOwner();
|
||||
if (u_owner->IsClient())
|
||||
corpse->AllowPlayerLoot(u_owner, 0);
|
||||
} else if (killer_mob && is_ldon_treasure) {
|
||||
Mob* ultimate_owner = killer_mob->GetUltimateOwner();
|
||||
if (ultimate_owner->IsClient()) {
|
||||
corpse->AllowPlayerLoot(ultimate_owner, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (zone && zone->adv_data) {
|
||||
ServerZoneAdventureDataReply_Struct *sr = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
|
||||
auto sr = (ServerZoneAdventureDataReply_Struct *) zone->adv_data;
|
||||
if (sr->type == Adventure_Kill) {
|
||||
zone->DoAdventureCountIncrease();
|
||||
}
|
||||
else if (sr->type == Adventure_Assassinate) {
|
||||
} else if (sr->type == Adventure_Assassinate) {
|
||||
if (sr->data_id == GetNPCTypeID()) {
|
||||
zone->DoAdventureCountIncrease();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
zone->DoAdventureAssassinationCountIncrease();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
entity_list.RemoveFromXTargets(this);
|
||||
}
|
||||
|
||||
|
||||
// Parse quests even if we're killed by an NPC
|
||||
if (oos) {
|
||||
if (IsNPC()) {
|
||||
const uint32 emote_id = GetEmoteID();
|
||||
if (emote_id) {
|
||||
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emote_id, killer_mob);
|
||||
}
|
||||
if (IsNPC()) {
|
||||
if (emoteid) {
|
||||
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDeath, emoteid, killer_mob);
|
||||
}
|
||||
}
|
||||
|
||||
if (oos->IsNPC()) {
|
||||
if (parse->HasQuestSub(oos->GetNPCTypeID(), EVENT_NPC_SLAY)) {
|
||||
parse->EventNPC(EVENT_NPC_SLAY, oos->CastToNPC(), this, "", 0);
|
||||
if (owner_or_self) {
|
||||
if (owner_or_self->IsNPC()) {
|
||||
if (parse->HasQuestSub(owner_or_self->GetNPCTypeID(), EVENT_NPC_SLAY)) {
|
||||
parse->EventNPC(EVENT_NPC_SLAY, owner_or_self->CastToNPC(), this, "", 0);
|
||||
}
|
||||
|
||||
const uint32 emote_id = oos->GetEmoteID();
|
||||
const uint32 emote_id = owner_or_self->GetEmoteID();
|
||||
if (emote_id) {
|
||||
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
|
||||
owner_or_self->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id, this);
|
||||
}
|
||||
|
||||
if (killer_mob) {
|
||||
@ -2854,10 +2964,12 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
}
|
||||
|
||||
WipeHateList();
|
||||
|
||||
p_depop = true;
|
||||
|
||||
if (killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted
|
||||
killer_mob->SetTarget(nullptr); //via AE effects and such..
|
||||
if (killer_mob && killer_mob->GetTarget() == this) { // We can kill things without having them targeted
|
||||
killer_mob->SetTarget(nullptr);
|
||||
}
|
||||
|
||||
entity_list.UpdateFindableNPCState(this, true);
|
||||
|
||||
@ -2875,7 +2987,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
std::vector<std::any> args = { corpse };
|
||||
|
||||
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0, &args);
|
||||
parse->EventNPC(EVENT_DEATH_COMPLETE, this, owner_or_self, export_string, 0, &args);
|
||||
}
|
||||
|
||||
// Zone controller process EVENT_DEATH_ZONE (Death events)
|
||||
@ -2891,7 +3003,7 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
|
||||
|
||||
std::vector<std::any> args = { corpse, this };
|
||||
|
||||
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
|
||||
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, owner_or_self, export_string, 0, &args);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -1800,9 +1800,8 @@ void Mob::AI_Event_Engaged(Mob *attacker, bool yell_for_help)
|
||||
parse->EventNPC(EVENT_COMBAT, CastToNPC(), attacker, "1", 0);
|
||||
}
|
||||
|
||||
const uint32 emote_id = GetEmoteID();
|
||||
if (emote_id) {
|
||||
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emote_id, attacker);
|
||||
if (emoteid) {
|
||||
CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::EnterCombat, emoteid, attacker);
|
||||
}
|
||||
|
||||
std::string mob_name = GetCleanName();
|
||||
|
||||
15
zone/npc.cpp
15
zone/npc.cpp
@ -438,7 +438,7 @@ NPC::NPC(const NPCType *npc_type_data, Spawn2 *in_respawn, const glm::vec4 &posi
|
||||
|
||||
qGlobals = nullptr;
|
||||
|
||||
SetEmoteID(static_cast<uint32>(npc_type_data->emoteid));
|
||||
SetEmoteID(npc_type_data->emoteid);
|
||||
InitializeBuffSlots();
|
||||
CalcBonuses();
|
||||
|
||||
@ -1113,9 +1113,8 @@ void NPC::UpdateEquipmentLight()
|
||||
}
|
||||
|
||||
void NPC::Depop(bool start_spawn_timer) {
|
||||
const uint32 emote_id = GetEmoteID();
|
||||
if (emote_id) {
|
||||
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn, emote_id);
|
||||
if (emoteid) {
|
||||
DoNPCEmote(EQ::constants::EmoteEventTypes::OnDespawn, emoteid);
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
@ -3073,10 +3072,8 @@ void NPC::SendPayload(int payload_id, std::string payload_value)
|
||||
NPC_Emote_Struct* NPC::GetNPCEmote(uint32 emote_id, uint8 event_) {
|
||||
std::vector<NPC_Emote_Struct*> emotes;
|
||||
|
||||
for (const auto &e : zone->npc_emote_list) {
|
||||
auto nes = e;
|
||||
|
||||
if (nes->emoteid == emote_id && nes->event_ == event_) {
|
||||
for (auto& e : zone->npc_emote_list) {
|
||||
if (e->emoteid == emote_id && e->event_ == event_) {
|
||||
emotes.emplace_back(e);
|
||||
}
|
||||
}
|
||||
@ -3098,7 +3095,7 @@ void NPC::DoNPCEmote(uint8 event_, uint32 emote_id, Mob* t)
|
||||
return;
|
||||
}
|
||||
|
||||
auto e = GetNPCEmote(emote_id, event_);
|
||||
const auto& e = GetNPCEmote(emote_id, event_);
|
||||
if (!e) {
|
||||
return;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user