Despawn ammo after use.
author[furrycat] <furrycat@furryclan.net>
Wed, 20 May 2009 14:02:51 +0000 (10:02 -0400)
committer[furrycat] <furrycat@furryclan.net>
Mon, 1 Jun 2009 22:01:22 +0000 (18:01 -0400)
Despawn ammo after a set number of uses defined in lw_despawn_ammo.

limited_weapons.sp

index ce71fa1..81aa4d3 100644 (file)
@@ -1,7 +1,17 @@
 #include <sourcemod>\r
-#define Version "0.1"\r
+#define Version "0.2"\r
 \r
-new Handle:despawn;\r
+new Handle:despawn_weapons;\r
+new Handle:despawn_ammo;\r
+\r
+/* Array to track players grabbed ammo. */\r
+new grabbed_ammo[MAXPLAYERS];\r
+#define NAME_BUFFER_LEN 32\r
+new namebuffer[NAME_BUFFER_LEN];\r
+/* XXX: Surely this should be enough for ammo spawners. */\r
+#define NUM_AMMO_ENTITIES 32\r
+new ammo_entities[NUM_AMMO_ENTITIES];\r
+new ammo_counts[NUM_AMMO_ENTITIES];\r
 \r
 public Plugin:myinfo = {\r
   name = "Limited weapons",\r
@@ -19,23 +29,110 @@ public OnPluginStart() {
   }\r
 \r
   /* Set up cvars. */\r
-  despawn = CreateConVar("limited_weapons_despawn", "1", "Remove weapon spawners immediately after use.");\r
+  despawn_weapons = CreateConVar("lw_despawn_weapons", "1", "Remove weapon spawners immediately after use.");\r
+  despawn_ammo = CreateConVar("lw_despawn_ammo", "4", "Remove ammo spawners after this many uses.  Set to 0 to disable removal.");\r
 \r
-  AutoExecConfig(true, "limited_weapons");\r
+  AutoExecConfig(true, "lw");\r
 \r
   /* Hooks. */\r
   HookEvent("spawner_give_item", spawner_give_item_callback);\r
+  HookEvent("player_use", player_use_callback);\r
+  HookEvent("ammo_pickup", ammo_pickup_callback);\r
 }\r
 \r
-/* Remove item spawner as soon as it has given an item. */\r
+/* A player picked up an item from a spawner. */\r
 public spawner_give_item_callback(Handle:event, const String:name[], bool:dontBroadcast) {\r
-  if (GetConVarInt(despawn)) {\r
-    new spawner = GetEventInt(event, "spawner");\r
-    if (IsValidEntity(spawner)) RemoveEdict(spawner);\r
+  /* Remove item spawner as soon as it has given an item. */\r
+  if (! GetConVarInt(despawn_weapons)) return;\r
+\r
+  new spawner = GetEventInt(event, "spawner");\r
+  if (! IsValidEntity(spawner)) return;\r
+\r
+  GetEdictClassname(spawner, namebuffer, NAME_BUFFER_LEN);\r
+\r
+  LogMessage("Removing %s (%d) after use.", namebuffer, spawner);\r
+  RemoveEdict(spawner);\r
+}\r
+\r
+/* A player interacted with something. */\r
+public player_use_callback(Handle:event, const String:name[], bool:dontBroadcast) {\r
+  /*\r
+    By the time this fires the value of grabbed_ammo[userid] will be 1 \r
+    if ammo was picked up.\r
+  */\r
+  new count = GetConVarInt(despawn_ammo);\r
+  if (! count) return;\r
+\r
+  new userid = GetEventInt(event, "userid");\r
+  new was_ammo = grabbed_ammo[userid];\r
+  /* Forget that this player interacted with anything. */\r
+  grabbed_ammo[userid] = 0;\r
+\r
+  new spawner = GetEventInt(event, "targetid");\r
+  if (! IsValidEntity(spawner)) return;\r
+\r
+  if (! was_ammo) return;\r
+\r
+  /* Check this is an ammo spawner.  Surely it must be. */\r
+  GetEdictClassname(spawner, namebuffer, NAME_BUFFER_LEN);\r
+  if (strcmp(namebuffer, "weapon_ammo_spawn")) return;\r
+\r
+  /* How many times? */\r
+  new index = get_ammo_index(spawner);\r
+  if (index == -1) return;\r
+\r
+  new used = ammo_counts[index] + 1;\r
+  ammo_counts[index] = used;\r
+\r
+  if (used >= count) {\r
+    LogMessage("Removing %s (%d) after %d use(s).", namebuffer, used, spawner);\r
+    RemoveEdict(spawner);\r
   }\r
 }\r
\r
+\r
+/* A player took ammo.  This is called before player_use.*/\r
+public ammo_pickup_callback(Handle:event, const String:name[], bool:dontBroadcast) {\r
+  /* Remember how many times the ammo was used. */\r
+  new count = GetConVarInt(despawn_ammo);\r
+  if (! count) return;\r
+\r
+  new userid = GetEventInt(event, "userid");\r
+\r
+  grabbed_ammo[userid] = 1;\r
+}\r
+\r
+/* Cheap hash-alike. */\r
+public int:get_ammo_index(int:entity) {\r
+  new i;\r
+  new count;\r
+  for (i = 0; i < NUM_AMMO_ENTITIES; i++) {\r
+    if (ammo_entities[i] == entity) return i;\r
+    else if (ammo_entities[i]) count++;\r
+  }\r
+\r
+  /* Is the array full? */\r
+  if (count >= NUM_AMMO_ENTITIES) {\r
+    return -1;\r
+  }\r
+\r
+  /* Add this index. */\r
+  for (i = 0; i < NUM_AMMO_ENTITIES; i++) {\r
+    if (ammo_entities[i]) continue;\r
+    ammo_entities[i] = entity;\r
+    return i;\r
+  }\r
+\r
+  /* Compiler food.  We shouldn't get here. */\r
+  return -1;\r
+}\r
+\r
 public OnMapStart() {\r
+  /* Zero out the ammo counts. */\r
+  new i;\r
+  for (i = 0; i < NUM_AMMO_ENTITIES; i++) {\r
+    ammo_entities[i] = 0;\r
+    ammo_counts[i] = 0;\r
+  }\r
 }\r
 \r
 public OnMapEnd() {\r