#pragma once #include "all.qh" CLASS(Inventory, Object) /** Stores counts of items, the id being the index */ ATTRIBARRAY(Inventory, inv_items, int, Items_MAX); /** Previous state */ ATTRIB(Inventory, inventory, Inventory); ENDCLASS(Inventory) /** Player inventory */ .Inventory inventory; REGISTER_NET_LINKED(ENT_CLIENT_INVENTORY) const int Inventory_groups_major = 16; const int Inventory_groups_minor = 8; // ceil(Items_MAX / Inventory_groups_major) #define G_MAJOR(id) (floor((id) / Inventory_groups_minor)) #define G_MINOR(id) ((id) % Inventory_groups_minor) #ifdef CSQC NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew) { make_pure(this); const int majorBits = ReadShort(); for (int i = 0; i < Inventory_groups_major; ++i) { if (!(majorBits & BIT(i))) { continue; } const int minorBits = ReadByte(); for (int j = 0; j < Inventory_groups_minor; ++j) { if (!(minorBits & BIT(j))) { continue; } const GameItem it = Items_from(Inventory_groups_minor * i + j); .int fld = inv_items[it.m_id]; int prev = this.(fld); int next = this.(fld) = ReadByte(); LOG_TRACEF("%s: %.0f -> %.0f", it.m_name, prev, next); } } return true; } #endif #ifdef SVQC void Inventory_Write(Inventory data) { if (!data) { WriteShort(MSG_ENTITY, 0); return; } TC(Inventory, data); int majorBits = 0; FOREACH(Items, true, { .int fld = inv_items[it.m_id]; const bool changed = data.inventory.(fld) != data.(fld); if (changed) { majorBits = BITSET(majorBits, BIT(G_MAJOR(it.m_id)), true); } }); WriteShort(MSG_ENTITY, majorBits); int minorBits = 0; int lastMaj = 0; int maj = 0; FOREACH(Items, majorBits & BIT(maj = G_MAJOR(it.m_id)), { .int fld = inv_items[it.m_id]; const bool changed = data.inventory.(fld) != (data.inventory.(fld) = data.(fld)); if (changed) { if (maj != lastMaj) { lastMaj = maj; #define X() MACRO_BEGIN \ if (minorBits) { \ WriteByte(MSG_ENTITY, minorBits); \ for (int j = 0; j < Inventory_groups_minor; ++j) { \ if (!(minorBits & BIT(j))) { \ continue; \ } \ const entity it = Items_from(Inventory_groups_minor * maj + j); \ WriteByte(MSG_ENTITY, data.inv_items[it.m_id]); \ } \ } \ MACRO_END X(); minorBits = 0; } minorBits = BITSET(minorBits, BIT(G_MINOR(it.m_id)), true); } }); X(); #undef X } #endif #undef G_MAJOR #undef G_MINOR #ifdef SVQC bool Inventory_Send(Inventory this, Client to, int sf) { TC(Inventory, this); WriteHeader(MSG_ENTITY, ENT_CLIENT_INVENTORY); entity e = this.owner; if (IS_SPEC(e)) e = e.enemy; TC(Player, e); Inventory data = e.inventory; Inventory_Write(data); return true; } void Inventory_new(entity e) { Inventory inv = NEW(Inventory), bak = NEW(Inventory); inv.inventory = bak; inv.drawonlytoclient = e; Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send); } void Inventory_delete(entity e) { delete(e.inventory.inventory); delete(e.inventory); } void Inventory_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; } #endif