Code updates for VM 0-08-00
Server-side
This commit is contained in:
Victor Chow 2001-08-13 17:26:53 +00:00
parent 3408381bf7
commit f4cf1c8a3b
12 changed files with 373 additions and 156 deletions

View file

@ -1345,6 +1345,7 @@ 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_MISSILE_HIT",
"EV_MISSILE_MISS",

View file

@ -1953,6 +1953,56 @@ static void PM_Weapon( void ) {
return;
}
//Elder: New 3rb Code
//force fire button down if STAT_BURST is < proper amount
//Otherwise release the button
if ( (pm->ps->weapon == WP_M4 &&
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) ||
(pm->ps->weapon == WP_MP5 &&
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE))
{
int weaponNum = pm->ps->weapon;
if (pm->ps->ammo[weaponNum] == 0)
{
pm->ps->stats[STAT_BURST] = 0;
}
else if (pm->cmd.buttons & BUTTON_ATTACK)// && client->ps.stats[STAT_BURST] > 0)
{
if ( pm->ps->stats[STAT_BURST] >= 0 && pm->ps->stats[STAT_BURST] < 3)
pm->cmd.buttons |= BUTTON_ATTACK;
else
pm->cmd.buttons &= ~BUTTON_ATTACK;
}
else if (pm->ps->stats[STAT_BURST] > 2)
{
pm->ps->stats[STAT_BURST] = 0;
pm->ps->weaponTime += 300;
}
//Don't need?
else if (pm->ps->stats[STAT_BURST] > 0)
pm->cmd.buttons |= BUTTON_ATTACK;
}
//Elder: New semi-auto code
if ( pm->ps->weapon == WP_PISTOL &&
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE)
{
if (pm->ps->ammo[WP_PISTOL] == 0)
{
pm->ps->stats[STAT_BURST] = 0;
}
else if ((pm->cmd.buttons & BUTTON_ATTACK) && pm->ps->stats[STAT_BURST])
{
pm->cmd.buttons &= ~BUTTON_ATTACK;
}
else if (pm->ps->stats[STAT_BURST])
{
pm->ps->weaponTime += 200;
pm->ps->stats[STAT_BURST] = 0;
}
}
// check for item using
// Elder: removed
/*
@ -2083,7 +2133,6 @@ static void PM_Weapon( void ) {
}
}
/*
if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
pm->ps->weaponTime = 0;
@ -2136,6 +2185,17 @@ static void PM_Weapon( void ) {
pm->ps->weaponstate = WEAPON_FIRING;
// Elder: increment stat if alt-fire mode --needs to be predicted as well
if ( (pm->ps->weapon == WP_M4 &&
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) ||
(pm->ps->weapon == WP_MP5 &&
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE) ||
(pm->ps->weapon == WP_PISTOL &&
(pm->ps->persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE))
{
pm->ps->stats[STAT_BURST]++;
}
//Elder: M4 kick code
//ent->client->ps.delta_angles[0] = ANGLE2SHORT(SHORT2ANGLE(ent->client->ps.delta_angles[0]) - 0.7);
if ( pm->ps->weapon == WP_M4 && ((pm->ps->persistant[PERS_WEAPONMODES] & RQ3_M4MODE) != RQ3_M4MODE) )

View file

@ -160,6 +160,7 @@
typedef enum {
RQ3_SOUND_KICK,
RQ3_SOUND_HEADSHOT,
RQ3_SOUND_KNIFEHIT,
RQ3_SOUND_KNIFEDEATH,
RQ3_SOUND_LCA, //lights, camera, action!
RQ3_SOUND_KEVLARHIT,
@ -710,6 +711,7 @@ typedef enum {
EV_BULLET_HIT_FLESH,
EV_BULLET_HIT_WALL,
EV_SSG3000_HIT_FLESH,
EV_JUMPKICK, // Elder: sound + jumpkick message
EV_MISSILE_HIT,
EV_MISSILE_MISS,

View file

@ -128,6 +128,8 @@ void P_DamageFeedback( gentity_t *player ) {
//Elder: headshot sound
case LOCATION_HEAD:
case LOCATION_FACE:
if (client->lasthurt_mod == MOD_KNIFE || client->lasthurt_mod == MOD_KNIFE_THROWN)
G_AddEvent( player, EV_RQ3_SOUND, RQ3_SOUND_KNIFEDEATH);
//Elder: do nothing -- sound is handled in g_combat.c again
//tent = G_TempEntity2(client->ps.origin, EV_RQ3_SOUND, RQ3_SOUND_HEADSHOT);
//Elder: takes more bandwidth but guarantees a headshot sound
@ -137,15 +139,7 @@ void P_DamageFeedback( gentity_t *player ) {
/*
case LOCATION_CHEST:
case LOCATION_SHOULDER:
//Play metal impact if vest was hit
if (client->damage_vest == qtrue)
{
tent = G_TempEntity2(client->ps.origin, EV_RQ3_SOUND, RQ3_SOUND_KEVLARHIT);
client->damage_vest = qfalse;
}
else
G_AddEvent( player, EV_PAIN, player->health );
G_AddEvent( player, EV_PAIN, player->health );
break;
*/
default:
@ -853,10 +847,11 @@ void BotTestSolid(vec3_t origin);
ThrowWeapon
XRAY FMJ
Returns the number of the weapon thrown
=============
*/
void ThrowWeapon( gentity_t *ent )
int ThrowWeapon( gentity_t *ent, qboolean forceThrow )
{
gclient_t *client;
usercmd_t *ucmd;
@ -875,15 +870,16 @@ void ThrowWeapon( gentity_t *ent )
//Elder: TODO: have to add a reloading case:
//weaponTime > 0 or weaponState == weapon_dropping? Or both?
//Still firing
if ( (ucmd->buttons & BUTTON_ATTACK) == BUTTON_ATTACK || client->ps.weaponTime > 0) {
return;
}
//Elder: Bandaging case
if (!forceThrow)
if ( (ucmd->buttons & BUTTON_ATTACK) == BUTTON_ATTACK || client->ps.weaponTime > 0)
return 0;
//Elder: Bandaging case -- handled in cgame
//else if (client->isBandaging) {
if ( (ent->client->ps.stats[STAT_RQ3] & RQ3_BANDAGE_WORK) == RQ3_BANDAGE_WORK) {
trap_SendServerCommand( ent-g_entities, va("print \"You are too busy bandaging...\n\""));
return;
}
//if ( (ent->client->ps.stats[STAT_RQ3] & RQ3_BANDAGE_WORK) == RQ3_BANDAGE_WORK) {
//trap_SendServerCommand( ent-g_entities, va("print \"You are too busy bandaging...\n\""));
//return;
//}
weap = 0;
@ -900,7 +896,9 @@ void ThrowWeapon( gentity_t *ent )
weap = WP_HANDCANNON;
if ((client->ps.stats[STAT_WEAPONS] & (1 << WP_SSG3000) ) == (1 << WP_SSG3000))
weap = WP_SSG3000;
if (weap == 0 ) return;
if (weap == 0 )
return 0;
xr_item = BG_FindItemForWeapon( weap );
//Elder: Send a server command instead of force-setting
@ -915,6 +913,8 @@ void ThrowWeapon( gentity_t *ent )
xr_drop->count= -1; // XRAY FMJ 0 is already taken, -1 means no ammo
client->uniqueWeapons--;
}
return weap;
}
/*
@ -1123,9 +1123,11 @@ void ClientThink_real( gentity_t *ent ) {
ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
}
//**************Elder: moved to bg_pmove.c (PM_Weapon)************//
//Elder: New 3rb Code
//force fire button down if STAT_BURST is < proper amount
//Otherwise release the button
/*
if ( (client->ps.weapon == WP_M4 &&
(client->ps.persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) ||
(client->ps.weapon == WP_MP5 &&
@ -1172,6 +1174,7 @@ void ClientThink_real( gentity_t *ent ) {
client->ps.stats[STAT_BURST] = 0;
}
}
*/
#ifdef MISSIONPACK
// check for invulnerability expansion before doing the Pmove
@ -1637,6 +1640,14 @@ void ClientEndFrame( gentity_t *ent ) {
ent->client->consecutiveShots = 0;
}
// Check to reset our openDoor boolean
if ( ent->client->openDoorTime &&
level.time - ent->client->openDoorTime > MAXDOORTIME )
{
ent->client->openDoor = qfalse;
ent->client->openDoorTime = 0;
}
if ( bg_itemlist[ent->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_LASER )
{
//Try to turn the laser on if it's off

View file

@ -1253,6 +1253,7 @@ void ClientSpawn(gentity_t *ent) {
//Blaze: Set the opendoor flag to 0
client->openDoor = qfalse;
client->openDoorTime = 0;
// don't allow full run speed for a bit
client->ps.pm_flags |= PMF_TIME_KNOCKBACK;

View file

@ -867,6 +867,29 @@ void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText )
// don't let text be too long for malicious reasons
char text[MAX_SAY_TEXT];
char location[64];
int validation;
// Elder: validate the client
validation = RQ3_ValidateSay( ent );
if (validation != SAY_OK)
{
// Only send one message for the initial offense
if (ent->client->pers.sayMuteTime == level.time)
{
if (validation == SAY_WARNING)
{
trap_SendServerCommand( ent-g_entities, va("print \"Exceeded message limit - ^3WARNING ^7(%i seconds).\n\"", SAY_WARNING_TIME));
}
else if (validation == SAY_BAN)
{
trap_SendServerCommand( ent-g_entities, va("print \"Exceeded message limit - ^1BAN ^7(%i seconds).\n\"", SAY_BAN_TIME));
}
}
return;
}
if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) {
mode = SAY_ALL;
@ -2082,10 +2105,11 @@ void Cmd_OpenDoor(gentity_t *ent)
{
if (Q_stricmp (door->classname, "func_door_rotating") == 0) {
ent->client->openDoor = qtrue;
//ent->client->ps.stats[STAT_OPENDOOR] = 1;
ent->client->openDoorTime = level.time;
}
else if (Q_stricmp (door->classname, "func_door") == 0) {
ent->client->openDoor = qtrue;
ent->client->openDoorTime = level.time;
}
}
}
@ -2288,18 +2312,19 @@ Cmd_DropWeapon_f XRAY FMJ
*/
void Cmd_DropWeapon_f( gentity_t *ent ) {
//Elder: added
if ( (ent->client->ps.stats[STAT_RQ3] & RQ3_BANDAGE_WORK) == RQ3_BANDAGE_WORK)
{
trap_SendServerCommand( ent-g_entities, va("print \"You are too busy bandaging!\n\""));
return;
}
else
{
//Elder: added -- checked in cgame
//if ( (ent->client->ps.stats[STAT_RQ3] & RQ3_BANDAGE_WORK) == RQ3_BANDAGE_WORK)
//{
//trap_SendServerCommand( ent-g_entities, va("print \"You are too busy bandaging!\n\""));
//return;
//}
//else
//{
//Elder: remove zoom bits
Cmd_Unzoom(ent);
ThrowWeapon( ent );
}
//Throwing away return here
ThrowWeapon( ent, qfalse );
//}
}
/*
@ -2347,7 +2372,7 @@ PlayerStats
*/
void Cmd_PlayerStats_f( gentity_t *ent )
{
char textbuf[1024];
//char textbuf[1024];
trap_SendServerCommand( ent-g_entities, va("print \"%s:\n\"",ent->client->pers.netname ));
@ -2506,3 +2531,70 @@ void ClientCommand( int clientNum ) {
else
trap_SendServerCommand( clientNum, va("print \"unknown cmd %s\n\"", cmd ) );
}
/*
===============
RQ3_ValidateSay
Added by Elder
Ensure that the client is not spamming because we need
sv_floodProtect off for fast reloads and what-not.
It's not perfect (ideally we'd cut them off in cgame
but messagemodes by-pass it), but at least it prevents
spam from reaching other clients.
===============
*/
int RQ3_ValidateSay ( gentity_t *ent )
{
int timeCheck;
if (ent->client->pers.sayWarnings)
timeCheck = SAY_WARNING_TIME * 1000;
else
timeCheck = SAY_BAN_TIME * 1000;
// check if already warned/banned
if (ent->client->pers.sayMuteTime &&
level.time - ent->client->pers.sayMuteTime < timeCheck)
{
if (ent->client->pers.sayWarnings)
return SAY_WARNING;
else
return SAY_BAN;
}
// check if a flooder
if (ent->client->pers.sayCount >= SAY_MAX_NUMBER &&
level.time - ent->client->pers.sayTime < SAY_PERIOD_TIME * 1000)
{
ent->client->pers.sayMuteTime = level.time;
// determine penalty level
if (ent->client->pers.sayWarnings >= SAY_MAX_WARNINGS)
{
// bans never reset, but warnings do
ent->client->pers.sayBans++;
ent->client->pers.sayWarnings = 0;
return SAY_BAN;
}
else
{
ent->client->pers.sayWarnings++;
return SAY_WARNING;
}
}
// regular say check
if (level.time - ent->client->pers.sayTime > SAY_PERIOD_TIME * 1000)
{
ent->client->pers.sayCount = 0;
ent->client->pers.sayTime = level.time;
ent->client->pers.sayMuteTime = 0;
}
ent->client->pers.sayCount++;
return SAY_OK;
}

View file

@ -817,7 +817,10 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int
self->client->ps.torsoAnim =
( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
G_AddEvent( self, EV_DEATH1 + i, killer );
// Elder: only do death sounds if not hit in the head
if ((self->client->lasthurt_location & LOCATION_HEAD) != LOCATION_HEAD &&
(self->client->lasthurt_location & LOCATION_FACE) != LOCATION_FACE )
G_AddEvent( self, EV_DEATH1 + i, killer );
// the body can still be gibbed
self->die = body_die;
@ -1227,7 +1230,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
//Blaze: If we shot a breakable item subtract the damage from its health and try to break it
if ( targ->s.eType == ET_BREAKABLE ) {
targ->health -= damage;
targ->health -= damage;
G_BreakGlass( targ, point, mod );
return;
}
@ -1516,8 +1519,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
//Elder: do shotgun report like AQ2
int playernum = targ - g_entities;
playernum--;
if (playernum >= 0 && playernum <= MAX_CLIENTS - 1)
//playernum--;
if (playernum >= 0 && playernum < MAX_CLIENTS)
tookShellHit[playernum] = 1;
}
else {
@ -1649,7 +1652,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
break;
case LOCATION_SHOULDER:
case LOCATION_CHEST:
//Vest stuff
//Vest stuff - is the knife supposed to be affected?
if (bg_itemlist[targ->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_KEVLAR)
{
//if ((attacker->client->ps.stats[STAT_WEAPONS] & (1 << WP_SSG3000)) == (1 << WP_SSG3000))
@ -1669,8 +1672,6 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
}
//Kevlar sound
tent = G_TempEntity2(targ->s.pos.trBase, EV_RQ3_SOUND, RQ3_SOUND_KEVLARHIT);
//Elder: flag for sound in feedback
//targ->client->damage_vest = qtrue;
}
else
{

View file

@ -69,6 +69,8 @@ typedef enum {
#define SP_AUTOOPEN 4 // Elder: revert to Q3 behaviour
#define SP_DOORTOGGLE 8 // Elder: added to enable mover toggling
#define MAXDOORTIME 100 // Elder: max time the opendoor key can stay open
//============================================================================
typedef struct gentity_s gentity_t;
@ -261,11 +263,33 @@ typedef struct {
int voteCount; // to prevent people from constantly calling votes
int teamVoteCount; // to prevent people from constantly calling votes
qboolean teamInfo; // send team overlay updates?
qboolean hadUniqueWeapon[MAX_WEAPONS]; //Elder: for "ammo" in last gun
qboolean hadUniqueWeapon[MAX_WEAPONS]; //Elder: for "ammo" in last gun
int sayTime; // Elder: say validation stuff
int sayCount;
int sayWarnings;
int sayBans;
int sayMuteTime;
} clientPersistant_t;
// Elder: spam prevention defaults
#define SAY_MAX_NUMBER 6
#define SAY_MAX_WARNINGS 3
#define SAY_PERIOD_TIME 3 // Elder: in seconds
#define SAY_WARNING_TIME 15
#define SAY_BAN_TIME 60 // Technically should drop client
typedef enum
{
SAY_BAN,
SAY_WARNING,
SAY_OK,
SAY_TOTAL
} sayValidations_t;
// this structure is cleared on each ClientSpawn(),
// except for 'client->pers' and 'client->sess'
struct gclient_s {
@ -329,7 +353,7 @@ struct gclient_s {
int lasthurt_mod; // type of damage the client did
// Begin Duffman
int lasthurt_location; // Where the client was hit.
int lasthurt_location; // Where the client was hit.
// End Duffman
// timers
@ -345,15 +369,16 @@ struct gclient_s {
qboolean fireHeld; // used for hook
gentity_t *hook; // grapple hook if out
int switchTeamTime; // time the player switched teams
int switchTeamTime; // time the player switched teams
// Begin Duffman
int numClips[MAX_WEAPONS]; // Number of clips each weapon has
int numClips[MAX_WEAPONS]; // Number of clips each weapon has
// End Duffman
qboolean openDoor;//Blaze: used to hold if someone has hit opendoor key
qboolean openDoor; //Blaze: used to hold if someone has hit opendoor key
int openDoorTime;
// timeResidual is used to handle events that happen every second
// like health / armor countdowns and regeneration
int timeResidual;
//Elder: C3A laser tutorial
@ -374,25 +399,13 @@ struct gclient_s {
//qboolean semi; // hawkins (semiauto mode for m4, mp5, pistol)
int shots; //Blaze: Number of shots fired so far with this weapon
// Homer: weaponstate vars for Cmd_Weapon
// make these a single bitmask? worth the effort?
// Moved to PERS_WEAPONMODES in bg_public.h
/* int mk23semi; // pistol to semi-auto
int mp5_3rb; // MP5 to 3rb
int m4_3rb; // M4 to 3rb
int grenRange; // range to throw grenade (short/medium/long)
int throwKnife; // knife to throwing
*/
//qboolean isBandaging; //Elder: player in the process of bandaging
// end Homer
int weaponfireNextTime; // for akimbos
int lastzoom; // Elder: save last zoom state when firing
int fastReloads; // Elder: for queuing M3/SSG reloads
int lastReloadTime; // Elder: for queuing M3/SSG reloads
int reloadAttempts; // Elder: for queuing M3/SSG reloads
int reloadStage;
int reloadStage; // Elder: 0, 1, 2 for sound queuing - move to stats?
int consecutiveShots; // Elder: for M4 ride-up/kick
int uniqueWeapons; // Elder: formerly a stat, now just a server var
@ -408,6 +421,7 @@ struct gclient_s {
char *areabits;
};
// Begin Duffman
int G_LocationDamage(vec3_t point, gentity_t* targ, gentity_t* attacker, int take);
void Cmd_Reload( gentity_t *ent ); // reloads the current weapon
@ -510,7 +524,7 @@ typedef struct {
void CheckBleeding(gentity_t *targ);
void StartBandage(gentity_t *ent);
void ThrowWeapon( gentity_t *ent );
int ThrowWeapon( gentity_t *ent, qboolean forceThrow );
void ThrowItem( gentity_t *ent );
gentity_t *dropWeapon( gentity_t *ent, gitem_t *item, float angle, int xr_flags ); // XRAY FMJ
//Blaze Reaction knife stuff
@ -540,7 +554,8 @@ void Cmd_OpenDoor(gentity_t *ent);
//Elder: C3A laser tutorial
void Laser_Gen (gentity_t *ent, qboolean enabled);
void Laser_Think( gentity_t *self );
//Elder: anti-spam stuff
int RQ3_ValidateSay ( gentity_t *ent );
//Elder: commented out for Homer
//void toggleSemi(gentity_t *ent);

View file

@ -468,7 +468,7 @@ void G_BreakGlass( gentity_t *ent, vec3_t point, int mod )
//Once it's below 255, we can send a more appropriate event
//This way, the mappers can use a single func_breakable
//while we process it on the server-side.
//Places to stuff: eventParm, generic1
//Places to stuff: eventParm
if( ent->health <= 0 ) {
//G_Printf("Original eParm: %i \n", ent->s.eventParm);

View file

@ -322,8 +322,7 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) {
//Elder: added
if ( !(ent->s.weapon == WP_KNIFE && other->s.eType == ET_BREAKABLE) ) {
G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
ent->s.origin, ent->damage,
0, ent->methodOfDeath);
ent->s.origin, ent->damage, 0, ent->methodOfDeath);
}
}
}
@ -753,12 +752,6 @@ gentity_t *fire_knife (gentity_t *self, vec3_t start, vec3_t dir)
gentity_t *bolt;
// vec3_t gVec;
// gVec[0] = 0;
// gVec[1] = g_gravity.value;
// gVec[2] = 0;
VectorNormalize (dir);
bolt = G_Spawn();
@ -787,9 +780,10 @@ gentity_t *fire_knife (gentity_t *self, vec3_t start, vec3_t dir)
VectorCopy (dir, bolt->s.apos.trBase);
VectorCopy (dir, bolt->r.currentAngles);
//Elder: not needed anymore
//Saving stuff for Makro's knife equations
VectorCopy( start, bolt->s.origin2);
VectorCopy( dir, bolt->s.angles2);
//VectorCopy( start, bolt->s.origin2);
//VectorCopy( dir, bolt->s.angles2);
return bolt;
}

View file

@ -1095,6 +1095,7 @@ void Touch_DoorTrigger( gentity_t *ent, gentity_t *other, trace_t *trace ) {
//G_Printf("Using a door\n");
Use_BinaryMover( ent->parent, ent, other );
other->client->openDoor = qfalse;
other->client->openDoorTime = 0;
}
}
}

View file

@ -35,7 +35,7 @@ void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout
/*
======================================================================
RQ3 Jump Kick
RQ3_JumpKick
Moved from g_active.c to g_weapon.c
Because it is a weapon!
@ -54,18 +54,19 @@ qboolean JumpKick( gentity_t *ent )
// set aiming directions
AngleVectors (ent->client->ps.viewangles, forward, right, up);
CalcMuzzlePoint ( ent, forward, right, up, muzzle );
// Elder: AQ2 offset
muzzle[2] -= (ent->client->ps.viewheight - 20);
VectorMA (muzzle, 25, forward, end);
//VectorMA (muzzle, 32, forward, end);
VectorMA (muzzle, 32, forward, end);
//VectorCopy( ent->s.origin, muzzle );
//muzzle[2] += 32;
// the muzzle really isn't the right point to test the jumpkick from
trap_Trace (&tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT);
//trap_Trace (&tr, ent->s.origin, ent->r.mins, ent->r.maxs, end, ent->s.number, MASK_SHOT);
//trap_Trace (&tr, ent->s.origin, NULL, NULL, end, ent->s.number, MASK_SHOT);
if ( tr.surfaceFlags & SURF_NOIMPACT ) {
return qfalse;
}
@ -99,26 +100,41 @@ qboolean JumpKick( gentity_t *ent )
damage, DAMAGE_NO_LOCATIONAL, MOD_KICK );
}
// send blood impact
// send blood impact + event stuff
/*
if ( traceEnt->takedamage && traceEnt->client ) {
tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
//tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT );
tent = G_TempEntity( tr.endpos, EV_JUMPKICK );
tent->s.otherEntityNum = traceEnt->s.number;
tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = ent->s.weapon;
}
*/
if (traceEnt->client && traceEnt->client->uniqueWeapons > 0)
if (traceEnt->client && traceEnt->takedamage)
{
//Elder: toss a unique weapon if kicked
//Todo: Need to make sure to cancel any reload attempts
//Todo: need to send a message to attacker and target about weapon kick
Cmd_Unzoom(traceEnt);
ThrowWeapon(traceEnt);
//trap_SendServerCommand( ent-g_entities, va("print \"You kicked %s's %s from his hands!\n\"", traceEnt->client->pers.netname, (traceEnt->client->ps.weapon)->pickup_name);
//trap_SendServerCommand( targ-g_entities, va("print \"Head Damage.\n\""));
}
tent = G_TempEntity( tr.endpos, EV_JUMPKICK );
tent->s.otherEntityNum = traceEnt->s.number;
tent->s.otherEntityNum2 = ent->s.number;
tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = 0;
if (traceEnt->client->uniqueWeapons > 0)
{
//Elder: toss a unique weapon if kicked
//Need to make sure to cancel any reload attempts - test this
Cmd_Unzoom(traceEnt);
traceEnt->client->fastReloads = 0;
traceEnt->client->reloadAttempts = 0;
traceEnt->client->ps.weaponTime = 0;
//Set the entity's weapon to the target's weapon before he/she throws it
tent->s.weapon = ThrowWeapon(traceEnt, qtrue);
}
// Don't need other sound event
kickSuccess = qfalse;
}
@ -153,7 +169,9 @@ qboolean JumpKick( gentity_t *ent )
//Elder: Our set of locally called sounds
if (kickSuccess)
{
G_AddEvent ( ent, EV_RQ3_SOUND, RQ3_SOUND_KICK);
}
return qtrue;
}
@ -1012,20 +1030,16 @@ void Knife_Attack ( gentity_t *self, int damage)
{
trace_t tr;
vec3_t end;
// vec3_t start;
// vec3_t aimdir;
gentity_t *hitent;
int passent;
gentity_t *tent;
//VectorMA (start, 90, aimdir, end);
passent = self->s.number;
VectorMA( muzzle, KNIFE_RANGE, forward, end );
trap_Trace (&tr,muzzle, NULL, NULL, end, passent, MASK_SHOT);
trap_Trace (&tr, muzzle, NULL, NULL, end, self->s.number, MASK_SHOT);
hitent = &g_entities[ tr.entityNum ];
// don't need to check for water
if (!((tr.surfaceFlags) && (tr.surfaceFlags & SURF_SKY)))
// don't need to check for water
//if (!((tr.surfaceFlags) && (tr.surfaceFlags & SURF_SKY)))
if (!(tr.surfaceFlags & SURF_SKY))
{
if (tr.fraction < 1.0)
{
@ -1033,19 +1047,24 @@ void Knife_Attack ( gentity_t *self, int damage)
{
//Elder: no knock-back on knife slashes
G_Damage (hitent, self, self, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_KNIFE );
return;
//return -2;
}
if (hitent->client)
{
tent = G_TempEntity(tr.endpos, EV_RQ3_SOUND);
tent->s.eventParm = RQ3_SOUND_KNIFEHIT;
}
}
else
{
//Elder TODO: take into account surface flags for clank
tent = G_TempEntity(tr.endpos, EV_MISSILE_MISS);
tent->s.eventParm = DirToByte(tr.plane.normal);
tent->s.weapon = WP_KNIFE;
}
}
else
//return 0;
return;
}
return;
//return 0; // we hit the sky, call it a miss
}
static int knives = 0;
//static int knives = 0;
//Elder: this function does not appear to be in use
@ -1258,7 +1277,7 @@ void Weapon_M4_Fire(gentity_t *ent)
// Homer: increment burst if needed
if ( (ent->client->ps.persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE )
{
ent->client->ps.stats[STAT_BURST]++;
//ent->client->ps.stats[STAT_BURST]++;
spread = M4_SPREAD * 0.7;
}
else
@ -1298,7 +1317,7 @@ void Weapon_MK23_Fire(gentity_t *ent)
if ( (ent->client->ps.persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE )
{
spread = PISTOL_SPREAD * 0.7;
ent->client->ps.stats[STAT_BURST]++;
//ent->client->ps.stats[STAT_BURST]++;
}
else
{
@ -1316,16 +1335,13 @@ SSG3000 Attack
void Weapon_SSG3000_FireOld(gentity_t *ent)
{
float spread;
//Elder: Don't print - will broadcast to server
//G_Printf("Zoom Level: %d\n", ent->client->zoomed);
//Elder: changed to use RQ3_Spread as well
//Elder: using new stat
//if ( (ent->client->ps.stats[STAT_RQ3] & RQ3_ZOOM_LOW) == RQ3_ZOOM_LOW ||
//(ent->client->ps.stats[STAT_RQ3] & RQ3_ZOOM_MED) == RQ3_ZOOM_MED) {
if (RQ3_isZoomed(ent)) {
if (RQ3_isZoomed(ent))
{
spread = 0;
}
else {
else
{
spread = RQ3_Spread(ent, SNIPER_SPREAD);
}
Bullet_Fire( ent, spread, SNIPER_DAMAGE, MOD_SNIPER);
@ -1359,6 +1375,7 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
gentity_t *unlinkedEntities[MAX_SSG3000_HITS];
qboolean hitBreakable;
qboolean hitKevlar;
float r;
float u;
float spread;
@ -1367,16 +1384,24 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
VectorMA (muzzle, 8192*16, forward, end);
//Elder: added to assist in zoom crap
if (RQ3_isZoomed(ent)) {
if (RQ3_isZoomed(ent))
{
spread = 0;
}
else {
spread = RQ3_Spread(ent, SNIPER_SPREAD);
else
{
/*
r = random() * M_PI * 2.0f;
u = sin(r) * crandom() * spread * 16;
r = cos(r) * crandom() * spread * 16;
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
*/
spread = RQ3_Spread(ent, SNIPER_SPREAD);
u = crandom() * spread * 16;
r = crandom() * spread * 16;
VectorMA (end, r, right, end);
VectorMA (end, u, up, end);
}
@ -1394,6 +1419,7 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
//Elder: need to store this flag because
//the entity may get wiped out in G_Damage
hitBreakable = qfalse;
hitKevlar = qfalse;
//G_Printf("(%d) SSG: Trapping trace\n", level.time);
@ -1422,6 +1448,10 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
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
if (bg_itemlist[traceEnt->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_KEVLAR)
hitKevlar = qtrue;
}
else
{
@ -1440,7 +1470,7 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
//Elder: go through non-solids and breakables
//If we ever wanted to "shoot through walls" we'd do stuff here
if ( hitBreakable == qfalse && (trace.contents & CONTENTS_SOLID)) {
if ( hitKevlar || (hitBreakable == qfalse && (trace.contents & CONTENTS_SOLID))) {
//G_Printf("(%d) SSG: did not hit breakable and hit solid, exiting loop\n", level.time);
break; // we hit something solid enough to stop the beam
}
@ -1535,7 +1565,7 @@ void Weapon_MP5_Fire(gentity_t *ent)
if ( (ent->client->ps.persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE )
{
spread = MP5_SPREAD * 0.7;
ent->client->ps.stats[STAT_BURST]++;
//ent->client->ps.stats[STAT_BURST]++;
}
else
{
@ -1620,51 +1650,60 @@ void RQ3_InitShotgunDamageReport( void )
memset(tookShellHit, 0, MAX_CLIENTS * sizeof(int));
}
//Elder: almost straight out of the AQ2 source
//Elder: similar to AQ2 source
#define MAX_NAME_REPORTS 8
void RQ3_ProduceShotgunDamageReport(gentity_t *self)
{
int l;
int total_to_print = 0;
int i;
int totalNames = 0;
int printed = 0;
static char textbuf[1024];
char textbuf[1024];
gclient_t *hitClient;
for (l = 1; l <= g_maxclients.integer; l++)
//for (l = 1; l <= g_maxclients.integer; l++)
// Run through array to see if anyone was hit
for (i = 0; i < MAX_CLIENTS; i++)
{
if (tookShellHit[i])
totalNames++;
}
if (totalNames)
{
// Clamp number of names to report
if (totalNames > MAX_NAME_REPORTS)
totalNames = MAX_NAME_REPORTS;
//Q_strncpyz(textbuf, "You hit", sizeof(textbuf));
strcpy(textbuf, "You hit ");
for (i = 0; i < MAX_CLIENTS; i++)
{
if (tookShellHit[l - 1])
total_to_print++;
}
if (total_to_print)
{
if (total_to_print > 10)
total_to_print = 10;
strcpy(textbuf, "You hit ");
for (l = 1; l <= g_maxclients.integer; l++)
if (tookShellHit[i])
{
if (tookShellHit[l - 1])
{
if (printed == (total_to_print - 1))
{
if (total_to_print == 2)
strcat(textbuf, " and ");
else if (total_to_print != 1)
strcat(textbuf, ", and ");
}
else if (printed)
strcat(textbuf, ", ");
strcat(textbuf, g_entities[l].client->pers.netname);
//strcat(textbuf, g_edicts[l].client->pers.netname);
printed++;
//grammar set
if (printed == (totalNames - 1))
{
if (totalNames == 2)
Q_strcat(textbuf, sizeof(textbuf), "^7 and ");
else if (totalNames != 1)
Q_strcat(textbuf, sizeof(textbuf), "^7, and ");
}
if (printed == total_to_print)
break;
else if (printed)
Q_strcat(textbuf, sizeof(textbuf), "^7, ");
//add to text buffer
hitClient = g_entities[i].client;
Q_strcat(textbuf, sizeof(textbuf), hitClient->pers.netname);
printed++;
}
trap_SendServerCommand( self-g_entities, va("print \"%s^7\n\"", textbuf));
//gi.cprintf(self, PRINT_HIGH, "%s\n", textbuf);
if (printed == totalNames)
break;
}
trap_SendServerCommand( self-g_entities, va("print \"%s^7.\n\"", textbuf));
//gi.cprintf(self, PRINT_HIGH, "%s\n", textbuf);
}
}
/*