2413 lines
57 KiB
C
2413 lines
57 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"
|
|
|
|
#ifdef QAGAME
|
|
#include "g_local.h"
|
|
#endif
|
|
|
|
#ifdef UI_EXPORTS
|
|
#include "../ui/ui_local.h"
|
|
#endif
|
|
|
|
#ifndef UI_EXPORTS
|
|
#ifndef QAGAME
|
|
#include "../cgame/cg_local.h"
|
|
#endif
|
|
#endif
|
|
|
|
//rww - not putting @ in front of these because
|
|
//we don't need them in a cgame striped lookup.
|
|
//Let me know if this causes problems, pat.
|
|
char *forceMasteryLevels[NUM_FORCE_MASTERY_LEVELS] =
|
|
{
|
|
"MASTERY0", //"Uninitiated", // FORCE_MASTERY_UNINITIATED,
|
|
"MASTERY1", //"Initiate", // FORCE_MASTERY_INITIATE,
|
|
"MASTERY2", //"Padawan", // FORCE_MASTERY_PADAWAN,
|
|
"MASTERY3", //"Jedi", // FORCE_MASTERY_JEDI,
|
|
"MASTERY4", //"Jedi Adept", // FORCE_MASTERY_JEDI_GUARDIAN,
|
|
"MASTERY5", //"Jedi Guardian", // FORCE_MASTERY_JEDI_ADEPT,
|
|
"MASTERY6", //"Jedi Knight", // FORCE_MASTERY_JEDI_KNIGHT,
|
|
"MASTERY7", //"Jedi Master" // FORCE_MASTERY_JEDI_MASTER,
|
|
};
|
|
|
|
int forceMasteryPoints[NUM_FORCE_MASTERY_LEVELS] =
|
|
{
|
|
0, // FORCE_MASTERY_UNINITIATED,
|
|
5, // FORCE_MASTERY_INITIATE,
|
|
10, // FORCE_MASTERY_PADAWAN,
|
|
20, // FORCE_MASTERY_JEDI,
|
|
30, // FORCE_MASTERY_JEDI_GUARDIAN,
|
|
50, // FORCE_MASTERY_JEDI_ADEPT,
|
|
75, // FORCE_MASTERY_JEDI_KNIGHT,
|
|
100 // FORCE_MASTERY_JEDI_MASTER,
|
|
};
|
|
|
|
int bgForcePowerCost[NUM_FORCE_POWERS][NUM_FORCE_POWER_LEVELS] = //0 == neutral
|
|
{
|
|
{ 0, 2, 4, 6 }, // Heal // FP_HEAL
|
|
{ 0, 0, 2, 6 }, // Jump //FP_LEVITATION,//hold/duration
|
|
{ 0, 2, 4, 6 }, // Speed //FP_SPEED,//duration
|
|
{ 0, 1, 3, 6 }, // Push //FP_PUSH,//hold/duration
|
|
{ 0, 1, 3, 6 }, // Pull //FP_PULL,//hold/duration
|
|
{ 0, 4, 6, 8 }, // Mind Trick //FP_TELEPATHY,//instant
|
|
{ 0, 1, 3, 6 }, // Grip //FP_GRIP,//hold/duration
|
|
{ 0, 2, 5, 8 }, // Lightning //FP_LIGHTNING,//hold/duration
|
|
{ 0, 4, 6, 8 }, // Dark Rage //FP_RAGE,//duration
|
|
{ 0, 2, 5, 8 }, // Protection //FP_PROTECT,//duration
|
|
{ 0, 1, 3, 6 }, // Absorb //FP_ABSORB,//duration
|
|
{ 0, 1, 3, 6 }, // Team Heal //FP_TEAM_HEAL,//instant
|
|
{ 0, 1, 3, 6 }, // Team Force //FP_TEAM_FORCE,//instant
|
|
{ 0, 2, 4, 6 }, // Drain //FP_DRAIN,//hold/duration
|
|
{ 0, 2, 5, 8 }, // Sight //FP_SEE,//duration
|
|
{ 0, 1, 5, 8 }, // Saber Attack //FP_SABERATTACK,
|
|
{ 0, 1, 5, 8 }, // Saber Defend //FP_SABERDEFEND,
|
|
{ 0, 4, 6, 8 } // Saber Throw //FP_SABERTHROW,
|
|
//NUM_FORCE_POWERS
|
|
};
|
|
|
|
int forcePowerSorted[NUM_FORCE_POWERS] =
|
|
{ //rww - always use this order when drawing force powers for any reason
|
|
FP_TELEPATHY,
|
|
FP_HEAL,
|
|
FP_ABSORB,
|
|
FP_PROTECT,
|
|
FP_TEAM_HEAL,
|
|
FP_LEVITATION,
|
|
FP_SPEED,
|
|
FP_PUSH,
|
|
FP_PULL,
|
|
FP_SEE,
|
|
FP_LIGHTNING,
|
|
FP_DRAIN,
|
|
FP_RAGE,
|
|
FP_GRIP,
|
|
FP_TEAM_FORCE,
|
|
FP_SABERATTACK,
|
|
FP_SABERDEFEND,
|
|
FP_SABERTHROW
|
|
};
|
|
|
|
int forcePowerDarkLight[NUM_FORCE_POWERS] = //0 == neutral
|
|
{ //nothing should be usable at rank 0..
|
|
FORCE_LIGHTSIDE,//FP_HEAL,//instant
|
|
0,//FP_LEVITATION,//hold/duration
|
|
0,//FP_SPEED,//duration
|
|
0,//FP_PUSH,//hold/duration
|
|
0,//FP_PULL,//hold/duration
|
|
FORCE_LIGHTSIDE,//FP_TELEPATHY,//instant
|
|
FORCE_DARKSIDE,//FP_GRIP,//hold/duration
|
|
FORCE_DARKSIDE,//FP_LIGHTNING,//hold/duration
|
|
FORCE_DARKSIDE,//FP_RAGE,//duration
|
|
FORCE_LIGHTSIDE,//FP_PROTECT,//duration
|
|
FORCE_LIGHTSIDE,//FP_ABSORB,//duration
|
|
FORCE_LIGHTSIDE,//FP_TEAM_HEAL,//instant
|
|
FORCE_DARKSIDE,//FP_TEAM_FORCE,//instant
|
|
FORCE_DARKSIDE,//FP_DRAIN,//hold/duration
|
|
0,//FP_SEE,//duration
|
|
0,//FP_SABERATTACK,
|
|
0,//FP_SABERDEFEND,
|
|
0//FP_SABERTHROW,
|
|
//NUM_FORCE_POWERS
|
|
};
|
|
|
|
int WeaponReadyAnim[WP_NUM_WEAPONS] =
|
|
{
|
|
TORSO_DROPWEAP1,//WP_NONE,
|
|
|
|
TORSO_WEAPONREADY3,//WP_STUN_BATON,
|
|
BOTH_STAND2,//WP_SABER,
|
|
TORSO_WEAPONREADY2,//WP_BRYAR_PISTOL,
|
|
TORSO_WEAPONREADY3,//WP_BLASTER,
|
|
TORSO_WEAPONREADY3,//TORSO_WEAPONREADY4,//WP_DISRUPTOR,
|
|
TORSO_WEAPONREADY3,//TORSO_WEAPONREADY5,//WP_BOWCASTER,
|
|
TORSO_WEAPONREADY3,//TORSO_WEAPONREADY6,//WP_REPEATER,
|
|
TORSO_WEAPONREADY3,//TORSO_WEAPONREADY7,//WP_DEMP2,
|
|
TORSO_WEAPONREADY3,//TORSO_WEAPONREADY8,//WP_FLECHETTE,
|
|
TORSO_WEAPONREADY3,//TORSO_WEAPONREADY9,//WP_ROCKET_LAUNCHER,
|
|
TORSO_WEAPONREADY10,//WP_THERMAL,
|
|
TORSO_WEAPONREADY10,//TORSO_WEAPONREADY11,//WP_TRIP_MINE,
|
|
TORSO_WEAPONREADY10,//TORSO_WEAPONREADY12,//WP_DET_PACK,
|
|
|
|
//NOT VALID (e.g. should never really be used):
|
|
BOTH_STAND1,//WP_EMPLACED_GUN,
|
|
TORSO_WEAPONREADY1//WP_TURRET,
|
|
};
|
|
|
|
int WeaponAttackAnim[WP_NUM_WEAPONS] =
|
|
{
|
|
BOTH_ATTACK1,//WP_NONE, //(shouldn't happen)
|
|
|
|
BOTH_ATTACK3,//WP_STUN_BATON,
|
|
BOTH_STAND2,//WP_SABER, //(has its own handling)
|
|
BOTH_ATTACK2,//WP_BRYAR_PISTOL,
|
|
BOTH_ATTACK3,//WP_BLASTER,
|
|
BOTH_ATTACK3,//BOTH_ATTACK4,//WP_DISRUPTOR,
|
|
BOTH_ATTACK3,//BOTH_ATTACK5,//WP_BOWCASTER,
|
|
BOTH_ATTACK3,//BOTH_ATTACK6,//WP_REPEATER,
|
|
BOTH_ATTACK3,//BOTH_ATTACK7,//WP_DEMP2,
|
|
BOTH_ATTACK3,//BOTH_ATTACK8,//WP_FLECHETTE,
|
|
BOTH_ATTACK3,//BOTH_ATTACK9,//WP_ROCKET_LAUNCHER,
|
|
BOTH_THERMAL_THROW,//WP_THERMAL,
|
|
BOTH_ATTACK3,//BOTH_ATTACK11,//WP_TRIP_MINE,
|
|
BOTH_ATTACK3,//BOTH_ATTACK12,//WP_DET_PACK,
|
|
|
|
//NOT VALID (e.g. should never really be used):
|
|
BOTH_STAND1,//WP_EMPLACED_GUN,
|
|
BOTH_ATTACK1//WP_TURRET,
|
|
};
|
|
|
|
|
|
/*
|
|
================
|
|
BG_LegalizedForcePowers
|
|
|
|
The magical function to end all functions.
|
|
This will take the force power string in powerOut and parse through it, then legalize
|
|
it based on the supposed rank and spit it into powerOut, returning true if it was legal
|
|
to begin with and false if not.
|
|
fpDisabled is actually only expected (needed) from the server, because the ui disables
|
|
force power selection anyway when force powers are disabled on the server.
|
|
================
|
|
*/
|
|
qboolean BG_LegalizedForcePowers(char *powerOut, int maxRank, qboolean freeSaber, int teamForce, int gametype, int fpDisabled)
|
|
{
|
|
char powerBuf[128];
|
|
char readBuf[128];
|
|
qboolean maintainsValidity = qtrue;
|
|
int powerLen = strlen(powerOut);
|
|
int i = 0;
|
|
int c = 0;
|
|
int allowedPoints = 0;
|
|
int usedPoints = 0;
|
|
int countDown = 0;
|
|
|
|
int final_Side;
|
|
int final_Powers[NUM_FORCE_POWERS];
|
|
|
|
if (powerLen >= 128)
|
|
{ //This should not happen. If it does, this is obviously a bogus string.
|
|
//They can have this string. Because I said so.
|
|
strcpy(powerBuf, "7-1-032330000000001333");
|
|
maintainsValidity = qfalse;
|
|
}
|
|
else
|
|
{
|
|
strcpy(powerBuf, powerOut); //copy it as the original
|
|
}
|
|
|
|
//first of all, print the max rank into the string as the rank
|
|
strcpy(powerOut, va("%i-", maxRank));
|
|
|
|
while (i < 128 && powerBuf[i] && powerBuf[i] != '-')
|
|
{
|
|
i++;
|
|
}
|
|
i++;
|
|
while (i < 128 && powerBuf[i] && powerBuf[i] != '-')
|
|
{
|
|
readBuf[c] = powerBuf[i];
|
|
c++;
|
|
i++;
|
|
}
|
|
readBuf[c] = 0;
|
|
i++;
|
|
//at this point, readBuf contains the intended side
|
|
final_Side = atoi(readBuf);
|
|
|
|
if (final_Side != FORCE_LIGHTSIDE &&
|
|
final_Side != FORCE_DARKSIDE)
|
|
{ //Not a valid side. You will be dark. Because I said so. (this is something that should never actually happen unless you purposely feed in an invalid config)
|
|
final_Side = FORCE_DARKSIDE;
|
|
maintainsValidity = qfalse;
|
|
}
|
|
|
|
if (teamForce)
|
|
{ //If we are under force-aligned teams, make sure we're on the right side.
|
|
if (final_Side != teamForce)
|
|
{
|
|
final_Side = teamForce;
|
|
//maintainsValidity = qfalse;
|
|
//Not doing this, for now. Let them join the team with their filtered powers.
|
|
}
|
|
}
|
|
|
|
//Now we have established a valid rank, and a valid side.
|
|
//Read the force powers in, and cut them down based on the various rules supplied.
|
|
c = 0;
|
|
while (i < 128 && powerBuf[i] && powerBuf[i] != '\n' && c < NUM_FORCE_POWERS)
|
|
{
|
|
readBuf[0] = powerBuf[i];
|
|
readBuf[1] = 0;
|
|
final_Powers[c] = atoi(readBuf);
|
|
c++;
|
|
i++;
|
|
}
|
|
|
|
//final_Powers now contains all the stuff from the string
|
|
//Set the maximum allowed points used based on the max rank level, and count the points actually used.
|
|
allowedPoints = forceMasteryPoints[maxRank];
|
|
|
|
i = 0;
|
|
while (i < NUM_FORCE_POWERS)
|
|
{ //if this power doesn't match the side we're on, then 0 it now.
|
|
if (final_Powers[i] &&
|
|
forcePowerDarkLight[i] &&
|
|
forcePowerDarkLight[i] != final_Side)
|
|
{
|
|
final_Powers[i] = 0;
|
|
//This is only likely to happen with g_forceBasedTeams. Let it slide.
|
|
}
|
|
|
|
if ( final_Powers[i] &&
|
|
(fpDisabled & (1 << i)) )
|
|
{ //if this power is disabled on the server via said server option, then we don't get it.
|
|
final_Powers[i] = 0;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if (gametype < GT_TEAM)
|
|
{ //don't bother with team powers then
|
|
final_Powers[FP_TEAM_HEAL] = 0;
|
|
final_Powers[FP_TEAM_FORCE] = 0;
|
|
}
|
|
|
|
usedPoints = 0;
|
|
i = 0;
|
|
while (i < NUM_FORCE_POWERS)
|
|
{
|
|
countDown = 0;
|
|
|
|
countDown = final_Powers[i];
|
|
|
|
while (countDown > 0)
|
|
{
|
|
usedPoints += bgForcePowerCost[i][countDown]; //[fp index][fp level]
|
|
//if this is jump, or we have a free saber and it's offense or defense, take the level back down on level 1
|
|
if ( countDown == 1 &&
|
|
((i == FP_LEVITATION) ||
|
|
(i == FP_SABERATTACK && freeSaber) ||
|
|
(i == FP_SABERDEFEND && freeSaber)) )
|
|
{
|
|
usedPoints -= bgForcePowerCost[i][countDown];
|
|
}
|
|
countDown--;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if (usedPoints > allowedPoints)
|
|
{ //Time to do the fancy stuff. (meaning, slowly cut parts off while taking a guess at what is most or least important in the config)
|
|
int attemptedCycles = 0;
|
|
int powerCycle = 2;
|
|
int minPow = 0;
|
|
|
|
if (freeSaber)
|
|
{
|
|
minPow = 1;
|
|
}
|
|
|
|
maintainsValidity = qfalse;
|
|
|
|
while (usedPoints > allowedPoints)
|
|
{
|
|
c = 0;
|
|
|
|
while (c < NUM_FORCE_POWERS && usedPoints > allowedPoints)
|
|
{
|
|
if (final_Powers[c] && final_Powers[c] < powerCycle)
|
|
{ //kill in order of lowest powers, because the higher powers are probably more important
|
|
if (c == FP_SABERATTACK &&
|
|
(final_Powers[FP_SABERDEFEND] > minPow || final_Powers[FP_SABERTHROW] > 0))
|
|
{ //if we're on saber attack, only suck it down if we have no def or throw either
|
|
int whichOne = FP_SABERTHROW; //first try throw
|
|
|
|
if (!final_Powers[whichOne])
|
|
{
|
|
whichOne = FP_SABERDEFEND; //if no throw, drain defense
|
|
}
|
|
|
|
while (final_Powers[whichOne] > 0 && usedPoints > allowedPoints)
|
|
{
|
|
if ( final_Powers[whichOne] > 1 ||
|
|
( (whichOne != FP_SABERATTACK || !freeSaber) &&
|
|
(whichOne != FP_SABERDEFEND || !freeSaber) ) )
|
|
{ //don't take attack or defend down on level 1 still, if it's free
|
|
usedPoints -= bgForcePowerCost[whichOne][final_Powers[whichOne]];
|
|
final_Powers[whichOne]--;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (final_Powers[c] > 0 && usedPoints > allowedPoints)
|
|
{
|
|
if ( final_Powers[c] > 1 ||
|
|
((c != FP_LEVITATION) &&
|
|
(c != FP_SABERATTACK || !freeSaber) &&
|
|
(c != FP_SABERDEFEND || !freeSaber)) )
|
|
{
|
|
usedPoints -= bgForcePowerCost[c][final_Powers[c]];
|
|
final_Powers[c]--;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
c++;
|
|
}
|
|
|
|
powerCycle++;
|
|
attemptedCycles++;
|
|
|
|
if (attemptedCycles > NUM_FORCE_POWERS)
|
|
{ //I think this should be impossible. But just in case.
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (usedPoints > allowedPoints)
|
|
{ //Still? Fine then.. we will kill all of your powers, except the freebies.
|
|
i = 0;
|
|
|
|
while (i < NUM_FORCE_POWERS)
|
|
{
|
|
final_Powers[i] = 0;
|
|
if (i == FP_LEVITATION ||
|
|
(i == FP_SABERATTACK && freeSaber) ||
|
|
(i == FP_SABERDEFEND && freeSaber))
|
|
{
|
|
final_Powers[i] = 1;
|
|
}
|
|
i++;
|
|
}
|
|
usedPoints = 0;
|
|
}
|
|
}
|
|
|
|
if (freeSaber)
|
|
{
|
|
if (final_Powers[FP_SABERATTACK] < 1)
|
|
{
|
|
final_Powers[FP_SABERATTACK] = 1;
|
|
}
|
|
if (final_Powers[FP_SABERDEFEND] < 1)
|
|
{
|
|
final_Powers[FP_SABERDEFEND] = 1;
|
|
}
|
|
}
|
|
if (final_Powers[FP_LEVITATION] < 1)
|
|
{
|
|
final_Powers[FP_LEVITATION] = 1;
|
|
}
|
|
|
|
i = 0;
|
|
while (i < NUM_FORCE_POWERS)
|
|
{
|
|
if (final_Powers[i] > FORCE_LEVEL_3)
|
|
{
|
|
final_Powers[i] = FORCE_LEVEL_3;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (fpDisabled)
|
|
{ //If we specifically have attack or def disabled, force them up to level 3. It's the way
|
|
//things work for the case of all powers disabled.
|
|
//If jump is disabled, down-cap it to level 1. Otherwise don't do a thing.
|
|
if (fpDisabled & (1 << FP_LEVITATION))
|
|
{
|
|
final_Powers[FP_LEVITATION] = 1;
|
|
}
|
|
if (fpDisabled & (1 << FP_SABERATTACK))
|
|
{
|
|
final_Powers[FP_SABERATTACK] = 3;
|
|
}
|
|
if (fpDisabled & (1 << FP_SABERDEFEND))
|
|
{
|
|
final_Powers[FP_SABERDEFEND] = 3;
|
|
}
|
|
}
|
|
|
|
if (final_Powers[FP_SABERATTACK] < 1)
|
|
{
|
|
final_Powers[FP_SABERDEFEND] = 0;
|
|
final_Powers[FP_SABERTHROW] = 0;
|
|
}
|
|
|
|
//We finally have all the force powers legalized and stored locally.
|
|
//Put them all into the string and return the result. We already have
|
|
//the rank there, so print the side and the powers now.
|
|
Q_strcat(powerOut, 128, va("%i-", final_Side));
|
|
|
|
i = strlen(powerOut);
|
|
c = 0;
|
|
while (c < NUM_FORCE_POWERS)
|
|
{
|
|
strcpy(readBuf, va("%i", final_Powers[c]));
|
|
powerOut[i] = readBuf[0];
|
|
c++;
|
|
i++;
|
|
}
|
|
powerOut[i] = 0;
|
|
|
|
return maintainsValidity;
|
|
}
|
|
|
|
/*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.
|
|
*/
|
|
|
|
/*QUAKED misc_shield_floor_unit (1 0 0) (-16 -16 0) (16 16 40)
|
|
#MODELNAME="/models/items/a_shield_converter.md3"
|
|
Gives shield energy when used.
|
|
|
|
"count" - max charge value (default 50)
|
|
"chargerate" - rechage 1 point every this many milliseconds (default 3000)
|
|
*/
|
|
|
|
gitem_t bg_itemlist[] =
|
|
{
|
|
{
|
|
NULL, // classname
|
|
NULL, // pickup_sound
|
|
{ NULL, // world_model[0]
|
|
NULL, // world_model[1]
|
|
0, 0} , // world_model[2],[3]
|
|
NULL, // view_model
|
|
/* icon */ NULL, // icon
|
|
/* pickup */ //NULL, // pickup_name
|
|
0, // quantity
|
|
0, // giType (IT_*)
|
|
0, // giTag
|
|
/* precache */ "", // precaches
|
|
/* sounds */ "" // sounds
|
|
}, // leave index 0 alone
|
|
|
|
//
|
|
// Pickups
|
|
//
|
|
|
|
/*QUAKED item_shield_sm_instant (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Instant shield pickup, restores 25
|
|
*/
|
|
{
|
|
"item_shield_sm_instant",
|
|
"sound/player/pickupshield.wav",
|
|
{ "models/map_objects/mp/psd_sm.md3",
|
|
0, 0, 0},
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/mp/small_shield",
|
|
/* pickup */// "Shield Small",
|
|
25,
|
|
IT_ARMOR,
|
|
1, //special for shield - max on pickup is maxhealth*tag, thus small shield goes up to 100 shield
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_shield_lrg_instant (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Instant shield pickup, restores 100
|
|
*/
|
|
{
|
|
"item_shield_lrg_instant",
|
|
"sound/player/pickupshield.wav",
|
|
{ "models/map_objects/mp/psd.md3",
|
|
0, 0, 0},
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/mp/large_shield",
|
|
/* pickup */// "Shield Large",
|
|
100,
|
|
IT_ARMOR,
|
|
2, //special for shield - max on pickup is maxhealth*tag, thus large shield goes up to 200 shield
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_medpak_instant (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Instant medpack pickup, heals 25
|
|
*/
|
|
{
|
|
"item_medpak_instant",
|
|
"sound/player/pickuphealth.wav",
|
|
{ "models/map_objects/mp/medpac.md3",
|
|
0, 0, 0 },
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/i_icon_medkit",
|
|
/* pickup */// "Medpack",
|
|
25,
|
|
IT_HEALTH,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
|
|
//
|
|
// ITEMS
|
|
//
|
|
|
|
/*QUAKED item_seeker (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
|
|
30 seconds of seeker drone
|
|
*/
|
|
{
|
|
"item_seeker",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/items/remote.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/i_icon_seeker",
|
|
/* pickup */// "Seeker Drone",
|
|
120,
|
|
IT_HOLDABLE,
|
|
HI_SEEKER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_shield (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
|
|
Portable shield
|
|
*/
|
|
{
|
|
"item_shield",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/map_objects/mp/shield.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/i_icon_shieldwall",
|
|
/* pickup */// "Forcefield",
|
|
120,
|
|
IT_HOLDABLE,
|
|
HI_SHIELD,
|
|
/* precache */ "",
|
|
/* sounds */ "sound/weapons/detpack/stick.wav sound/movers/doors/forcefield_on.wav sound/movers/doors/forcefield_off.wav sound/movers/doors/forcefield_lp.wav sound/effects/bumpfield.wav",
|
|
},
|
|
|
|
/*QUAKED item_medpac (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
|
|
Bacta canister pickup, heals 25 on use
|
|
*/
|
|
{
|
|
"item_medpac", //should be item_bacta
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/map_objects/mp/bacta.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/i_icon_bacta",
|
|
/* pickup */// "Bacta Canister",
|
|
25,
|
|
IT_HOLDABLE,
|
|
HI_MEDPAC,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_datapad (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
|
|
Do not place this.
|
|
*/
|
|
{
|
|
"item_datapad",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/items/datapad.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ NULL,
|
|
/* pickup */// "Datapad",
|
|
1,
|
|
IT_HOLDABLE,
|
|
HI_DATAPAD,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_binoculars (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
|
|
These will be standard equipment on the player - DO NOT PLACE
|
|
*/
|
|
{
|
|
"item_binoculars",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/items/binoculars.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/i_icon_zoom",
|
|
/* pickup */// "Binoculars",
|
|
60,
|
|
IT_HOLDABLE,
|
|
HI_BINOCULARS,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_sentry_gun (.3 .3 1) (-8 -8 -0) (8 8 16) suspended
|
|
Sentry gun inventory pickup.
|
|
*/
|
|
{
|
|
"item_sentry_gun",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/items/psgun.glm",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/i_icon_sentrygun",
|
|
/* pickup */// "Sentry Gun",
|
|
120,
|
|
IT_HOLDABLE,
|
|
HI_SENTRY_GUN,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_force_enlighten_light (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Adds one rank to all Force powers temporarily. Only light jedi can use.
|
|
*/
|
|
{
|
|
"item_force_enlighten_light",
|
|
"sound/player/enlightenment.wav",
|
|
{ "models/map_objects/mp/jedi_enlightenment.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/mpi_jlight",
|
|
/* pickup */// "Light Force Enlightenment",
|
|
25,
|
|
IT_POWERUP,
|
|
PW_FORCE_ENLIGHTENED_LIGHT,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_force_enlighten_dark (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Adds one rank to all Force powers temporarily. Only dark jedi can use.
|
|
*/
|
|
{
|
|
"item_force_enlighten_dark",
|
|
"sound/player/enlightenment.wav",
|
|
{ "models/map_objects/mp/dk_enlightenment.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/mpi_dklight",
|
|
/* pickup */// "Dark Force Enlightenment",
|
|
25,
|
|
IT_POWERUP,
|
|
PW_FORCE_ENLIGHTENED_DARK,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_force_boon (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Unlimited Force Pool for a short time.
|
|
*/
|
|
{
|
|
"item_force_boon",
|
|
"sound/player/boon.wav",
|
|
{ "models/map_objects/mp/force_boon.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/mpi_fboon",
|
|
/* pickup */// "Force Boon",
|
|
25,
|
|
IT_POWERUP,
|
|
PW_FORCE_BOON,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED item_ysalimari (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
A small lizard carried on the player, which prevents the possessor from using any Force power. However, he is unaffected by any Force power.
|
|
*/
|
|
{
|
|
"item_ysalimari",
|
|
"sound/player/ysalimari.wav",
|
|
{ "models/map_objects/mp/ysalimari.md3",
|
|
0, 0, 0} ,
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/mpi_ysamari",
|
|
/* pickup */// "Ysalamiri",
|
|
25,
|
|
IT_POWERUP,
|
|
PW_YSALAMIRI,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// WEAPONS
|
|
//
|
|
|
|
/*QUAKED weapon_stun_baton (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Don't place this
|
|
*/
|
|
{
|
|
"weapon_stun_baton",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/stun_baton/baton_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/stun_baton/baton.md3",
|
|
/* icon */ "gfx/hud/w_icon_stunbaton",
|
|
/* pickup */// "Stun Baton",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_STUN_BATON,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_saber (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Don't place this
|
|
*/
|
|
{
|
|
"weapon_saber",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/saber/saber_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/saber/saber_w.md3",
|
|
/* icon */ "gfx/hud/w_icon_lightsaber",
|
|
/* pickup */// "Lightsaber",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_SABER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_bryar_pistol (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Don't place this
|
|
*/
|
|
{
|
|
"weapon_bryar_pistol",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/briar_pistol/briar_pistol_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/briar_pistol/briar_pistol.md3",
|
|
/* icon */ "gfx/hud/w_icon_rifle",
|
|
/* pickup */// "Bryar Pistol",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_BRYAR_PISTOL,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_blaster",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/blaster_r/blaster_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/blaster_r/blaster.md3",
|
|
/* icon */ "gfx/hud/w_icon_blaster",
|
|
/* pickup */// "E11 Blaster Rifle",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_BLASTER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_disruptor (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_disruptor",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/disruptor/disruptor_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/disruptor/disruptor.md3",
|
|
/* icon */ "gfx/hud/w_icon_disruptor",
|
|
/* pickup */// "Tenloss Disruptor Rifle",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_DISRUPTOR,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_bowcaster (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_bowcaster",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/bowcaster/bowcaster_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/bowcaster/bowcaster.md3",
|
|
/* icon */ "gfx/hud/w_icon_bowcaster",
|
|
/* pickup */// "Wookiee Bowcaster",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_BOWCASTER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_repeater (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_repeater",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/heavy_repeater/heavy_repeater_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/heavy_repeater/heavy_repeater.md3",
|
|
/* icon */ "gfx/hud/w_icon_repeater",
|
|
/* pickup */// "Imperial Heavy Repeater",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_REPEATER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_demp2 (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
NOTENOTE This weapon is not yet complete. Don't place it.
|
|
*/
|
|
{
|
|
"weapon_demp2",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/demp2/demp2_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/demp2/demp2.md3",
|
|
/* icon */ "gfx/hud/w_icon_demp2",
|
|
/* pickup */// "DEMP2",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_DEMP2,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_flechette (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_flechette",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/golan_arms/golan_arms_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/golan_arms/golan_arms.md3",
|
|
/* icon */ "gfx/hud/w_icon_flechette",
|
|
/* pickup */// "Golan Arms Flechette",
|
|
100,
|
|
IT_WEAPON,
|
|
WP_FLECHETTE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_rocket_launcher (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_rocket_launcher",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/merr_sonn/merr_sonn_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/merr_sonn/merr_sonn.md3",
|
|
/* icon */ "gfx/hud/w_icon_merrsonn",
|
|
/* pickup */// "Merr-Sonn Missile System",
|
|
3,
|
|
IT_WEAPON,
|
|
WP_ROCKET_LAUNCHER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_thermal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"ammo_thermal",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/thermal/thermal_pu.md3",
|
|
"models/weapons2/thermal/thermal_w.glm", 0, 0},
|
|
/* view */ "models/weapons2/thermal/thermal.md3",
|
|
/* icon */ "gfx/hud/w_icon_thermal",
|
|
/* pickup */// "Thermal Detonators",
|
|
4,
|
|
IT_AMMO,
|
|
AMMO_THERMAL,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_tripmine (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"ammo_tripmine",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/laser_trap/laser_trap_pu.md3",
|
|
"models/weapons2/laser_trap/laser_trap_w.glm", 0, 0},
|
|
/* view */ "models/weapons2/laser_trap/laser_trap.md3",
|
|
/* icon */ "gfx/hud/w_icon_tripmine",
|
|
/* pickup */// "Trip Mines",
|
|
3,
|
|
IT_AMMO,
|
|
AMMO_TRIPMINE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_detpack (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"ammo_detpack",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/detpack/det_pack_pu.md3", "models/weapons2/detpack/det_pack_proj.glm", "models/weapons2/detpack/det_pack_w.glm", 0},
|
|
/* view */ "models/weapons2/detpack/det_pack.md3",
|
|
/* icon */ "gfx/hud/w_icon_detpack",
|
|
/* pickup */// "Det Packs",
|
|
3,
|
|
IT_AMMO,
|
|
AMMO_DETPACK,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_thermal (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_thermal",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/thermal/thermal_w.glm", "models/weapons2/thermal/thermal_pu.md3",
|
|
0, 0 },
|
|
/* view */ "models/weapons2/thermal/thermal.md3",
|
|
/* icon */ "gfx/hud/w_icon_thermal",
|
|
/* pickup */// "Thermal Detonator",
|
|
4,
|
|
IT_WEAPON,
|
|
WP_THERMAL,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_trip_mine (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_trip_mine",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/laser_trap/laser_trap_w.glm", "models/weapons2/laser_trap/laser_trap_pu.md3",
|
|
0, 0},
|
|
/* view */ "models/weapons2/laser_trap/laser_trap.md3",
|
|
/* icon */ "gfx/hud/w_icon_tripmine",
|
|
/* pickup */// "Trip Mine",
|
|
3,
|
|
IT_WEAPON,
|
|
WP_TRIP_MINE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_det_pack (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_det_pack",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/detpack/det_pack_proj.glm", "models/weapons2/detpack/det_pack_pu.md3", "models/weapons2/detpack/det_pack_w.glm", 0},
|
|
/* view */ "models/weapons2/detpack/det_pack.md3",
|
|
/* icon */ "gfx/hud/w_icon_detpack",
|
|
/* pickup */// "Det Pack",
|
|
3,
|
|
IT_WEAPON,
|
|
WP_DET_PACK,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED weapon_emplaced (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
*/
|
|
{
|
|
"weapon_emplaced",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/blaster_r/blaster_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/blaster_r/blaster.md3",
|
|
/* icon */ "gfx/hud/w_icon_blaster",
|
|
/* pickup */// "Emplaced Gun",
|
|
50,
|
|
IT_WEAPON,
|
|
WP_EMPLACED_GUN,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
|
|
//NOTE: This is to keep things from messing up because the turret weapon type isn't real
|
|
{
|
|
"weapon_turretwp",
|
|
"sound/weapons/w_pkup.wav",
|
|
{ "models/weapons2/blaster_r/blaster_w.glm",
|
|
0, 0, 0},
|
|
/* view */ "models/weapons2/blaster_r/blaster.md3",
|
|
/* icon */ "gfx/hud/w_icon_blaster",
|
|
/* pickup */// "Turret Gun",
|
|
50,
|
|
IT_WEAPON,
|
|
WP_TURRET,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// AMMO ITEMS
|
|
//
|
|
|
|
/*QUAKED ammo_force (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Don't place this
|
|
*/
|
|
{
|
|
"ammo_force",
|
|
"sound/player/pickupenergy.wav",
|
|
{ "models/items/energy_cell.md3",
|
|
0, 0, 0},
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/w_icon_blaster",
|
|
/* pickup */// "Force??",
|
|
100,
|
|
IT_AMMO,
|
|
AMMO_FORCE,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_blaster (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Ammo for the Bryar and Blaster pistols.
|
|
*/
|
|
{
|
|
"ammo_blaster",
|
|
"sound/player/pickupenergy.wav",
|
|
{ "models/items/energy_cell.md3",
|
|
0, 0, 0},
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/i_icon_battery",
|
|
/* pickup */// "Blaster Pack",
|
|
100,
|
|
IT_AMMO,
|
|
AMMO_BLASTER,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_powercell (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Ammo for Tenloss Disruptor, Wookie Bowcaster, and the Destructive Electro Magnetic Pulse (demp2 ) guns
|
|
*/
|
|
{
|
|
"ammo_powercell",
|
|
"sound/player/pickupenergy.wav",
|
|
{ "models/items/power_cell.md3",
|
|
0, 0, 0},
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/mp/ammo_power_cell",
|
|
/* pickup */// "Power Cell",
|
|
100,
|
|
IT_AMMO,
|
|
AMMO_POWERCELL,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_metallic_bolts (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Ammo for Imperial Heavy Repeater and the Golan Arms Flechette
|
|
*/
|
|
{
|
|
"ammo_metallic_bolts",
|
|
"sound/player/pickupenergy.wav",
|
|
{ "models/items/metallic_bolts.md3",
|
|
0, 0, 0},
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/mp/ammo_metallic_bolts",
|
|
/* pickup */// "Metallic Bolts",
|
|
100,
|
|
IT_AMMO,
|
|
AMMO_METAL_BOLTS,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16) suspended
|
|
Ammo for Merr-Sonn portable missile launcher
|
|
*/
|
|
{
|
|
"ammo_rockets",
|
|
"sound/player/pickupenergy.wav",
|
|
{ "models/items/rockets.md3",
|
|
0, 0, 0},
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/mp/ammo_rockets",
|
|
/* pickup */// "Rockets",
|
|
3,
|
|
IT_AMMO,
|
|
AMMO_ROCKETS,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
|
|
//
|
|
// POWERUP ITEMS
|
|
//
|
|
/*QUAKED team_CTF_redflag (1 0 0) (-16 -16 -16) (16 16 16)
|
|
Only in CTF games
|
|
*/
|
|
{
|
|
"team_CTF_redflag",
|
|
NULL,
|
|
{ "models/flags/r_flag.md3",
|
|
"models/flags/r_flag_ysal.md3", 0, 0 },
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/mpi_rflag",
|
|
/* pickup */// "Red Flag",
|
|
0,
|
|
IT_TEAM,
|
|
PW_REDFLAG,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
/*QUAKED team_CTF_blueflag (0 0 1) (-16 -16 -16) (16 16 16)
|
|
Only in CTF games
|
|
*/
|
|
{
|
|
"team_CTF_blueflag",
|
|
NULL,
|
|
{ "models/flags/b_flag.md3",
|
|
"models/flags/b_flag_ysal.md3", 0, 0 },
|
|
/* view */ NULL,
|
|
/* icon */ "gfx/hud/mpi_bflag",
|
|
/* pickup */// "Blue Flag",
|
|
0,
|
|
IT_TEAM,
|
|
PW_BLUEFLAG,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
//
|
|
// PERSISTANT POWERUP ITEMS
|
|
//
|
|
|
|
/*QUAKED team_CTF_neutralflag (0 0 1) (-16 -16 -16) (16 16 16)
|
|
Only in One Flag CTF games
|
|
*/
|
|
{
|
|
"team_CTF_neutralflag",
|
|
NULL,
|
|
{ "models/flags/n_flag.md3",
|
|
0, 0, 0 },
|
|
/* view */ NULL,
|
|
/* icon */ "icons/iconf_neutral1",
|
|
/* pickup */// "Neutral Flag",
|
|
0,
|
|
IT_TEAM,
|
|
PW_NEUTRALFLAG,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
{
|
|
"item_redcube",
|
|
"sound/player/pickupenergy.wav",
|
|
{ "models/powerups/orb/r_orb.md3",
|
|
0, 0, 0 },
|
|
/* view */ NULL,
|
|
/* icon */ "icons/iconh_rorb",
|
|
/* pickup */// "Red Cube",
|
|
0,
|
|
IT_TEAM,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
{
|
|
"item_bluecube",
|
|
"sound/player/pickupenergy.wav",
|
|
{ "models/powerups/orb/b_orb.md3",
|
|
0, 0, 0 },
|
|
/* view */ NULL,
|
|
/* icon */ "icons/iconh_borb",
|
|
/* pickup */// "Blue Cube",
|
|
0,
|
|
IT_TEAM,
|
|
0,
|
|
/* precache */ "",
|
|
/* sounds */ ""
|
|
},
|
|
|
|
// end of list marker
|
|
{NULL}
|
|
};
|
|
|
|
int bg_numItems = sizeof(bg_itemlist) / sizeof(bg_itemlist[0]) - 1;
|
|
|
|
float vectoyaw( const vec3_t vec ) {
|
|
float yaw;
|
|
|
|
if (vec[YAW] == 0 && vec[PITCH] == 0) {
|
|
yaw = 0;
|
|
} else {
|
|
if (vec[PITCH]) {
|
|
yaw = ( atan2( vec[YAW], vec[PITCH]) * 180 / M_PI );
|
|
} else if (vec[YAW] > 0) {
|
|
yaw = 90;
|
|
} else {
|
|
yaw = 270;
|
|
}
|
|
if (yaw < 0) {
|
|
yaw += 360;
|
|
}
|
|
}
|
|
|
|
return yaw;
|
|
}
|
|
|
|
qboolean BG_HasYsalamiri(int gametype, playerState_t *ps)
|
|
{
|
|
if (gametype == GT_CTY &&
|
|
(ps->powerups[PW_REDFLAG] || ps->powerups[PW_BLUEFLAG]))
|
|
{
|
|
return qtrue;
|
|
}
|
|
|
|
if (ps->powerups[PW_YSALAMIRI])
|
|
{
|
|
return qtrue;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_CanUseFPNow(int gametype, playerState_t *ps, int time, forcePowers_t power)
|
|
{
|
|
if (BG_HasYsalamiri(gametype, ps))
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
if ( ps->forceRestricted || ps->trueNonJedi )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
if (ps->duelInProgress)
|
|
{
|
|
if (power != FP_SABERATTACK && power != FP_SABERDEFEND && /*power != FP_SABERTHROW &&*/
|
|
power != FP_LEVITATION)
|
|
{
|
|
if (!ps->saberLockFrame || power != FP_PUSH)
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ps->saberLockFrame || ps->saberLockTime > time)
|
|
{
|
|
if (power != FP_PUSH)
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
if (ps->fallingToDeath)
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
==============
|
|
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;
|
|
|
|
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_FindItem
|
|
|
|
===============
|
|
*/
|
|
gitem_t *BG_FindItem( const char *classname ) {
|
|
gitem_t *it;
|
|
|
|
for ( it = bg_itemlist + 1 ; it->classname ; it++ ) {
|
|
if ( !Q_stricmp( it->classname, classname) )
|
|
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;
|
|
}
|
|
|
|
int BG_ProperForceIndex(int power)
|
|
{
|
|
int i = 0;
|
|
|
|
while (i < NUM_FORCE_POWERS)
|
|
{
|
|
if (forcePowerSorted[i] == power)
|
|
{
|
|
return i;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void BG_CycleForce(playerState_t *ps, int direction)
|
|
{
|
|
int i = ps->fd.forcePowerSelected;
|
|
int x = i;
|
|
int presel = i;
|
|
int foundnext = -1;
|
|
|
|
if (!ps->fd.forcePowersKnown & (1 << x) ||
|
|
x >= NUM_FORCE_POWERS ||
|
|
x == -1)
|
|
{ //apparently we have no valid force powers
|
|
return;
|
|
}
|
|
|
|
x = BG_ProperForceIndex(x);
|
|
presel = x;
|
|
|
|
if (direction == 1)
|
|
{ //get the next power
|
|
x++;
|
|
}
|
|
else
|
|
{ //get the previous power
|
|
x--;
|
|
}
|
|
|
|
if (x >= NUM_FORCE_POWERS)
|
|
{ //cycled off the end.. cycle around to the first
|
|
x = 0;
|
|
}
|
|
if (x < 0)
|
|
{ //cycled off the beginning.. cycle around to the last
|
|
x = NUM_FORCE_POWERS-1;
|
|
}
|
|
|
|
i = forcePowerSorted[x]; //the "sorted" value of this power
|
|
|
|
while (x != presel)
|
|
{ //loop around to the current force power
|
|
if (ps->fd.forcePowersKnown & (1 << i) && i != ps->fd.forcePowerSelected)
|
|
{ //we have the force power
|
|
if (i != FP_LEVITATION &&
|
|
i != FP_SABERATTACK &&
|
|
i != FP_SABERDEFEND &&
|
|
i != FP_SABERTHROW)
|
|
{ //it's selectable
|
|
foundnext = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (direction == 1)
|
|
{ //next
|
|
x++;
|
|
}
|
|
else
|
|
{ //previous
|
|
x--;
|
|
}
|
|
|
|
if (x >= NUM_FORCE_POWERS)
|
|
{ //loop around
|
|
x = 0;
|
|
}
|
|
if (x < 0)
|
|
{ //loop around
|
|
x = NUM_FORCE_POWERS-1;
|
|
}
|
|
|
|
i = forcePowerSorted[x]; //set to the sorted value again
|
|
}
|
|
|
|
if (foundnext != -1)
|
|
{ //found one, select it
|
|
ps->fd.forcePowerSelected = foundnext;
|
|
}
|
|
}
|
|
|
|
int BG_GetItemIndexByTag(int tag, int type)
|
|
{ //Get the itemlist index from the tag and type
|
|
int i = 0;
|
|
|
|
while (i < bg_numItems)
|
|
{
|
|
if (bg_itemlist[i].giTag == tag &&
|
|
bg_itemlist[i].giType == type)
|
|
{
|
|
return i;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void BG_CycleInven(playerState_t *ps, int direction)
|
|
{
|
|
int i;
|
|
int original;
|
|
|
|
i = bg_itemlist[ps->stats[STAT_HOLDABLE_ITEM]].giTag;
|
|
original = i;
|
|
|
|
if (direction == 1)
|
|
{ //next
|
|
i++;
|
|
}
|
|
else
|
|
{ //previous
|
|
i--;
|
|
}
|
|
|
|
while (i != original)
|
|
{ //go in a full loop until hitting something, if hit nothing then select nothing
|
|
if (ps->stats[STAT_HOLDABLE_ITEMS] & (1 << i))
|
|
{ //we have it, select it.
|
|
ps->stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(i, IT_HOLDABLE);
|
|
break;
|
|
}
|
|
|
|
if (direction == 1)
|
|
{ //next
|
|
i++;
|
|
}
|
|
else
|
|
{ //previous
|
|
i--;
|
|
}
|
|
|
|
if (i < 0)
|
|
{ //wrap around to the last
|
|
i = HI_NUM_HOLDABLE;
|
|
}
|
|
else if (i >= HI_NUM_HOLDABLE)
|
|
{ //wrap around to the first
|
|
i = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
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];
|
|
|
|
if ( ps )
|
|
{
|
|
if ( ps->trueJedi )
|
|
{//force powers and saber only
|
|
if ( item->giType != IT_TEAM //not a flag
|
|
&& item->giType != IT_ARMOR//not shields
|
|
&& (item->giType != IT_WEAPON || item->giTag != WP_SABER)//not a saber
|
|
&& (item->giType != IT_HOLDABLE || item->giTag != HI_SEEKER)//not a seeker
|
|
&& (item->giType != IT_POWERUP || item->giTag == PW_YSALAMIRI) )//not a force pick-up
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
else if ( ps->trueNonJedi )
|
|
{//can't pick up force powerups
|
|
if ( (item->giType == IT_POWERUP && item->giTag != PW_YSALAMIRI) //if a powerup, can only can pick up ysalamiri
|
|
|| (item->giType == IT_HOLDABLE && item->giTag == HI_SEEKER)//if holdable, cannot pick up seeker
|
|
|| (item->giType == IT_WEAPON && item->giTag == WP_SABER ) )//or if it's a saber
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
if ( ps->isJediMaster && item && (item->giType == IT_WEAPON || item->giType == IT_AMMO))
|
|
{//jedi master cannot pick up weapons
|
|
return qfalse;
|
|
}
|
|
if ( ps->duelInProgress )
|
|
{ //no picking stuff up while in a duel, no matter what the type is
|
|
return qfalse;
|
|
}
|
|
}
|
|
else
|
|
{//safety return since below code assumes a non-null ps
|
|
return qfalse;
|
|
}
|
|
|
|
switch( item->giType ) {
|
|
case IT_WEAPON:
|
|
if (ent->generic1 == ps->clientNum && ent->powerups)
|
|
{
|
|
return qfalse;
|
|
}
|
|
if (!(ent->eFlags & EF_DROPPEDWEAPON) && (ps->stats[STAT_WEAPONS] & (1 << item->giTag)) &&
|
|
item->giTag != WP_THERMAL && item->giTag != WP_TRIP_MINE && item->giTag != WP_DET_PACK)
|
|
{ //weaponstay stuff.. if this isn't dropped, and you already have it, you don't get it.
|
|
return qfalse;
|
|
}
|
|
return qtrue; // weapons are always picked up
|
|
|
|
case IT_AMMO:
|
|
if ( ps->ammo[item->giTag] >= ammoData[item->giTag].max) {
|
|
return qfalse; // can't hold any more
|
|
}
|
|
return qtrue;
|
|
|
|
case IT_ARMOR:
|
|
if ( ps->stats[STAT_ARMOR] >= ps->stats[STAT_MAX_HEALTH] * item->giTag ) {
|
|
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 ((ps->fd.forcePowersActive & (1 << FP_RAGE)))
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
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 && (ps->powerups[PW_YSALAMIRI]))
|
|
{
|
|
if (item->giTag != PW_YSALAMIRI)
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
return qtrue; // powerups are always picked up
|
|
|
|
case IT_TEAM: // team items, such as flags
|
|
if( gametype == GT_CTF || gametype == GT_CTY ) {
|
|
// 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:
|
|
if ( ps->stats[STAT_HOLDABLE_ITEMS] & (1 << item->giTag))
|
|
{
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
|
|
case IT_BAD:
|
|
Com_Error( ERR_DROP, "BG_CanItemBeGrabbed: IT_BAD" );
|
|
default:
|
|
#ifndef Q3_VM
|
|
#ifndef NDEBUG // bk0001204
|
|
Com_Printf("BG_CanItemBeGrabbed: unknown enum %d\n", item->giType );
|
|
#endif
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
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:
|
|
#ifdef QAGAME
|
|
Com_Error( ERR_DROP, "BG_EvaluateTrajectory: [GAME SIDE] unknown trType: %i", tr->trType );
|
|
#else
|
|
Com_Error( ERR_DROP, "BG_EvaluateTrajectory: [CLIENTGAME SIDE] unknown trType: %i", tr->trType );
|
|
#endif
|
|
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_CLIENTJOIN",
|
|
|
|
"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",
|
|
|
|
"EV_JUMP_PAD", // boing sound at origin", jump sound on player
|
|
|
|
"EV_PRIVATE_DUEL",
|
|
|
|
"EV_JUMP",
|
|
"EV_ROLL",
|
|
"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_ALT_FIRE",
|
|
"EV_SABER_ATTACK",
|
|
"EV_SABER_HIT",
|
|
"EV_SABER_BLOCK",
|
|
"EV_SABER_UNHOLSTER",
|
|
"EV_BECOME_JEDIMASTER",
|
|
"EV_DISRUPTOR_MAIN_SHOT",
|
|
"EV_DISRUPTOR_SNIPER_SHOT",
|
|
"EV_DISRUPTOR_SNIPER_MISS",
|
|
"EV_DISRUPTOR_HIT",
|
|
"EV_DISRUPTOR_ZOOMSOUND",
|
|
|
|
"EV_PREDEFSOUND",
|
|
|
|
"EV_TEAM_POWER",
|
|
|
|
"EV_SCREENSHAKE",
|
|
|
|
"EV_USE", // +Use key
|
|
|
|
"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_ITEMUSEFAIL",
|
|
|
|
"EV_ITEM_RESPAWN",
|
|
"EV_ITEM_POP",
|
|
"EV_PLAYER_TELEPORT_IN",
|
|
"EV_PLAYER_TELEPORT_OUT",
|
|
|
|
"EV_GRENADE_BOUNCE", // eventParm will be the soundindex
|
|
"EV_MISSILE_STICK",
|
|
|
|
"EV_PLAY_EFFECT",
|
|
"EV_PLAY_EFFECT_ID", //finally gave in and added it..
|
|
|
|
"EV_MUTE_SOUND",
|
|
"EV_GENERAL_SOUND",
|
|
"EV_GLOBAL_SOUND", // no attenuation
|
|
"EV_GLOBAL_TEAM_SOUND",
|
|
"EV_ENTITY_SOUND",
|
|
|
|
"EV_PLAY_ROFF",
|
|
|
|
"EV_GLASS_SHATTER",
|
|
"EV_DEBRIS",
|
|
|
|
"EV_MISSILE_HIT",
|
|
"EV_MISSILE_MISS",
|
|
"EV_MISSILE_MISS_METAL",
|
|
"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_FORCE_DRAINED",
|
|
|
|
"EV_GIB_PLAYER", // gib a previously living player
|
|
"EV_SCOREPLUM", // score plum
|
|
|
|
"EV_CTFMESSAGE",
|
|
|
|
"EV_SAGA_ROUNDOVER",
|
|
"EV_SAGA_OBJECTIVECOMPLETE",
|
|
|
|
"EV_DESTROY_GHOUL2_INSTANCE",
|
|
|
|
"EV_DESTROY_WEAPON_MODEL",
|
|
|
|
"EV_GIVE_NEW_RANK",
|
|
"EV_SET_FREE_SABER",
|
|
"EV_SET_FORCE_DISABLE",
|
|
|
|
"EV_WEAPON_CHARGE",
|
|
"EV_WEAPON_CHARGE_ALT",
|
|
|
|
"EV_SHIELD_HIT",
|
|
|
|
"EV_DEBUG_LINE",
|
|
"EV_TESTLINE",
|
|
"EV_STOPLOOPINGSOUND",
|
|
"EV_STARTLOOPINGSOUND",
|
|
"EV_TAUNT",
|
|
|
|
"EV_TAUNT_YES",
|
|
"EV_TAUNT_NO",
|
|
"EV_TAUNT_FOLLOWME",
|
|
"EV_TAUNT_GETFLAG",
|
|
"EV_TAUNT_GUARDBASE",
|
|
"EV_TAUNT_PATROL",
|
|
|
|
"EV_BODY_QUEUE_COPY"
|
|
|
|
};
|
|
|
|
/*
|
|
===============
|
|
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 && ps->pm_type != PM_FLOAT ) {
|
|
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;
|
|
}
|
|
}
|
|
// 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;
|
|
|
|
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 );
|
|
}
|
|
|
|
s->trickedentindex = ps->fd.forceMindtrickTargetIndex;
|
|
s->trickedentindex2 = ps->fd.forceMindtrickTargetIndex2;
|
|
s->trickedentindex3 = ps->fd.forceMindtrickTargetIndex3;
|
|
s->trickedentindex4 = ps->fd.forceMindtrickTargetIndex4;
|
|
|
|
s->forceFrame = ps->saberLockFrame;
|
|
|
|
s->emplacedOwner = ps->electrifyTime;
|
|
|
|
s->speed = ps->speed;
|
|
|
|
s->genericenemyindex = ps->genericEnemyIndex;
|
|
|
|
s->activeForcePass = ps->activeForcePass;
|
|
|
|
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;
|
|
|
|
s->saberInFlight = ps->saberInFlight;
|
|
s->saberEntityNum = ps->saberEntityNum;
|
|
s->saberMove = ps->saberMove;
|
|
s->forcePowersActive = ps->fd.forcePowersActive;
|
|
|
|
if (ps->duelInProgress)
|
|
{
|
|
s->bolt1 = 1;
|
|
}
|
|
else
|
|
{
|
|
s->bolt1 = 0;
|
|
}
|
|
|
|
if (ps->dualBlade)
|
|
{
|
|
s->bolt2 = 1;
|
|
}
|
|
else
|
|
{
|
|
s->bolt2 = 0;
|
|
}
|
|
|
|
s->otherEntityNum2 = ps->emplacedIndex;
|
|
|
|
s->shouldtarget = ps->saberHolstered; //reuse bool in entitystate for players differently
|
|
s->teamowner = ps->usingATST;
|
|
|
|
if (ps->genericEnemyIndex != -1)
|
|
{
|
|
s->eFlags |= EF_SEEKERDRONE;
|
|
}
|
|
|
|
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 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;
|
|
}
|
|
}
|
|
|
|
s->loopSound = ps->loopSound;
|
|
s->generic1 = ps->generic1;
|
|
|
|
//NOT INCLUDED IN ENTITYSTATETOPLAYERSTATE:
|
|
s->modelindex2 = ps->weaponstate;
|
|
s->constantLight = ps->weaponChargeTime;
|
|
|
|
VectorCopy(ps->lastHitLoc, s->origin2);
|
|
|
|
s->isJediMaster = ps->isJediMaster;
|
|
|
|
s->time2 = ps->holocronBits;
|
|
|
|
s->fireflag = ps->fd.saberAnimLevel;
|
|
}
|
|
|
|
/*
|
|
========================
|
|
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;
|
|
|
|
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 );
|
|
}
|
|
|
|
s->trickedentindex = ps->fd.forceMindtrickTargetIndex;
|
|
s->trickedentindex2 = ps->fd.forceMindtrickTargetIndex2;
|
|
s->trickedentindex3 = ps->fd.forceMindtrickTargetIndex3;
|
|
s->trickedentindex4 = ps->fd.forceMindtrickTargetIndex4;
|
|
|
|
s->forceFrame = ps->saberLockFrame;
|
|
|
|
s->emplacedOwner = ps->electrifyTime;
|
|
|
|
s->speed = ps->speed;
|
|
|
|
s->genericenemyindex = ps->genericEnemyIndex;
|
|
|
|
s->activeForcePass = ps->activeForcePass;
|
|
|
|
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;
|
|
|
|
s->saberInFlight = ps->saberInFlight;
|
|
s->saberEntityNum = ps->saberEntityNum;
|
|
s->saberMove = ps->saberMove;
|
|
s->forcePowersActive = ps->fd.forcePowersActive;
|
|
|
|
if (ps->duelInProgress)
|
|
{
|
|
s->bolt1 = 1;
|
|
}
|
|
else
|
|
{
|
|
s->bolt1 = 0;
|
|
}
|
|
|
|
if (ps->dualBlade)
|
|
{
|
|
s->bolt2 = 1;
|
|
}
|
|
else
|
|
{
|
|
s->bolt2 = 0;
|
|
}
|
|
|
|
s->otherEntityNum2 = ps->emplacedIndex;
|
|
|
|
s->shouldtarget = ps->saberHolstered; //reuse bool in entitystate for players differently
|
|
s->teamowner = ps->usingATST;
|
|
|
|
if (ps->genericEnemyIndex != -1)
|
|
{
|
|
s->eFlags |= EF_SEEKERDRONE;
|
|
}
|
|
|
|
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 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;
|
|
}
|
|
}
|
|
|
|
s->loopSound = ps->loopSound;
|
|
s->generic1 = ps->generic1;
|
|
|
|
//NOT INCLUDED IN ENTITYSTATETOPLAYERSTATE:
|
|
s->modelindex2 = ps->weaponstate;
|
|
s->constantLight = ps->weaponChargeTime;
|
|
|
|
VectorCopy(ps->lastHitLoc, s->origin2);
|
|
|
|
s->isJediMaster = ps->isJediMaster;
|
|
|
|
s->time2 = ps->holocronBits;
|
|
|
|
s->fireflag = ps->fd.saberAnimLevel;
|
|
}
|
|
|
|
/*
|
|
=============================================================================
|
|
|
|
PLAYER ANGLES
|
|
|
|
=============================================================================
|
|
*/
|
|
#define MAX_POOL_SIZE 2048000 //1024000
|
|
|
|
static char bg_pool[MAX_POOL_SIZE];
|
|
static int bg_poolSize = 0;
|
|
static int bg_poolTail = MAX_POOL_SIZE;
|
|
|
|
void *BG_Alloc ( int size )
|
|
{
|
|
bg_poolSize = ((bg_poolSize + 0x00000003) & 0xfffffffc);
|
|
|
|
if (bg_poolSize + size > bg_poolTail)
|
|
{
|
|
Com_Error( ERR_DROP, "BG_Alloc: buffer exceeded tail (%d > %d)", bg_poolSize + size, bg_poolTail);
|
|
return 0;
|
|
}
|
|
|
|
bg_poolSize += size;
|
|
|
|
return &bg_pool[bg_poolSize-size];
|
|
}
|
|
|
|
void *BG_AllocUnaligned ( int size )
|
|
{
|
|
if (bg_poolSize + size > bg_poolTail)
|
|
{
|
|
Com_Error( ERR_DROP, "BG_AllocUnaligned: buffer exceeded tail (%d > %d)", bg_poolSize + size, bg_poolTail);
|
|
return 0;
|
|
}
|
|
|
|
bg_poolSize += size;
|
|
|
|
return &bg_pool[bg_poolSize-size];
|
|
}
|
|
|
|
void *BG_TempAlloc( int size )
|
|
{
|
|
size = ((size + 0x00000003) & 0xfffffffc);
|
|
|
|
if (bg_poolTail - size < bg_poolSize)
|
|
{
|
|
Com_Error( ERR_DROP, "BG_TempAlloc: buffer exceeded head (%d > %d)", bg_poolTail - size, bg_poolSize);
|
|
return 0;
|
|
}
|
|
|
|
bg_poolTail -= size;
|
|
|
|
return &bg_pool[bg_poolTail];
|
|
}
|
|
|
|
void BG_TempFree( int size )
|
|
{
|
|
size = ((size + 0x00000003) & 0xfffffffc);
|
|
|
|
if (bg_poolTail+size > MAX_POOL_SIZE)
|
|
{
|
|
Com_Error( ERR_DROP, "BG_TempFree: tail greater than size (%d > %d)", bg_poolTail+size, MAX_POOL_SIZE );
|
|
}
|
|
|
|
bg_poolTail += size;
|
|
}
|
|
|
|
char *BG_StringAlloc ( const char *source )
|
|
{
|
|
char *dest;
|
|
|
|
dest = BG_Alloc ( strlen ( source ) + 1 );
|
|
strcpy ( dest, source );
|
|
return dest;
|
|
}
|
|
|
|
qboolean BG_OutOfMemory ( void )
|
|
{
|
|
return bg_poolSize >= MAX_POOL_SIZE;
|
|
}
|