Skip to content

Commit 3afd403

Browse files
committed
container: add C_Container.HasContainerItem
Classic Era addition (present in the 1.15.x client, absent in 5.4.8) — a plain occupancy check for a bag slot. Occupancy sibling of GetContainerItemID: resolves (bagIndex, slotIndex) the same way and returns whether the CGItem is non-null. Presence only, so it reports true for a just-looted item even before its static data caches. Returns false for empty slots and out-of-range indices.
1 parent e103021 commit 3afd403

3 files changed

Lines changed: 73 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Full per-function reference: **[docs/API.md](docs/API.md)**.
2424
| [Combat](docs/API.md#combat) | `InCombatLockdown` |
2525
| [CVar](docs/API.md#cvar) | `C_CVar.GetCVarBool` |
2626
| [Cursor](docs/API.md#cursor) | `GetCursorInfo` |
27-
| [Container](docs/API.md#container) | `C_Container.CalculateTotalNumberOfFreeBagSlots`, `C_Container.GetContainerItemCharges`, `C_Container.GetContainerItemDurability`, `C_Container.GetContainerItemID`, `C_Container.GetContainerItemRepairCost`, `C_Container.GetContainerNumFreeSlots`, `C_Container.GetItemCooldown`, `C_Container.IsContainerItemOpenable`, `C_Container.MoveItem`, `C_Container.PlayerHasHearthstone`, `C_Container.SwapItems`, `C_Container.UseHearthstone`, `GetItemCooldown` |
27+
| [Container](docs/API.md#container) | `C_Container.CalculateTotalNumberOfFreeBagSlots`, `C_Container.GetContainerItemCharges`, `C_Container.GetContainerItemDurability`, `C_Container.GetContainerItemID`, `C_Container.GetContainerItemRepairCost`, `C_Container.GetContainerNumFreeSlots`, `C_Container.GetItemCooldown`, `C_Container.HasContainerItem`, `C_Container.IsContainerItemOpenable`, `C_Container.MoveItem`, `C_Container.PlayerHasHearthstone`, `C_Container.SwapItems`, `C_Container.UseHearthstone`, `GetItemCooldown` |
2828
| [Coroutine](docs/API.md#coroutine) | `coroutine.create`, `coroutine.resume`, `coroutine.yield`, `coroutine.status`, `coroutine.wrap` |
2929
| [Creature](docs/API.md#creature) | `C_CreatureInfo.GetCreatureID`, `C_CreatureInfo.GetCreatureInfoByID`, `C_CreatureInfo.RequestLoadCreatureByID`, `C_CreatureInfo.GetRaceInfo`, `C_CreatureInfo.GetClassInfo`, `C_CreatureInfo.GetCreatureFamilyInfo`, `C_CreatureInfo.GetCreatureFamilyIDs`, `C_CreatureInfo.GetFactionInfo`, `C_CreatureInfo.GetCreatureTypeInfo`, `C_CreatureInfo.GetCreatureTypeIDs` |
3030
| EncodingUtil | `C_EncodingUtil.CompressString`, `C_EncodingUtil.DecompressString`, `C_EncodingUtil.EncodeBase64`, `C_EncodingUtil.DecodeBase64`, `C_EncodingUtil.EncodeHex`, `C_EncodingUtil.DecodeHex`, `C_EncodingUtil.SerializeJSON`, `C_EncodingUtil.DeserializeJSON`, `C_EncodingUtil.SerializeCBOR`, `C_EncodingUtil.DeserializeCBOR` |

docs/API.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ build instructions.
4040

4141
- [Container](#container)
4242
- [`C_Container.GetContainerItemID(bagIndex, slotIndex)`](#c_containergetcontaineritemidbagindex-slotindex)
43+
- [`C_Container.HasContainerItem(bagIndex, slotIndex)`](#c_containerhascontaineritembagindex-slotindex)
4344
- [`GetItemCooldown(itemInfo)` / `C_Container.GetItemCooldown(itemID)`](#getitemcooldowniteminfo--c_containergetitemcooldownitemid)
4445
- [`C_Container.GetContainerItemDurability(containerIndex, slotIndex)`](#c_containergetcontaineritemdurabilitycontainerindex-slotindex)
4546
- [`C_Container.GetContainerItemRepairCost(containerIndex, slotIndex)`](#c_containergetcontaineritemrepaircostcontainerindex-slotindex)
@@ -1061,6 +1062,25 @@ for slot = 1, 16 do
10611062
end
10621063
```
10631064

1065+
### `C_Container.HasContainerItem(bagIndex, slotIndex)`
1066+
1067+
Returns `true` if the given bag slot currently holds an item, `false`
1068+
otherwise (empty slot or out-of-range indices). The occupancy sibling of
1069+
`GetContainerItemID` — same slot resolution, but a plain presence check.
1070+
1071+
- `bagIndex = 0` — the player's main backpack; `1..4` — equipped bag slots.
1072+
- `slotIndex` — 1-based.
1073+
1074+
Presence only: it does **not** require the item's static data to be cached,
1075+
so it returns `true` for a just-looted item even before `GetContainerItemID`
1076+
/ `GetItemInfo` resolve for it.
1077+
1078+
```lua
1079+
if C_Container.HasContainerItem(0, 1) then
1080+
-- backpack slot 1 is occupied
1081+
end
1082+
```
1083+
10641084
### `GetItemCooldown(itemInfo)` / `C_Container.GetItemCooldown(itemID)`
10651085

10661086
Returns `(startTime, duration, enable)` for the cooldown of the

src/container/HasItem.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// This file is part of ClassicAPI.
2+
//
3+
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
4+
// of the GNU General Public License as published by the Free Software Foundation, either
5+
// version 3 of the License, or (at your option) any later version.
6+
//
7+
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
8+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9+
// PURPOSE. See the GNU General Public License for more details.
10+
//
11+
// You should have received a copy of the GNU General Public License along with
12+
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
13+
14+
// `C_Container.HasContainerItem(bagIndex, slotIndex)` — returns whether the
15+
// given bag slot currently holds an item (a Classic Era addition). It's the
16+
// occupancy sibling of `GetContainerItemID`: resolves the slot to its CGItem
17+
// the same way (`Item::Location::ResolveBag` → engine `PackBagSlot` →
18+
// `GetItemBySlot`), and a populated slot yields a non-null pointer while an
19+
// empty slot yields null. Presence only — it does not depend on the item's
20+
// static data being cached. Returns `false` for empty slots and invalid
21+
// bag/slot indices.
22+
23+
#include "Game.h"
24+
#include "item/Location.h"
25+
26+
namespace Container::HasItem {
27+
28+
namespace {
29+
30+
int __fastcall Script_C_Container_HasContainerItem(void *L) {
31+
if (!Game::Lua::IsNumber(L, 1) || !Game::Lua::IsNumber(L, 2)) {
32+
Game::Lua::Error(L, "Usage: C_Container.HasContainerItem(bagIndex, slotIndex)");
33+
return 0;
34+
}
35+
const int bagID = static_cast<int>(Game::Lua::ToNumber(L, 1));
36+
const int slotIndex = static_cast<int>(Game::Lua::ToNumber(L, 2));
37+
38+
const bool hasItem = Item::Location::ResolveBag(L, bagID, slotIndex) != nullptr;
39+
Game::Lua::PushBool(L, hasItem);
40+
return 1;
41+
}
42+
43+
void RegisterLuaFunctions() {
44+
Game::Lua::RegisterTableFunction("C_Container", "HasContainerItem",
45+
&Script_C_Container_HasContainerItem);
46+
}
47+
48+
const Game::ModuleAutoRegister _autoreg{&RegisterLuaFunctions};
49+
50+
} // namespace
51+
52+
} // namespace Container::HasItem

0 commit comments

Comments
 (0)