[Quest API] Adds new methods to NPCs and Corpses (#1510)

- Add $npc->HasItem(item_id) to Perl.
- Add $npc->CountItem(item_id) to Perl.
- Add $npc->GetItemIDBySlot(loot_slot) to Perl.
- Add $npc->GetFirstSlotByItemID(item_id) to Perl.
- Add $corpse->HasItem(item_id) to Perl.
- Add $corpse->CountItem(item_id) to Perl.
- Add $corpse->GetItemIDBySlot(loot_slot) to Perl.
- Add $corpse->GetFirstSlotByItemID(item_id) to Perl.
- Add npc:HasItem(item_id) to Lua.
- Add npc:CountItem(item_id) to Lua.
- Add npc:GetItemIDBySlot(loot_slot) to Lua.
- Add npc:GetFirstSlotByItemID(item_id) to Lua.
- Add corpse:HasItem(item_id) to Lua.
- Add corpse:CountItem(item_id) to Lua.
- Add corpse:GetItemIDBySlot(loot_slot) to Lua.
- Add corpse:GetFirstSlotByItemID(item_id) to Lua.

These methods will allow server operators to view the loot a current has in a slot, the first slot found by item ID, count the item by ID, and see if the NPC has the item.

With that functionality you could build a custom loot system and modify loot more dynamically.
This commit is contained in:
Kinglykrab 2021-08-31 01:42:08 -04:00 committed by GitHub
parent 642cbfcadc
commit 26299354b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 358 additions and 2 deletions

View File

@ -1454,6 +1454,75 @@ void Corpse::QueryLoot(Client* to) {
}
}
bool Corpse::HasItem(uint32 item_id) {
if (!database.GetItem(item_id)) {
return false;
}
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (!loot_item) {
LogError("NPC::CountItem() - ItemList error, null item");
continue;
}
if (!loot_item->item_id || !database.GetItem(loot_item->item_id)) {
LogError("NPC::CountItem() - Database error, invalid item");
continue;
}
if (loot_item->item_id == item_id) {
return true;
}
}
return false;
}
uint16 Corpse::CountItem(uint32 item_id) {
uint16 item_count = 0;
if (!database.GetItem(item_id)) {
return item_count;
}
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (!loot_item) {
LogError("NPC::CountItem() - ItemList error, null item");
continue;
}
if (!loot_item->item_id || !database.GetItem(loot_item->item_id)) {
LogError("NPC::CountItem() - Database error, invalid item");
continue;
}
if (loot_item->item_id == item_id) {
item_count += loot_item->charges;
}
}
return item_count;
}
uint32 Corpse::GetItemIDBySlot(uint16 loot_slot) {
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (loot_item->lootslot == loot_slot) {
return loot_item->item_id;
}
}
return 0;
}
uint16 Corpse::GetFirstSlotByItemID(uint32 item_id) {
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (loot_item->item_id == item_id) {
return loot_item->lootslot;
}
}
return 0;
}
bool Corpse::Summon(Client* client, bool spell, bool CheckDistance) {
uint32 dist2 = 10000; // pow(100, 2);
if (!spell) {

View File

@ -113,6 +113,10 @@ class Corpse : public Mob {
/* Corpse: Loot */
void QueryLoot(Client* to);
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 GetItemIDBySlot(uint16 loot_slot);
uint16 GetFirstSlotByItemID(uint32 item_id);
void LootItem(Client* client, const EQApplicationPacket* app);
void EndLoot(Client* client, const EQApplicationPacket* app);
void MakeLootRequestPackets(Client* client, const EQApplicationPacket* app);

View File

@ -152,6 +152,26 @@ void Lua_Corpse::AddLooter(Lua_Mob who) {
self->AddLooter(who);
}
bool Lua_Corpse::HasItem(uint32 item_id) {
Lua_Safe_Call_Bool();
return self->HasItem(item_id);
}
uint16 Lua_Corpse::CountItem(uint32 item_id) {
Lua_Safe_Call_Int();
return self->CountItem(item_id);
}
uint32 Lua_Corpse::GetItemIDBySlot(uint16 loot_slot) {
Lua_Safe_Call_Int();
return self->GetItemIDBySlot(loot_slot);
}
uint16 Lua_Corpse::GetFirstSlotByItemID(uint32 item_id) {
Lua_Safe_Call_Int();
return self->GetFirstSlotByItemID(item_id);
}
luabind::scope lua_register_corpse() {
return luabind::class_<Lua_Corpse, Lua_Mob>("Corpse")
.def(luabind::constructor<>())
@ -185,7 +205,11 @@ luabind::scope lua_register_corpse() {
.def("GetSilver", (uint32(Lua_Corpse::*)(void))&Lua_Corpse::GetSilver)
.def("GetGold", (uint32(Lua_Corpse::*)(void))&Lua_Corpse::GetGold)
.def("GetPlatinum", (uint32(Lua_Corpse::*)(void))&Lua_Corpse::GetPlatinum)
.def("AddLooter", (void(Lua_Corpse::*)(Lua_Mob))&Lua_Corpse::AddLooter);
.def("AddLooter", (void(Lua_Corpse::*)(Lua_Mob))&Lua_Corpse::AddLooter)
.def("HasItem", (bool(Lua_Corpse::*)(uint32))&Lua_Corpse::HasItem)
.def("CountItem", (uint16(Lua_Corpse::*)(uint32))&Lua_Corpse::CountItem)
.def("GetItemIDBySlot", (uint32(Lua_Corpse::*)(uint16))&Lua_Corpse::GetItemIDBySlot)
.def("GetFirstSlotByItemID", (uint16(Lua_Corpse::*)(uint32))&Lua_Corpse::GetFirstSlotByItemID);
}
#endif

View File

@ -54,6 +54,10 @@ public:
uint32 GetGold();
uint32 GetPlatinum();
void AddLooter(Lua_Mob who);
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 GetItemIDBySlot(uint16 loot_slot);
uint16 GetFirstSlotByItemID(uint32 item_id);
};
#endif

View File

@ -582,6 +582,30 @@ void Lua_NPC::ClearLastName()
self->ClearLastName();
}
bool Lua_NPC::HasItem(uint32 item_id)
{
Lua_Safe_Call_Bool();
return self->HasItem(item_id);
}
uint16 Lua_NPC::CountItem(uint32 item_id)
{
Lua_Safe_Call_Int();
return self->CountItem(item_id);
}
uint32 Lua_NPC::GetItemIDBySlot(uint16 loot_slot)
{
Lua_Safe_Call_Int();
return self->GetItemIDBySlot(loot_slot);
}
uint16 Lua_NPC::GetFirstSlotByItemID(uint32 item_id)
{
Lua_Safe_Call_Int();
return self->GetFirstSlotByItemID(item_id);
}
luabind::scope lua_register_npc() {
return luabind::class_<Lua_NPC, Lua_Mob>("NPC")
.def(luabind::constructor<>())
@ -698,7 +722,11 @@ luabind::scope lua_register_npc() {
.def("ScaleNPC", (void(Lua_NPC::*)(uint8))&Lua_NPC::ScaleNPC)
.def("IsRaidTarget", (bool(Lua_NPC::*)(void))&Lua_NPC::IsRaidTarget)
.def("ChangeLastName", (void(Lua_NPC::*)(const char*))&Lua_NPC::ChangeLastName)
.def("ClearLastName", (void(Lua_NPC::*)(void))&Lua_NPC::ClearLastName);
.def("ClearLastName", (void(Lua_NPC::*)(void))&Lua_NPC::ClearLastName)
.def("HasItem", (bool(Lua_NPC::*)(uint32))&Lua_NPC::HasItem)
.def("CountItem", (uint16(Lua_NPC::*)(uint32))&Lua_NPC::CountItem)
.def("GetItemIDBySlot", (uint32(Lua_NPC::*)(uint16))&Lua_NPC::GetItemIDBySlot)
.def("GetFirstSlotByItemID", (uint16(Lua_NPC::*)(uint32))&Lua_NPC::GetFirstSlotByItemID);
}
#endif

View File

@ -140,6 +140,10 @@ public:
bool IsRaidTarget();
void ChangeLastName(const char *lastname);
void ClearLastName();
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 GetItemIDBySlot(uint16 slot_id);
uint16 GetFirstSlotByItemID(uint32 item_id);
};
#endif

View File

@ -674,6 +674,75 @@ void NPC::QueryLoot(Client* to)
to->Message(Chat::White, "| %i Platinum %i Gold %i Silver %i Copper", platinum, gold, silver, copper);
}
bool NPC::HasItem(uint32 item_id) {
if (!database.GetItem(item_id)) {
return false;
}
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (!loot_item) {
LogError("NPC::CountItem() - ItemList error, null item");
continue;
}
if (!loot_item->item_id || !database.GetItem(loot_item->item_id)) {
LogError("NPC::CountItem() - Database error, invalid item");
continue;
}
if (loot_item->item_id == item_id) {
return true;
}
}
return false;
}
uint16 NPC::CountItem(uint32 item_id) {
uint16 item_count = 0;
if (!database.GetItem(item_id)) {
return item_count;
}
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (!loot_item) {
LogError("NPC::CountItem() - ItemList error, null item");
continue;
}
if (!loot_item->item_id || !database.GetItem(loot_item->item_id)) {
LogError("NPC::CountItem() - Database error, invalid item");
continue;
}
if (loot_item->item_id == item_id) {
item_count += loot_item->charges;
}
}
return item_count;
}
uint32 NPC::GetItemIDBySlot(uint16 loot_slot) {
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (loot_item->lootslot == loot_slot) {
return loot_item->item_id;
}
}
return 0;
}
uint16 NPC::GetFirstSlotByItemID(uint32 item_id) {
for (auto current_item = itemlist.begin(); current_item != itemlist.end(); ++current_item) {
ServerLootItem_Struct* loot_item = *current_item;
if (loot_item->item_id == item_id) {
return loot_item->lootslot;
}
}
return 0;
}
void NPC::AddCash(uint16 in_copper, uint16 in_silver, uint16 in_gold, uint16 in_platinum) {
if(in_copper >= 0)
copper = in_copper;

View File

@ -204,6 +204,10 @@ public:
void AddCash();
void RemoveCash();
void QueryLoot(Client* to);
bool HasItem(uint32 item_id);
uint16 CountItem(uint32 item_id);
uint32 GetItemIDBySlot(uint16 loot_slot);
uint16 GetFirstSlotByItemID(uint32 item_id);
uint32 CountLoot();
inline uint32 GetLoottableID() const { return loottable_id; }
virtual void UpdateEquipmentLight();

View File

@ -1741,6 +1741,77 @@ XS(XS_NPC_IsRaidTarget) {
XSRETURN(1);
}
XS(XS_NPC_HasItem); /* prototype to pass -Wmissing-prototypes */
XS(XS_NPC_HasItem) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: NPC::HasItem(THIS, uint32 item_id)"); // @categories Script Utility
{
NPC *THIS;
bool has_item = false;
uint32 item_id = (uint32) SvUV(ST(1));
VALIDATE_THIS_IS_NPC;
has_item = THIS->HasItem(item_id);
ST(0) = boolSV(has_item);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_NPC_CountItem);
XS(XS_NPC_CountItem) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: NPC::CountItem(THIS, uint32 item_id)"); // @categories Script Utility
{
NPC *THIS;
uint16 item_count = 0;
uint32 item_id = (uint32) SvUV(ST(1));
dXSTARG;
VALIDATE_THIS_IS_NPC;
item_count = THIS->CountItem(item_id);
XSprePUSH;
PUSHu((UV) item_count);
}
XSRETURN(1);
}
XS(XS_NPC_GetItemIDBySlot);
XS(XS_NPC_GetItemIDBySlot) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: NPC::GetItemIDBySlot(THIS, uint16 loot_slot)"); // @categories Script Utility
{
NPC *THIS;
uint32 item_id = 0;
uint16 loot_slot = (uint16) SvUV(ST(1));
dXSTARG;
VALIDATE_THIS_IS_NPC;
item_id = THIS->GetItemIDBySlot(loot_slot);
XSprePUSH;
PUSHu((UV) item_id);
}
XSRETURN(1);
}
XS(XS_NPC_GetFirstSlotByItemID);
XS(XS_NPC_GetFirstSlotByItemID) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: NPC::GetFirstSlotByItemID(THIS, uint32 item_id)"); // @categories Script Utility
{
NPC *THIS;
uint16 loot_slot = 0;
uint32 item_id = (uint32) SvUV(ST(1));
dXSTARG;
VALIDATE_THIS_IS_NPC;
loot_slot = THIS->GetFirstSlotByItemID(item_id);
XSprePUSH;
PUSHu((UV) loot_slot);
}
XSRETURN(1);
}
#ifdef __cplusplus
extern "C"
#endif
@ -1859,6 +1930,10 @@ XS(boot_NPC) {
newXSproto(strcpy(buf, "RecalculateSkills"), XS_NPC_RecalculateSkills, file, "$");
newXSproto(strcpy(buf, "ScaleNPC"), XS_NPC_ScaleNPC, file, "$$");
newXSproto(strcpy(buf, "IsRaidTarget"), XS_NPC_IsRaidTarget, file, "$");
newXSproto(strcpy(buf, "HasItem"), XS_NPC_HasItem, file, "$$");
newXSproto(strcpy(buf, "CountItem"), XS_NPC_CountItem, file, "$$");
newXSproto(strcpy(buf, "GetItemIDBySlot"), XS_NPC_GetItemIDBySlot, file, "$$");
newXSproto(strcpy(buf, "GetFirstSlotByItemID"), XS_NPC_GetFirstSlotByItemID, file, "$$");
XSRETURN_YES;
}

View File

@ -528,6 +528,77 @@ XS(XS_Corpse_IsRezzed) {
XSRETURN(1);
}
XS(XS_Corpse_HasItem); /* prototype to pass -Wmissing-prototypes */
XS(XS_Corpse_HasItem) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Corpse::HasItem(THIS, uint32 item_id)"); // @categories Script Utility
{
Corpse *THIS;
bool has_item = false;
uint32 item_id = (uint32) SvUV(ST(1));
VALIDATE_THIS_IS_CORPSE;
has_item = THIS->HasItem(item_id);
ST(0) = boolSV(has_item);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Corpse_CountItem);
XS(XS_Corpse_CountItem) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Corpse::CountItem(THIS, uint32 item_id)"); // @categories Script Utility
{
Corpse *THIS;
uint16 item_count = 0;
uint32 item_id = (uint32) SvUV(ST(1));
dXSTARG;
VALIDATE_THIS_IS_CORPSE;
item_count = THIS->CountItem(item_id);
XSprePUSH;
PUSHu((UV) item_count);
}
XSRETURN(1);
}
XS(XS_Corpse_GetItemIDBySlot);
XS(XS_Corpse_GetItemIDBySlot) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Corpse::GetItemIDBySlot(THIS, uint16 loot_slot)"); // @categories Script Utility
{
Corpse *THIS;
uint32 item_id = 0;
uint16 loot_slot = (uint16) SvUV(ST(1));
dXSTARG;
VALIDATE_THIS_IS_CORPSE;
item_id = THIS->GetItemIDBySlot(loot_slot);
XSprePUSH;
PUSHu((UV) item_id);
}
XSRETURN(1);
}
XS(XS_Corpse_GetFirstSlotByItemID);
XS(XS_Corpse_GetFirstSlotByItemID) {
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Corpse::GetFirstSlotByItemID(THIS, uint32 item_id)"); // @categories Script Utility
{
Corpse *THIS;
uint16 loot_slot = 0;
uint32 item_id = (uint32) SvUV(ST(1));
dXSTARG;
VALIDATE_THIS_IS_CORPSE;
loot_slot = THIS->GetFirstSlotByItemID(item_id);
XSprePUSH;
PUSHu((UV) loot_slot);
}
XSRETURN(1);
}
#ifdef __cplusplus
extern "C"
#endif
@ -574,6 +645,10 @@ XS(boot_Corpse) {
newXSproto(strcpy(buf, "AllowMobLoot"), XS_Corpse_AllowMobLoot, file, "$$$");
newXSproto(strcpy(buf, "AddLooter"), XS_Corpse_AddLooter, file, "$$");
newXSproto(strcpy(buf, "IsRezzed"), XS_Corpse_IsRezzed, file, "$");
newXSproto(strcpy(buf, "HasItem"), XS_Corpse_HasItem, file, "$$");
newXSproto(strcpy(buf, "CountItem"), XS_Corpse_CountItem, file, "$$");
newXSproto(strcpy(buf, "GetItemIDBySlot"), XS_Corpse_GetItemIDBySlot, file, "$$");
newXSproto(strcpy(buf, "GetFirstSlotByItemID"), XS_Corpse_GetFirstSlotByItemID, file, "$$");
XSRETURN_YES;
}