#include "../common/stats.qh"
#include "../common/teams.qh"
+#include "../common/items/all.qh"
+
#include "../common/weapons/all.qh"
#include "../csqcmodellib/cl_model.qh"
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
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;
../common/urllib.qc
../common/util.qc
+../common/items/all.qc
+
../common/monsters/all.qc
../common/weapons/all.qc // TODO
}
}
+void GenericCommand_dumpitems(float request)
+{
+ switch(request)
+ {
+ case CMD_REQUEST_COMMAND:
+ {
+ Dump_Items();
+ return;
+ }
+
+ default:
+ case CMD_REQUEST_USAGE:
+ {
+ printf("\nUsage:^3 %s dumpitems", GetProgramCommandPrefix());
+ return;
+ }
+ }
+}
+
void GenericCommand_dumpnotifs(float request)
{
switch(request)
#define GENERIC_COMMANDS(request,arguments,command) \
GENERIC_COMMAND("addtolist", GenericCommand_addtolist(request, arguments), "Add a string to a cvar") \
GENERIC_COMMAND("dumpcommands", GenericCommand_dumpcommands(request), "Dump all commands on the program to *_cmd_dump.txt") \
+ GENERIC_COMMAND("dumpitems", GenericCommand_dumpitems(request), "Dump all items to the console") \
GENERIC_COMMAND("dumpnotifs", GenericCommand_dumpnotifs(request), "Dump all notifications into notifications_dump.txt") \
GENERIC_COMMAND("dumpweapons", GenericCommand_dumpweapons(request), "Dump all weapons into weapons_dump.txt") \
GENERIC_COMMAND("maplist", GenericCommand_maplist(request, arguments), "Automatic control of maplist") \
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;
--- /dev/null
+#include "item/ammo.qc"
+#include "item/armor.qc"
+#include "item/buff.qc"
+#include "item/health.qc"
+#include "item/jetpack.qc"
+#include "item/pickup.qc"
+#include "item/powerup.qc"
--- /dev/null
+#ifndef ALL_C
+#define ALL_C
+#include "all.qh"
+
+#include "all.inc"
+
+void Dump_Items()
+{
+ ITEMS_FOREACH(true, LAMBDA({
+ ITEM_HANDLE(Show, it);
+ }));
+}
+
+#endif
--- /dev/null
+#ifndef ALL_H
+#define ALL_H
+
+const int MAX_ITEMS = 24;
+entity ITEMS[MAX_ITEMS];
+
+#define ITEMS_FOREACH(pred, body) do { \
+ for (int i = 0; i < ITEM_COUNT; i++) { \
+ const noref entity it = ITEMS[i]; \
+ if (pred) { body } \
+ } \
+} while(0)
+
+void RegisterItems();
+void Dump_Items();
+
+#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 fld = inv_items[i];
+ int prev = data.(fld);
+ int next = data.(fld) = 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 fld = inv_items[i];
+ bits = BITSET(bits, BIT(i), data.inventory.(fld) != (data.inventory.(fld) = data.(fld)));
+ }));
+ 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
--- /dev/null
+#ifndef GAMEITEM_H
+#define GAMEITEM_H
+#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); }
+ENDCLASS(GameItem)
+
+
+int ITEM_COUNT;
+#define REGISTER_ITEM(id, class, body) \
+ entity ITEM_##id; \
+ void RegisterItems_##id() { \
+ const entity this = NEW(class); \
+ ITEM_##id = this; \
+ this.m_id = ITEM_COUNT; \
+ ITEMS[ITEM_COUNT++] = this; \
+ body \
+ } \
+ ACCUMULATE_FUNCTION(RegisterItems, RegisterItems_##id)
+
+#endif
--- /dev/null
+#include "ammo.qh"
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) \
+ REGISTER_ITEM(id, Ammo, LAMBDA( \
+ IF(SV, CONFIGURE \
+ , respawntime = GET(g_pickup_respawntime_ammo) \
+ , respawntimejitter = GET(g_pickup_respawntimejitter_ammo) \
+ ) \
+ UNWORDS(__VA_ARGS__) \
+ ))
+
+DEFINE(Bullets
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_bullets.mdl"
+ , name = "bullets"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 2000
+ , itemid = IT_NAILS
+ )
+)
+DEFINE(Cells
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_cells.md3"
+ , name = "cells"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 2000
+ , itemid = IT_CELLS
+ )
+)
+DEFINE(Plasma
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_cells.md3"
+ , name = "plasma"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 2000
+ , itemid = IT_PLASMA
+ )
+)
+DEFINE(Rockets
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_rockets.md3"
+ , name = "rockets"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 3000
+ , itemid = IT_ROCKETS
+ )
+)
+DEFINE(Shells
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_shells.md3"
+ , name = "shells"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 500
+ , itemid = IT_SHELLS
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef AMMO_H
+#define AMMO_H
+#include "pickup.qh"
+CLASS(Ammo, Pickup)
+#ifdef SVQC
+ ATTRIB(Ammo, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+#endif
+ENDCLASS(Ammo)
+#endif
--- /dev/null
+#include "armor.qh"
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) REGISTER_ITEM(id, Armor, UNWORDS(__VA_ARGS__))
+
+DEFINE(ArmorSmall
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_small.md3"
+ , sound = "misc/armor1.wav"
+ , name = "5 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemid = IT_ARMOR_SHARD
+ , respawntime = GET(g_pickup_respawntime_short)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_short)
+ )
+)
+
+DEFINE(ArmorMedium
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_medium.md3"
+ , sound = "misc/armor10.wav"
+ , name = "25 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_MID
+ , itemid = IT_ARMOR
+ , respawntime = GET(g_pickup_respawntime_medium)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_medium)
+ )
+)
+
+DEFINE(ArmorBig
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_big.md3"
+ , sound = "misc/armor17_5.wav"
+ , name = "50 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 20000 // FIXME: higher than BOT_PICKUP_RATING_HIGH?
+ , itemid = IT_ARMOR
+ , respawntime = GET(g_pickup_respawntime_long)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_long)
+ )
+)
+
+DEFINE(ArmorLarge
+ ,APPLY(CONFIGURE
+ , model = "models/items/item_armor_large.md3"
+ , sound = "misc/armor25.wav"
+ , name = "100 Armor"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_HIGH
+ , itemid = IT_ARMOR
+ , respawntime = GET(g_pickup_respawntime_long)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_long)
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef ARMOR_H
+#define ARMOR_H
+#include "pickup.qh"
+CLASS(Armor, Pickup)
+#ifdef SVQC
+ ATTRIB(Armor, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+#endif
+ENDCLASS(Armor)
+#endif
--- /dev/null
+#include "buff.qh"
+
+REGISTER_ITEM(DefaultBuff, Buff, LAMBDA())
--- /dev/null
+#ifndef BUFF_H
+#define BUFF_H
+#include "pickup.qh"
+CLASS(Buff, Pickup)
+ ATTRIB(Buff, m_name, string, "Buff")
+ENDCLASS(Buff)
+#endif
--- /dev/null
+#include "health.qh"
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) REGISTER_ITEM(id, Health, UNWORDS(__VA_ARGS__))
+
+DEFINE(HealthSmall
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h1.md3"
+ , sound = "misc/minihealth.wav"
+ , name = "5 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemid = IT_5HP
+ , respawntime = GET(g_pickup_respawntime_short)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_short)
+ )
+)
+
+DEFINE(HealthMedium
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h25.md3"
+ , sound = "misc/mediumhealth.wav"
+ , name = "25 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_MID
+ , itemid = IT_25HP
+ , respawntime = GET(g_pickup_respawntime_short)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_short)
+ )
+)
+
+DEFINE(HealthLarge
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h50.md3"
+ , sound = "misc/mediumhealth.wav"
+ , name = "50 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_MID
+ , itemid = IT_25HP
+ , respawntime = GET(g_pickup_respawntime_medium)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_medium)
+ )
+)
+
+DEFINE(HealthMega
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h100.md3"
+ , sound = "misc/megahealth.wav"
+ , name = "100 Health"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_HIGH
+ , itemid = IT_HEALTH
+ , respawntime = GET(g_pickup_respawntime_long)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_long)
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef HEALTH_H
+#define HEALTH_H
+#include "pickup.qh"
+CLASS(Health, Pickup)
+#ifdef SVQC
+ ATTRIB(Health, m_pickupevalfunc, float(entity player, entity item), commodity_pickupevalfunc)
+#endif
+ENDCLASS(Health)
+#endif
--- /dev/null
+#ifdef SVQC
+ #include "../../../server/t_items.qh"
+ #include "../../../server/constants.qh"
+#endif
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) REGISTER_ITEM(id, Pickup, UNWORDS(__VA_ARGS__))
+
+DEFINE(Jetpack
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_jetpack.md3"
+ , name = "Jet pack"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemflags = FL_POWERUP
+ , itemid = IT_JETPACK
+ , pickupevalfunc = commodity_pickupevalfunc
+ , respawntime = GET(g_pickup_respawntime_powerup)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup)
+ )
+)
+
+DEFINE(JetpackFuel
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_fuel.md3"
+ , name = "Fuel"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemid = IT_FUEL
+ , pickupevalfunc = commodity_pickupevalfunc
+ , respawntime = GET(g_pickup_respawntime_ammo)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_ammo)
+ )
+)
+
+DEFINE(JetpackRegen
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_fuelregen.md3"
+ , name = "Fuel regenerator"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_LOW
+ , itemflags = FL_POWERUP
+ , itemid = IT_FUEL_REGEN
+ , pickupevalfunc = commodity_pickupevalfunc
+ , respawntime = GET(g_pickup_respawntime_powerup)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup)
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /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
--- /dev/null
+#ifndef PICKUP_H
+#define PICKUP_H
+#include "../item.qh"
+CLASS(Pickup, GameItem)
+ ATTRIB(Pickup, m_model, string, string_null)
+ ATTRIB(Pickup, m_sound, string, "misc/itempickup.wav")
+ ATTRIB(Pickup, m_name, string, string_null)
+ METHOD(Pickup, show, void(entity this))
+ void Pickup_show(entity this) { printf("%s: %s\n", etos(this), this.m_name); }
+#ifdef SVQC
+ ATTRIB(Pickup, m_botvalue, int, 0)
+ ATTRIB(Pickup, m_itemflags, int, 0)
+ ATTRIB(Pickup, m_itemid, int, 0)
+ ATTRIB(Pickup, m_pickupevalfunc, float(entity player, entity item), generic_pickupevalfunc)
+ ATTRIB(Pickup, m_respawntime, float(), func_null)
+ 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);
+#endif
+ENDCLASS(Pickup)
+
+#ifdef SVQC
+// For g_pickup_respawntime
+#include "../../../server/defs.qh"
+// Getters to dynamically retrieve the values of g_pickup_respawntime*
+GETTER(float, g_pickup_respawntime_weapon)
+GETTER(float, g_pickup_respawntime_superweapon)
+GETTER(float, g_pickup_respawntime_ammo)
+GETTER(float, g_pickup_respawntime_short)
+GETTER(float, g_pickup_respawntime_medium)
+GETTER(float, g_pickup_respawntime_long)
+GETTER(float, g_pickup_respawntime_powerup)
+GETTER(float, g_pickup_respawntimejitter_weapon)
+GETTER(float, g_pickup_respawntimejitter_superweapon)
+GETTER(float, g_pickup_respawntimejitter_ammo)
+GETTER(float, g_pickup_respawntimejitter_short)
+GETTER(float, g_pickup_respawntimejitter_medium)
+GETTER(float, g_pickup_respawntimejitter_long)
+GETTER(float, g_pickup_respawntimejitter_powerup)
+
+#endif
+
+#endif
--- /dev/null
+#include "powerup.qh"
+#include "../../../server/t_items.qh"
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+#define DEFINE(id, ...) \
+ REGISTER_ITEM(id, Ammo, LAMBDA( \
+ IF(SV, CONFIGURE \
+ , botvalue = 100000 \
+ , itemflags = FL_POWERUP \
+ , respawntime = GET(g_pickup_respawntime_powerup) \
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup) \
+ ) \
+ UNWORDS(__VA_ARGS__) \
+ ))
+
+DEFINE(Strength
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_strength.md3"
+ , sound = "misc/powerup.wav"
+ , name = "Strength Powerup"
+ )
+ ,IF(SV, CONFIGURE
+ , itemid = IT_STRENGTH
+ )
+)
+DEFINE(Shield
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_invincible.md3"
+ , sound = "misc/powerup_shield.wav"
+ , name = "Shield"
+ )
+ ,IF(SV, CONFIGURE
+ , itemid = IT_INVINCIBLE
+ )
+)
+
+#undef WITH
+#undef CONFIGURE
+#undef DEFINE
--- /dev/null
+#ifndef POWERUP_H
+#define POWERUP_H
+#include "pickup.qh"
+CLASS(Powerup, Pickup)
+ENDCLASS(Powerup)
+
+#ifdef SVQC
+// For FL_POWERUP
+#include "../../../server/constants.qh"
+#endif
+
+#endif
--- /dev/null
+#ifndef OO_H
+#define OO_H
+
+#ifdef MENUQC
+ #define NULL (null_entity)
+#else
+ #define NULL (world)
+#endif
+
+.string classname;
+.string vtblname;
+.entity vtblbase;
+entity spawnVtbl(entity this, entity base)
+{
+ entity vtbl = spawn();
+ copyentity(this, vtbl);
+ vtbl.vtblname = vtbl.classname;
+ vtbl.classname = "vtbl";
+ vtbl.vtblbase = base ? base : vtbl; // Top level objects use vtbl as base
+ return vtbl;
+}
+
+entity Object_vtbl;
+entity spawnObject(entity this, entity)
+{
+ this = spawn();
+ this.classname = "Object";
+ if (!Object_vtbl) Object_vtbl = spawnVtbl(this, NULL);
+ return this;
+}
+
+// Classes have a `spawn##cname(entity, entity)` constructor
+// The parameters are used as locals for [[accumulate]]
+
+// Macro to hide this implementation detail
+#define NEW(cname) (spawn##cname(NULL, NULL))
+
+#define CLASS(cname, base) \
+entity spawn##cname(entity this, entity basevtbl) { \
+ this = NEW(base); basevtbl = base##_vtbl; \
+}
+
+#define METHOD(cname, name, prototype) \
+prototype cname##_##name; \
+.prototype name; \
+[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \
+ this.name = cname##_##name; \
+}
+
+#define ATTRIB(cname, name, type, val) \
+.type name; \
+[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \
+ this.name = val; \
+}
+
+#define ATTRIBARRAY(cname, name, type, cnt) \
+.type name[cnt];
+
+#define ENDCLASS(cname) \
+.bool instanceOf##cname; \
+entity cname##_vtbl; \
+[[accumulate]] [[last]] entity spawn##cname(entity this, entity basevtbl) { \
+ this.instanceOf##cname = true; \
+ this.classname = #cname; \
+ if (!cname##_vtbl) cname##_vtbl = spawnVtbl(this, basevtbl); \
+ return this; \
+}
+
+#define SUPER(cname) (cname##_vtbl.vtblbase)
+
+#endif
[[deprecated("use true")]] [[alias("true")]] const bool TRUE;
[[deprecated("use false")]] [[alias("false")]] const bool FALSE;
+#ifdef GMQCC
+ #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+#else
+ #define OVERLOAD_(F,_9,_8,_7,_6,_5,_4,_3,_2,_1,n,...) F##_##n
+ #define OVERLOAD(F, ...) OVERLOAD_(F,__VA_ARGS__,9,8,7,6,5,4,3,2,1)(__VA_ARGS__)
+#endif
+
+#define LAMBDA(...) { __VA_ARGS__ ; }
+
+#define MAP(f, ...) OVERLOAD(MAP, f, __VA_ARGS__)
+#define MAP_2(f, it) f(it)
+#define MAP_3(f, it, ...) f(it)MAP_2(f, __VA_ARGS__)
+#define MAP_4(f, it, ...) f(it)MAP_3(f, __VA_ARGS__)
+#define MAP_5(f, it, ...) f(it)MAP_4(f, __VA_ARGS__)
+#define MAP_6(f, it, ...) f(it)MAP_5(f, __VA_ARGS__)
+#define MAP_7(f, it, ...) f(it)MAP_6(f, __VA_ARGS__)
+#define MAP_8(f, it, ...) f(it)MAP_7(f, __VA_ARGS__)
+#define MAP_9(f, it, ...) f(it)MAP_8(f, __VA_ARGS__)
+#define MAP_10(f, it, ...) f(it)MAP_9(f, __VA_ARGS__)
+#define MAP_11(f, it, ...) f(it)MAP_10(f, __VA_ARGS__)
+#define MAP_12(f, it, ...) f(it)MAP_11(f, __VA_ARGS__)
+#define MAP_13(f, it, ...) f(it)MAP_12(f, __VA_ARGS__)
+#define MAP_14(f, it, ...) f(it)MAP_13(f, __VA_ARGS__)
+#define MAP_15(f, it, ...) f(it)MAP_14(f, __VA_ARGS__)
+#define MAP_16(f, it, ...) f(it)MAP_15(f, __VA_ARGS__)
+#define MAP_17(f, it, ...) f(it)MAP_16(f, __VA_ARGS__)
+#define MAP_18(f, it, ...) f(it)MAP_17(f, __VA_ARGS__)
+#define MAP_19(f, it, ...) f(it)MAP_18(f, __VA_ARGS__)
+#define MAP_20(f, it, ...) f(it)MAP_19(f, __VA_ARGS__)
+
+#define IDENTITY(it) it
+
+#define UNWORDS(...) MAP(IDENTITY, __VA_ARGS__)
+
+#define APPLY(f, ...) f(__VA_ARGS__)
+
+#ifdef SVQC
+ #define SV(f, ...) f(__VA_ARGS__)
+#else
+ #define SV(f, ...)
+#endif
+
+#ifdef CSQC
+ #define CL(f, ...) f(__VA_ARGS__)
+#else
+ #define CL(f, ...)
+#endif
+
+#define IF(cond, f, ...) cond(f, __VA_ARGS__)
+
+#define GET(name) name##get
+#define GETTER(type, name) type GET(name)() { return name; }
+
#define BIT(n) (1 << (n))
-#define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) &~ (mask))
+#ifndef BRANCHLESS_BITSET
+ #define BITSET(var, mask, flag) (flag ? (var) | (mask) : (var) &~ (mask))
+#else
+ #define BITSET(var, mask, flag) ((var) ^ (-(flag) ^ (var)) & (mask))
+#endif
#endif
#include "oo/classes.qc"
#include "xonotic/util.qh"
+#include "../common/items/all.qh"
#include "../common/weapons/all.qh"
#include "../common/mapinfo.qh"
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
RegisterSLCategories();
#ifndef BASE_H
#define BASE_H
+#include "../../common/oo.qh"
+
#include "../../common/util.qh"
#include "../../dpdefs/keycodes.qh"
-#define NULL (null_entity)
#define world NULL
-.string classname;
-.string vtblname;
-.entity vtblbase;
-entity spawnVtbl(entity this, entity base)
-{
- entity vtbl = spawn();
- copyentity(this, vtbl);
- vtbl.vtblname = vtbl.classname;
- vtbl.classname = "vtbl";
- vtbl.vtblbase = base ? base : vtbl; // Top level objects use vtbl as base
- return vtbl;
-}
-
-entity Object_vtbl;
-entity spawnObject(entity this, entity)
-{
- this = spawn();
- this.classname = "Object";
- if (!Object_vtbl) Object_vtbl = spawnVtbl(this, null_entity);
- return this;
-}
-
-// Classes have a `spawn##cname(entity, entity)` constructor
-// The parameters are used as locals for [[accumulate]]
-
-// Macro to hide this implementation detail
-#define NEW(cname) (spawn##cname(null_entity, null_entity))
-
-#define CLASS(cname, base) \
-entity spawn##cname(entity this, entity basevtbl) { \
- this = NEW(base); basevtbl = base##_vtbl; \
-}
-
-#define METHOD(cname, name, prototype) \
-prototype cname##_##name; \
-.prototype name; \
-[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \
- this.name = cname##_##name; \
-}
-
-#define ATTRIB(cname, name, type, val) \
-.type name; \
-[[accumulate]] entity spawn##cname(entity this, entity basevtbl) { \
- this.name = val; \
-}
-
-#define ATTRIBARRAY(cname, name, type, cnt) \
-.type name[cnt];
-
-#define ENDCLASS(cname) \
-.bool instanceOf##cname; \
-entity cname##_vtbl; \
-[[last]] entity spawn##cname(entity this, entity basevtbl) { \
- this.instanceOf##cname = true; \
- this.classname = #cname; \
- if (!cname##_vtbl) cname##_vtbl = spawnVtbl(this, basevtbl); \
- return this; \
-}
-
-#define SUPER(cname) (cname##_vtbl.vtblbase)
-
-#endif
\ No newline at end of file
+#endif
../common/urllib.qc
../common/util.qc
+../common/items/all.qc
+
../common/monsters/all.qc
../common/weapons/all.qc // TODO
#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);
#include "../common/stats.qh"
#include "../common/teams.qh"
#include "../common/util.qh"
+#include "../common/items/all.qh"
#include "../common/weapons/all.qh"
const float LATENCY_THINKRATE = 10;
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
// needs to be done so early because of the constants they create
CALL_ACCUMULATED_FUNCTION(RegisterWeapons);
CALL_ACCUMULATED_FUNCTION(RegisterMonsters);
+ CALL_ACCUMULATED_FUNCTION(RegisterItems);
CALL_ACCUMULATED_FUNCTION(RegisterGametypes);
CALL_ACCUMULATED_FUNCTION(RegisterNotifications);
CALL_ACCUMULATED_FUNCTION(RegisterDeathtypes);
}
-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
#include "../cl_client.qh"
#include "../../common/buffs.qh"
+#include "../../common/items/item.qh"
+
+#define WITH(it) this.m_##it;
+#define CONFIGURE(...) MAP(WITH, __VA_ARGS__)
+
+float instagib_respawntime_ammo = 45;
+float instagib_respawntimejitter_ammo = 0;
+GETTER(float, instagib_respawntime_ammo)
+GETTER(float, instagib_respawntimejitter_ammo)
+
+REGISTER_ITEM(VaporizerCells, Pickup, APPLY(UNWORDS
+ ,APPLY(CONFIGURE
+ , model = "models/items/a_cells.md3"
+ , sound = "misc/itempickup.wav"
+ , name = "Vaporizer Ammo"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = 100
+ , itemid = IT_CELLS
+ , respawntime = GET(instagib_respawntime_ammo)
+ , respawntimejitter = GET(instagib_respawntimejitter_ammo)
+ )
+))
+
+REGISTER_ITEM(ExtraLife, Pickup, APPLY(UNWORDS
+ ,APPLY(CONFIGURE
+ , model = "models/items/g_h100.md3"
+ , sound = "misc/megahealth.wav"
+ , name = "Extralife"
+ )
+ ,IF(SV, CONFIGURE
+ , botvalue = BOT_PICKUP_RATING_HIGH
+ , itemflags = FL_POWERUP
+ , itemid = IT_NAILS
+ , respawntime = GET(g_pickup_respawntime_powerup)
+ , respawntimejitter = GET(g_pickup_respawntimejitter_powerup)
+ )
+))
+
+#undef WITH
+#undef CONFIGURE
+
void spawnfunc_item_minst_cells (void)
{
if (!g_instagib) { remove(self); return; }
if (!self.ammo_cells)
self.ammo_cells = autocvar_g_instagib_ammo_drop;
- StartItem ("models/items/a_cells.md3",
- "misc/itempickup.wav", 45, 0,
- "Vaporizer Ammo", IT_CELLS, 0, 0, generic_pickupevalfunc, 100);
+ StartItemA (ITEM_VaporizerCells);
}
void instagib_health_mega()
{
self.max_health = 1;
- StartItem ("models/items/g_h100.md3",
- "misc/megahealth.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
- "Extralife", IT_NAILS, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+ StartItemA (ITEM_ExtraLife);
}
.float instagib_nextthink;
../common/test.qc
../common/urllib.qc
../common/util.qc
+
+../common/items/all.qc
+
../common/weapons/config.qc
../common/weapons/all.qc // TODO
#include "t_items.qh"
+#include "../common/items/all.qc"
+
#if defined(SVQC)
#include "_all.qh"
return 1;
}
+.entity itemdef;
+
void Item_Touch (void)
{
entity e, head;
self.invincible_finished = max(0, self.invincible_finished - time);
self.superweapons_finished = max(0, self.superweapons_finished - time);
}
-
- if(!Item_GiveTo(self, other))
+ entity it = self.itemdef;
+ bool gave = (it && it.instanceOfPickup) ? ITEM_HANDLE(Pickup, it, self, other) : Item_GiveTo(self, other);
+ if (!gave)
{
if (self.classname == "droppedweapon")
{
if (self.classname == "droppedweapon")
remove (self);
- else if (!self.spawnshieldtime)
- return;
- else
+ else if (self.spawnshieldtime)
{
if(self.team)
{
return;
}
}
+
+void StartItemA (entity a)
+{
+ self.itemdef = a;
+ StartItem(a.m_model, a.m_sound, a.m_respawntime(), a.m_respawntimejitter(), a.m_name, a.m_itemid, 0, a.m_itemflags, a.m_pickupevalfunc, a.m_botvalue);
+}
+
void spawnfunc_item_rockets (void) {
if(!self.ammo_rockets)
self.ammo_rockets = g_pickup_rockets;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_rockets.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "rockets", IT_ROCKETS, 0, 0, commodity_pickupevalfunc, 3000);
+ StartItemA (ITEM_Rockets);
}
void spawnfunc_item_bullets (void) {
self.ammo_nails = g_pickup_nails;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_bullets.mdl", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "bullets", IT_NAILS, 0, 0, commodity_pickupevalfunc, 2000);
+ StartItemA (ITEM_Bullets);
}
void spawnfunc_item_cells (void) {
self.ammo_cells = g_pickup_cells;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
+ StartItemA (ITEM_Cells);
}
void spawnfunc_item_plasma()
self.ammo_plasma = g_pickup_plasma;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "plasma", IT_PLASMA, 0, 0, commodity_pickupevalfunc, 2000);
+ StartItemA (ITEM_Plasma);
}
void spawnfunc_item_shells (void) {
self.ammo_shells = g_pickup_shells;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/a_shells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "shells", IT_SHELLS, 0, 0, commodity_pickupevalfunc, 500);
+ StartItemA (ITEM_Shells);
}
void spawnfunc_item_armor_small (void) {
self.max_armorvalue = g_pickup_armorsmall_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorsmall_anyway;
- StartItem ("models/items/item_armor_small.md3", "misc/armor1.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_ArmorSmall);
}
void spawnfunc_item_armor_medium (void) {
self.max_armorvalue = g_pickup_armormedium_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armormedium_anyway;
- StartItem ("models/items/item_armor_medium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+ StartItemA (ITEM_ArmorMedium);
}
void spawnfunc_item_armor_big (void) {
self.max_armorvalue = g_pickup_armorbig_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorbig_anyway;
- StartItem ("models/items/item_armor_big.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000);
+ StartItemA (ITEM_ArmorBig);
}
void spawnfunc_item_armor_large (void) {
self.max_armorvalue = g_pickup_armorlarge_max;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_armorlarge_anyway;
- StartItem ("models/items/item_armor_large.md3", "misc/armor25.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+ StartItemA (ITEM_ArmorLarge);
}
void spawnfunc_item_health_small (void) {
self.health = g_pickup_healthsmall;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthsmall_anyway;
- StartItem ("models/items/g_h1.md3", "misc/minihealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Health", IT_5HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_HealthSmall);
}
void spawnfunc_item_health_medium (void) {
self.health = g_pickup_healthmedium;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthmedium_anyway;
- StartItem ("models/items/g_h25.md3", "misc/mediumhealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "25 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+ StartItemA (ITEM_HealthMedium);
}
void spawnfunc_item_health_large (void) {
self.health = g_pickup_healthlarge;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_healthlarge_anyway;
- StartItem ("models/items/g_h50.md3", "misc/mediumhealth.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "50 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+ StartItemA (ITEM_HealthLarge);
}
void spawnfunc_item_health_mega (void) {
- if(!self.max_health)
- self.max_health = g_pickup_healthmega_max;
- if(!self.health)
- self.health = g_pickup_healthmega;
- if(!self.pickup_anyway)
- self.pickup_anyway = g_pickup_healthmega_anyway;
- StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+ if(!self.max_health)
+ self.max_health = g_pickup_healthmega_max;
+ if(!self.health)
+ self.health = g_pickup_healthmega;
+ if(!self.pickup_anyway)
+ self.pickup_anyway = g_pickup_healthmega_anyway;
+ StartItemA (ITEM_HealthMega);
}
// support old misnamed entities
precache_sound("weapons/strength_fire.wav");
if(!self.strength_finished)
self.strength_finished = autocvar_g_balance_powerup_strength_time;
- StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
+ StartItemA (ITEM_Strength);
}
void spawnfunc_item_invincible (void) {
if(!self.invincible_finished)
self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
- StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Shield", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
+ StartItemA (ITEM_Shield);
}
// compatibility:
self.ammo_fuel = g_pickup_fuel;
if(!self.pickup_anyway)
self.pickup_anyway = g_pickup_ammo_anyway;
- StartItem ("models/items/g_fuel.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "Fuel", IT_FUEL, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_JetpackFuel);
}
void spawnfunc_item_fuel_regen(void)
spawnfunc_item_fuel();
return;
}
- StartItem ("models/items/g_fuelregen.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Fuel regenerator", IT_FUEL_REGEN, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_JetpackRegen);
}
void spawnfunc_item_jetpack(void)
spawnfunc_item_fuel();
return;
}
- StartItem ("models/items/g_jetpack.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Jet pack", IT_JETPACK, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+ StartItemA (ITEM_Jetpack);
}
float GiveWeapon(entity e, float wpn, float op, float val)
// where is 64... ?
const int IT_FUEL = 128;
// -Wdouble-declaration
-// const int IT_SHELLS = 256;
+#define IT_SHELLS 256
// -Wdouble-declaration
-// const int IT_NAILS = 512;
+#define IT_NAILS 512
// -Wdouble-declaration
-// const int IT_ROCKETS = 1024;
+#define IT_ROCKETS 1024
// -Wdouble-declaration
-// const int IT_CELLS = 2048;
+#define IT_CELLS 2048
const int IT_SUPERWEAPON = 4096;
const int IT_STRENGTH = 8192;
const int IT_INVINCIBLE = 16384;