[Bug Fix] Fix EVENT_KILLED_MERIT firing before NPC removal (#4185)

* [Bug Fix] Fix EVENT_KILLED_MERIT firing before NPC removal

# Notes
- NPCs were parsing this event too early and anything that checked if they were still alive in `EVENT_KILLED_MERIT` would show them still alive because of this.

# Image

* Code cleanup

* Update client.h

* Add GetRaidOrGroupOrSelf() to Perl/Lua

* Update to luabind::object, fix logic per comments.

* Fix

* Fix per comments.
This commit is contained in:
Alex King 2024-03-17 17:32:44 -04:00 committed by GitHub
parent e5bdbc4f1e
commit ee12a7ad2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 114 additions and 22 deletions

View File

@ -2618,12 +2618,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
}
if (m.member) {
m.member->RecordKilledNPCEvent(this);
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
parse->EventNPC(EVENT_KILLED_MERIT, this, m.member, "killed", 0);
}
if (RuleB(NPC, EnableMeritBasedFaction)) {
m.member->SetFactionLevel(
m.member->CharacterID(),
@ -2683,18 +2677,11 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
}
}
/* Send the EVENT_KILLED_MERIT event and update kill tasks
* for all group members */
/* Update kill tasks for all group members */
for (const auto& m : killer_group->members) {
if (m && m->IsClient()) {
Client* c = m->CastToClient();
c->RecordKilledNPCEvent(this);
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
parse->EventNPC(EVENT_KILLED_MERIT, this, c, "killed", 0);
}
if (RuleB(NPC, EnableMeritBasedFaction)) {
c->SetFactionLevel(
c->CharacterID(),
@ -2756,13 +2743,6 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
}
}
/* 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(),
@ -2991,6 +2971,17 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
m_combat_record.Stop();
if (give_exp_client && !IsCorpse()) {
const auto& v = give_exp_client->GetRaidOrGroupOrSelf(true);
for (const auto& m : v) {
m->CastToClient()->RecordKilledNPCEvent(this);
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_KILLED_MERIT)) {
parse->EventNPC(EVENT_KILLED_MERIT, this, m, "killed", 0);
}
}
}
if (parse->HasQuestSub(GetNPCTypeID(), EVENT_DEATH_COMPLETE)) {
const auto& export_string = fmt::format(
"{} {} {} {} {} {} {} {} {}",

View File

@ -12320,3 +12320,34 @@ int Client::GetEXPPercentage()
return static_cast<int>(std::round(scaled * 100.0 / 330.0)); // unscaled pct
}
std::vector<Mob*> Client::GetRaidOrGroupOrSelf(bool clients_only)
{
std::vector<Mob*> v;
if (IsRaidGrouped()) {
Raid* r = GetRaid();
if (r) {
for (const auto& m : r->members) {
if (m.member && (!m.is_bot || !clients_only)) {
v.emplace_back(m.member);
}
}
}
} else if (IsGrouped()) {
Group* g = GetGroup();
if (g) {
for (const auto& m : g->members) {
if (m && (m->IsClient() || !clients_only)) {
v.emplace_back(m);
}
}
}
} else {
v.emplace_back(this);
}
return v;
}

View File

@ -272,6 +272,8 @@ public:
int GetQuiverHaste(int delay);
void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false);
std::vector<Mob*> GetRaidOrGroupOrSelf(bool clients_only = false);
void AI_Init();
void AI_Start(uint32 iMoveDelay = 0);
void AI_Stop();

View File

@ -3308,6 +3308,38 @@ bool Lua_Client::RemoveAlternateCurrencyValue(uint32 currency_id, uint32 amount)
return self->RemoveAlternateCurrencyValue(currency_id, amount);
}
luabind::object Lua_Client::GetRaidOrGroupOrSelf(lua_State* L)
{
auto t = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
auto l = self->GetRaidOrGroupOrSelf();
int i = 1;
for (const auto& e : l) {
t[i] = Lua_Mob(e);
i++;
}
}
return t;
}
luabind::object Lua_Client::GetRaidOrGroupOrSelf(lua_State* L, bool clients_only)
{
auto t = luabind::newtable(L);
if (d_) {
auto self = reinterpret_cast<NativeType*>(d_);
auto l = self->GetRaidOrGroupOrSelf(clients_only);
int i = 1;
for (const auto& e : l) {
t[i] = Lua_Mob(e);
i++;
}
}
return t;
}
luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>())
@ -3542,6 +3574,8 @@ luabind::scope lua_register_client() {
.def("GetRaceBitmask", (int(Lua_Client::*)(void))&Lua_Client::GetRaceBitmask)
.def("GetRadiantCrystals", (uint32(Lua_Client::*)(void))&Lua_Client::GetRadiantCrystals)
.def("GetRaid", (Lua_Raid(Lua_Client::*)(void))&Lua_Client::GetRaid)
.def("GetRaidOrGroupOrSelf", (luabind::object(Lua_Client::*)(lua_State*))&Lua_Client::GetRaidOrGroupOrSelf)
.def("GetRaidOrGroupOrSelf", (luabind::object(Lua_Client::*)(lua_State*,bool))&Lua_Client::GetRaidOrGroupOrSelf)
.def("GetRaidPoints", (uint32(Lua_Client::*)(void))&Lua_Client::GetRaidPoints)
.def("GetRaceAbbreviation", (std::string(Lua_Client::*)(void))&Lua_Client::GetRaceAbbreviation)
.def("GetRawItemAC", (int(Lua_Client::*)(void))&Lua_Client::GetRawItemAC)

View File

@ -496,6 +496,8 @@ public:
int GetAAEXPPercentage();
int GetEXPPercentage();
bool IsInAGuild();
luabind::object GetRaidOrGroupOrSelf(lua_State* L);
luabind::object GetRaidOrGroupOrSelf(lua_State* L, bool clients_only);
void ApplySpell(int spell_id);
void ApplySpell(int spell_id, int duration);

View File

@ -3311,7 +3311,7 @@ luabind::object Lua_Mob::GetBuffs(lua_State* L) {
auto l = self->GetBuffs();
int i = 1;
for (int slot_id = 0; slot_id < self->GetMaxBuffSlots(); slot_id++) {
t[i] = l[slot_id];
t[i] = Lua_Buff(&l[slot_id]);
i++;
}
}

View File

@ -3113,6 +3113,36 @@ bool Perl_Client_RemoveAlternateCurrencyValue(Client* self, uint32 currency_id,
return self->RemoveAlternateCurrencyValue(currency_id, amount);
}
perl::array Perl_Client_GetRaidOrGroupOrSelf(Client* self)
{
perl::array result;
const auto& l = self->GetRaidOrGroupOrSelf();
result.reserve(l.size());
for (const auto& e : l) {
result.push_back(e);
}
return result;
}
perl::array Perl_Client_GetRaidOrGroupOrSelf(Client* self, bool clients_only)
{
perl::array result;
const auto& l = self->GetRaidOrGroupOrSelf(clients_only);
result.reserve(l.size());
for (const auto& e : l) {
result.push_back(e);
}
return result;
}
void perl_register_client()
{
perl::interpreter perl(PERL_GET_THX);
@ -3346,6 +3376,8 @@ void perl_register_client()
package.add("GetRaceBitmask", &Perl_Client_GetRaceBitmask);
package.add("GetRadiantCrystals", &Perl_Client_GetRadiantCrystals);
package.add("GetRaid", &Perl_Client_GetRaid);
package.add("GetRaidOrGroupOrSelf", (perl::array(*)(Client*))&Perl_Client_GetRaidOrGroupOrSelf);
package.add("GetRaidOrGroupOrSelf", (perl::array(*)(Client*, bool))&Perl_Client_GetRaidOrGroupOrSelf);
package.add("GetRaidPoints", &Perl_Client_GetRaidPoints);
package.add("GetRawItemAC", &Perl_Client_GetRawItemAC);
package.add("GetRawSkill", &Perl_Client_GetRawSkill);