mirror of
https://github.com/UberGames/RPG-X2.git
synced 2024-11-28 15:13:11 +00:00
1783 lines
41 KiB
C
1783 lines
41 KiB
C
// Copyright (C) 1999-2000 Id Software, Inc.
|
|
//
|
|
// bg_misc.c -- both games misc functions, all completely stateless
|
|
|
|
#include "q_shared.h"
|
|
#include "bg_public.h"
|
|
|
|
int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode );
|
|
void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
|
|
void trap_FS_FCloseFile( fileHandle_t f );
|
|
void trap_FS_Read( void *buffer, int len, fileHandle_t f );
|
|
|
|
// If you change these: PLEASE CHANGE THE COMMENTS ON THE AMMO PICKUPS, WHICH DETAIL THE QUANTITY IN THE CLIP
|
|
#define AMMO_PHASER_CLIP 50
|
|
#define AMMO_COMPRESSION_CLIP 32
|
|
#define AMMO_IMOD_CLIP 15
|
|
#define AMMO_SCAVENGER_CLIP 30
|
|
#define AMMO_STASIS_CLIP 15
|
|
#define AMMO_GRENADE_CLIP 10
|
|
#define AMMO_TETRION_CLIP 40
|
|
#define AMMO_QUANTUM_CLIP 6
|
|
#define AMMO_DREADNOUGHT_CLIP 40
|
|
|
|
char races[256];
|
|
|
|
int Max_Ammo[WP_NUM_WEAPONS] =
|
|
{
|
|
0, // WP_NONE,
|
|
50, // WP_PHASER, !! this should match PHASER_AMMO_MAX defined in bg_public
|
|
128, // WP_COMPRESSION_RIFLE,
|
|
60, // WP_NULL_HAND,
|
|
100, // WP_COFFEE,
|
|
50, // WP_DISRUPTOR,
|
|
30, // WP_GRENADE_LAUNCHER,
|
|
120, // WP_TR116,
|
|
20, // WP_QUANTUM_BURST,
|
|
50, // WP_DERMAL_REGEN,
|
|
50, // WP_VOYAGER_HYPO,
|
|
50, // WP_TOOLKIT,
|
|
100, // WP_MEDKIT,
|
|
50, // WP_TRICORDER,
|
|
50, // WP_PADD,
|
|
50, // WP_NEUTRINO_PROBE,
|
|
64 // WP_TR116
|
|
|
|
};
|
|
|
|
/*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, //char *classname; // spawning name
|
|
NULL, //char *pickup_sound;
|
|
NULL, //char *world_model;
|
|
NULL, //char *view_model;
|
|
/* icon */ NULL, //char *icon;
|
|
/* pickup */ NULL, //char *pickup_name; // for printing on pickup
|
|
0, //int quantity; // for ammo how much, or duration of powerup
|
|
0, //itemType_t giType; // IT_* flags
|
|
0, //int giTag;
|
|
/* precache */ "", //char *precaches; // string of all models and images this item will use
|
|
/* sounds */ "" //char *sounds; // string of all sounds this item will use
|
|
}, // leave index 0 alone
|
|
|
|
//
|
|
// WEAPONS
|
|
//
|
|
|
|
|
|
/*QUAKED weapon_phaser (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_phaser",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/phaser/phaser_w.md3", //world
|
|
"models/weapons2/phaser/phaser.md3", //view
|
|
/* icon */ "icons/w_icon_phaser",
|
|
/* pickup */ "Phaser",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_PHASER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_compressionrifle (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_compressionrifle",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/prifle/prifle_w.md3", //world
|
|
"models/weapons2/prifle/prifle.md3", //view
|
|
/* icon */ "icons/w_icon_rifle",
|
|
/* pickup */ "Phaser Compression Rifle",
|
|
AMMO_COMPRESSION_CLIP,
|
|
IT_WEAPON,
|
|
WP_COMPRESSION_RIFLE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_imod (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_imod",
|
|
"sound/silence.wav", //"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/hand/hand_w.md3", //"models/weapons2/imod/imod2_w.md3",//world
|
|
"models/weapons2/hand/hand.md3", //"models/weapons2/imod/imod2.md3", //view
|
|
/* icon */ "icons/w_icon_hand",
|
|
/* pickup */ " ",
|
|
AMMO_IMOD_CLIP,
|
|
IT_WEAPON,
|
|
WP_NULL_HAND,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_scavenger (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_scavenger",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/coffeecup/coffeecup_w.md3", //world
|
|
"models/weapons2/coffeecup/coffeecup.md3", //view
|
|
/* icon */ "icons/w_icon_coffee",
|
|
/* pickup */ "Coffee, Black",
|
|
AMMO_SCAVENGER_CLIP,
|
|
IT_WEAPON,
|
|
WP_COFFEE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_stasisweapon (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_stasisweapon",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/alien_disruptor/disruptor_w.md3", //world
|
|
"models/weapons2/alien_disruptor/disruptor.md3", //view
|
|
/* icon */ "icons/w_icon_disruptor",
|
|
/* pickup */ "Disruptor",
|
|
AMMO_STASIS_CLIP,
|
|
IT_WEAPON,
|
|
WP_DISRUPTOR,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_grenadelauncher",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/launcher/launcher_w.md3", //world
|
|
"models/weapons2/launcher/launcher.md3", //view
|
|
/* icon */ "icons/w_icon_grenade",
|
|
/* pickup */ "Compound Grenade Launcher",
|
|
AMMO_GRENADE_CLIP,
|
|
IT_WEAPON,
|
|
WP_GRENADE_LAUNCHER,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/weapons/glauncher/bounce1.wav sound/weapons/glauncher/bounce2.wav"
|
|
},
|
|
|
|
/*QUAKED weapon_tetriondisruptor (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_tetriondisruptor",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/tr116/tr-116_w.md3",//world
|
|
"models/weapons2/tr116/tr-116.md3", //view
|
|
/* icon */ "icons/w_icon_tr116",
|
|
/* pickup */ "TR-116",
|
|
AMMO_TETRION_CLIP,
|
|
IT_WEAPON,
|
|
WP_TR116,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_quantumburst (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_quantumburst",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/q_burst/q_burst_w.md3", //world
|
|
"models/weapons2/q_burst/q_burst.md3", //view
|
|
/* icon */ "icons/w_icon_quantum",
|
|
/* pickup */ "Photon Burst",
|
|
AMMO_QUANTUM_CLIP,
|
|
IT_WEAPON,
|
|
WP_QUANTUM_BURST,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_dreadnought (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_dreadnought",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/dermal_regen/dermal_regen_w.md3",
|
|
"models/weapons2/dermal_regen/dermal_regen.md3",
|
|
/* icon */ "icons/w_icon_dermalregen",
|
|
/* pickup */ "Dermal Regenerator",
|
|
AMMO_DREADNOUGHT_CLIP,
|
|
IT_WEAPON,
|
|
WP_DERMAL_REGEN,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// AMMO ITEMS
|
|
//
|
|
|
|
/*QUAKED ammo_compressionrifle (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
32 ammo for the compression rifle
|
|
*/
|
|
{
|
|
"ammo_compressionrifle",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/prifle_ammo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_phaser_sm",
|
|
/* pickup */ "Phaser Compression Rifle Ammo",
|
|
AMMO_COMPRESSION_CLIP,
|
|
IT_AMMO,
|
|
WP_COMPRESSION_RIFLE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_imod (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
15 ammo for the I-MOD
|
|
*/
|
|
{
|
|
"ammo_imod",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/imod_ammo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_imod",
|
|
/* pickup */ "I-MOD Ammo",
|
|
AMMO_IMOD_CLIP,
|
|
IT_AMMO,
|
|
WP_NULL_HAND,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_scavenger (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
30 ammo for the scavenger rifle
|
|
*/
|
|
{
|
|
"ammo_scavenger",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/scavenger_ammo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_scav",
|
|
/* pickup */ "Scavenger Weapon Ammo",
|
|
AMMO_SCAVENGER_CLIP,
|
|
IT_AMMO,
|
|
WP_COFFEE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_stasis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
15 ammo for the stasis weapon
|
|
*/
|
|
{
|
|
"ammo_stasis",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/stasis_ammo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_stasis_sm",
|
|
/* pickup */ "Stasis Weapon Ammo",
|
|
AMMO_STASIS_CLIP,
|
|
IT_AMMO,
|
|
WP_DISRUPTOR,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
10 ammo for the grenade launcher
|
|
*/
|
|
{
|
|
"ammo_grenades",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/glauncher_ammo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_glauncher_sm",
|
|
/* pickup */ "Compound Grenade Launcher Ammo",
|
|
AMMO_GRENADE_CLIP,
|
|
IT_AMMO,
|
|
WP_GRENADE_LAUNCHER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_tetriondisruptor (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
40 ammo for the tetrYon disruptor
|
|
*/
|
|
{
|
|
"ammo_tetriondisruptor",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/tetrion_ammo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_tetrion_sm",
|
|
/* pickup */ "Tetryon Pulse Disruptor Ammo",
|
|
AMMO_TETRION_CLIP,
|
|
IT_AMMO,
|
|
WP_TR116,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_quantumburst (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
6 ammo for the quantum burst weapon
|
|
*/
|
|
{
|
|
"ammo_quantumburst",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/torpedo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_torpedo_sm",
|
|
/* pickup */ "Photon Burst Ammo",
|
|
AMMO_QUANTUM_CLIP,
|
|
IT_AMMO,
|
|
WP_QUANTUM_BURST,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_dreadnought (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
40 ammo for the dreadnought/arc welder
|
|
*/
|
|
{
|
|
"ammo_dreadnought",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/arc_ammo.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_a_arc_sm",
|
|
/* pickup */ "Dermal Regenerator Ammo",
|
|
AMMO_DREADNOUGHT_CLIP,
|
|
IT_AMMO,
|
|
WP_DERMAL_REGEN,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// ARMOR
|
|
//
|
|
|
|
/*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
5 points of shields
|
|
*/
|
|
{
|
|
"item_armor_shard",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/armor_shard.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/icon_shards",
|
|
/* pickup */ "Incremental Shield Boost",
|
|
5,
|
|
IT_ARMOR,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
50 points of shields
|
|
*/
|
|
{
|
|
"item_armor_combat",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/armor.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_armor_sm",
|
|
/* pickup */ "Personal Deflector Screen",
|
|
50,
|
|
IT_ARMOR,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
100 points of shields
|
|
*/
|
|
{
|
|
"item_armor_body",
|
|
"sound/player/suitenergy.wav",
|
|
"models/powerups/trek/armor2.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_superarmor_sm",
|
|
/* pickup */ "Isokinetic Deflector Screen",
|
|
100,
|
|
IT_ARMOR,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// HEALTH
|
|
//
|
|
|
|
/*QUAKED item_hypo_small (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
5 points of health, max of 200
|
|
*/
|
|
{
|
|
"item_hypo_small",
|
|
"sound/player/pickuphealth.wav",
|
|
"models/powerups/trek/hypo_single.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_health_sm",
|
|
/* pickup */ "Booster Hypospray",
|
|
5,
|
|
IT_HEALTH,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_hypo (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
25 points of health, max of 100
|
|
*/
|
|
{
|
|
"item_hypo",
|
|
"sound/player/suithealth.wav",
|
|
"models/powerups/trek/hypo_double.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_health2_sm",
|
|
/* pickup */ "Emergency Hypospray",
|
|
25,
|
|
IT_HEALTH,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// HOLDABLE ITEMS
|
|
//
|
|
|
|
/*QUAKED holdable_transporter (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
pick it up and it stays in your inventory until used, at which time you drop it in front of you and it still
|
|
kind of resides in your inventory. when you use it _again_ it activates and anyone can walk through the transporter.
|
|
*/
|
|
{
|
|
"holdable_transporter",
|
|
"sound/items/holdable.wav",
|
|
"models/powerups/trek/transporter.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_transport_sm",
|
|
/* pickup */ "Personal Transporter Device",
|
|
60,
|
|
IT_HOLDABLE,
|
|
HI_TRANSPORTER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED holdable_medkit (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
pick it up and it stays in your inventory until used, at which time it sets your health to 100
|
|
*/
|
|
{
|
|
"holdable_medkit",
|
|
"sound/items/holdable.wav",
|
|
"models/powerups/trek/med_kit.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_health3_sm",
|
|
/* pickup */ "Portable Medkit",
|
|
60,
|
|
IT_HOLDABLE,
|
|
HI_MEDKIT,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/items/use_medkit.wav"
|
|
},
|
|
|
|
//
|
|
// POWERUP ITEMS
|
|
//
|
|
|
|
|
|
/*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
multiplies your weapon's damage for 30 seconds
|
|
*/
|
|
{
|
|
"item_quad",
|
|
"sound/items/quaddamage.wav",
|
|
"models/powerups/trek/quad_damage.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_quad",
|
|
/* pickup */ "Quantum Weapon Enhancer",
|
|
30,
|
|
IT_POWERUP,
|
|
PW_QUAD,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/items/damage3.wav"
|
|
},
|
|
|
|
/*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
20 seconds of invulnerability
|
|
*/
|
|
{
|
|
"item_enviro",
|
|
"sound/items/protect.wav",
|
|
"models/powerups/trek/armor3.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/envirosuit",
|
|
/* pickup */ "Metaphasic Shielding",
|
|
20,
|
|
IT_POWERUP,
|
|
PW_BATTLESUIT,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/items/protect3.wav"
|
|
},
|
|
|
|
/*QUAKED item_haste (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
for 30 seconds you run at %150 of your normal speed and your firing delays are 3/4 as long
|
|
*/
|
|
{
|
|
"item_haste",
|
|
"sound/items/haste.wav",
|
|
"models/powerups/trek/haste.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_haste",
|
|
/* pickup */ "Temporal Accelerator",
|
|
30,
|
|
IT_POWERUP,
|
|
PW_HASTE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_invis (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
20 seconds of invisibility
|
|
*/
|
|
{
|
|
"item_invis",
|
|
"sound/items/invisibility.wav",
|
|
"models/powerups/trek/invisible.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_invisibility",
|
|
/* pickup */ "Personal Cloaking Device",
|
|
20,
|
|
IT_POWERUP,
|
|
PW_INVIS,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_regen (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
for 30 seconds you get 5 health every second, up to 200 health
|
|
*/
|
|
{
|
|
"item_regen",
|
|
"sound/items/regeneration.wav",
|
|
"models/powerups/trek/regen.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/regen",
|
|
/* pickup */ "Nano-Regenerative Protoplasmer",
|
|
30,
|
|
IT_POWERUP,
|
|
PW_REGEN,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/items/regen.wav"
|
|
},
|
|
|
|
/*QUAKED item_flight (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
30 seconds of flight
|
|
*/
|
|
{
|
|
"item_flight",
|
|
"sound/items/flight.wav",
|
|
"models/powerups/trek/flight.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/dm_flight",
|
|
/* pickup */ "Anti-Gravity Pack",
|
|
30,
|
|
IT_POWERUP,
|
|
PW_FLIGHT,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/items/flight.wav"
|
|
},
|
|
|
|
/*QUAKED team_CTF_redflag (1 0 0) (-24 -24 -16) (24 24 32)
|
|
Only in CTF games
|
|
*/
|
|
{
|
|
"team_CTF_redflag",
|
|
"sound/voice/computer/misc/haveflag.wav",
|
|
"models/flags/flag_red.md3", //world !! must match cg_main media and botfiles/items.c !!
|
|
NULL,
|
|
/* icon */ "icons/iconf_red",
|
|
/* pickup */ "Red Flag",
|
|
0,
|
|
IT_TEAM,
|
|
PW_REDFLAG,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/voice/computer/misc/stolen.wav sound/voice/computer/misc/stolen_e.wav sound/voice/computer/misc/returned.wav sound/voice/computer/misc/returned_e.wav"
|
|
},
|
|
|
|
/*QUAKED team_CTF_blueflag (0 0 1) (-24 -24 -16) (24 24 32)
|
|
Only in CTF games
|
|
*/
|
|
{
|
|
"team_CTF_blueflag",
|
|
"sound/voice/computer/misc/haveflag.wav",
|
|
"models/flags/flag_blue.md3",//must match cg_main media and botfiles/items.c
|
|
NULL,
|
|
/* icon */ "icons/iconf_blu",
|
|
/* pickup */ "Blue Flag",
|
|
0,
|
|
IT_TEAM,
|
|
PW_BLUEFLAG,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/voice/computer/misc/dropped.wav sound/voice/computer/misc/dropped_e.wav sound/voice/computer/misc/scored.wav sound/voice/computer/misc/scored_e.wav"
|
|
},
|
|
|
|
/*QUAKED holdable_detpack (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
BLAMMO!
|
|
*/
|
|
{
|
|
"holdable_detpack",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/detpak.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/icon_detpack",
|
|
/* pickup */ "Ultritium Explosive Charge",
|
|
1, // 5,
|
|
IT_HOLDABLE,
|
|
HI_DETPACK,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/weapons/detpacklatch.wav sound/weapons/explosions/detpakexplode.wav"
|
|
},
|
|
|
|
/*QUAKED item_seeker (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
30 seconds of seeker drone
|
|
*/
|
|
{
|
|
"item_seeker",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/flyer.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/icon_seeker",
|
|
/* pickup */ "Seeker Drone",
|
|
30,
|
|
IT_POWERUP,
|
|
PW_SEEKER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED holdable_shield (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
About 25 seconds or 250 hit points of a portashield.
|
|
*/
|
|
{
|
|
"holdable_shield",
|
|
"sound/player/pickupenergy.wav",
|
|
"models/powerups/trek/shield_gen.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/icon_shield",
|
|
/* pickup */ "Portable Force Field",
|
|
1,
|
|
IT_HOLDABLE,
|
|
HI_SHIELD,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/weapons/detpacklatch.wav sound/movers/forceup.wav sound/ambience/spark5.wav"
|
|
},
|
|
|
|
|
|
/*QUAKED Holographic_decoy (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
About 1 minute of a holographic decoy.
|
|
*/
|
|
{
|
|
"Holographic_decoy",
|
|
"sound/items/holdable.wav",
|
|
"models/powerups/trek/decoy.md3", //world
|
|
NULL,
|
|
/* icon */ "icons/icon_decoy",
|
|
/* pickup */ "Holographic Decoy",
|
|
1,
|
|
IT_HOLDABLE,
|
|
HI_DECOY,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// New Weapons
|
|
//
|
|
|
|
/*QUAKED weapon_voyager_hypo (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_voyager_hypo",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/hypospray/hypospray_w.md3", //world
|
|
"models/weapons2/hypospray/hypospray.md3", //view
|
|
/* icon */ "icons/w_icon_hypo",
|
|
/* pickup */ "Hypo",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_VOYAGER_HYPO,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_borg_assimilator (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_borg_assimilator",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/toolkit/toolkit_w.md3", //world
|
|
"models/weapons2/toolkit/toolkit.md3", //view
|
|
/* icon */ "icons/w_icon_toolkit",
|
|
/* pickup */ "Toolkit",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_TOOLKIT,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_borg_weapon (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_borg_weapon",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/medkit/medkit_w.md3", //world
|
|
"models/weapons2/medkit/medkit.md3", //view
|
|
/* icon */ "icons/w_icon_medkit",
|
|
/* pickup */ "Medkit",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_MEDKIT,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_tricorder (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_tricorder",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/tricorder/tricorder_w.md3", //world
|
|
"models/weapons2/tricorder/tricorder.md3", //view
|
|
/* icon */ "icons/w_icon_tricorder",
|
|
/* pickup */ "Tricorder",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_TRICORDER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_padd (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_padd",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/padd/padd_w.md3", //world
|
|
"models/weapons2/padd/padd.md3", //view
|
|
/* icon */ "icons/w_icon_padd",
|
|
/* pickup */ "Padd",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_PADD,
|
|
/* precache */ "",
|
|
/* sounds */ "",
|
|
},
|
|
|
|
/*QUAKED weapon_engtool (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_engtool",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/neutrino_probe/neutrino_probe_w.md3", //world
|
|
"models/weapons2/neutrino_probe/neutrino_probe.md3", //view
|
|
/* icon */ "icons/w_icon_neutrinoprobe",
|
|
/* pickup */ "Neutrino Probe",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_NEUTRINO_PROBE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_tr116 (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_tr116",
|
|
"sound/weapons/w_pkup.wav",
|
|
"models/weapons2/tr116/tr116_w.md3", //world
|
|
"models/weapons2/tr116/tr116.md3", //view
|
|
/* icon */ "icons/w_icon_tr116",
|
|
/* pickup */ "TR-116",
|
|
AMMO_PHASER_CLIP,
|
|
IT_WEAPON,
|
|
WP_TR116,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
// end of list marker
|
|
{NULL}
|
|
};
|
|
|
|
int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1;
|
|
|
|
/*
|
|
==============
|
|
BG_FindItemWithClassname
|
|
==============
|
|
*/
|
|
gitem_t *BG_FindItemWithClassname(const char *name)
|
|
{
|
|
int i = 0;
|
|
gitem_t *item = NULL;
|
|
|
|
if ( (NULL == name) || (0 == name[0]) )
|
|
{
|
|
return NULL;
|
|
}
|
|
for (i = 0; i < bg_numItems; i++)
|
|
{
|
|
item = &bg_itemlist[i];
|
|
if (!strcmp(name, item->classname))
|
|
{
|
|
return item;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
BG_FindClassnameForHoldable
|
|
==============
|
|
*/
|
|
char *BG_FindClassnameForHoldable(holdable_t pw)
|
|
{
|
|
gitem_t *item = BG_FindItemForHoldable(pw);
|
|
|
|
if (item)
|
|
{
|
|
return item->classname;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
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].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;
|
|
//if(ent->client->sess.sessionClass){
|
|
//}
|
|
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_FindItemForAmmo
|
|
|
|
===============
|
|
*/
|
|
gitem_t *BG_FindItemForAmmo( weapon_t weapon ) {
|
|
gitem_t *it;
|
|
|
|
for ( it = bg_itemlist + 1 ; it->classname ; it++) {
|
|
if ( it->giType == IT_AMMO && it->giTag == weapon ) {
|
|
return it;
|
|
}
|
|
}
|
|
|
|
Com_Error( ERR_DROP, "Couldn't find item for ammo %i", weapon);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
BG_FindItem
|
|
|
|
===============
|
|
*/
|
|
gitem_t *BG_FindItem( const char *pickupName/*const char *classname*/ ) {
|
|
gitem_t *it;
|
|
|
|
for ( it = bg_itemlist + 1 ; it->classname ; it++ ) {
|
|
if ( !Q_stricmp( it->pickup_name, pickupName )/*!Q_stricmp( it->classname, classname)*/ )//RPG-X: RedTechie - Trying to fix give cmd
|
|
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( const entityState_t *ent, const playerState_t *ps ) {
|
|
gitem_t *item;
|
|
|
|
//_______________________________________________________________
|
|
/* SYNC with g_items global var
|
|
int Max_Ammo[WP_NUM_WEAPONS] =
|
|
{
|
|
0, // WP_NONE,
|
|
50, // WP_PHASER, !! this should match PHASER_AMMO_MAX defined in bg_public
|
|
128, // WP_COMPRESSION_RIFLE,
|
|
60, // WP_NULL_HAND,
|
|
100, // WP_COFFEE,
|
|
50, // WP_DISRUPTOR,
|
|
30, // WP_GRENADE_LAUNCHER,
|
|
120, // WP_TR116,
|
|
20, // WP_QUANTUM_BURST,
|
|
120, // WP_DERMAL_REGEN,
|
|
100, // WP_VOYAGER_HYPO,
|
|
100, // WP_TOOLKIT,
|
|
100 // WP_MEDKIT
|
|
|
|
};
|
|
//_______________________________________________________________
|
|
*/
|
|
|
|
|
|
if ( ent->modelindex < 1 || ent->modelindex >= bg_numItems ) {
|
|
//Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: index out of range" );
|
|
//Com_Printf ("BG_CanItemBeGrabbed: index out of range\n");
|
|
return qfalse;
|
|
}
|
|
|
|
// The player used to not be able to pickup stuff when ghosted. Now it automatically unghosts them.
|
|
//RPG-X: RedTechie - No we want to keep ghost >:)
|
|
/*if (ps->powerups[PW_GHOST])
|
|
{
|
|
return qfalse;
|
|
}*/
|
|
|
|
item = &bg_itemlist[ent->modelindex];
|
|
|
|
if ( ps->persistant[PERS_CLASS] == PC_BORG && item->giType != IT_TEAM )//FIXME: check for pModAssimilation mode being on
|
|
{//borg cannot pick up anything but flags
|
|
return qfalse;
|
|
}
|
|
|
|
switch( item->giType )
|
|
{
|
|
case IT_WEAPON:
|
|
if ( ps->stats[STAT_WEAPONS] & (1 << item->giTag) && ps->ammo[ item->giTag ] >= Max_Ammo[ item->giTag ] )
|
|
{
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
|
|
case IT_AMMO:
|
|
if ( ps->ammo[ item->giTag ] >= Max_Ammo[ item->giTag ]) {
|
|
return qfalse; // can't hold any more
|
|
}
|
|
if ( ps->persistant[PERS_CLASS] != PC_NOCLASS )//FIXME: should be checking g_pModSpecialties->integer != 0 )
|
|
{
|
|
if ( ps->persistant[PERS_CLASS] != PC_ACTIONHERO )
|
|
{
|
|
//only pick it up if you have the weapon
|
|
if ( !(ps->stats[STAT_WEAPONS]&(1<<item->giTag)) )
|
|
{//don't have the weapon that uses this ammo
|
|
return qfalse;
|
|
}
|
|
}
|
|
}
|
|
return qtrue;
|
|
|
|
case IT_ARMOR:
|
|
// we also clamp armor to the maxhealth for handicapping
|
|
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:
|
|
if ( ps->persistant[PERS_CLASS] == PC_ACTIONHERO )
|
|
{
|
|
if ( item->giTag == PW_REGEN )
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
else if ( ps->persistant[PERS_CLASS] != PC_NOCLASS )//FIXME: should be checking g_pModSpecialties->integer != 0 )
|
|
{//in specialty mode, only certain classes can use certain powerups
|
|
//FIXME: breaks bots!
|
|
switch( item->giTag )
|
|
{
|
|
case PW_QUAD:
|
|
if ( ps->persistant[PERS_CLASS] != PC_HEAVY )
|
|
{
|
|
return qfalse;
|
|
}
|
|
break;
|
|
case PW_BATTLESUIT:
|
|
if ( ps->persistant[PERS_CLASS] != PC_MEDIC )
|
|
{
|
|
return qfalse;
|
|
}
|
|
break;
|
|
case PW_FLIGHT:
|
|
if ( ps->persistant[PERS_CLASS] != PC_INFILTRATOR )
|
|
{
|
|
return qfalse;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
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_RED) {
|
|
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_BLUE) {
|
|
if (item->giTag == PW_REDFLAG ||
|
|
(item->giTag == PW_BLUEFLAG && ent->modelindex2) ||
|
|
(item->giTag == PW_BLUEFLAG && ps->powerups[PW_REDFLAG]))
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
BG_AddPredictableEventToPlayerstate
|
|
|
|
Handles the sequence numbers
|
|
===============
|
|
*/
|
|
void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps ) {
|
|
ps->events[ps->eventSequence & (MAX_PS_EVENTS-1)] = newEvent;
|
|
ps->eventParms[ps->eventSequence & (MAX_PS_EVENTS-1)] = eventParm;
|
|
ps->eventSequence++;
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
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;
|
|
char medicrevive[32];
|
|
int medicrevive_int;
|
|
|
|
//RPG-X: RedTechie - Attempted to fix player going invisible now they just dont go invisible (me being picky) a player is never going to notice this
|
|
trap_Cvar_VariableStringBuffer( "rpg_medicsrevive", medicrevive, 32 );
|
|
medicrevive_int = atoi(medicrevive);
|
|
if ( ps->pm_type == PM_INTERMISSION || ps->pm_type == PM_SPECTATOR ) {
|
|
s->eType = ET_INVISIBLE;
|
|
} else if ( ps->stats[STAT_HEALTH] <= GIB_HEALTH ) {
|
|
if(medicrevive_int == 1){
|
|
s->eType = ET_PLAYER; //RPG-X: RedTechie - No gibbing! Before it was s->eType = ET_INVISIBLE;
|
|
}else{
|
|
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 );
|
|
}
|
|
|
|
s->apos.trType = TR_INTERPOLATE;
|
|
VectorCopy( ps->viewangles, s->apos.trBase );
|
|
if ( snap ) {
|
|
SnapVector( s->apos.trBase );
|
|
}
|
|
|
|
s->angles2[YAW] = 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 ( ( !medicrevive_int && ps->stats[STAT_HEALTH] <= 0 ) ||
|
|
( medicrevive_int > 0 && ps->stats[STAT_HEALTH] <= 1 ) )
|
|
{ //RPG-X: TiM: Bah Red... u gotta account for these flags with ur system
|
|
s->eFlags |= EF_DEAD; //or it screws up the model system
|
|
} else {
|
|
s->eFlags &= ~EF_DEAD;
|
|
}
|
|
|
|
if ( ps->externalEvent ) {
|
|
s->event = ps->externalEvent;
|
|
s->eventParm = ps->externalEventParm;
|
|
} else if ( ps->entityEventSequence < ps->eventSequence ) {
|
|
int seq;
|
|
|
|
if ( ps->entityEventSequence < ps->eventSequence - MAX_PS_EVENTS) {
|
|
ps->entityEventSequence = ps->eventSequence - MAX_PS_EVENTS;
|
|
}
|
|
seq = ps->entityEventSequence & (MAX_PS_EVENTS-1);
|
|
s->event = ps->events[ seq ] | ( ( ps->entityEventSequence & 3 ) << 8 );
|
|
s->eventParm = ps->eventParms[ seq ];
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define MAX_ITEMNAMES 45
|
|
|
|
const char *itemnames[MAX_ITEMNAMES] =
|
|
{
|
|
|
|
"nothing",
|
|
"WEAPON_PHASER",
|
|
"WEAPON_COMPRESSIONRIFLE",
|
|
"WEAPON_IMOD",
|
|
"WEAPON_SCAVENGERRIFLE",
|
|
"WEAPON_STASIS",
|
|
"WEAPON_GRENADELAUNCHER",
|
|
"WEAPON_DISRUPTOR",
|
|
"WEAPON_QUANTUM",
|
|
"WEAPON_DREADNOUGHT",
|
|
|
|
"AMMO_COMPRESSIONRIFLE",
|
|
"AMMO_IMOD",
|
|
"AMMO_SCAVENGERRIFLE",
|
|
"AMMO_STASIS",
|
|
"AMMO_GRENADELAUNCHER",
|
|
"AMMO_DISRUPTOR",
|
|
"AMMO_QUANTUM",
|
|
"AMMO_DREADNOUGHT",
|
|
|
|
"ITEM_ARMOR_SHARD",
|
|
"ITEM_ARMOR",
|
|
"ITEM_HEAVY_ARMOR",
|
|
"ITEM_HYPO_SMALL",
|
|
"ITEM_HYPO",
|
|
|
|
"HOLDABLE_TRANSPORTER",
|
|
"HOLDABLE_MEDKIT",
|
|
"HOLDABLE_QUADDAMAGE",
|
|
"HOLDABLE_BATTLESUIT",
|
|
"HOLDABLE_SPEED",
|
|
"HOLDABLE_INVISIBILITY",
|
|
"HOLDABLE_REGENERATION",
|
|
"HOLDABLE_FLIGHT",
|
|
"HOLDABLE_REDFLAG",
|
|
"HOLDABLE_BLUEFLAG",
|
|
"HOLDABLE_DETPACK",
|
|
"ITEM_SEEKER",
|
|
"HOLDABLE_SHIELD",
|
|
"HOLOGRAPHIC_DECOY", // decoy temp
|
|
|
|
"WEAPON_VOYAGER_HYPO",
|
|
"WEAPON_BORG_ASSIMILATOR",
|
|
"WEAPON_BORG_WEAPON",
|
|
"WEAPON_TRICORDER",
|
|
"WEAPON_PADD",
|
|
"WEAPON_ENGTOOL",
|
|
"WEAPON_TR116",
|
|
|
|
NULL
|
|
};
|
|
|
|
|
|
#define MAX_ITEMNAMEFILE 5000
|
|
char itemNameBuffer[MAX_ITEMNAMEFILE];
|
|
|
|
/*
|
|
=================
|
|
BG_ParseItemsText
|
|
=================
|
|
*/
|
|
void BG_ParseItemsText(char *buff)
|
|
{
|
|
char *token;
|
|
char *buffer;
|
|
int i,len;
|
|
|
|
COM_BeginParseSession();
|
|
|
|
buffer = buff;
|
|
while ( buffer )
|
|
{
|
|
token = COM_ParseExt( &buffer, qtrue );
|
|
|
|
i=0;
|
|
while (itemnames[i])
|
|
{
|
|
if (Q_stricmp(token, itemnames[i])==0)
|
|
{
|
|
token = COM_ParseExt( &buffer, qtrue );
|
|
if (token[0])
|
|
{
|
|
len = strlen(token);
|
|
if (len)
|
|
{
|
|
bg_itemlist[i].pickup_name = (buffer - (len + 1)); // The +1 is to get rid of the " at the beginning of the sting.
|
|
*(buffer - 1) = '\0'; // Place an string end where is belongs.
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
BG_LanguageFilename - create a filename with an extension based on the value in g_language
|
|
*/
|
|
void BG_LanguageFilename(char *baseName,char *baseExtension,char *finalName)
|
|
{
|
|
char language[32];
|
|
fileHandle_t file;
|
|
|
|
trap_Cvar_VariableStringBuffer( "g_language", language, 32 );
|
|
|
|
// If it's English then no extension
|
|
if (language[0]=='\0' || Q_stricmp ("ENGLISH",language)==0)
|
|
{
|
|
Com_sprintf(finalName,MAX_QPATH,"%s.%s",baseName,baseExtension);
|
|
}
|
|
else
|
|
{
|
|
Com_sprintf(finalName,MAX_QPATH,"%s_%s.%s",baseName,language,baseExtension);
|
|
|
|
//Attempt to load the file
|
|
trap_FS_FOpenFile( finalName, &file, FS_READ );
|
|
|
|
if ( file == 0 ) // This extension doesn't exist, go English.
|
|
{
|
|
Com_sprintf(finalName,MAX_QPATH,"%s.%s",baseName,baseExtension); //the caller will give the error if this isn't there
|
|
}
|
|
else
|
|
{
|
|
trap_FS_FCloseFile( file );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void BG_LoadItemNames(void)
|
|
{
|
|
char fileName[MAX_QPATH];
|
|
int len;
|
|
fileHandle_t f;
|
|
|
|
BG_LanguageFilename("ext_data/mp_itemnames","dat",fileName);
|
|
|
|
len = trap_FS_FOpenFile( fileName, &f, FS_READ );
|
|
|
|
if ( !f )
|
|
{
|
|
Com_Printf( S_COLOR_RED "BG_LoadItemNames : MP_ITEMNAMES.DAT file not found!\n");
|
|
return;
|
|
}
|
|
|
|
if ( len > MAX_ITEMNAMEFILE )
|
|
{
|
|
Com_Printf( S_COLOR_RED "BG_LoadItemNames : MP_ITEMNAMES.DAT too big!\n");
|
|
return;
|
|
}
|
|
|
|
// initialise the data area
|
|
memset(itemNameBuffer, 0, sizeof(itemNameBuffer));
|
|
|
|
trap_FS_Read( itemNameBuffer, len, f );
|
|
|
|
trap_FS_FCloseFile( f );
|
|
|
|
BG_ParseItemsText(itemNameBuffer);
|
|
|
|
}
|
|
|
|
/*
|
|
======================
|
|
G_ParseAnimationFileSex
|
|
|
|
Read a configuration file to get the sex
|
|
models/players_rpgx/munro/animation.cfg
|
|
======================
|
|
*/
|
|
static gender_t G_ParseAnimationFileSex( const char *filename) {
|
|
char *text_p;
|
|
int len;
|
|
char *token;
|
|
char text[20000];
|
|
fileHandle_t f;
|
|
char animfile[MAX_QPATH];
|
|
|
|
strcpy(animfile, filename);
|
|
len = strlen(animfile);
|
|
strcpy(&animfile[len-strlen("groups.cfg")], "animation.cfg");
|
|
|
|
// load the file
|
|
len = trap_FS_FOpenFile( animfile, &f, FS_READ );
|
|
if ( len <= 0 ) {
|
|
return GENDER_NEUTER;
|
|
}
|
|
if ( len >= sizeof( text ) - 1 ) {
|
|
Com_Printf( "File %s too long\n", animfile );
|
|
trap_FS_FCloseFile( f );
|
|
return GENDER_NEUTER;
|
|
}
|
|
trap_FS_Read( text, len, f );
|
|
text[len] = 0;
|
|
trap_FS_FCloseFile( f );
|
|
|
|
// parse the text
|
|
text_p = text;
|
|
|
|
// read optional parameters
|
|
while ( 1 ) {
|
|
token = COM_Parse( &text_p );
|
|
if ( !token[0] ) {
|
|
break;
|
|
}
|
|
if ( !Q_stricmp( token, "sex" ) ) {
|
|
token = COM_Parse( &text_p );
|
|
if ( !token[0] ) {
|
|
break;
|
|
}
|
|
if ( token[0] == 'f' || token[0] == 'F' ) {
|
|
return GENDER_FEMALE;
|
|
} else if ( token[0] == 'n' || token[0] == 'N' ) {
|
|
return GENDER_NEUTER;
|
|
} else {
|
|
return GENDER_MALE;
|
|
}
|
|
}
|
|
}
|
|
return GENDER_MALE;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
RE_RegisterSkin
|
|
|
|
===============
|
|
*/
|
|
#define MAX_GROUP_FILE_SIZE 5000
|
|
char* BG_RegisterRace( const char *name ) {
|
|
char *text_p;
|
|
char *token;
|
|
int len;
|
|
fileHandle_t f;
|
|
char text[MAX_GROUP_FILE_SIZE];
|
|
gender_t theSex;
|
|
|
|
memset (races, 0, sizeof(races));
|
|
memset (text, 0, sizeof(text));
|
|
|
|
// load and parse the skin file
|
|
len = trap_FS_FOpenFile( name, &f, FS_READ );
|
|
if ( !f ) {
|
|
// if we didn't get a races file, use an empty one.
|
|
Com_sprintf(races, sizeof(races), "unknown");
|
|
return races;
|
|
}
|
|
if ( len >= sizeof( text ) - 1)
|
|
{
|
|
Com_Printf( S_COLOR_RED "file too large: %s is %i, max allowed is %i", name, len, sizeof( text ) );
|
|
trap_FS_FCloseFile( f );
|
|
return races;
|
|
}
|
|
|
|
trap_FS_Read( text, len, f );
|
|
trap_FS_FCloseFile( f );
|
|
|
|
theSex = G_ParseAnimationFileSex(name);
|
|
if (theSex == GENDER_MALE) {
|
|
strcat(races, "Male,");
|
|
} else if (theSex == GENDER_FEMALE) {
|
|
strcat(races, "Female,");
|
|
}
|
|
|
|
text_p = text;
|
|
while ( *text_p ) {
|
|
// get surface name
|
|
token = COM_Parse( &text_p );
|
|
|
|
if ( !token[0] ) {
|
|
break;
|
|
}
|
|
|
|
// if we about to break the races size list then dump us out
|
|
if (strlen(races) + strlen(token) > 256) {
|
|
break;
|
|
}
|
|
|
|
// add it into the race list
|
|
strcat(races, token);
|
|
// put a comma between the names
|
|
strcat(races, ",");
|
|
|
|
if ( *text_p == ',' ) {
|
|
text_p++;
|
|
}
|
|
|
|
if (!Q_stricmp ("borg", token) ) {
|
|
if (theSex == GENDER_MALE) {
|
|
// add it into the race list
|
|
strcat(races, "BorgMale,");
|
|
} else if (theSex == GENDER_FEMALE) {
|
|
strcat(races, "BorgFemale,");
|
|
} else {
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// just in case
|
|
if (!races[0])
|
|
{
|
|
Com_sprintf(races, sizeof(races), "unknown");
|
|
}
|
|
else
|
|
{ //lose the last comma
|
|
races[strlen(races)-1] = 0;
|
|
}
|
|
|
|
return races;
|
|
}
|
|
|
|
qboolean BG_ParseRankNames( char* fileName, rankNames_t rankNames[] ) {
|
|
fileHandle_t f;
|
|
int file_len;
|
|
char charText[20000];
|
|
char* textPtr;
|
|
char* token;
|
|
int i = 0;
|
|
|
|
file_len = trap_FS_FOpenFile( fileName, &f, FS_READ );
|
|
|
|
if ( file_len<= 0 ) {
|
|
return qfalse;
|
|
}
|
|
|
|
if ( file_len >= ( sizeof(charText) - 1) ) {
|
|
Com_Printf( S_COLOR_RED "File length of %s is too long.\n", fileName );
|
|
}
|
|
|
|
memset( &charText, 0, sizeof( charText ) );
|
|
memset( rankNames, 0, sizeof( rankNames ) );
|
|
|
|
trap_FS_Read( charText, file_len, f );
|
|
|
|
charText[file_len] = 0;
|
|
|
|
trap_FS_FCloseFile( f );
|
|
|
|
COM_BeginParseSession();
|
|
|
|
textPtr = charText;
|
|
|
|
token = COM_Parse( &textPtr );
|
|
|
|
if ( !token[0] ) {
|
|
Com_Printf( S_COLOR_RED "No data found in buffer: %s\n", fileName );
|
|
return qfalse;
|
|
}
|
|
|
|
if ( Q_stricmpn( token, "{", 1 ) ) {
|
|
Com_Printf( S_COLOR_RED "No beginning { found in %s\n", fileName );
|
|
return qfalse;
|
|
}
|
|
|
|
//Parse out the default cell. Default has no names anyway,
|
|
//but in case a n00bie modder put names in anyway.
|
|
SkipBracedSection( &textPtr );
|
|
|
|
while( 1 ) {
|
|
//lastPtr = textPtr;
|
|
token = COM_Parse( &textPtr );
|
|
if( !token[0] ) {
|
|
break;
|
|
}
|
|
|
|
if ( i >= MAX_RANKS ) {
|
|
break;
|
|
}
|
|
|
|
//If we hit an open brace (ie, assuming we hit the start of a new rank cell)
|
|
if ( !Q_stricmpn( token, "{", 1 ) ) {
|
|
while ( 1 ) {
|
|
token = COM_Parse( &textPtr );
|
|
if( !token[0] ) {
|
|
break;
|
|
}
|
|
|
|
//We hit a MenuTexture entry, since this uses { symbols, we'll skip these to stop errors.
|
|
if ( !Q_stricmpn( token, "MenuTexture", 11 ) ) {
|
|
SkipRestOfLine( &textPtr );
|
|
continue;
|
|
}
|
|
|
|
if ( !Q_stricmpn( token, "ConsoleName", 11) ) {
|
|
if ( COM_ParseString( &textPtr, &token ) ) {
|
|
continue;
|
|
}
|
|
|
|
Q_strncpyz( rankNames[i].consoleName, token, sizeof( rankNames[i].consoleName ) );
|
|
|
|
continue;
|
|
}
|
|
else if ( !Q_stricmpn( token, "FormalName", 10) ) {
|
|
if ( COM_ParseString( &textPtr, &token ) ) {
|
|
continue;
|
|
}
|
|
|
|
Q_strncpyz( rankNames[i].formalName, token, sizeof( rankNames[i].formalName ) );
|
|
|
|
continue;
|
|
}
|
|
//We hit the end of the cell.
|
|
else if ( !Q_stricmpn( token, "}", 1 ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Error check. If we didn't get both a formal and console name, pwn the caller. ;P
|
|
if ( !rankNames[i].consoleName[0] || !rankNames[i].formalName[0] ) {
|
|
Com_Printf( S_COLOR_RED "One or more rank names were not found in rank#: %i\n", i );
|
|
return qfalse;
|
|
}
|
|
else {
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
return qtrue;
|
|
}
|
|
|