case ENT_CLIENT_WARPZONE_TELEPORTED: WarpZone_Teleported_Read(bIsNewEntity); break;
case ENT_CLIENT_TRIGGER_MUSIC: Ent_ReadTriggerMusic(); break;
case ENT_CLIENT_HOOK: Ent_ReadHook(bIsNewEntity, ENT_CLIENT_HOOK); break;
+ case ENT_CLIENT_INVENTORY: Inventory_Read(self); break;
case ENT_CLIENT_ARC_BEAM: Ent_ReadArcBeam(bIsNewEntity); break;
case ENT_CLIENT_ACCURACY: Ent_ReadAccuracy(); break;
case ENT_CLIENT_AUXILIARYXHAIR: Net_AuXair2(bIsNewEntity); break;
const int ENT_CLIENT_WARPZONE_CAMERA = 25;
const int ENT_CLIENT_TRIGGER_MUSIC = 26;
const int ENT_CLIENT_HOOK = 27;
+const int ENT_CLIENT_INVENTORY = 28;
const int ENT_CLIENT_ARC_BEAM = 29; // WEAPONTODO: fix numbers
const int ENT_CLIENT_ACCURACY = 30;
const int ENT_CLIENT_SHOWNAMES = 31;
#include "item/buff.qc"
#include "item/health.qc"
#include "item/jetpack.qc"
+#include "item/pickup.qc"
#include "item/powerup.qc"
#ifndef ALL_H
#define ALL_H
-const int MAX_ITEMS = 23;
+const int MAX_ITEMS = 24;
entity ITEMS[MAX_ITEMS];
#define ITEMS_FOREACH(pred, body) do { \
for (int i = 0; i < ITEM_COUNT; i++) { \
- const entity it = ITEMS[i]; \
+ const noref entity it = ITEMS[i]; \
if (pred) { body } \
} \
} while(0)
void RegisterItems();
void Dump_Items();
-#ifdef CSQC
-void ReadItems()
-{
-/*
- const int flags = read();
- for (int i = 0; i < MAX_ITEMS; i++) {
- if (flags & BIT(i)) {
- self.items[i] = read();
- }
- }
-*/
-}
#endif
-#ifdef SVQC
-void WriteItems()
-{
-
-}
-#endif
-
-#endif
+#include "inventory.qh"
--- /dev/null
+#ifndef INVENTORY_H
+#define INVENTORY_H
+
+#include "all.qh"
+#include "item/pickup.qh"
+
+entityclass(Inventory);
+/** Stores counts of items, the id being the index */
+class(Inventory) .int inv_items[MAX_ITEMS];
+
+/** Player inventory; Inventories also have one inventory for storing the previous state */
+.Inventory inventory;
+
+#ifdef CSQC
+void Inventory_Read(Inventory data)
+{
+ const int bits = ReadInt24_t();
+ ITEMS_FOREACH(bits & BIT(i), LAMBDA({
+ int prev = data.inv_items[i];
+ int next = data.inv_items[i] = ReadByte();
+ dprintf("%s: %.0f -> %.0f\n", ITEMS[i].m_name, prev, next);
+ }));
+}
+#endif
+
+#ifdef SVQC
+void Inventory_Write(Inventory data)
+{
+ int bits = 0;
+ ITEMS_FOREACH(true, LAMBDA({
+ .int idx = inv_items[i];
+ bits = BITSET(bits, BIT(i), data.inventory.(idx) != (data.inventory.(idx) = data.(idx)));
+ }));
+ WriteInt24_t(MSG_ENTITY, bits);
+ ITEMS_FOREACH(bits & BIT(i), LAMBDA({
+ WriteByte(MSG_ENTITY, data.inv_items[i]);
+ }));
+}
+#endif
+
+#ifdef SVQC
+bool Inventory_Send(entity to, int sf)
+{
+ WriteByte(MSG_ENTITY, ENT_CLIENT_INVENTORY);
+ entity e = self.owner;
+ if (IS_SPEC(e)) e = e.enemy;
+ Inventory data = e.inventory;
+ Inventory_Write(data);
+ return true;
+}
+
+void Inventory_new(entity e)
+{
+ Inventory inv = new(Inventory), bak = new(Inventory);
+ inv.classname = "inventory", bak.classname = "inventory";
+ inv.inventory = bak;
+ inv.drawonlytoclient = e;
+ Net_LinkEntity((inv.owner = e).inventory = inv, false, 0, Inventory_Send);
+}
+void Inventory_delete(entity e) { remove(e.inventory.inventory); remove(e.inventory); }
+void Inventory_update(entity e) { e.inventory.SendFlags = 0xFFFFFF; }
+#endif
+
+#endif
#include "../oo.qh"
#define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
CLASS(GameItem, Object)
+ ATTRIB(GameItem, m_id, int, 0)
METHOD(GameItem, show, void(entity this))
void GameItem_show(entity this) { print("A game item\n"); }
void ITEM_HANDLE(Show, entity this) { this.show(this); }
void RegisterItems_##id() { \
const entity this = NEW(class); \
ITEM_##id = this; \
+ this.m_id = ITEM_COUNT; \
ITEMS[ITEM_COUNT++] = this; \
body \
} \
--- /dev/null
+#include "pickup.qh"
+
+#ifdef SVQC
+bool ITEM_HANDLE(Pickup, entity this, entity item, entity player) {
+ bool b = this.giveTo(this, item, player);
+ if (b) {
+ dprintf("entity %i picked up %s\n", player, this.m_name);
+ player.inventory.inv_items[this.m_id]++;
+ Inventory_update(player);
+ }
+ return b;
+}
+#endif
ATTRIB(Pickup, m_respawntimejitter, float(), func_null)
METHOD(Pickup, giveTo, bool(entity this, entity item, entity player))
bool Pickup_giveTo(entity this, entity item, entity player) { return Item_GiveTo(item, player); }
- bool ITEM_HANDLE(Pickup, entity this, entity item, entity player) { printf("%s picked up %s\n", etos(player), this.m_name); return this.giveTo(this, item, player); }
+ bool ITEM_HANDLE(Pickup, entity this, entity item, entity player);
#endif
ENDCLASS(Pickup)
#include "../common/net_notice.qh"
+#include "../common/items/inventory.qh"
+
#include "../common/monsters/sv_monsters.qh"
#include "../warpzonelib/server.qh"
PlayerScore_Attach(self);
ClientData_Attach();
accuracy_init(self);
+ Inventory_new(self);
bot_clientconnect();
bot_relinkplayerlist();
accuracy_free(self);
+ Inventory_delete(self);
ClientData_Detach();
PlayerScore_Detach(self);
}
-void Net_LinkEntity(entity e, float docull, float dt, bool(entity, int) sendfunc)
+void Net_LinkEntity(entity e, bool docull, float dt, bool(entity, int) sendfunc)
{
vector mi, ma;
float sound_allowed(float dest, entity e);
void InitializeEntity(entity e, void(void) func, float order);
void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer);
-void Net_LinkEntity(entity e, float docull, float dt, float(entity, float) sendfunc);
+void Net_LinkEntity(entity e, bool docull, float dt, bool(entity, int) sendfunc);
#endif