summaryrefslogtreecommitdiff
path: root/src/game/bg_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/bg_misc.c')
-rw-r--r--src/game/bg_misc.c1709
1 files changed, 1709 insertions, 0 deletions
diff --git a/src/game/bg_misc.c b/src/game/bg_misc.c
new file mode 100644
index 00000000..130ff0d8
--- /dev/null
+++ b/src/game/bg_misc.c
@@ -0,0 +1,1709 @@
+// Copyright (C) 1999-2000 Id Software, Inc.
+//
+// bg_misc.c -- both games misc functions, all completely stateless
+
+/*
+ * Portions Copyright (C) 2000-2001 Tim Angus
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* To assertain which portions are licensed under the GPL and which are
+ * licensed by Id Software, Inc. please run a diff between the equivalent
+ * versions of the "Tremulous" modification and the unmodified "Quake3"
+ * game source code.
+ */
+
+#include "q_shared.h"
+#include "bg_public.h"
+
+/*QUAKED item_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended
+DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION.
+The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface.
+
+If an item is the target of another entity, it will not spawn in until fired.
+
+An item fires all of its targets when it is picked up. If the toucher can't carry it, the targets won't be fired.
+
+"notfree" if set to 1, don't spawn in free for all games
+"notteam" if set to 1, don't spawn in team games
+"notsingle" if set to 1, don't spawn in single player games
+"wait" override the default wait before respawning. -1 = never respawn automatically, which can be used with targeted spawning.
+"random" random number of plus or minus seconds varied from the respawn time
+"count" override quantity or duration on most items.
+*/
+
+gitem_t bg_itemlist[] =
+{
+ {
+ NULL,
+ NULL,
+ { NULL,
+ NULL,
+ 0, 0} ,
+/* icon */ NULL,
+/* pickup */ NULL,
+ 0,
+ 0,
+ 0,
+/* precache */ "",
+/* sounds */ ""
+ }, // leave index 0 alone
+
+ //
+ // ARMOR
+ //
+
+/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_armor_shard",
+ "sound/misc/ar1_pkup.wav",
+ { "models/powerups/armor/shard.md3",
+ "models/powerups/armor/shard_sphere.md3",
+ 0, 0} ,
+ "icons/iconr_shard",
+ "Armor Shard",
+ 5,
+ IT_ARMOR,
+ 0,
+ "",
+ ""
+ },*/
+
+/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_armor_combat",
+ "sound/misc/ar2_pkup.wav",
+ { "models/powerups/armor/armor_yel.md3",
+ 0, 0, 0},
+ "icons/iconr_yellow",
+ "Armor",
+ 50,
+ IT_ARMOR,
+ 0,
+ "",
+ ""
+ },*/
+
+/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_armor_body",
+ "sound/misc/ar3_pkup.wav",
+ { "models/powerups/armor/armor_red.md3",
+ 0, 0, 0},
+ "icons/iconr_red",
+ "Heavy Armor",
+ 100,
+ IT_ARMOR,
+ 0,
+ "",
+ ""
+ },*/
+
+ //
+ // health
+ //
+/*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_health_small",
+ "sound/items/s_health.wav",
+ { "models/powerups/health/small_cross.md3",
+ "models/powerups/health/small_sphere.md3",
+ 0, 0 },
+ "icons/iconh_green",
+ "5 Health",
+ 5,
+ IT_HEALTH,
+ 0,
+ "",
+ ""
+ },*/
+
+/*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_health",
+ "sound/items/n_health.wav",
+ { "models/powerups/health/medium_cross.md3",
+ "models/powerups/health/medium_sphere.md3",
+ 0, 0 },
+ "icons/iconh_yellow",
+ "25 Health",
+ 25,
+ IT_HEALTH,
+ 0,
+ "",
+ ""
+ },*/
+
+/*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_health_large",
+ "sound/items/l_health.wav",
+ { "models/powerups/health/large_cross.md3",
+ "models/powerups/health/large_sphere.md3",
+ 0, 0 },
+ "icons/iconh_red",
+ "50 Health",
+ 50,
+ IT_HEALTH,
+ 0,
+ "",
+ ""
+ },*/
+
+/*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_health_mega",
+ "sound/items/m_health.wav",
+ { "models/powerups/health/mega_cross.md3",
+ "models/powerups/health/mega_sphere.md3",
+ 0, 0 },
+ "icons/iconh_mega",
+ "Mega Health",
+ 100,
+ IT_HEALTH,
+ 0,
+ "",
+ ""
+ },*/
+
+
+ //
+ // WEAPONS
+ //
+
+/*QUAKED weapon_gauntlet (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+
+//TA:FIXME: must keep gauntlet and machinegun for now or bots have a fit and prevent game working
+
+ {
+ "weapon_gauntlet",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/gauntlet/gauntlet.md3",
+ 0, 0, 0},
+ "icons/iconw_gauntlet",
+ "Gauntlet",
+ 0,
+ IT_WEAPON,
+ WP_GAUNTLET,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_venom (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_venom",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/gauntlet/gauntlet.md3",
+ 0, 0, 0},
+ "icons/iconw_gauntlet",
+ "Venom",
+ 0,
+ IT_WEAPON,
+ WP_VENOM,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_abuild (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_abuild",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/gauntlet/gauntlet.md3",
+ 0, 0, 0},
+ "icons/iconw_gauntlet",
+ "ABuild",
+ 0,
+ IT_WEAPON,
+ WP_ABUILD,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_hbuild (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_hbuild",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/gauntlet/gauntlet.md3",
+ 0, 0, 0},
+ "icons/iconw_gauntlet",
+ "HBuild",
+ 0,
+ IT_WEAPON,
+ WP_HBUILD,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_scanner (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_scanner",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/shotgun/shotgun.md3",
+ 0, 0, 0},
+ "icons/iconw_shotgun",
+ "Scanner",
+ 0,
+ IT_WEAPON,
+ WP_SCANNER,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "weapon_shotgun",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/shotgun/shotgun.md3",
+ 0, 0, 0},
+ "icons/iconw_shotgun",
+ "Shotgun",
+ 10,
+ IT_WEAPON,
+ WP_SHOTGUN,
+ "",
+ ""
+ },*/
+
+/*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_machinegun",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/machinegun/machinegun.md3",
+ 0, 0, 0},
+ "icons/iconw_machinegun",
+ "Machinegun",
+ 40,
+ IT_WEAPON,
+ WP_MACHINEGUN,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_chaingun",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/machinegun/machinegun.md3",
+ 0, 0, 0},
+ "icons/iconw_machinegun",
+ "Chaingun",
+ 40,
+ IT_WEAPON,
+ WP_CHAINGUN,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_ggrenade (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_ggrenade",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/gauntlet/gauntlet.md3",
+ 0, 0, 0},
+ "icons/iconw_gauntlet",
+ "Gas Grenade",
+ 0,
+ IT_WEAPON,
+ WP_GGRENADE,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "weapon_grenadelauncher",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/grenadel/grenadel.md3",
+ 0, 0, 0},
+ "icons/iconw_grenade",
+ "Grenade Launcher",
+ 10,
+ IT_WEAPON,
+ WP_GRENADE_LAUNCHER,
+ "",
+ "sound/weapons/grenade/hgrenb1a.wav sound/weapons/grenade/hgrenb2a.wav"
+ },*/
+
+/*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "weapon_rocketlauncher",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/rocketl/rocketl.md3",
+ 0, 0, 0},
+ "icons/iconw_rocket",
+ "Rocket Launcher",
+ 10,
+ IT_WEAPON,
+ WP_ROCKET_LAUNCHER,
+ "",
+ ""
+ },*/
+
+/*QUAKED weapon_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "weapon_lightning",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/lightning/lightning.md3",
+ 0, 0, 0},
+ "icons/iconw_lightning",
+ "Lightning Gun",
+ 100,
+ IT_WEAPON,
+ WP_LIGHTNING,
+ "",
+ ""
+ },*/
+
+/*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "weapon_railgun",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/railgun/railgun.md3",
+ 0, 0, 0},
+ "icons/iconw_railgun",
+ "Railgun",
+ 10,
+ IT_WEAPON,
+ WP_RAILGUN,
+ "",
+ ""
+ },*/
+
+/*QUAKED weapon_plasmagun (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_plasmagun",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/plasma/plasma.md3",
+ 0, 0, 0},
+ "icons/iconw_plasma",
+ "Plasma Gun",
+ 50,
+ IT_WEAPON,
+ WP_PLASMAGUN,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_flamer (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_flamer",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/plasma/plasma.md3",
+ 0, 0, 0},
+ "icons/iconw_plasma",
+ "Flame Thrower",
+ 50,
+ IT_WEAPON,
+ WP_FLAMER,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ {
+ "weapon_bfg",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/bfg/bfg.md3",
+ 0, 0, 0},
+ "icons/iconw_bfg",
+ "Dual BFG",
+ 0,
+ IT_WEAPON,
+ WP_BFG,
+ "",
+ ""
+ },
+
+/*QUAKED weapon_grapplinghook (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "weapon_grapplinghook",
+ "sound/misc/w_pkup.wav",
+ { "models/weapons2/grapple/grapple.md3",
+ 0, 0, 0},
+ "icons/iconw_grapple",
+ "Grappling Hook",
+ 0,
+ IT_WEAPON,
+ WP_GRAPPLING_HOOK,
+ "",
+ ""
+ },*/
+
+ //
+ // AMMO ITEMS
+ //
+
+/*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_shells",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/shotgunam.md3",
+ 0, 0, 0},
+ "icons/icona_shotgun",
+ "Shells",
+ 10,
+ IT_AMMO,
+ WP_SHOTGUN,
+ "",
+ ""
+ },*/
+
+/*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_bullets",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/machinegunam.md3",
+ 0, 0, 0},
+ "icons/icona_machinegun",
+ "Bullets",
+ 50,
+ IT_AMMO,
+ WP_MACHINEGUN,
+ "",
+ ""
+ },*/
+
+/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_grenades",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/grenadeam.md3",
+ 0, 0, 0},
+ "icons/icona_grenade",
+ "Grenades",
+ 5,
+ IT_AMMO,
+ WP_GRENADE_LAUNCHER,
+ "",
+ ""
+ },*/
+
+/*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_cells",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/plasmaam.md3",
+ 0, 0, 0},
+ "icons/icona_plasma",
+ "Cells",
+ 30,
+ IT_AMMO,
+ WP_PLASMAGUN,
+ "",
+ ""
+ },*/
+
+/*QUAKED ammo_lightning (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_lightning",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/lightningam.md3",
+ 0, 0, 0},
+ "icons/icona_lightning",
+ "Lightning",
+ 60,
+ IT_AMMO,
+ WP_LIGHTNING,
+ "",
+ ""
+ },*/
+
+/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_rockets",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/rocketam.md3",
+ 0, 0, 0},
+ "icons/icona_rocket",
+ "Rockets",
+ 5,
+ IT_AMMO,
+ WP_ROCKET_LAUNCHER,
+ "",
+ ""
+ },*/
+
+/*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_slugs",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/railgunam.md3",
+ 0, 0, 0},
+ "icons/icona_railgun",
+ "Slugs",
+ 10,
+ IT_AMMO,
+ WP_RAILGUN,
+ "",
+ ""
+ },*/
+
+/*QUAKED ammo_bfg (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "ammo_bfg",
+ "sound/misc/am_pkup.wav",
+ { "models/powerups/ammo/bfgam.md3",
+ 0, 0, 0},
+ "icons/icona_bfg",
+ "Bfg Ammo",
+ 15,
+ IT_AMMO,
+ WP_BFG,
+ "",
+ ""
+ },*/
+
+ //
+ // HOLDABLE ITEMS
+ //
+/*QUAKED holdable_teleporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "holdable_teleporter",
+ "sound/items/holdable.wav",
+ { "models/powerups/holdable/teleporter.md3",
+ 0, 0, 0},
+ "icons/teleporter",
+ "Personal Teleporter",
+ 60,
+ IT_HOLDABLE,
+ HI_TELEPORTER,
+ "",
+ ""
+ },*/
+
+/*QUAKED holdable_medkit (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "holdable_medkit",
+ "sound/items/holdable.wav",
+ { "models/powerups/holdable/medkit.md3",
+ "models/powerups/holdable/medkit_sphere.md3",
+ 0, 0},
+ "icons/medkit",
+ "Medkit",
+ 60,
+ IT_HOLDABLE,
+ HI_MEDKIT,
+ "",
+ "sound/items/use_medkit.wav"
+ },*/
+
+ //
+ // POWERUP ITEMS
+ //
+/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_quad",
+ "sound/items/quaddamage.wav",
+ { "models/powerups/instant/quad.md3",
+ "models/powerups/instant/quad_ring.md3",
+ 0, 0 },
+ "icons/quad",
+ "Quad Damage",
+ 30,
+ IT_POWERUP,
+ PW_QUAD,
+ "",
+ "sound/items/damage2.wav sound/items/damage3.wav"
+ },*/
+
+/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_enviro",
+ "sound/items/protect.wav",
+ { "models/powerups/instant/enviro.md3",
+ "models/powerups/instant/enviro_ring.md3",
+ 0, 0 },
+ "icons/envirosuit",
+ "Battle Suit",
+ 30,
+ IT_POWERUP,
+ PW_BATTLESUIT,
+ "",
+ "sound/items/airout.wav sound/items/protect3.wav"
+ },*/
+
+/*QUAKED item_haste (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_haste",
+ "sound/items/haste.wav",
+ { "models/powerups/instant/haste.md3",
+ "models/powerups/instant/haste_ring.md3",
+ 0, 0 },
+ "icons/haste",
+ "Speed",
+ 30,
+ IT_POWERUP,
+ PW_HASTE,
+ "",
+ ""
+ },*/
+
+/*QUAKED item_invis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_invis",
+ "sound/items/invisibility.wav",
+ { "models/powerups/instant/invis.md3",
+ "models/powerups/instant/invis_ring.md3",
+ 0, 0 },
+ "icons/invis",
+ "Invisibility",
+ 30,
+ IT_POWERUP,
+ PW_INVIS,
+ "",
+ ""
+ },*/
+
+/*QUAKED item_regen (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_regen",
+ "sound/items/regeneration.wav",
+ { "models/powerups/instant/regen.md3",
+ "models/powerups/instant/regen_ring.md3",
+ 0, 0 },
+ "icons/regen",
+ "Regeneration",
+ 30,
+ IT_POWERUP,
+ PW_REGEN,
+ "",
+ "sound/items/regen.wav"
+ },*/
+
+/*QUAKED item_flight (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
+*/
+ /*{
+ "item_flight",
+ "sound/items/flight.wav",
+ { "models/powerups/instant/flight.md3",
+ "models/powerups/instant/flight_ring.md3",
+ 0, 0 },
+ "icons/flight",
+ "Flight",
+ 60,
+ IT_POWERUP,
+ PW_FLIGHT,
+ "",
+ "sound/items/flight.wav"
+ },*/
+
+/*QUAKED team_droid_spawn (0 0 1) (-16 -16 -16) (16 16 16)
+TA: droid spawn item
+*/
+ {
+ "team_droid_spawn",
+ "sound/items/holdable.wav",
+ { "models/bitems/aspawn.md3", 0, 0, 0 },
+ "icons/teleporter", //icon
+ "Droid Spawn", //pickup
+ 0,
+ IT_BUILDABLE,
+ BA_A_SPAWN,
+ "", //precache
+ "" //sounds
+ },
+
+/*QUAKED team_droid_def1 (0 0 1) (-16 -16 -16) (16 16 16)
+TA: droid defense item
+*/
+ {
+ "team_droid_def1",
+ "sound/items/holdable.wav",
+ { "models/bitems/adef1.md3", 0, 0, 0 },
+ "icons/teleporter", //icon
+ "Droid Defense", //pickup
+ 0,
+ IT_BUILDABLE,
+ BA_A_DEF1,
+ "", //precache
+ "" //sounds
+ },
+
+/*QUAKED team_human_spawn (0 0 1) (-16 -16 -16) (16 16 16)
+TA: human spawn item
+*/
+ {
+ "team_human_spawn",
+ "sound/items/holdable.wav",
+ { "models/bitems/hspawn.md3", 0, 0, 0 },
+ "icons/teleporter", //icon
+ "Human Spawn", //pickup
+ 0,
+ IT_BUILDABLE,
+ BA_H_SPAWN,
+ "", //precache
+ "" //sounds
+ },
+
+/*QUAKED team_human_def1 (0 0 1) (-16 -16 -16) (16 16 16)
+TA: human defense item
+*/
+ {
+ "team_human_def1",
+ "sound/items/holdable.wav",
+ { "models/bitems/turret-base.md3", "models/bitems/turret-top.md3", 0, 0 },
+ "icons/teleporter", //icon
+ "Human Defense", //pickup
+ 0,
+ IT_BUILDABLE,
+ BA_H_DEF1,
+ "", //precache
+ "" //sounds
+ },
+
+/*QUAKED team_human_mcu (0 0 1) (-16 -16 -16) (16 16 16)
+TA: human defense item
+*/
+ {
+ "team_human_mcu",
+ "sound/items/holdable.wav",
+ { "models/bitems/adef1.md3", 0, 0, 0 },
+ "icons/teleporter", //icon
+ "Human MCU", //pickup
+ 0,
+ IT_BUILDABLE,
+ BA_H_MCU,
+ "", //precache
+ "" //sounds
+ },
+
+/*QUAKED upgrade_torch (0 0 1) (-16 -16 -16) (16 16 16)
+*/
+ {
+ "upgrade_torch",
+ "sound/items/holdable.wav",
+ { 0, 0, 0, 0 },
+ "icons/teleporter", //icon
+ "Torch", //pickup
+ 0,
+ IT_UPGRADE,
+ UP_TORCH,
+ "", //precache
+ "" //sounds
+ },
+
+/*QUAKED upgrade_nvg (0 0 1) (-16 -16 -16) (16 16 16)
+*/
+ {
+ "upgrade_nvg",
+ "sound/items/holdable.wav",
+ { 0, 0, 0, 0 },
+ "icons/teleporter", //icon
+ "NVG", //pickup
+ 0,
+ IT_UPGRADE,
+ UP_NVG,
+ "", //precache
+ "" //sounds
+ },
+
+/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16)
+Only in CTF games
+*/
+ /*{
+ "team_CTF_redflag",
+ "sound/teamplay/flagtk_red.wav",
+ { "models/flags/r_flag.md3",
+ 0, 0, 0 },
+ "icons/iconf_red1",
+ "Red Flag",
+ 0,
+ IT_TEAM,
+ PW_REDFLAG,
+ "",
+ "sound/teamplay/flagcap_red.wav sound/teamplay/flagtk_red.wav sound/teamplay/flagret_red.wav"
+ },*/
+
+/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16)
+Only in CTF games
+*/
+ /*{
+ "team_CTF_blueflag",
+ "sound/teamplay/flagtk_blu.wav",
+ { "models/flags/b_flag.md3",
+ 0, 0, 0 },
+ "icons/iconf_blu1",
+ "Blue Flag",
+ 0,
+ IT_TEAM,
+ PW_BLUEFLAG,
+ "",
+ "sound/teamplay/flagcap_blu.wav sound/teamplay/flagtk_blu.wav sound/teamplay/flagret_blu.wav"
+ },*/
+
+ // end of list marker
+ {NULL}
+};
+
+int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1;
+
+
+/*
+==============
+BG_FindItemForPowerup
+==============
+*/
+gitem_t *BG_FindItemForPowerup( powerup_t pw ) {
+ int i;
+
+ for ( i = 0 ; i < bg_numItems ; i++ ) {
+ if ( (bg_itemlist[i].giType == IT_POWERUP /*||
+ bg_itemlist[i].giType == IT_TEAM ||
+ bg_itemlist[i].giType == IT_PERSISTANT_POWERUP*/) &&
+ bg_itemlist[i].giTag == pw ) {
+ return &bg_itemlist[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+/*
+==============
+BG_FindItemForHoldable
+==============
+*/
+gitem_t *BG_FindItemForHoldable( holdable_t pw ) {
+ int i;
+
+ for ( i = 0 ; i < bg_numItems ; i++ ) {
+ if ( bg_itemlist[i].giType == IT_HOLDABLE && bg_itemlist[i].giTag == pw ) {
+ return &bg_itemlist[i];
+ }
+ }
+
+ Com_Error( ERR_DROP, "HoldableItem not found" );
+
+ return NULL;
+}
+
+
+/*
+===============
+BG_FindItemForWeapon
+
+===============
+*/
+gitem_t *BG_FindItemForWeapon( weapon_t weapon ) {
+ gitem_t *it;
+
+ for ( it = bg_itemlist + 1 ; it->classname ; it++) {
+ if ( it->giType == IT_WEAPON && it->giTag == weapon ) {
+ return it;
+ }
+ }
+
+ Com_Error( ERR_DROP, "Couldn't find item for weapon %i", weapon);
+ return NULL;
+}
+
+
+/*
+===============
+BG_FindItemForBuildable
+
+TA: new function for finding buildable items
+===============
+*/
+gitem_t *BG_FindItemForBuildable( buildable_t buildable ) {
+ gitem_t *it;
+
+ for ( it = bg_itemlist + 1 ; it->classname ; it++) {
+ if ( it->giType == IT_BUILDABLE && it->giTag == buildable ) {
+ return it;
+ }
+ }
+
+ Com_Error( ERR_DROP, "Couldn't find item for buildable %i", buildable);
+ return NULL;
+}
+
+
+/*
+===============
+BG_FindItemForUpgrade
+
+TA: new function for finding upgrade items
+===============
+*/
+gitem_t *BG_FindItemForUpgrade( upgrade_t upgrade ) {
+ gitem_t *it;
+
+ for ( it = bg_itemlist + 1 ; it->classname ; it++) {
+ if ( it->giType == IT_UPGRADE && it->giTag == upgrade ) {
+ return it;
+ }
+ }
+
+ Com_Error( ERR_DROP, "Couldn't find item for upgrade %i", upgrade);
+ return NULL;
+}
+
+
+/*
+===============
+BG_FindItem
+
+===============
+*/
+gitem_t *BG_FindItem( const char *pickupName ) {
+ gitem_t *it;
+
+ for ( it = bg_itemlist + 1 ; it->classname ; it++ ) {
+ if ( !Q_stricmp( it->pickup_name, pickupName ) )
+ return it;
+ }
+
+ return NULL;
+}
+
+/*
+============
+BG_PlayerTouchesItem
+
+Items can be picked up without actually touching their physical bounds to make
+grabbing them easier
+============
+*/
+qboolean BG_PlayerTouchesItem( playerState_t *ps, entityState_t *item, int atTime ) {
+ vec3_t origin;
+
+ BG_EvaluateTrajectory( &item->pos, atTime, origin );
+
+ // we are ignoring ducked differences here
+ if ( ps->origin[0] - origin[0] > 44
+ || ps->origin[0] - origin[0] < -50
+ || ps->origin[1] - origin[1] > 36
+ || ps->origin[1] - origin[1] < -36
+ || ps->origin[2] - origin[2] > 36
+ || ps->origin[2] - origin[2] < -36 ) {
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+/*
+================
+BG_CanItemBeGrabbed
+
+Returns false if the item should not be picked up.
+This needs to be the same for client side prediction and server use.
+================
+*/
+qboolean BG_CanItemBeGrabbed( int gametype, const entityState_t *ent, const playerState_t *ps ) {
+ gitem_t *item;
+
+ if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) {
+ Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" );
+ }
+
+ item = &bg_itemlist[ent->modelindex];
+
+ switch( item->giType ) {
+ case IT_WEAPON:
+ return qtrue; // weapons are always picked up
+
+ case IT_AMMO:
+ if ( ps->ammo[ item->giTag ] >= 200 ) {
+ return qfalse; // can't hold any more
+ }
+ return qtrue;
+
+ case IT_ARMOR:
+ if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
+ return qfalse;
+ }
+ return qtrue;
+
+ case IT_HEALTH:
+ // small and mega healths will go over the max, otherwise
+ // don't pick up if already at max
+ if ( item->quantity == 5 || item->quantity == 100 ) {
+ if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] * 2 ) {
+ return qfalse;
+ }
+ return qtrue;
+ }
+
+ if ( ps->stats[STAT_HEALTH] >= ps->stats[STAT_MAX_HEALTH] ) {
+ return qfalse;
+ }
+ return qtrue;
+
+ case IT_POWERUP:
+ return qtrue; // powerups are always picked up
+
+ case IT_TEAM: // team items, such as flags
+ // ent->modelindex2 is non-zero on items if they are dropped
+ // we need to know this because we can pick up our dropped flag (and return it)
+ // but we can't pick up our flag at base
+ if (ps->persistant[PERS_TEAM] == TEAM_HUMANS) {
+ //TA: remove powerups
+ /*if (item->giTag == PW_BLUEFLAG ||
+ (item->giTag == PW_REDFLAG && ent->modelindex2) ||
+ (item->giTag == PW_REDFLAG && ps->powerups[PW_BLUEFLAG]))
+ return qtrue;*/
+ } else if (ps->persistant[PERS_TEAM] == TEAM_DROIDS) {
+ /*if (item->giTag == PW_REDFLAG ||
+ (item->giTag == PW_BLUEFLAG && ent->modelindex2) ||
+ (item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG]))
+ return qtrue;*/
+ }
+ return qfalse;
+
+ //TA: not using the q3 holdable items code
+ /*case IT_HOLDABLE:
+ // can only hold one item at a time
+ if ( ps->stats[STAT_HOLDABLE_ITEM] ) {
+ return qfalse;
+ }
+ return qtrue;*/
+
+ case IT_BAD:
+ Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" );
+ }
+
+ return qfalse;
+}
+
+//======================================================================
+
+/*
+================
+BG_EvaluateTrajectory
+
+================
+*/
+void BG_EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) {
+ float deltaTime;
+ float phase;
+
+ switch( tr->trType ) {
+ case TR_STATIONARY:
+ case TR_INTERPOLATE:
+ VectorCopy( tr->trBase, result );
+ break;
+ case TR_LINEAR:
+ deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
+ VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
+ break;
+ case TR_SINE:
+ deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;
+ phase = sin( deltaTime * M_PI * 2 );
+ VectorMA( tr->trBase, phase, tr->trDelta, result );
+ break;
+ case TR_LINEAR_STOP:
+ if ( atTime > tr->trTime + tr->trDuration ) {
+ atTime = tr->trTime + tr->trDuration;
+ }
+ deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
+ if ( deltaTime < 0 ) {
+ deltaTime = 0;
+ }
+ VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
+ break;
+ case TR_GRAVITY:
+ deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
+ VectorMA( tr->trBase, deltaTime, tr->trDelta, result );
+ result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity...
+ break;
+ default:
+ Com_Error( ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime );
+ break;
+ }
+}
+
+/*
+================
+BG_EvaluateTrajectoryDelta
+
+For determining velocity at a given time
+================
+*/
+void BG_EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) {
+ float deltaTime;
+ float phase;
+
+ switch( tr->trType ) {
+ case TR_STATIONARY:
+ case TR_INTERPOLATE:
+ VectorClear( result );
+ break;
+ case TR_LINEAR:
+ VectorCopy( tr->trDelta, result );
+ break;
+ case TR_SINE:
+ deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration;
+ phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos
+ phase *= 0.5;
+ VectorScale( tr->trDelta, phase, result );
+ break;
+ case TR_LINEAR_STOP:
+ if ( atTime > tr->trTime + tr->trDuration ) {
+ VectorClear( result );
+ return;
+ }
+ VectorCopy( tr->trDelta, result );
+ break;
+ case TR_GRAVITY:
+ deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds
+ VectorCopy( tr->trDelta, result );
+ result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity...
+ break;
+ default:
+ Com_Error( ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime );
+ break;
+ }
+}
+
+char *eventnames[] = {
+ "EV_NONE",
+
+ "EV_FOOTSTEP",
+ "EV_FOOTSTEP_METAL",
+ "EV_FOOTSPLASH",
+ "EV_FOOTWADE",
+ "EV_SWIM",
+
+ "EV_STEP_4",
+ "EV_STEP_8",
+ "EV_STEP_12",
+ "EV_STEP_16",
+
+ "EV_FALL_SHORT",
+ "EV_FALL_MEDIUM",
+ "EV_FALL_FAR",
+
+ "EV_JUMP_PAD", // boing sound at origin", jump sound on player
+
+ "EV_JUMP",
+ "EV_WATER_TOUCH", // foot touches
+ "EV_WATER_LEAVE", // foot leaves
+ "EV_WATER_UNDER", // head touches
+ "EV_WATER_CLEAR", // head leaves
+
+ "EV_ITEM_PICKUP", // normal item pickups are predictable
+ "EV_GLOBAL_ITEM_PICKUP", // powerup / team sounds are broadcast to everyone
+
+ "EV_NOAMMO",
+ "EV_CHANGE_WEAPON",
+ "EV_FIRE_WEAPON",
+
+ "EV_USE_ITEM0",
+ "EV_USE_ITEM1",
+ "EV_USE_ITEM2",
+ "EV_USE_ITEM3",
+ "EV_USE_ITEM4",
+ "EV_USE_ITEM5",
+ "EV_USE_ITEM6",
+ "EV_USE_ITEM7",
+ "EV_USE_ITEM8",
+ "EV_USE_ITEM9",
+ "EV_USE_ITEM10",
+ "EV_USE_ITEM11",
+ "EV_USE_ITEM12",
+ "EV_USE_ITEM13",
+ "EV_USE_ITEM14",
+ "EV_USE_ITEM15",
+
+ "EV_ITEM_RESPAWN",
+ "EV_ITEM_POP",
+ "EV_PLAYER_TELEPORT_IN",
+ "EV_PLAYER_TELEPORT_OUT",
+
+ "EV_GRENADE_BOUNCE", // eventParm will be the soundindex
+
+ "EV_GENERAL_SOUND",
+ "EV_GLOBAL_SOUND", // no attenuation
+ "EV_GLOBAL_TEAM_SOUND",
+
+ "EV_BULLET_HIT_FLESH",
+ "EV_BULLET_HIT_WALL",
+
+ "EV_MISSILE_HIT",
+ "EV_MISSILE_MISS",
+ "EV_MISSILE_MISS_METAL",
+ "EV_RAILTRAIL",
+ "EV_SHOTGUN",
+ "EV_BULLET", // otherEntity is the shooter
+
+ "EV_PAIN",
+ "EV_DEATH1",
+ "EV_DEATH2",
+ "EV_DEATH3",
+ "EV_OBITUARY",
+
+ "EV_POWERUP_QUAD",
+ "EV_POWERUP_BATTLESUIT",
+ "EV_POWERUP_REGEN",
+
+ "EV_GIB_PLAYER", // gib a previously living player
+ "EV_SCOREPLUM", // score plum
+
+//#ifdef MISSIONPACK
+ "EV_PROXIMITY_MINE_STICK",
+ "EV_PROXIMITY_MINE_TRIGGER",
+ "EV_KAMIKAZE", // kamikaze explodes
+ "EV_OBELISKEXPLODE", // obelisk explodes
+ "EV_INVUL_IMPACT", // invulnerability sphere impact
+ "EV_JUICED", // invulnerability juiced effect
+ "EV_LIGHTNINGBOLT", // lightning bolt bounced of invulnerability sphere
+//#endif
+
+ "EV_DEBUG_LINE",
+ "EV_STOPLOOPINGSOUND",
+ "EV_TAUNT"
+
+};
+
+/*
+===============
+BG_AddPredictableEventToPlayerstate
+
+Handles the sequence numbers
+===============
+*/
+
+void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
+
+void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) {
+#ifdef _DEBUG
+ {
+ char buf[256];
+ trap_Cvar_VariableStringBuffer("showevents", buf, sizeof(buf));
+ if ( atof(buf) != 0 ) {
+#ifdef QAGAME
+ Com_Printf(" game event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);
+#else
+ Com_Printf("Cgame event svt %5d -> %5d: num = %20s parm %d\n", ps->pmove_framecount/*ps->commandTime*/, ps->eventSequence, eventnames[newEvent], eventParm);
+#endif
+ }
+ }
+#endif
+ ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent;
+ ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm;
+ ps->eventSequence++;
+}
+
+
+/*
+========================
+BG_TouchJumpPad
+========================
+*/
+void BG_TouchJumpPad( playerState_t *ps, entityState_t *jumppad ) {
+ vec3_t angles;
+ float p;
+ int effectNum;
+
+ // spectators don't use jump pads
+ if ( ps->pm_type != PM_NORMAL ) {
+ return;
+ }
+
+ // flying characters don't hit bounce pads
+ if ( ps->powerups[PW_FLIGHT] ) {
+ return;
+ }
+
+ // if we didn't hit this same jumppad the previous frame
+ // then don't play the event sound again if we are in a fat trigger
+ if ( ps->jumppad_ent != jumppad->number ) {
+
+ vectoangles( jumppad->origin2, angles);
+ p = fabs( AngleNormalize180( angles[PITCH] ) );
+ if( p < 45 ) {
+ effectNum = 0;
+ } else {
+ effectNum = 1;
+ }
+ BG_AddPredictableEventToPlayerstate( EV_JUMP_PAD, effectNum, ps );
+ }
+ // remember hitting this jumppad this frame
+ ps->jumppad_ent = jumppad->number;
+ ps->jumppad_frame = ps->pmove_framecount;
+ // give the player the velocity from the jumppad
+ VectorCopy( jumppad->origin2, ps->velocity );
+}
+
+
+/*
+========================
+BG_PlayerStateToEntityState
+
+This is done after each set of usercmd_t on the server,
+and after local prediction on the client
+========================
+*/
+void BG_PlayerStateToEntityState( playerState_t *ps, entityState_t *s, qboolean snap ) {
+ int i;
+ vec3_t ceilingNormal = { 0, 0, -1 };
+
+ if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {
+ s->eType = ET_INVISIBLE;
+ } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
+ s->eType = ET_INVISIBLE;
+ } else {
+ s->eType = ET_PLAYER;
+ }
+
+ s->number = ps->clientNum;
+
+ s->pos.trType = TR_INTERPOLATE;
+ VectorCopy( ps->origin, s->pos.trBase );
+ if ( snap ) {
+ SnapVector( s->pos.trBase );
+ }
+ //set the trDelta for flag direction
+ VectorCopy( ps->velocity, s->pos.trDelta );
+
+ s->apos.trType = TR_INTERPOLATE;
+ VectorCopy( ps->viewangles, s->apos.trBase );
+ if ( snap ) {
+ SnapVector( s->apos.trBase );
+ }
+
+ //TA: i need for other things :)
+ //s->angles2[YAW] = ps->movementDir;
+ s->time2 = ps->movementDir;
+ s->legsAnim = ps->legsAnim;
+ s->torsoAnim = ps->torsoAnim;
+ s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
+ // so corpses can also reference the proper config
+ s->eFlags = ps->eFlags;
+ if ( ps->stats[STAT_HEALTH] <= 0 ) {
+ s->eFlags |= EF_DEAD;
+ } else {
+ s->eFlags &= ~EF_DEAD;
+ }
+
+ if ( ps->externalEvent ) {
+ s->event = ps->externalEvent;
+ s->eventParm = ps->externalEventParm;
+ } else {
+ int seq;
+
+ if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {
+ ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
+ }
+ seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1);
+ s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
+ s->eventParm = ps->eventParms[ seq ];
+ if ( ps->entityEventSequence < ps->eventSequence ) {
+ ps->entityEventSequence++;
+ }
+ }
+
+ s->weapon = ps->weapon;
+ s->groundEntityNum = ps->groundEntityNum;
+
+ /*s->powerups = 0;
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ if ( ps->powerups[ i ] ) {
+ s->powerups |= 1 << i;
+ }
+ }*/
+
+ //TA: use powerups field to store team/class info:
+ s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 );
+
+ //TA: have to get the surfNormal thru somehow...
+ if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC )
+ {
+ VectorCopy( ceilingNormal, s->angles2 );
+ }
+ else
+ {
+ VectorCopy( ps->grapplePoint, s->angles2 );
+ }
+
+ s->loopSound = ps->loopSound;
+ s->generic1 = ps->generic1;
+}
+
+
+/*
+========================
+BG_PlayerStateToEntityStateExtraPolate
+
+This is done after each set of usercmd_t on the server,
+and after local prediction on the client
+========================
+*/
+void BG_PlayerStateToEntityStateExtraPolate( playerState_t *ps, entityState_t *s, int time, qboolean snap ) {
+ int i;
+ vec3_t ceilingNormal = { 0, 0, -1 };
+
+ if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {
+ s->eType = ET_INVISIBLE;
+ } else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
+ s->eType = ET_INVISIBLE;
+ } else {
+ s->eType = ET_PLAYER;
+ }
+
+ s->number = ps->clientNum;
+
+ s->pos.trType = TR_LINEAR_STOP;
+ VectorCopy( ps->origin, s->pos.trBase );
+ if ( snap ) {
+ SnapVector( s->pos.trBase );
+ }
+ // set the trDelta for flag direction and linear prediction
+ VectorCopy( ps->velocity, s->pos.trDelta );
+ // set the time for linear prediction
+ s->pos.trTime = time;
+ // set maximum extra polation time
+ s->pos.trDuration = 50; // 1000 / sv_fps (default = 20)
+
+ s->apos.trType = TR_INTERPOLATE;
+ VectorCopy( ps->viewangles, s->apos.trBase );
+ if ( snap ) {
+ SnapVector( s->apos.trBase );
+ }
+
+ //TA: i need for other things :)
+ //s->angles2[YAW] = ps->movementDir;
+ s->time2 = ps->movementDir;
+ s->legsAnim = ps->legsAnim;
+ s->torsoAnim = ps->torsoAnim;
+ s->clientNum = ps->clientNum; // ET_PLAYER looks here instead of at number
+ // so corpses can also reference the proper config
+ s->eFlags = ps->eFlags;
+ if ( ps->stats[STAT_HEALTH] <= 0 ) {
+ s->eFlags |= EF_DEAD;
+ } else {
+ s->eFlags &= ~EF_DEAD;
+ }
+
+ if ( ps->externalEvent ) {
+ s->event = ps->externalEvent;
+ s->eventParm = ps->externalEventParm;
+ } else {
+ int seq;
+
+ if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {
+ ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
+ }
+ seq = (ps->entityEventSequence-1) & (MAX_PS_EVENTS-1);
+ s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
+ s->eventParm = ps->eventParms[ seq ];
+ if ( ps->entityEventSequence < ps->eventSequence ) {
+ ps->entityEventSequence++;
+ }
+ }
+
+ s->weapon = ps->weapon;
+ s->groundEntityNum = ps->groundEntityNum;
+
+ /*s->powerups = 0;
+ for ( i = 0 ; i < MAX_POWERUPS ; i++ ) {
+ if ( ps->powerups[ i ] ) {
+ s->powerups |= 1 << i;
+ }
+ }*/
+
+ //TA: use powerups field to store team/class info:
+ s->powerups = ps->stats[ STAT_PTEAM ] | ( ps->stats[ STAT_PCLASS ] << 8 );
+
+ //TA: have to get the surfNormal thru somehow...
+ if( ps->stats[ STAT_STATE ] & SS_GPISROTVEC )
+ {
+ VectorCopy( ceilingNormal, s->angles2 );
+ }
+ else
+ {
+ VectorCopy( ps->grapplePoint, s->angles2 );
+ }
+
+ s->loopSound = ps->loopSound;
+ s->generic1 = ps->generic1;
+}
+
+
+//TA: extract the ammo quantity from the array
+void BG_unpackAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int *quan, int *clips, int *maxclips )
+{
+ int ammoarray[32];
+ int i;
+
+ for( i = 0; i <= 15; i++ )
+ ammoarray[ i ] = ammo[ i ];
+
+ for( i = 16; i <= 31; i++ )
+ ammoarray[ i ] = ammo2[ i - 16 ];
+
+ if( quan != NULL )
+ *quan = ammoarray[ weapon ] & 0x03FF;
+
+ if( clips != NULL )
+ *clips = ( ammoarray[ weapon ] >> 10 ) & 0x07;
+
+ if( maxclips != NULL )
+ *maxclips = ( ammoarray[ weapon ] >> 13 ) & 0x07;
+}
+
+//TA: pack the ammo quantity into the array
+void BG_packAmmoArray( int weapon, int ammo[ ], int ammo2[ ], int quan, int clips, int maxclips )
+{
+ int weaponvalue;
+
+ weaponvalue = quan | ( clips << 10 ) | ( maxclips << 13 );
+
+ if( weapon <= 15 )
+ ammo[ weapon ] = weaponvalue;
+ else if( weapon >= 16 )
+ ammo2[ weapon - 16 ] = weaponvalue;
+}
+
+//TA: check whether infinite ammo
+qboolean BG_infiniteAmmo( int weapon )
+{
+ switch( weapon )
+ {
+ case WP_VENOM:
+ case WP_ABUILD:
+ case WP_HBUILD:
+ case WP_SCANNER:
+ return qtrue;
+ break;
+
+ //nothing else has infinite ammo
+ default:
+ return qfalse;
+ break;
+ }
+}
+
+//TA: pack weapons into the array
+void BG_packWeapon( int weapon, int stats[ ] )
+{
+ int weaponList, i;
+
+ weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 );
+
+ weaponList |= ( 1 << weapon );
+
+ stats[ STAT_WEAPONS ] = weaponList & 0x0000FFFF;
+ stats[ STAT_WEAPONS2 ] = ( weaponList & 0xFFFF0000 ) >> 16;
+
+}
+
+//TA: check whether array contains weapon
+qboolean BG_gotWeapon( int weapon, int stats[ ] )
+{
+ int weaponList, i;
+
+ weaponList = ( stats[ STAT_WEAPONS ] & 0x0000FFFF ) | ( ( stats[ STAT_WEAPONS2 ] << 16 ) & 0xFFFF0000 );
+
+ return( weaponList & ( 1 << weapon ) );
+}
+
+//TA: pack items into array
+void BG_packItem( int item, int stats[ ] )
+{
+ stats[ STAT_ITEMS ] |= ( 1 << item );
+}
+
+//TA: remove items from array
+void BG_removeItem( int item, int stats[ ] )
+{
+ stats[ STAT_ITEMS ] &= ~( 1 << item );
+}
+
+//TA: check if item is in array
+qboolean BG_gotItem( int item, int stats[ ] )
+{
+ return( stats[ STAT_ITEMS ] & ( 1 << item ) );
+}
+
+//TA: set item active in array
+void BG_activateItem( int item, int stats[ ] )
+{
+ stats[ STAT_ACTIVEITEMS ] |= ( 1 << item );
+}
+
+//TA: set item deactive in array
+void BG_deactivateItem( int item, int stats[ ] )
+{
+ stats[ STAT_ACTIVEITEMS ] &= ~( 1 << item );
+}
+
+//TA: check if item active in array
+qboolean BG_activated( int item, int stats[ ] )
+{
+ return( stats[ STAT_ACTIVEITEMS ] & ( 1 << item ) );
+}
+
+//TA: set attributes in array
+void BG_packAttributes( int fov, int bob, int steptime, int stats[ ] )
+{
+ stats[ STAT_ATTRIBS ] = ( ( (int)( (float)fov/10.0 ) & 0x1F ) << 10 ) | ( ( bob & 0x1F ) << 5 ) | ( (int)( (float)steptime/25.0 ) & 0x1F );
+}
+
+//TA: get attributes from array
+void BG_unpackAttributes( int *fov, int *bob, int *steptime, int stats[ ] )
+{
+ if( fov != NULL )
+ *fov = ( ( stats[ STAT_ATTRIBS ] >> 10 ) & 0x1F ) * 10;
+
+ if( bob != NULL )
+ *bob = ( stats[ STAT_ATTRIBS ] >> 5 ) & 0x1F;
+
+ if( steptime != NULL )
+ *steptime = ( stats[ STAT_ATTRIBS ] & 0x1F ) * 25;
+}