Code for the 0-10-0x VM releases
Server-side
This commit is contained in:
Victor Chow 2001-08-30 09:47:39 +00:00
parent 8ea88d097b
commit 9e2222ecf1
12 changed files with 688 additions and 106 deletions

View file

@ -1312,7 +1312,9 @@ char *eventnames[] = {
"EV_NOAMMO",
"EV_CHANGE_WEAPON",
"EV_FIRE_WEAPON",
"EV_RELOAD_WEAPON," // Elder: reload weapon sounds
"EV_RELOAD_WEAPON0", // Elder: reload weapon sounds
"EV_RELOAD_WEAPON1", // Elder: reload weapon sounds
"EV_RELOAD_WEAPON2", // Elder: reload weapon sounds
"EV_USE_ITEM0",
"EV_USE_ITEM1",
@ -1347,8 +1349,10 @@ char *eventnames[] = {
"EV_BULLET_HIT_FLESH",
"EV_BULLET_HIT_WALL",
"EV_SSG3000_HIT_FLESH", //Elder: SSG3000 blood spray
"EV_JUMPKICK", //Elder: sound + jumpkick message
"EV_BULLET_HIT_METAL", // Elder: sparks
"EV_BULLET_HIT_KEVLAR", // Elder: sparks
"EV_SSG3000_HIT_FLESH", // Elder: SSG3000 blood spray
"EV_JUMPKICK", // Elder: sound + jumpkick message
"EV_MISSILE_HIT",
"EV_MISSILE_MISS",

View file

@ -109,6 +109,7 @@ void PM_AddEvent( int newEvent ) {
PM_AddEvent
Elder: stuffs event parameters
Be careful because you are stuffing the player
===============
*/
void PM_AddEvent2( int newEvent, int eventParm ) {
@ -1831,16 +1832,25 @@ static void PM_BeginWeaponChange( int weapon ) {
if (pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000)
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4)
PM_StartWeaponAnim(WP_ANIM_DISARM);
}
// Elder: cancel reload stuff here
pm->ps->stats[STAT_RELOADTIME] = 0;
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
pm->ps->stats[STAT_RQ3] &= ~RQ3_FASTRELOADS;
pm->ps->stats[STAT_RQ3] &= ~RQ3_LOCKRELOADS;
pm->ps->weaponstate = WEAPON_DROPPING;
//Elder: temp hack
if (pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000)
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4)
PM_StartWeaponAnim(WP_ANIM_DISARM);
PM_StartTorsoAnim( TORSO_DROP );
@ -1915,7 +1925,8 @@ static void PM_FinishWeaponChange( void ) {
if (pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000)
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4)
PM_StartWeaponAnim(WP_ANIM_ACTIVATE);
PM_StartTorsoAnim( TORSO_RAISE );
@ -1942,7 +1953,8 @@ static void PM_TorsoAnimation( void ) {
if (pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000)
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4)
PM_ContinueWeaponAnim( WP_ANIM_IDLE );
// PM_ContinueWeaponAnim( WP_ANIM_READY );
@ -1970,6 +1982,298 @@ static void PM_WeaponAnimation( void ) {
return;
}
/*
==============
PM_Reload
Added by Elder
What a mess this is :/
FIXME: This is poorly implemented
Does reload stuff like fast-reloads, sound events,
some ammo synchronization, etc.
Clip management is handled on the server (ReloadWeapon)
because we can't store all the clips in a playerstate (nor should we)
It is triggered by BUTTON_AFFIRMATIVE (bind +button5)
==============
*/
static void PM_Reload( void )
{
// int weapon = pm->ps->weapon;
// only normal/noclip players can reload
if (pm->ps->pm_type > PM_NOCLIP)
{
pm->ps->pm_flags &= ~PMF_RELOAD_HELD;
pm->ps->stats[STAT_RELOADTIME] = 0;
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
pm->ps->stats[STAT_RQ3] &= ~RQ3_FASTRELOADS;
pm->ps->stats[STAT_RQ3] &= ~RQ3_LOCKRELOADS;
return;
}
if ( pm->cmd.buttons & BUTTON_AFFIRMATIVE ) {
if ( !(pm->ps->pm_flags & PMF_RELOAD_HELD) )
{
// prevent throttling
pm->ps->pm_flags |= PMF_RELOAD_HELD;
// check for bursting or weapon delay
if (pm->ps->stats[STAT_BURST] > 0 || pm->ps->weaponTime > 0)
return;
// check for bandaging
if (pm->ps->stats[STAT_RQ3] & RQ3_BANDAGE_WORK)
return;
// check for full clip or non-reloadable weapons
if (pm->ps->ammo[pm->ps->weapon] == ClipAmountForAmmo(pm->ps->weapon) ||
pm->ps->weapon == WP_KNIFE ||
pm->ps->weapon == WP_GRENADE)
{
//Com_Printf("No need to reload.\n");
return;
}
// check for insufficient ammo
if (pm->ps->stats[STAT_CLIPS] <= 0)
{
//Com_Printf("Out of ammo.\n");
return;
}
else if (pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_AKIMBO)
{
if (pm->ps->stats[STAT_CLIPS] < 2)
{
//Com_Printf("Not enough ammo.\n");
return;
}
}
// check for fast-reload interrupt
if (pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000)
{
if (pm->ps->stats[STAT_RELOADTIME] > 0) {
if ( pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS )
{
Com_Printf("============= Locked out in fast-reload interrupt\n");
}
else
{
//if (pm->ps->ammo[pm->ps->weapon] + pm->ps->stats[STAT_RELOADATTEMPTS] < ClipAmountForAmmo(pm->ps->weapon) &&
//pm->ps->stats[STAT_RELOADATTEMPTS] < pm->ps->stats[STAT_CLIPS])
if (pm->ps->stats[STAT_RELOADATTEMPTS] < ClipAmountForAmmo(pm->ps->weapon))
{
//Com_Printf("Hit fast-reload entrance\n");
// add to reload queue and enable fast-reloads flag
pm->ps->stats[STAT_RQ3] |= RQ3_FASTRELOADS;
pm->ps->stats[STAT_RELOADATTEMPTS]++;
Com_Printf("======== Reload attempts: %i ========\n", pm->ps->stats[STAT_RELOADATTEMPTS]);
}
return;
}
}
}
// fresh reload
if (pm->ps->stats[STAT_RELOADTIME] == 0)
{
// set reload time according to weapon
switch (pm->ps->weapon)
{
case WP_PISTOL:
pm->ps->stats[STAT_RELOADTIME] = RQ3_PISTOL_RELOAD_DELAY;
break;
case WP_AKIMBO:
pm->ps->stats[STAT_RELOADTIME] = RQ3_AKIMBO_RELOAD_DELAY;
break;
case WP_M3:
pm->ps->stats[STAT_RELOADTIME] = RQ3_M3_RELOAD_DELAY;
pm->ps->stats[STAT_RELOADATTEMPTS]++;
break;
case WP_M4:
pm->ps->stats[STAT_RELOADTIME] = RQ3_M4_RELOAD_DELAY;
break;
case WP_MP5:
pm->ps->stats[STAT_RELOADTIME] = RQ3_MP5_RELOAD_DELAY;
break;
case WP_HANDCANNON:
pm->ps->stats[STAT_RELOADTIME] = RQ3_HANDCANNON_RELOAD_DELAY;
break;
case WP_SSG3000:
pm->ps->stats[STAT_RELOADTIME] = RQ3_SSG3000_RELOAD_DELAY;
pm->ps->stats[STAT_RELOADATTEMPTS]++;
break;
}
pm->ps->weaponstate = WEAPON_RELOADING;
PM_AddEvent(EV_RELOAD_WEAPON0);
//Com_Printf("Starting reload\n");
return;
}
}
}
else
{
pm->ps->pm_flags &= ~PMF_RELOAD_HELD;
}
// in-progress reload
if (pm->ps->stats[STAT_RELOADTIME] > 0)
{
pm->ps->stats[STAT_RELOADTIME] -= pml.msec;
// process any fast-reload stuff here
if (pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000) {
if ((pm->ps->stats[STAT_RQ3] & RQ3_FASTRELOADS) && pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
{
if (pm->ps->weapon == WP_M3)
{
// knock down reload time if doing fast-reloads
if (pm->ps->stats[STAT_RELOADTIME] > RQ3_M3_FAST_RELOAD_DELAY)
{
//Com_Printf("Reducing reload time\n");
pm->ps->stats[STAT_RELOADTIME] = RQ3_M3_FAST_RELOAD_DELAY;
}
}
else
{
// knock down reload time if doing fast-reloads
if (pm->ps->stats[STAT_RELOADTIME] > RQ3_SSG3000_FAST_RELOAD_DELAY)
{
//Com_Printf("Reducing reload time\n");
pm->ps->stats[STAT_RELOADTIME] = RQ3_SSG3000_FAST_RELOAD_DELAY;
}
}
}
}
// insert stage 1 sound events here; check against the reload time
// finished reload
if (pm->ps->stats[STAT_RELOADTIME] <= 0)
{
int ammotoadd;
ammotoadd = ClipAmountForReload(pm->ps->weapon);
if (pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000)
{
// need to also check here because of fast-reloads
if (ammotoadd + pm->ps->ammo[pm->ps->weapon] > ClipAmountForAmmo(pm->ps->weapon) ||
pm->ps->stats[STAT_CLIPS] <= 0)
{
ammotoadd = pm->ps->ammo[pm->ps->weapon];
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
}
else
ammotoadd += pm->ps->ammo[pm->ps->weapon];
}
// akimbo and MK23 synchronization
if (pm->ps->weapon == WP_AKIMBO)
{
pm->ps->ammo[WP_PISTOL] = RQ3_PISTOL_AMMO;
}
else if (pm->ps->weapon == WP_PISTOL &&
(pm->ps->stats[STAT_WEAPONS] & (1 << WP_AKIMBO)))
{
// weird? That's because we gave one pistol a full clip
pm->ps->ammo[WP_AKIMBO] = pm->ps->ammo[WP_AKIMBO] - pm->ps->ammo[WP_PISTOL] + ammotoadd;
if (pm->ps->ammo[WP_AKIMBO] > RQ3_AKIMBO_AMMO)
pm->ps->ammo[WP_AKIMBO] = RQ3_AKIMBO_AMMO;
}
if ( !(pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS) )
pm->ps->ammo[pm->ps->weapon] = ammotoadd;
// handle continuous fast-reloads
if ((pm->ps->weapon == WP_M3 || pm->ps->weapon == WP_SSG3000) &&
(pm->ps->stats[STAT_RQ3] & RQ3_FASTRELOADS) )//&&
//pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
{
if ( !(pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS) &&
pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
{
//Com_Printf("Fast-reload cycle repeating\n");
if (pm->ps->weapon == WP_M3)
pm->ps->stats[STAT_RELOADTIME] += RQ3_M3_FAST_RELOAD_DELAY;
else
pm->ps->stats[STAT_RELOADTIME] += RQ3_SSG3000_FAST_RELOAD_DELAY;
pm->ps->stats[STAT_RELOADATTEMPTS]--;
if (pm->ps->stats[STAT_RELOADATTEMPTS] > 0)
PM_StartWeaponAnim(WP_ANIM_RELOAD);
//PM_StartWeaponAnim(WP_ANIM_EXTRA1);
if (pm->ps->stats[STAT_CLIPS] > 0)
{
Com_Printf("Sending event from continuous fast-reloads\n");
PM_AddEvent(EV_RELOAD_WEAPON2);
}
else
{
Com_Printf("Negative event prevented\n");
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
}
}
else
{
Com_Printf("============= Locked out in continuous fast-reloads\n");
}
// finishing up fast reloads
if ((pm->ps->stats[STAT_RQ3] & RQ3_FASTRELOADS) &&
pm->ps->stats[STAT_RELOADATTEMPTS] == 0)
{
//Com_Printf("Fast-reload cycle ending\n");
if (pm->ps->weapon == WP_M3)
pm->ps->stats[STAT_RELOADTIME] += RQ3_M3_FINISH_RELOAD_DELAY;
else
pm->ps->stats[STAT_RELOADTIME] += RQ3_SSG3000_FINISH_RELOAD_DELAY;
pm->ps->stats[STAT_RQ3] &= ~RQ3_FASTRELOADS;
// lock fast-reloads during finish delay
pm->ps->stats[STAT_RQ3] |= RQ3_LOCKRELOADS;
Com_Printf("<<<<<<<<<<<<< Locking\n");
}
return;
}
// normal reload case
//else
//{
// unlock
if (pm->ps->stats[STAT_RQ3] & RQ3_LOCKRELOADS)
{
Com_Printf(">>>>>>>>>>>>> Unlocking\n");
pm->ps->stats[STAT_RQ3] &= ~RQ3_LOCKRELOADS;
}
else
{
Com_Printf("Sending event from normal reload\n");
PM_AddEvent(EV_RELOAD_WEAPON2);
}
//Com_Printf("Finished reload\n");
pm->ps->stats[STAT_RELOADTIME] = 0;
pm->ps->stats[STAT_RELOADATTEMPTS] = 0;
pm->ps->weaponstate = WEAPON_READY;
//}
} // end finish reload
} // end in-progress reload
}
/*
==============
PM_Weapon
@ -2102,7 +2406,8 @@ static void PM_Weapon( void ) {
(pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000))
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4))
PM_ContinueWeaponAnim(WP_ANIM_IDLE);
}
}
@ -2122,11 +2427,11 @@ static void PM_Weapon( void ) {
pm->ps->stats[STAT_WEAPONS] &= ~( 1 << WP_GRENADE);
}*/
if ( pm->ps->weaponTime > 0 ) {
// Elder: added STAT_RELOADTIME check
if ( pm->ps->weaponTime > 0 || pm->ps->stats[STAT_RELOADTIME] > 0) {
return;
}
//Com_Printf("Weaponstate (%d)\n", pm->ps->weaponstate);
// change weapon if time
if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
@ -2148,7 +2453,8 @@ static void PM_Weapon( void ) {
if (pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000)
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4)
PM_StartWeaponAnim( WP_ANIM_IDLE );
return;
}
@ -2233,10 +2539,12 @@ static void PM_Weapon( void ) {
// QUARANTINE - Weapon animations
// This should change pm->ps->generic1 so we can animate
// Elder: don't repeat if on semi-auto
// temp hack
if (pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000)
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4)
PM_StartWeaponAnim( WP_ANIM_FIRE );
}
}
@ -2293,7 +2601,7 @@ static void PM_Weapon( void ) {
//Elder: remove one more bullet/shell if handcannon/akimbo
else if (pm->ps->weapon == WP_HANDCANNON)
{
pm->ps->ammo[ pm->ps->weapon ]--;
pm->ps->ammo[ WP_HANDCANNON ]--;
}
//Elder: take away an extra bullet if available - handled in g_weapon.c as well
else if (pm->ps->weapon == WP_AKIMBO && pm->ps->ammo[ WP_AKIMBO ] > 0) {
@ -2301,7 +2609,7 @@ static void PM_Weapon( void ) {
}
//Elder: sync bullets a la AQ2 style
if (pm->ps->weapon == WP_AKIMBO && pm->ps->ammo[pm->ps->weapon] < 12) {
if (pm->ps->weapon == WP_AKIMBO && pm->ps->ammo[WP_AKIMBO] < 12) {
pm->ps->ammo[WP_PISTOL] = pm->ps->ammo[WP_AKIMBO];
}
else if (pm->ps->weapon == WP_PISTOL && pm->ps->ammo[WP_AKIMBO] > 0) {
@ -2538,8 +2846,42 @@ static void PM_LadderMove( void ) {
vec3_t lookAhead;
vec3_t trEndTest;
// New experimental jump code -- not too good
#if 0
// Elder: ladder jump crap
lookAhead[0] = pml.forward[0];
lookAhead[1] = pml.forward[1];
lookAhead[2] = 0;
VectorNormalize (lookAhead);
// Calculate end point
VectorMA (pm->ps->origin, 1, lookAhead, trEndTest);
//trEndTest[2] += 20;
trEndTest[2] += 6;
// Calculate start point
VectorCopy(pm->ps->origin, lookAhead);
//lookAhead[2] += 16;
lookAhead[2] += 2;
pm->trace (&tr, lookAhead, pm->mins, pm->maxs, trEndTest,
pm->ps->clientNum, MASK_PLAYERSOLID);
if (tr.fraction == 1 || !(tr.surfaceFlags & SURF_LADDER))
{
// good conditions -- now we can set up a double jump on the ladder
if (pm->debugLevel)
Com_Printf("Ladder jump conditions met...\n");
if (pm->ps->stats[STAT_JUMPTIME] > 0 && PM_CheckJump())
{
if (pm->debugLevel)
Com_Printf("Trying ladder jump...\n");
pml.ladder = qfalse;
}
}
// End ladder jump crap
#endif
PM_Friction ();
//pml.ladder = qtrue;
scale = PM_CmdScale( &pm->cmd );
@ -2566,6 +2908,8 @@ static void PM_LadderMove( void ) {
wishspeed = pm->ps->speed * pm_ladderScale;
}
// Old ladder jump code -- right now it works better
#if 1
// Elder: ladder jump crap
lookAhead[0] = pml.forward[0];
lookAhead[1] = pml.forward[1];
@ -2589,11 +2933,12 @@ static void PM_LadderMove( void ) {
if (PM_CheckJump())
{
if (pm->debugLevel)
Com_Printf("Trying airmove ladder jump...\n");
Com_Printf("Trying ladder jump...\n");
}
}
// End ladder jump crap
#endif
PM_Accelerate (wishdir, wishspeed, pm_ladderAccelerate);
// This SHOULD help us with sloped ladders, but it remains untested.
@ -2610,7 +2955,7 @@ static void PM_LadderMove( void ) {
PM_SlideMove( qfalse ); // move without gravity
// Elder: stop legs from animating
PM_ForceLegsAnim( LEGS_IDLE );
PM_ForceLegsAnim( LEGS_JUMP );
}
@ -2648,8 +2993,12 @@ void CheckLadder( void )
pml.ladder = qtrue;
// Elder: does this work?
if (pml.ladder && pml.previous_ladder)
if (pml.ladder && pml.previous_ladder == qfalse)
{
if (pm->debugLevel)
Com_Printf("Hit ladder hard\n");
PM_CrashLand();
}
}
@ -2847,6 +3196,7 @@ void PmoveSingle (pmove_t *pmove) {
PM_SetWaterLevel();
// weapons
PM_Reload();
PM_Weapon();
//weapon animations(rq3 specific)
@ -2854,7 +3204,8 @@ void PmoveSingle (pmove_t *pmove) {
if (pm->ps->weapon == WP_PISTOL ||
pm->ps->weapon == WP_M3 ||
pm->ps->weapon == WP_HANDCANNON ||
pm->ps->weapon == WP_SSG3000)
pm->ps->weapon == WP_SSG3000 ||
pm->ps->weapon == WP_M4)
PM_WeaponAnimation();
// torso animation

View file

@ -388,6 +388,8 @@ typedef enum {
WP_ANIM_DISARM,
WP_ANIM_ACTIVATE,
//WP_ANIM_EMPTY,
//WP_ANIM_EXTRA1,
//WP_ANIM_EXTRA2,
MAX_WEAPON_ANIMATIONS
} wpAnimNumber_t;
@ -405,6 +407,7 @@ typedef enum {
#define PMF_FOLLOW 4096 // spectate following another player
#define PMF_SCOREBOARD 8192 // spectate as a scoreboard
#define PMF_INVULEXPAND 16384 // invulnerability sphere set to full size
#define PMF_RELOAD_HELD 32768 // Elder: new reload code
#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK)
@ -460,7 +463,7 @@ typedef enum {
STAT_PERSISTANT_POWERUP,
#endif
STAT_WEAPONS, // 16 bit fields
STAT_ARMOR, // Elder: technically we don't need this anymore - maybe for vest
STAT_ARMOR, // Elder: technically we don't need this anymore
STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?)
@ -469,22 +472,28 @@ typedef enum {
//These are RQ3-related specific stats
STAT_CLIPS, // Num Clips player currently has
STAT_STREAK,
STAT_BURST, // number of shots in burst
STAT_JUMPTIME, // Blaze RE: Double jump
//STAT_UNIQUEWEAPONS, // Elder - wasteful stat - moved to gclient_s
STAT_JUMPTIME, // Blaze: Double jump
STAT_RELOADTIME, // Elder: Reload sound triggering and weapon switch override
STAT_RELOADATTEMPTS, // Elder: For fast-reload queuing
STAT_FALLDAMAGE,
STAT_RQ3, // Blaze: Will hold a few flags for bandage, etc info
STAT_RQ3 // Blaze: Will hold a few flags for bandage, etc info
//STAT_STREAK, // Elder: wasteful stat -- only used on server-side ATM
} statIndex_t;
//STAT_RQ3 stat info
#define RQ3_LEGDAMAGE 1 //If this bit is set, the player has leg damage
#define RQ3_BANDAGE_NEED 2
#define RQ3_BANDAGE_WORK 4
//Elder: zoom stat - 1x = 0, 2x = zoom low, 4x = zoom_med, 6x = zoom_low + zoom_med
// Elder: zoom stat - 1x = 0, 2x = zoom low, 4x = zoom_med, 6x = zoom_low + zoom_med
#define RQ3_ZOOM_LOW 8
#define RQ3_ZOOM_MED 16
#define RQ3_THROWWEAPON 32 //Present if dropping weapon via cmd or kicked away
#define RQ3_THROWWEAPON 32 // Present if dropping weapon via cmd or kicked away
#define RQ3_FASTRELOADS 64 // Fast-reloads flag
#define RQ3_LOCKRELOADS 128 // Lock-reloads at end of fast-reload cycle
// Elder: reload status; 0 + 1 = stage 2
//#define RQ3_RELOADSTAGE0 256
//#define RQ3_RELOADSTAGE1 512
// player_state->persistant[] indexes
@ -525,6 +534,7 @@ typedef enum {
#ifdef MISSIONPACK
#define EF_TICKING 0x00000002 // used to make players play the prox mine ticking sound
#endif
#define EF_HANDCANNON_SMOKED 0x00000002 // Elder: HC Smoke
#define EF_TELEPORT_BIT 0x00000004 // toggled every time the origin abruptly changes
#define EF_AWARD_EXCELLENT 0x00000008 // draw an excellent sprite
#define EF_PLAYER_EVENT 0x00000010
@ -560,6 +570,7 @@ typedef enum {
PW_BLUEFLAG,
PW_NEUTRALFLAG,
PW_SCOUT,
PW_GUARD,
PW_DOUBLER,
@ -612,20 +623,78 @@ typedef enum {
WP_NUM_WEAPONS
} weapon_t;
// Elder: for our end-level awards later on
// I was just brainstorming a whole bunch of necessary records
// This should probably be defined in g_local.h because it
// will almost be exclusively for the server to utilize
// We can send config strings to the individual players
// for their own review and the global config string would
// contain the global ones with rewards
typedef enum {
RECORD_HEADSHOTS,
RECORD_CHESTSHOTS,
RECORD_STOMACHSHOTS,
RECORD_LEGSHOTS,
RECORD_FALLINGDEATHS,
RECORD_CAMPCOUNT,
RECORD_JUMPCOUNT, // e.g. rabbit or monkey award
RECORD_SUICIDES, // e.g. for MPELP award
RECORD_STEALTHKILLS,
RECORD_FRAGSTEALS,
RECORD_TOTAL
// Location-hit tally - Where this player shot at
REC_HEADSHOTS,
REC_CHESTSHOTS,
REC_STOMACHSHOTS,
REC_LEGSHOTS,
REC_FRONTSHOTS,
REC_BACKSHOTS,
REC_LEFTSHOTS,
REC_RIGHTSHOTS,
REC_CORPSESHOTS, // sickos - takes precedence over above records on carcasses
REC_GIBSHOTS, // sickos - takes precedence over above records on carcasses
// Weapon usage tally
REC_MP5SHOTS,
REC_M4SHOTS,
REC_MK23SHOTS,
REC_SSG3000SHOTS,
REC_HANDCANNONSHOTS,
REC_M3SHOTS,
REC_AKIMBOSHOTS,
REC_GRENADESHOTS,
REC_KNIFETHROWSHOTS,
REC_KNIFESLASHSHOTS,
REC_MK23HITS,
REC_M3HITS,
REC_MP5HITS,
REC_M4HITS,
REC_SSG3000HITS,
REC_HANDCANNONHITS,
REC_AKIMBOHITS,
REC_GRENADEHITS,
REC_KNIFETHROWHITS,
REC_KNIFESLASHHITS,
REC_KICKHITS,
// Death tally
REC_HEADDEATHS,
REC_CHESTDEATHS,
REC_STOMACHDEATHS,
REC_LEGDEATHS,
REC_MK23DEATHS,
REC_M3DEATHS,
REC_MP5DEATHS,
REC_M4DEATHS,
REC_SSG3000DEATHS,
REC_HANDCANNONDEATHS,
REC_AKIMBODEATHS,
REC_GRENADEDEATHS,
REC_KNIFETHROWDEATHS,
REC_KNIFESLASHDEATHS,
REC_BLEEDDEATHS,
REC_FALLINGDEATHS,
REC_SUICIDES, // e.g. for MPELP award, those loonies :)
REC_WORLDDEATHS, // crushers, doors, etc.
REC_STEALTHKILLS, // this is a derived record -- remove?
// Movement tally - dunno about these ones since they are related to pmove
REC_CAMPCOUNT,
REC_CROUCHCOUNT,
REC_JUMPCOUNT, // e.g. rabbit or monkey award
// Player interaction tally
REC_FRAGSTEALS, // this is a derived record -- remove?
REC_CHATCOUNT,
REC_GESTURECOUNT,
REC_NUM_RECORDS
} rq3record_t;
@ -696,7 +765,9 @@ typedef enum {
EV_NOAMMO,
EV_CHANGE_WEAPON,
EV_FIRE_WEAPON,
EV_RELOAD_WEAPON, // Elder: reload weapon sounds
EV_RELOAD_WEAPON0, // Elder: reload weapon sounds
EV_RELOAD_WEAPON1, // Elder: reload weapon sounds
EV_RELOAD_WEAPON2, // Elder: reload weapon sounds
EV_USE_ITEM0,
EV_USE_ITEM1,
@ -731,6 +802,8 @@ typedef enum {
EV_BULLET_HIT_FLESH,
EV_BULLET_HIT_WALL,
EV_BULLET_HIT_METAL, // Elder: sparks
EV_BULLET_HIT_KEVLAR, // Elder: sparks
EV_SSG3000_HIT_FLESH,
EV_JUMPKICK, // Elder: sound + jumpkick message

View file

@ -152,6 +152,21 @@ void P_DamageFeedback( gentity_t *player ) {
client->ps.damageCount = count;
// Elder: HC Smoke
/*
if (client->lasthurt_mod == MOD_HANDCANNON)
{
G_Printf("Feedback: damage_blood: %i, damage_knockback: %i\n",
client->damage_blood, client->damage_knockback);
}
*/
if (client->lasthurt_mod == MOD_HANDCANNON &&
client->damage_blood >= 120 &&
client->damage_knockback >= RQ3_HANDCANNON_KICK * 6)
{
client->ps.eFlags |= EF_HANDCANNON_SMOKED;
}
//
// clear totals
//
@ -698,7 +713,18 @@ void ClientEvents( gentity_t *ent, int oldEventSequence ) {
case EV_FIRE_WEAPON:
FireWeapon( ent );
break;
/*
case EV_RELOAD_WEAPON0:
ReloadWeapon ( ent, 0 );
break;
case EV_RELOAD_WEAPON1:
ReloadWeapon ( ent, 1 );
break;
*/
case EV_RELOAD_WEAPON2:
ReloadWeapon ( ent, 2 );
break;
case EV_CHANGE_WEAPON:
//Elder: not a good place to put stuff
//ent->client->zoomed=0;
@ -1613,15 +1639,13 @@ void ClientEndFrame( gentity_t *ent ) {
} else {
ent->s.eFlags &= ~EF_CONNECTION;
}
// Blaze: Do Bleed
// if(ent->client->bleeding)
// CheckBleeding(ent); // perform once-a-second actions
//Elder: moved unique item spawning to new function called RQ3_CheckUniqueItems
// Begin Duffman
//Update the clips Amount in weapon for the client
// Update the clips Amount in weapon for the client
// Elder: the STAT takes precedence over the server-side only listing
ent->client->ps.stats[STAT_CLIPS] = ent->client->numClips[ent->client->ps.weapon];
// End Duffman
ent->client->ps.stats[STAT_HEALTH] = ent->health; // FIXME: get rid of ent->health...

View file

@ -1228,7 +1228,7 @@ void ClientSpawn(gentity_t *ent) {
// health will count down towards max_health
ent->health = client->ps.stats[STAT_HEALTH] = 100;// max health of 100 client->ps.stats[STAT_MAX_HEALTH];//Blaze: removed * 1.25 becase we wanna start at 100 health
// reset streak count
client->ps.stats[STAT_STREAK] = 0;
client->killStreak = 0;
G_SetOrigin( ent, spawn_origin );
VectorCopy( spawn_origin, client->ps.origin );

View file

@ -1680,7 +1680,8 @@ void Cmd_Bandage (gentity_t *ent)
if (ent->client->ps.weapon == WP_PISTOL ||
ent->client->ps.weapon == WP_M3 ||
ent->client->ps.weapon == WP_HANDCANNON ||
ent->client->ps.weapon == WP_SSG3000)
ent->client->ps.weapon == WP_SSG3000 ||
ent->client->ps.weapon == WP_M4)
{
ent->client->ps.generic1 = ( ( ent->client->ps.generic1 & ANIM_TOGGLEBIT )
^ ANIM_TOGGLEBIT ) | WP_ANIM_DISARM;
@ -2021,7 +2022,9 @@ void Cmd_Reload( gentity_t *ent )
^ ANIM_TOGGLEBIT ) | TORSO_DROP;
//}
ent->client->ps.weaponTime += delay;
// Elder: handled in pmove now
// ent->client->ps.weaponTime += delay;
//Elder: at this point there should be sufficient ammo requirements to reload
if (ent->client->numClips[weapon] > 0) {
@ -2150,8 +2153,8 @@ void Cmd_Weapon(gentity_t *ent)
return;
}
//Can't reload while firing
if ( ent->client->ps.weaponTime > 0)
//Can't use weapon while firing
if ( ent->client->ps.weaponTime > 0 || ent->client->ps.stats[STAT_RELOADTIME] > 0)
return;
//Elder: added brackets, and-ops and not-ops instead of logical ops
@ -2513,10 +2516,10 @@ void ClientCommand( int clientNum ) {
else if (Q_stricmp (cmd, "reload") == 0)
{
//Elder: add to reload queue if using fast-reloadable weapons
if (ent->client->ps.weapon == WP_M3 || ent->client->ps.weapon == WP_SSG3000)
ent->client->reloadAttempts++;
//if (ent->client->ps.weapon == WP_M3 || ent->client->ps.weapon == WP_SSG3000)
//ent->client->reloadAttempts++;
//G_Printf("Trying a reload...\n");
Cmd_Reload( ent );
//Cmd_Reload( ent );
}
// End Duffman
//Blaze's Open door command

View file

@ -541,7 +541,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
//Elder: added;
self->client->ps.stats[STAT_RQ3] &= ~RQ3_BANDAGE_WORK;
self->client->ps.stats[STAT_RQ3] &= ~RQ3_BANDAGE_NEED;
self->client->ps.stats[STAT_STREAK] = 0;
self->client->killStreak = 0;
//Elder: stop reload attempts
self->client->reloadAttempts = 0;
@ -631,37 +631,37 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
AddScore( attacker, self->r.currentOrigin, -1 );
} else {
// Increase number of kills this life for attacker
attacker->client->ps.stats[STAT_STREAK]++;
attacker->client->killStreak++;
// DM reward scoring, should add an if statement to get around this when
// we add teamplay.
if (attacker->client->ps.stats[STAT_STREAK] < 4)
if (attacker->client->killStreak < 4)
AddScore( attacker, self->r.currentOrigin, 1 );
else if (attacker->client->ps.stats[STAT_STREAK] < 8)
else if (attacker->client->killStreak < 8)
{ AddScore( attacker, self->r.currentOrigin, 2 );
DMReward = G_TempEntity(self->r.currentOrigin ,EV_DMREWARD);
DMReward->s.otherEntityNum2 = killer;
DMReward->s.eventParm = attacker->client->ps.stats[STAT_STREAK];
DMReward->s.eventParm = attacker->client->killStreak;
DMReward->r.svFlags = SVF_BROADCAST;
}
else if (attacker->client->ps.stats[STAT_STREAK] < 16)
else if (attacker->client->killStreak < 16)
{ AddScore( attacker, self->r.currentOrigin, 4 );
DMReward = G_TempEntity(self->r.currentOrigin ,EV_DMREWARD);
DMReward->s.otherEntityNum2 = killer;
DMReward->s.eventParm = attacker->client->ps.stats[STAT_STREAK];
DMReward->s.eventParm = attacker->client->killStreak;
DMReward->r.svFlags = SVF_BROADCAST;
}
else if (attacker->client->ps.stats[STAT_STREAK] < 32)
else if (attacker->client->killStreak < 32)
{ AddScore( attacker, self->r.currentOrigin, 8 );
DMReward = G_TempEntity(self->r.currentOrigin ,EV_DMREWARD);
DMReward->s.otherEntityNum2 = killer;
DMReward->s.eventParm = attacker->client->ps.stats[STAT_STREAK];
DMReward->s.eventParm = attacker->client->killStreak;
DMReward->r.svFlags = SVF_BROADCAST;
}
else
{ AddScore( attacker, self->r.currentOrigin, 16 );
DMReward = G_TempEntity(self->r.currentOrigin ,EV_DMREWARD);
DMReward->s.otherEntityNum2 = killer;
DMReward->s.eventParm = attacker->client->ps.stats[STAT_STREAK];
DMReward->s.eventParm = attacker->client->killStreak;
DMReward->r.svFlags = SVF_BROADCAST;
}
@ -681,7 +681,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
self->client->ps.persistant[PERS_PLAYEREVENTS] ^= PLAYEREVENT_GAUNTLETREWARD;
}
// check for two kills in a short amount of time
// if this is close enough to the last kill, give a reward sound
if ( level.time - attacker->client->lastKillTime < CARNAGE_REWARD_TIME ) {
@ -801,6 +801,17 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
self->s.weapon = WP_NONE;
self->s.powerups = 0;
// Elder: HC smoke
//G_Printf("player_die: damage_knockback: %i\n", self->client->damage_knockback);
if (meansOfDeath == MOD_HANDCANNON && self->client->damage_knockback > RQ3_HANDCANNON_KICK * 4) //self->client->ps.stats[STAT_HEALTH] < -50)
{
//G_Printf("Smoked\n");
self->client->ps.eFlags |= EF_HANDCANNON_SMOKED;
}
self->r.contents = CONTENTS_CORPSE;
self->s.angles[0] = 0;
@ -1697,6 +1708,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
//Vest stuff - is the knife supposed to be affected?
if (bg_itemlist[targ->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_KEVLAR)
{
targ->client->kevlarHit = qtrue;
//if ((attacker->client->ps.stats[STAT_WEAPONS] & (1 << WP_SSG3000)) == (1 << WP_SSG3000))
if (attacker->client->ps.weapon == WP_SSG3000)
{
@ -1717,7 +1729,11 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
}
//Kevlar sound
if (mod != MOD_KNIFE && mod != MOD_KNIFE_THROWN)
tent = G_TempEntity2(targ->s.pos.trBase, EV_RQ3_SOUND, RQ3_SOUND_KEVLARHIT);
{
tent = G_TempEntity(targ->s.pos.trBase, EV_BULLET_HIT_KEVLAR);
tent->s.eventParm = DirToByte(dir);
//tent = G_TempEntity2(targ->s.pos.trBase, EV_RQ3_SOUND, RQ3_SOUND_KEVLARHIT);
}
}
else
{
@ -1792,6 +1808,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
//if ( client ) {
//targ->flags |= FL_NO_KNOCKBACK;
//}
if (targ->health < -999) {
targ->health = -999;
}

View file

@ -202,12 +202,9 @@ int Pickup_Holdable( gentity_t *ent, gentity_t *other ) {
void Add_Ammo (gentity_t *ent, int weapon, int count, int bandolierFactor)
{
//Blaze: Reaction stuff, add to clip when picking up ammo packs
//Elder: Modified to use constants def'd in bg_public.h
ent->client->numClips[weapon] += count;
switch (weapon)
{
@ -1301,6 +1298,8 @@ void G_SpawnItem (gentity_t *ent, gitem_t *item) {
G_SpawnFloat( "random", "0", &ent->random );
G_SpawnFloat( "wait", "0", &ent->wait );
//TODO: check spawn angles; client-side should make use of them too
RegisterItem( item );
if ( G_ItemDisabled(item) )
return;

View file

@ -335,6 +335,7 @@ struct gclient_s {
int accuracy_hits; // total number of hits
//Blaze: For weapon stats
//Will need to pass these along in g_client to the new client after spawn
// Elder: to be merged into rq3Record_t for more comprehensive tracking
int knifeShots;
int knifeHits;
int mk23Shots;
@ -410,6 +411,7 @@ struct gclient_s {
int weaponfireNextTime; // for akimbos
int lastzoom; // Elder: save last zoom state when firing
// These are now obsolete with the new reload code
int fastReloads; // Elder: for queuing M3/SSG reloads
int lastReloadTime; // Elder: for queuing M3/SSG reloads
int reloadAttempts; // Elder: for queuing M3/SSG reloads
@ -418,6 +420,8 @@ struct gclient_s {
int consecutiveShots; // Elder: for M4 ride-up/kick
int uniqueWeapons; // Elder: formerly a stat, now just a server var
int uniqueItems;
int killStreak; // Elder: replaces the old STAT_STREAK
qboolean kevlarHit; // Elder: kevlar hit -- FIXME: poor implementation
//int records[RECORD_TOTAL]; // Elder: for our awards when we implement it
@ -758,6 +762,7 @@ qboolean G_FilterPacket (char *from);
// g_weapon.c
//
void FireWeapon( gentity_t *ent );
void ReloadWeapon ( gentity_t *ent, int stage ); // Elder: added
#ifdef MISSIONPACK
void G_StartKamikaze( gentity_t *ent );
#endif

View file

@ -427,6 +427,9 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
//Elder: knife handling routines go HERE, not in g_main.c !!!
if (ent->s.weapon == WP_KNIFE) {
if ( other->takedamage && other->client) {
// Elder: must add it in here if we remove it from above
G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, ent->s.origin, THROW_DAMAGE, 0, MOD_KNIFE_THROWN);
//hit a player - send the gurgle or embedding sound event
}
else {

View file

@ -999,29 +999,45 @@ void Blocked_Door( gentity_t *ent, gentity_t *other ) {
// remove anything other than a client
if ( !other->client ) {
// except CTF flags!!!!
if( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) {
if ( other->s.eType == ET_ITEM && other->item->giType == IT_TEAM ) {
Team_DroppedFlagThink( other );
return;
}
// Elder: added to handle weapons in door paths -
// later we'll need to handle items here too
if( other->s.eType == ET_ITEM && other->item->giType == IT_WEAPON ) {
switch ( other->item->giTag ) {
case WP_MP5:
case WP_M4:
case WP_M3:
case WP_HANDCANNON:
case WP_SSG3000:
RQ3_DroppedWeaponThink( other );
return;
case WP_GRENADE:
case WP_PISTOL:
case WP_KNIFE:
case WP_AKIMBO:
default:
break;
// Elder: added to handle items and weapons in door paths
if ( other->s.eType == ET_ITEM && other->item->giType == IT_WEAPON)
{
switch ( other->item->giTag )
{
case WP_MP5:
case WP_M4:
case WP_M3:
case WP_HANDCANNON:
case WP_SSG3000:
RQ3_DroppedWeaponThink( other );
return;
break;
case WP_GRENADE:
case WP_PISTOL:
case WP_KNIFE:
case WP_AKIMBO:
default:
break;
}
}
if ( other->s.eType == ET_ITEM && other->item->giType == IT_HOLDABLE) {
switch ( other->item->giTag )
{
case HI_LASER:
case HI_BANDOLIER:
case HI_KEVLAR:
case HI_SILENCER:
case HI_SLIPPERS:
RQ3_DroppedItemThink( other );
return;
break;
default:
break;
}
}
G_TempEntity( other->s.origin, EV_ITEM_POP );
G_FreeEntity( other );

View file

@ -326,7 +326,6 @@ void SnapVectorTowards( vec3_t v, vec3_t to ) {
#define MACHINEGUN_DAMAGE 7
#define MACHINEGUN_TEAM_DAMAGE 5 // wimpier MG in teamplay
void Bullet_Fire (gentity_t *ent, float spread, int damage, int MOD ) {
trace_t tr;
vec3_t end;
@ -392,8 +391,13 @@ void Bullet_Fire (gentity_t *ent, float spread, int damage, int MOD ) {
// send bullet impact
if ( traceEnt->takedamage && traceEnt->client ) {
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
tent->s.eventParm = traceEnt->s.number;
if (bg_itemlist[traceEnt->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag != HI_KEVLAR)
{
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
//tent->s.eventParm = traceEnt->s.number;
tent->s.eventParm = DirToByte(forward);
tent->s.otherEntityNum2 = traceEnt->s.number;
}
if( LogAccuracyHit( traceEnt, ent ) ) {
ent->client->accuracy_hits++;
switch (MOD)
@ -418,6 +422,10 @@ void Bullet_Fire (gentity_t *ent, float spread, int damage, int MOD ) {
//} else if ( tr.surfaceFlags & SURF_GRASS ) {
//tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH);
//tent->s.eventParm = DirToByte( tr.plane.normal );
} else if ( (tr.surfaceFlags & SURF_METALSTEPS) ||
(tr.surfaceFlags & SURF_METAL2) ) {
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_METAL );
tent->s.eventParm = DirToByte( tr.plane.normal );
} else {
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL );
tent->s.eventParm = DirToByte( tr.plane.normal );
@ -444,6 +452,19 @@ void Bullet_Fire (gentity_t *ent, float spread, int damage, int MOD ) {
#endif
G_Damage( traceEnt, ent, ent, forward, tr.endpos,
damage, 0, MOD);
// FIXME: poor implementation
if (traceEnt->client && bg_itemlist[traceEnt->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_KEVLAR) {
if (traceEnt->client->kevlarHit == qfalse) {
tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH );
//tent->s.eventParm = traceEnt->s.number;
tent->s.eventParm = DirToByte(forward);
tent->s.otherEntityNum2 = traceEnt->s.number;
}
else
traceEnt->client->kevlarHit = qfalse;
}
#ifdef MISSIONPACK
}
#endif
@ -1431,13 +1452,15 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
traceEnt = &g_entities[ trace.entityNum ];
if ( traceEnt->takedamage ) {
if ( traceEnt->takedamage )
{
//G_Printf("(%d) SSG: hit damagable entity\n", level.time);
//flag hitBreakable - bullets go through even
//if it doesn't "shatter" - but that's usually
//not the case
if ( traceEnt->s.eType == ET_BREAKABLE ) {
if ( traceEnt->s.eType == ET_BREAKABLE )
{
//G_Printf("(%d) SSG: Hit a breakable\n", level.time);
hitBreakable = qtrue;
}
@ -1445,29 +1468,51 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
// send impacts
if ( traceEnt->client )
{
//if (bg_itemlist[traceEnt->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag != HI_KEVLAR)
//{
tent[unlinked] = G_TempEntity( trace.endpos, EV_SSG3000_HIT_FLESH );
//tent[unlinked]->s.eventParm = DirToByte( trace.plane.normal );
tent[unlinked]->s.eventParm = traceEnt->s.number;
//Check to see if we've hit kevlar
tent[unlinked]->s.eventParm = DirToByte( forward );
tent[unlinked]->s.otherEntityNum2 = traceEnt->s.number;
tent[unlinked]->s.otherEntityNum = ent->s.number;
//}
//tent[unlinked]->s.eventParm = traceEnt->s.number;
//Check to see if we've hit kevlar -- FIXME: wrong way to do it
if (bg_itemlist[traceEnt->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_KEVLAR)
hitKevlar = qtrue;
}
else
{
tent[unlinked] = G_TempEntity( trace.endpos, EV_BULLET_HIT_WALL );
tent[unlinked]->s.eventParm = DirToByte( trace.plane.normal );
}
tent[unlinked]->s.otherEntityNum = ent->s.number;
// impact type
if ( (trace.surfaceFlags & SURF_METALSTEPS) ||
(trace.surfaceFlags & SURF_METAL2) )
tent[unlinked] = G_TempEntity( trace.endpos, EV_BULLET_HIT_METAL );
else
tent[unlinked] = G_TempEntity( trace.endpos, EV_BULLET_HIT_WALL );
if( LogAccuracyHit( traceEnt, ent ) ) {
tent[unlinked]->s.eventParm = DirToByte( trace.plane.normal );
tent[unlinked]->s.otherEntityNum = ent->s.number;
}
if( LogAccuracyHit( traceEnt, ent ) )
{
hits++;
}
//G_Printf("(%d) SSG: Doing damage to target\n", level.time);
G_Damage (traceEnt, ent, ent, forward, trace.endpos, damage, 0, MOD_SNIPER);
// FIXME: poor implementation
/*
if (traceEnt->client && bg_itemlist[traceEnt->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_KEVLAR)
{
// reset kevlar flag
traceEnt->client->kevlarHit = qfalse;
// set SSG kevlar flag so we stop piercing
hitKevlar = qtrue;
}
*/
}
//Elder: go through non-solids and breakables
//If we ever wanted to "shoot through walls" we'd do stuff here
if ( hitKevlar || (hitBreakable == qfalse && (trace.contents & CONTENTS_SOLID))) {
@ -1500,7 +1545,13 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
// no explosion at end if SURF_NOIMPACT
if ( !(trace.surfaceFlags & SURF_NOIMPACT) )
{
tentWall = G_TempEntity( trace.endpos, EV_BULLET_HIT_WALL );
if ( (trace.surfaceFlags & SURF_METALSTEPS) ||
(trace.surfaceFlags & SURF_METAL2) )
tentWall = G_TempEntity( trace.endpos, EV_BULLET_HIT_METAL );
else
{
tentWall = G_TempEntity( trace.endpos, EV_BULLET_HIT_WALL );
}
tentWall->s.eventParm = DirToByte( trace.plane.normal );
tentWall->s.otherEntityNum = ent->s.number;
}
@ -2273,3 +2324,39 @@ void Laser_Think( gentity_t *self )
self->nextthink = level.time + 10;
}
/*
=================
ReloadWeapon
Added by Elder
Handles server-side management of numclips
=================
*/
void ReloadWeapon ( gentity_t *ent, int stage )
{
if (stage == 2)
{
G_Printf("Hit server-side reload\n");
ent->client->numClips[ent->client->ps.weapon]--;
// remove an extra clip if using HC or Akimbos
if (ent->client->ps.weapon == WP_HANDCANNON ||
ent->client->ps.weapon == WP_AKIMBO)
ent->client->numClips[ent->client->ps.weapon]--;
//Elder: sync hc and m3 ammo + mk23 and akimbo ammo - a switch might look nicer
if (ent->client->ps.weapon == WP_M3) {
ent->client->numClips[WP_HANDCANNON] = ent->client->numClips[WP_M3];
}
else if (ent->client->ps.weapon == WP_HANDCANNON) {
ent->client->numClips[WP_M3] = ent->client->numClips[WP_HANDCANNON];
}
else if(ent->client->ps.weapon == WP_PISTOL) {
ent->client->numClips[WP_AKIMBO] = ent->client->numClips[WP_PISTOL];
}
else if (ent->client->ps.weapon == WP_AKIMBO) {
ent->client->numClips[WP_PISTOL] = ent->client->numClips[WP_AKIMBO];
}
}
}