mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-19 16:31:29 +00:00
[Quest API] Add client->SummonBaggedItems(bag_item_id, bag_items_ref) to Perl/Lua.
Alternative apis using arrays of hash items for EQEmu/Server#1575 Perl usage: ```pl # create as an array, pass as reference my @bag_items = ( { item_id => 1001, charges => 1 }, { item_id => 1002, charges => 1 }, { item_id => 10037, charges => 10 }, ); $client->SummonBaggedItems(17403, \@bag_items); # create directly as an array reference my $bag_items = [ { item_id => 1001, charges => 1 }, { item_id => 1002, charges => 1 }, { item_id => 10037, charges => 10 }, ]; $client->SummonBaggedItems(17403, $bag_items); ``` Lua Usage: ```lua local bag_items = { { item_id = 1001, charges = 1 }, { item_id = 1002, charges = 1 }, { item_id = 10037, charges = 10 } } e.other:SummonBaggedItems(17403, bag_items);
This commit is contained in:
parent
9a413cf553
commit
5560b198ca
@ -10567,3 +10567,65 @@ std::vector<Client *> Client::GetPartyMembers()
|
|||||||
|
|
||||||
return clients_to_update;
|
return clients_to_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::SummonBaggedItems(uint32 bag_item_id, const std::vector<ServerLootItem_Struct>& bag_items)
|
||||||
|
{
|
||||||
|
if (bag_items.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: maybe some common functions for SE_SummonItem and SE_SummonItemIntoBag
|
||||||
|
|
||||||
|
const EQ::ItemData* bag_item = database.GetItem(bag_item_id);
|
||||||
|
if (!bag_item)
|
||||||
|
{
|
||||||
|
Message(Chat::Red, fmt::format("Unable to summon item [{}]. Item not found.", bag_item_id).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CheckLoreConflict(bag_item))
|
||||||
|
{
|
||||||
|
DuplicateLoreMessage(bag_item_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bag_item_charges = 1; // just summoning a single bag
|
||||||
|
EQ::ItemInstance* summoned_bag = database.CreateItem(bag_item_id, bag_item_charges);
|
||||||
|
if (!summoned_bag || !summoned_bag->IsClassBag())
|
||||||
|
{
|
||||||
|
Message(Chat::Red, fmt::format("Failed to summon bag item [{}]", bag_item_id).c_str());
|
||||||
|
safe_delete(summoned_bag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& item : bag_items)
|
||||||
|
{
|
||||||
|
uint8 open_slot = summoned_bag->FirstOpenSlot();
|
||||||
|
if (open_slot == 0xff)
|
||||||
|
{
|
||||||
|
Message(Chat::Red, "Attempting to summon item in to bag, but there is no room in the summoned bag!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EQ::ItemData* current_item = database.GetItem(item.item_id);
|
||||||
|
|
||||||
|
if (CheckLoreConflict(current_item))
|
||||||
|
{
|
||||||
|
DuplicateLoreMessage(item.item_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EQ::ItemInstance* summoned_bag_item = database.CreateItem(item.item_id, item.charges);
|
||||||
|
if (summoned_bag_item)
|
||||||
|
{
|
||||||
|
summoned_bag->PutItem(open_slot, *summoned_bag_item);
|
||||||
|
safe_delete(summoned_bag_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PushItemOnCursor(*summoned_bag);
|
||||||
|
SendItemPacket(EQ::invslot::slotCursor, summoned_bag, ItemPacketLimbo);
|
||||||
|
safe_delete(summoned_bag);
|
||||||
|
}
|
||||||
|
|||||||
@ -913,6 +913,7 @@ public:
|
|||||||
void PutLootInInventory(int16 slot_id, const EQ::ItemInstance &inst, ServerLootItem_Struct** bag_item_data = 0);
|
void PutLootInInventory(int16 slot_id, const EQ::ItemInstance &inst, ServerLootItem_Struct** bag_item_data = 0);
|
||||||
bool AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
|
bool AutoPutLootInInventory(EQ::ItemInstance& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
|
||||||
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQ::invslot::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
|
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQ::invslot::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
|
||||||
|
void SummonBaggedItems(uint32 bag_item_id, const std::vector<ServerLootItem_Struct>& bag_items);
|
||||||
void SetStats(uint8 type,int16 set_val);
|
void SetStats(uint8 type,int16 set_val);
|
||||||
void IncStats(uint8 type,int16 increase_val);
|
void IncStats(uint8 type,int16 increase_val);
|
||||||
void DropItem(int16 slot_id, bool recurse = true);
|
void DropItem(int16 slot_id, bool recurse = true);
|
||||||
|
|||||||
@ -2229,6 +2229,31 @@ void Lua_Client::UntrainDiscBySpellID(uint16 spell_id, bool update_client) {
|
|||||||
self->UntrainDiscBySpellID(spell_id, update_client);
|
self->UntrainDiscBySpellID(spell_id, update_client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Lua_Client::SummonBaggedItems(uint32 bag_item_id, luabind::adl::object bag_items_table) {
|
||||||
|
Lua_Safe_Call_Void();
|
||||||
|
if (luabind::type(bag_items_table) != LUA_TTABLE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ServerLootItem_Struct> bagged_items;
|
||||||
|
|
||||||
|
luabind::raw_iterator end; // raw_iterator uses lua_rawget
|
||||||
|
for (luabind::raw_iterator it(bag_items_table); it != end; ++it)
|
||||||
|
{
|
||||||
|
// verify array element is a table for item details
|
||||||
|
if (luabind::type(*it) == LUA_TTABLE)
|
||||||
|
{
|
||||||
|
// no need to try/catch, quest lua parser already catches exceptions
|
||||||
|
ServerLootItem_Struct item{};
|
||||||
|
item.item_id = luabind::object_cast<uint32>((*it)["item_id"]);
|
||||||
|
item.charges = luabind::object_cast<int16>((*it)["charges"]);
|
||||||
|
bagged_items.emplace_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self->SummonBaggedItems(bag_item_id, bagged_items);
|
||||||
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_client() {
|
luabind::scope lua_register_client() {
|
||||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -2604,7 +2629,8 @@ luabind::scope lua_register_client() {
|
|||||||
.def("RemoveItem", (void(Lua_Client::*)(uint32,uint32))&Lua_Client::RemoveItem)
|
.def("RemoveItem", (void(Lua_Client::*)(uint32,uint32))&Lua_Client::RemoveItem)
|
||||||
.def("SetGMStatus", (void(Lua_Client::*)(int32))&Lua_Client::SetGMStatus)
|
.def("SetGMStatus", (void(Lua_Client::*)(int32))&Lua_Client::SetGMStatus)
|
||||||
.def("UntrainDiscBySpellID", (void(Lua_Client::*)(uint16))&Lua_Client::UntrainDiscBySpellID)
|
.def("UntrainDiscBySpellID", (void(Lua_Client::*)(uint16))&Lua_Client::UntrainDiscBySpellID)
|
||||||
.def("UntrainDiscBySpellID", (void(Lua_Client::*)(uint16,bool))&Lua_Client::UntrainDiscBySpellID);
|
.def("UntrainDiscBySpellID", (void(Lua_Client::*)(uint16,bool))&Lua_Client::UntrainDiscBySpellID)
|
||||||
|
.def("SummonBaggedItems", (void(Lua_Client::*)(uint32,luabind::adl::object))&Lua_Client::SummonBaggedItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_inventory_where() {
|
luabind::scope lua_register_inventory_where() {
|
||||||
|
|||||||
@ -215,6 +215,7 @@ public:
|
|||||||
bool attuned);
|
bool attuned);
|
||||||
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5,
|
void SummonItem(uint32 item_id, int charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5,
|
||||||
bool attuned, int to_slot);
|
bool attuned, int to_slot);
|
||||||
|
void SummonBaggedItems(uint32 bag_item_id, luabind::adl::object bag_items_table);
|
||||||
void SetStats(int type, int value);
|
void SetStats(int type, int value);
|
||||||
void IncStats(int type, int value);
|
void IncStats(int type, int value);
|
||||||
void DropItem(int slot_id);
|
void DropItem(int slot_id);
|
||||||
|
|||||||
@ -5712,6 +5712,57 @@ XS(XS_Client_UntrainDiscBySpellID) {
|
|||||||
XSRETURN_EMPTY;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS_Client_SummonBaggedItems); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_Client_SummonBaggedItems) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 3) {
|
||||||
|
Perl_croak(aTHX_ "Usage: Client::SummonBaggedItems(THIS, uint32 bag_item_id, ARRAYREF bag_items_array)"); // @categories Inventory and Items, Script Utility
|
||||||
|
}
|
||||||
|
|
||||||
|
Client* THIS;
|
||||||
|
VALIDATE_THIS_IS_CLIENT;
|
||||||
|
|
||||||
|
uint32 bag_item_id = (uint32) SvUV(ST(1));
|
||||||
|
|
||||||
|
// verify we're receiving a reference to an array type
|
||||||
|
SV* bag_items_avref = ST(2);
|
||||||
|
if (!bag_items_avref || !SvROK(bag_items_avref) || SvTYPE(SvRV(bag_items_avref)) != SVt_PVAV)
|
||||||
|
{
|
||||||
|
Perl_croak(aTHX_ "Client::SummonBaggedItems second argument is not a reference to an array");
|
||||||
|
}
|
||||||
|
|
||||||
|
// dereference into the array
|
||||||
|
AV* bag_items_av = (AV*)SvRV(bag_items_avref);
|
||||||
|
|
||||||
|
std::vector<ServerLootItem_Struct> bagged_items;
|
||||||
|
|
||||||
|
auto count = av_len(bag_items_av) + 1;
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
SV** element = av_fetch(bag_items_av, i, 0);
|
||||||
|
|
||||||
|
// verify array element is a hash reference containing item details
|
||||||
|
if (element && SvROK(*element) && SvTYPE(SvRV(*element)) == SVt_PVHV)
|
||||||
|
{
|
||||||
|
HV* hash = (HV*)SvRV(*element); // dereference
|
||||||
|
|
||||||
|
SV** item_id_ptr = hv_fetchs(hash, "item_id", false);
|
||||||
|
SV** item_charges_ptr = hv_fetchs(hash, "charges", false);
|
||||||
|
if (item_id_ptr && item_charges_ptr)
|
||||||
|
{
|
||||||
|
ServerLootItem_Struct item{};
|
||||||
|
item.item_id = static_cast<uint32>(SvUV(*item_id_ptr));
|
||||||
|
item.charges = static_cast<int16>(SvIV(*item_charges_ptr));
|
||||||
|
bagged_items.emplace_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
THIS->SummonBaggedItems(bag_item_id, bagged_items);
|
||||||
|
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
#endif
|
#endif
|
||||||
@ -6001,6 +6052,7 @@ XS(boot_Client) {
|
|||||||
newXSproto(strcpy(buf, "Sit"), XS_Client_Sit, file, "$");
|
newXSproto(strcpy(buf, "Sit"), XS_Client_Sit, file, "$");
|
||||||
newXSproto(strcpy(buf, "SlotConvert2"), XS_Client_SlotConvert2, file, "$$");
|
newXSproto(strcpy(buf, "SlotConvert2"), XS_Client_SlotConvert2, file, "$$");
|
||||||
newXSproto(strcpy(buf, "Stand"), XS_Client_Stand, file, "$");
|
newXSproto(strcpy(buf, "Stand"), XS_Client_Stand, file, "$");
|
||||||
|
newXSproto(strcpy(buf, "SummonBaggedItems"), XS_Client_SummonBaggedItems, file, "$$$");
|
||||||
newXSproto(strcpy(buf, "SummonItem"), XS_Client_SummonItem, file, "$$;$$$$$$$$");
|
newXSproto(strcpy(buf, "SummonItem"), XS_Client_SummonItem, file, "$$;$$$$$$$$");
|
||||||
newXSproto(strcpy(buf, "TakeMoneyFromPP"), XS_Client_TakeMoneyFromPP, file, "$$;$");
|
newXSproto(strcpy(buf, "TakeMoneyFromPP"), XS_Client_TakeMoneyFromPP, file, "$$;$");
|
||||||
newXSproto(strcpy(buf, "TGB"), XS_Client_TGB, file, "$");
|
newXSproto(strcpy(buf, "TGB"), XS_Client_TGB, file, "$");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user