diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 6796fc0a6..164021bf6 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -7623,6 +7623,43 @@ XS(XS__worldwideaddldonwin) { XSRETURN_EMPTY; } +XS(XS__isnpcspawned); +XS(XS__isnpcspawned) { + dXSARGS; + if (items < 1) + Perl_croak(aTHX_ "Usage: quest::isnpcspawned(npc_id_one, npc_id_two, npc_idthree, npc_id_four, npc_id_five...[no limit])"); + { + std::vector npc_ids; + bool is_spawned = false; + for (int index = 0; index < items; index++) { + npc_ids.push_back((uint32)SvUV(ST(index))); + } + is_spawned = entity_list.IsNPCSpawned(npc_ids); + ST(0) = boolSV(is_spawned); + sv_2mortal(ST(0)); + XSRETURN(1); + } +} + +XS(XS__countspawnednpcs); +XS(XS__countspawnednpcs) { + dXSARGS; + if (items < 1) + Perl_croak(aTHX_ "Usage: quest::countspawnednpcs(npc_id_one, npc_id_two, npc_idthree, npc_id_four, npc_id_five...[no limit])"); + { + dXSTARG; + std::vector npc_ids; + uint32 npc_count = 0; + for (int index = 0; index < items; index++) { + npc_ids.push_back((uint32)SvUV(ST(index))); + } + npc_count = entity_list.CountSpawnedNPCs(npc_ids); + XSprePUSH; + PUSHu((UV)npc_count); + XSRETURN(1); + } +} + /* This is the callback perl will look for to setup the quest package's XSUBs @@ -7718,6 +7755,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "collectitems"), XS__collectitems, file); newXS(strcpy(buf, "completedtasksinset"), XS__completedtasksinset, file); newXS(strcpy(buf, "countitem"), XS__countitem, file); + newXS(strcpy(buf, "countspawnednpcs"), XS__countspawnednpcs, file); newXS(strcpy(buf, "createdoor"), XS__CreateDoor, file); newXS(strcpy(buf, "creategroundobject"), XS__CreateGroundObject, file); newXS(strcpy(buf, "creategroundobjectfrommodel"), XS__CreateGroundObjectFromModel, file); @@ -7926,6 +7964,7 @@ EXTERN_C XS(boot_quest) { newXS(strcpy(buf, "incstat"), XS__incstat, file); newXS(strcpy(buf, "isdisctome"), XS__isdisctome, file); newXS(strcpy(buf, "isdooropen"), XS__isdooropen, file); + newXS(strcpy(buf, "isnpcspawned"), XS__isnpcspawned, file); newXS(strcpy(buf, "istaskactive"), XS__istaskactive, file); newXS(strcpy(buf, "istaskactivityactive"), XS__istaskactivityactive, file); newXS(strcpy(buf, "istaskappropriate"), XS__istaskappropriate, file); diff --git a/zone/entity.cpp b/zone/entity.cpp index 47e03afba..b506ca01a 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -1201,6 +1201,34 @@ bool EntityList::IsMobSpawnedByNpcTypeID(uint32 get_id) return false; } +bool EntityList::IsNPCSpawned(std::vector npc_ids) +{ + return CountSpawnedNPCs(npc_ids) != 0; +} + +uint32 EntityList::CountSpawnedNPCs(std::vector npc_ids) +{ + uint32 npc_count = 0; + if (npc_list.empty() || npc_ids.empty()) { + return npc_count; + } + + for (auto current_npc : npc_list) { + if ( + std::find( + npc_ids.begin(), + npc_ids.end(), + current_npc.second->GetNPCTypeID() + ) != npc_ids.end() && + current_npc.second->GetID() != 0 + ) { + npc_count++; + } + } + + return npc_count; +} + Object *EntityList::GetObjectByDBID(uint32 id) { if (id == 0 || object_list.empty()) diff --git a/zone/entity.h b/zone/entity.h index 1690799a1..2890c18f5 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -158,6 +158,8 @@ public: Mob *GetMob(const char* name); Mob *GetMobByNpcTypeID(uint32 get_id); bool IsMobSpawnedByNpcTypeID(uint32 get_id); + bool IsNPCSpawned(std::vector npc_ids); + uint32 CountSpawnedNPCs(std::vector npc_ids); Mob *GetTargetForVirus(Mob* spreader, int range); inline NPC *GetNPCByID(uint16 id) { diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 3338bea5c..404a074ef 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -3121,6 +3121,66 @@ void lua_world_wide_update_activity(uint32 task_id, int activity_id, int activit quest_manager.WorldWideTaskUpdate(update_type, task_id, activity_id, activity_count, enforce_level_requirement, min_status, max_status); } +bool lua_is_npc_spawned(luabind::adl::object table) { + if(luabind::type(table) != LUA_TTABLE) { + return false; + } + + std::vector npc_ids; + int index = 1; + while (luabind::type(table[index]) != LUA_TNIL) { + auto current_id = table[index]; + uint32 npc_id = 0; + if(luabind::type(current_id) != LUA_TNIL) { + try { + npc_id = luabind::object_cast(current_id); + } catch(luabind::cast_failed &) { + } + } else { + break; + } + + npc_ids.push_back(npc_id); + ++index; + } + + if (npc_ids.empty()) { + return false; + } + + return entity_list.IsNPCSpawned(npc_ids); +} + +uint32 lua_count_spawned_npcs(luabind::adl::object table) { + if(luabind::type(table) != LUA_TTABLE) { + return 0; + } + + std::vector npc_ids; + int index = 1; + while (luabind::type(table[index]) != LUA_TNIL) { + auto current_id = table[index]; + uint32 npc_id = 0; + if(luabind::type(current_id) != LUA_TNIL) { + try { + npc_id = luabind::object_cast(current_id); + } catch(luabind::cast_failed &) { + } + } else { + break; + } + + npc_ids.push_back(npc_id); + ++index; + } + + if (npc_ids.empty()) { + return 0; + } + + return entity_list.CountSpawnedNPCs(npc_ids); +} + #define LuaCreateNPCParse(name, c_type, default_value) do { \ cur = table[#name]; \ if(luabind::type(cur) != LUA_TNIL) { \ @@ -3560,6 +3620,8 @@ luabind::scope lua_register_general() { luabind::def("get_item_stat", &lua_get_item_stat), luabind::def("get_spell_stat", (int(*)(uint32,std::string))&lua_get_spell_stat), luabind::def("get_spell_stat", (int(*)(uint32,std::string,uint8))&lua_get_spell_stat), + luabind::def("is_npc_spawned", &lua_is_npc_spawned), + luabind::def("count_spawned_npcs", &lua_count_spawned_npcs), /* Cross Zone