[Quest API] Add Lua handlers for zone controller events (#2514)

This cleans up some of the NPC::Death event dispatch code.

Adds handlers for EVENT_SPAWN_ZONE and EVENT_DEATH_ZONE used by zone
controller and fixes the death handler exports which were incorrect.
This commit is contained in:
hg 2022-11-05 11:13:39 -04:00 committed by GitHub
parent 070bf64d6a
commit 9c7dd70b5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 93 additions and 97 deletions

View File

@ -2318,52 +2318,37 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
LogCombat("Fatal blow dealt by [{}] with [{}] damage, spell [{}], skill [{}]",
((killer_mob) ? (killer_mob->GetName()) : ("[nullptr]")), damage, spell, attack_skill);
Mob *oos = nullptr;
if (killer_mob) {
oos = killer_mob->GetOwnerOrSelf();
std::string export_string = fmt::format(
"{} {} {} {}",
killer_mob->GetID(),
damage,
spell,
static_cast<int>(attack_skill)
);
if (parse->EventNPC(EVENT_DEATH, this, oos, export_string, 0) != 0) {
if (GetHP() < 0) {
SetHP(0);
}
return false;
}
Mob* oos = killer_mob ? killer_mob->GetOwnerOrSelf() : nullptr;
if ((killer_mob->IsClient() || killer_mob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20] = { 0 };
std::string export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
entity_list.MessageCloseString(
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, DamageMessages),
Chat::NonMelee, /* 283 */
HIT_NON_MELEE, /* %1 hit %2 for %3 points of non-melee damage. */
killer_mob->GetCleanName(), /* Message1 */
GetCleanName(), /* Message2 */
ConvertArray(damage, val1) /* Message3 */
);
// todo: multiple attacks causes this to fire multiple times (DoAttackRounds, DoMain/OffHandAttackRounds, DoRiposte, spells?)
if (parse->EventNPC(EVENT_DEATH, this, oos, export_string, 0) != 0) {
if (GetHP() < 0) {
SetHP(0);
}
return false;
}
else {
std::string export_string = fmt::format(
"{} {} {} {}",
0,
damage,
spell,
static_cast<int>(attack_skill)
if (killer_mob && (killer_mob->IsClient() || killer_mob->IsBot()) && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20] = { 0 };
entity_list.MessageCloseString(
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, DamageMessages),
Chat::NonMelee, /* 283 */
HIT_NON_MELEE, /* %1 hit %2 for %3 points of non-melee damage. */
killer_mob->GetCleanName(), /* Message1 */
GetCleanName(), /* Message2 */
ConvertArray(damage, val1) /* Message3 */
);
if (parse->EventNPC(EVENT_DEATH, this, nullptr, export_string, 0) != 0) {
if (GetHP() < 0) {
SetHP(0);
}
return false;
}
}
if (IsEngaged()) {
@ -2752,35 +2737,12 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
entity_list.UpdateFindableNPCState(this, true);
std::string export_string = fmt::format(
"{} {} {} {}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill)
);
parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, export_string, 0);
combat_record.Stop();
/* Zone controller process EVENT_DEATH_ZONE (Death events) */
if (RuleB(Zone, UseZoneController)) {
auto controller = entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID);
if (controller && GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID) {
export_string = fmt::format(
"{} {} {} {} {} {:.2f} {:.2f} {:.2f} {:.2f}",
killer_mob ? killer_mob->GetID() : 0,
damage,
spell,
static_cast<int>(attack_skill),
GetNPCTypeID(),
GetX(),
GetY(),
GetZ(),
GetHeading()
);
parse->EventNPC(EVENT_DEATH_ZONE, controller, nullptr, export_string, 0);
}
}
std::vector<std::any> args = { this };
DispatchZoneControllerEvent(EVENT_DEATH_ZONE, oos, export_string, 0, &args);
return true;
}

View File

@ -1599,6 +1599,7 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_DEATH_ZONE:
case EVENT_DEATH:
case EVENT_DEATH_COMPLETE: {
Seperator sep(data);
@ -1606,6 +1607,18 @@ void PerlembParser::ExportEventVariables(
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
if (extra_pointers && !extra_pointers->empty())
{
NPC* killed = std::any_cast<NPC*>(extra_pointers->at(0));
if (killed)
{
ExportVar(package_name.c_str(), "killed_npc_id", killed->GetNPCTypeID());
ExportVar(package_name.c_str(), "killed_x", killed->GetX());
ExportVar(package_name.c_str(), "killed_y", killed->GetY());
ExportVar(package_name.c_str(), "killed_z", killed->GetZ());
ExportVar(package_name.c_str(), "killed_h", killed->GetHeading());
}
}
break;
}
case EVENT_DROP_ITEM: {
@ -1617,22 +1630,8 @@ void PerlembParser::ExportEventVariables(
break;
}
case EVENT_SPAWN_ZONE: {
Seperator sep(data);
ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]);
ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]);
break;
}
case EVENT_DEATH_ZONE: {
Seperator sep(data);
ExportVar(package_name.c_str(), "killer_id", sep.arg[0]);
ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]);
ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]);
ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]);
ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]);
ExportVar(package_name.c_str(), "killed_x", sep.arg[5]);
ExportVar(package_name.c_str(), "killed_y", sep.arg[6]);
ExportVar(package_name.c_str(), "killed_z", sep.arg[7]);
ExportVar(package_name.c_str(), "killed_h", sep.arg[8]);
ExportVar(package_name.c_str(), "spawned_entity_id", mob->GetID());
ExportVar(package_name.c_str(), "spawned_npc_id", mob->GetNPCTypeID());
break;
}
case EVENT_USE_SKILL: {

View File

@ -729,17 +729,7 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
entity_list.ScanCloseMobs(npc->close_mobs, npc, true);
/* Zone controller process EVENT_SPAWN_ZONE */
if (RuleB(Zone, UseZoneController)) {
auto controller = entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID);
if (controller && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){
std::string export_string = fmt::format(
"{} {}",
npc->GetID(),
npc->GetNPCTypeID()
);
parse->EventNPC(EVENT_SPAWN_ZONE, controller, nullptr, export_string, 0);
}
}
npc->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, npc, "", 0, nullptr);
/**
* Set whether NPC was spawned in or out of water

View File

@ -194,12 +194,14 @@ LuaParser::LuaParser() {
NPCArgumentDispatch[EVENT_TIMER] = handle_npc_timer;
NPCArgumentDispatch[EVENT_DEATH] = handle_npc_death;
NPCArgumentDispatch[EVENT_DEATH_COMPLETE] = handle_npc_death;
NPCArgumentDispatch[EVENT_DEATH_ZONE] = handle_npc_death;
NPCArgumentDispatch[EVENT_CAST] = handle_npc_cast;
NPCArgumentDispatch[EVENT_CAST_BEGIN] = handle_npc_cast;
NPCArgumentDispatch[EVENT_FEIGN_DEATH] = handle_npc_single_client;
NPCArgumentDispatch[EVENT_ENTER_AREA] = handle_npc_area;
NPCArgumentDispatch[EVENT_LEAVE_AREA] = handle_npc_area;
NPCArgumentDispatch[EVENT_LOOT_ZONE] = handle_npc_loot_zone;
NPCArgumentDispatch[EVENT_SPAWN_ZONE] = handle_npc_spawn_zone;
PlayerArgumentDispatch[EVENT_SAY] = handle_player_say;
PlayerArgumentDispatch[EVENT_ENVIRONMENTAL_DAMAGE] = handle_player_environmental_damage;

View File

@ -189,9 +189,12 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init,
Seperator sep(data.c_str());
lua_pushinteger(L, std::stoi(sep.arg[0]));
lua_setfield(L, -2, "killer_id");
lua_pushinteger(L, std::stoi(sep.arg[1]));
lua_setfield(L, -2, "damage");
int spell_id = std::stoi(sep.arg[1]);
int spell_id = std::stoi(sep.arg[2]);
if(IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
@ -204,8 +207,16 @@ void handle_npc_death(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init,
lua_setfield(L, -2, "spell");
}
lua_pushinteger(L, std::stoi(sep.arg[2]));
lua_pushinteger(L, std::stoi(sep.arg[3]));
lua_setfield(L, -2, "skill_id");
if (extra_pointers && !extra_pointers->empty())
{
Lua_NPC l_npc(std::any_cast<NPC*>(extra_pointers->at(0)));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L);
lua_setfield(L, -2, "killed");
}
}
void handle_npc_cast(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
@ -255,6 +266,14 @@ void handle_npc_loot_zone(QuestInterface *parse, lua_State* L, NPC* npc, Mob *in
lua_setfield(L, -2, "corpse");
}
void handle_npc_spawn_zone(QuestInterface* parse, lua_State* L, NPC* npc, Mob* init, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers) {
Lua_NPC l_npc(std::any_cast<NPC*>(init->CastToNPC()));
luabind::adl::object l_npc_o = luabind::adl::object(L, l_npc);
l_npc_o.push(L);
lua_setfield(L, -2, "other");
}
//Player
void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers) {
@ -289,9 +308,12 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st
lua_setfield(L, -2, "other");
lua_pushinteger(L, std::stoi(sep.arg[1]));
lua_setfield(L, -2, "killer_id");
lua_pushinteger(L, std::stoi(sep.arg[2]));
lua_setfield(L, -2, "damage");
int spell_id = std::stoi(sep.arg[2]);
int spell_id = std::stoi(sep.arg[3]);
if(IsValidSpell(spell_id)) {
Lua_Spell l_spell(&spells[spell_id]);
luabind::adl::object l_spell_o = luabind::adl::object(L, l_spell);
@ -304,7 +326,7 @@ void handle_player_death(QuestInterface *parse, lua_State* L, Client* client, st
lua_setfield(L, -2, "spell");
}
lua_pushinteger(L, std::stoi(sep.arg[3]));
lua_pushinteger(L, std::stoi(sep.arg[4]));
lua_setfield(L, -2, "skill");
}

View File

@ -43,6 +43,8 @@ void handle_npc_null(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, s
std::vector<std::any> *extra_pointers);
void handle_npc_loot_zone(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers);
void handle_npc_spawn_zone(QuestInterface *parse, lua_State* L, NPC* npc, Mob *init, std::string data, uint32 extra_data,
std::vector<std::any> *extra_pointers);
//Player
void handle_player_say(QuestInterface *parse, lua_State* L, Client* client, std::string data, uint32 extra_data,

View File

@ -3764,3 +3764,18 @@ int NPC::GetRolledItemCount(uint32 item_id)
return rolled_count;
}
int NPC::DispatchZoneControllerEvent(QuestEventID evt, Mob* init,
const std::string& data, uint32 extra, std::vector<std::any>* pointers)
{
int ret = 0;
if (RuleB(Zone, UseZoneController) && GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID)
{
auto controller = entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID);
if (controller)
{
ret = parse->EventNPC(evt, controller, init, data, extra, pointers);
}
}
return ret;
}

View File

@ -27,6 +27,7 @@
#include "zonedump.h"
#include "../common/loottable.h"
#include <any>
#include <deque>
#include <list>
@ -549,6 +550,9 @@ public:
void ReloadSpells();
static LootDropEntries_Struct NewLootDropEntry();
int DispatchZoneControllerEvent(QuestEventID evt, Mob* init, const std::string& data, uint32 extra, std::vector<std::any>* pointers);
protected:
const NPCType* NPCTypedata;