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_FLESH",
"EV_BULLET_HIT_WALL", "EV_BULLET_HIT_WALL",
"EV_SSG3000_HIT_FLESH", //Elder: SSG3000 blood spray "EV_SSG3000_HIT_FLESH", //Elder: SSG3000 blood spray
"EV_JUMPKICK", //Elder: sound + jumpkick message
"EV_MISSILE_HIT", "EV_MISSILE_HIT",
"EV_MISSILE_MISS", "EV_MISSILE_MISS",

View file

@ -1953,6 +1953,56 @@ static void PM_Weapon( void ) {
return; 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 // check for item using
// Elder: removed // Elder: removed
/* /*
@ -2083,7 +2133,6 @@ static void PM_Weapon( void ) {
} }
} }
/* /*
if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) { if ( ! (pm->cmd.buttons & BUTTON_ATTACK) ) {
pm->ps->weaponTime = 0; pm->ps->weaponTime = 0;
@ -2136,6 +2185,17 @@ static void PM_Weapon( void ) {
pm->ps->weaponstate = WEAPON_FIRING; 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 //Elder: M4 kick code
//ent->client->ps.delta_angles[0] = ANGLE2SHORT(SHORT2ANGLE(ent->client->ps.delta_angles[0]) - 0.7); //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) ) if ( pm->ps->weapon == WP_M4 && ((pm->ps->persistant[PERS_WEAPONMODES] & RQ3_M4MODE) != RQ3_M4MODE) )

View file

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

View file

@ -128,6 +128,8 @@ void P_DamageFeedback( gentity_t *player ) {
//Elder: headshot sound //Elder: headshot sound
case LOCATION_HEAD: case LOCATION_HEAD:
case LOCATION_FACE: 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 //Elder: do nothing -- sound is handled in g_combat.c again
//tent = G_TempEntity2(client->ps.origin, EV_RQ3_SOUND, RQ3_SOUND_HEADSHOT); //tent = G_TempEntity2(client->ps.origin, EV_RQ3_SOUND, RQ3_SOUND_HEADSHOT);
//Elder: takes more bandwidth but guarantees a headshot sound //Elder: takes more bandwidth but guarantees a headshot sound
@ -137,15 +139,7 @@ void P_DamageFeedback( gentity_t *player ) {
/* /*
case LOCATION_CHEST: case LOCATION_CHEST:
case LOCATION_SHOULDER: case LOCATION_SHOULDER:
//Play metal impact if vest was hit G_AddEvent( player, EV_PAIN, player->health );
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 );
break; break;
*/ */
default: default:
@ -853,10 +847,11 @@ void BotTestSolid(vec3_t origin);
ThrowWeapon ThrowWeapon
XRAY FMJ XRAY FMJ
Returns the number of the weapon thrown
============= =============
*/ */
void ThrowWeapon( gentity_t *ent ) int ThrowWeapon( gentity_t *ent, qboolean forceThrow )
{ {
gclient_t *client; gclient_t *client;
usercmd_t *ucmd; usercmd_t *ucmd;
@ -875,15 +870,16 @@ void ThrowWeapon( gentity_t *ent )
//Elder: TODO: have to add a reloading case: //Elder: TODO: have to add a reloading case:
//weaponTime > 0 or weaponState == weapon_dropping? Or both? //weaponTime > 0 or weaponState == weapon_dropping? Or both?
//Still firing //Still firing
if ( (ucmd->buttons & BUTTON_ATTACK) == BUTTON_ATTACK || client->ps.weaponTime > 0) { if (!forceThrow)
return; if ( (ucmd->buttons & BUTTON_ATTACK) == BUTTON_ATTACK || client->ps.weaponTime > 0)
} return 0;
//Elder: Bandaging case
//Elder: Bandaging case -- handled in cgame
//else if (client->isBandaging) { //else if (client->isBandaging) {
if ( (ent->client->ps.stats[STAT_RQ3] & RQ3_BANDAGE_WORK) == RQ3_BANDAGE_WORK) { //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\"")); //trap_SendServerCommand( ent-g_entities, va("print \"You are too busy bandaging...\n\""));
return; //return;
} //}
weap = 0; weap = 0;
@ -900,7 +896,9 @@ void ThrowWeapon( gentity_t *ent )
weap = WP_HANDCANNON; weap = WP_HANDCANNON;
if ((client->ps.stats[STAT_WEAPONS] & (1 << WP_SSG3000) ) == (1 << WP_SSG3000)) if ((client->ps.stats[STAT_WEAPONS] & (1 << WP_SSG3000) ) == (1 << WP_SSG3000))
weap = WP_SSG3000; weap = WP_SSG3000;
if (weap == 0 ) return; if (weap == 0 )
return 0;
xr_item = BG_FindItemForWeapon( weap ); xr_item = BG_FindItemForWeapon( weap );
//Elder: Send a server command instead of force-setting //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 xr_drop->count= -1; // XRAY FMJ 0 is already taken, -1 means no ammo
client->uniqueWeapons--; client->uniqueWeapons--;
} }
return weap;
} }
/* /*
@ -1123,9 +1123,11 @@ void ClientThink_real( gentity_t *ent ) {
ent->client->pers.cmd.buttons |= BUTTON_GESTURE; ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
} }
//**************Elder: moved to bg_pmove.c (PM_Weapon)************//
//Elder: New 3rb Code //Elder: New 3rb Code
//force fire button down if STAT_BURST is < proper amount //force fire button down if STAT_BURST is < proper amount
//Otherwise release the button //Otherwise release the button
/*
if ( (client->ps.weapon == WP_M4 && if ( (client->ps.weapon == WP_M4 &&
(client->ps.persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) || (client->ps.persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) ||
(client->ps.weapon == WP_MP5 && (client->ps.weapon == WP_MP5 &&
@ -1172,6 +1174,7 @@ void ClientThink_real( gentity_t *ent ) {
client->ps.stats[STAT_BURST] = 0; client->ps.stats[STAT_BURST] = 0;
} }
} }
*/
#ifdef MISSIONPACK #ifdef MISSIONPACK
// check for invulnerability expansion before doing the Pmove // check for invulnerability expansion before doing the Pmove
@ -1637,6 +1640,14 @@ void ClientEndFrame( gentity_t *ent ) {
ent->client->consecutiveShots = 0; 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 ) if ( bg_itemlist[ent->client->ps.stats[STAT_HOLDABLE_ITEM]].giTag == HI_LASER )
{ {
//Try to turn the laser on if it's off //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 //Blaze: Set the opendoor flag to 0
client->openDoor = qfalse; client->openDoor = qfalse;
client->openDoorTime = 0;
// don't allow full run speed for a bit // don't allow full run speed for a bit
client->ps.pm_flags |= PMF_TIME_KNOCKBACK; 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 // don't let text be too long for malicious reasons
char text[MAX_SAY_TEXT]; char text[MAX_SAY_TEXT];
char location[64]; 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 ) { if ( g_gametype.integer < GT_TEAM && mode == SAY_TEAM ) {
mode = SAY_ALL; mode = SAY_ALL;
@ -2082,10 +2105,11 @@ void Cmd_OpenDoor(gentity_t *ent)
{ {
if (Q_stricmp (door->classname, "func_door_rotating") == 0) { if (Q_stricmp (door->classname, "func_door_rotating") == 0) {
ent->client->openDoor = qtrue; 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) { else if (Q_stricmp (door->classname, "func_door") == 0) {
ent->client->openDoor = qtrue; 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 ) { void Cmd_DropWeapon_f( gentity_t *ent ) {
//Elder: added //Elder: added -- checked in cgame
if ( (ent->client->ps.stats[STAT_RQ3] & RQ3_BANDAGE_WORK) == RQ3_BANDAGE_WORK) //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\"")); //trap_SendServerCommand( ent-g_entities, va("print \"You are too busy bandaging!\n\""));
return; //return;
} //}
else //else
{ //{
//Elder: remove zoom bits //Elder: remove zoom bits
Cmd_Unzoom(ent); Cmd_Unzoom(ent);
ThrowWeapon( ent ); //Throwing away return here
} ThrowWeapon( ent, qfalse );
//}
} }
/* /*
@ -2347,7 +2372,7 @@ PlayerStats
*/ */
void Cmd_PlayerStats_f( gentity_t *ent ) 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 )); trap_SendServerCommand( ent-g_entities, va("print \"%s:\n\"",ent->client->pers.netname ));
@ -2506,3 +2531,70 @@ void ClientCommand( int clientNum ) {
else else
trap_SendServerCommand( clientNum, va("print \"unknown cmd %s\n\"", cmd ) ); 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 =
( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; ( ( 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 // the body can still be gibbed
self->die = body_die; 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 //Blaze: If we shot a breakable item subtract the damage from its health and try to break it
if ( targ->s.eType == ET_BREAKABLE ) { if ( targ->s.eType == ET_BREAKABLE ) {
targ->health -= damage; targ->health -= damage;
G_BreakGlass( targ, point, mod ); G_BreakGlass( targ, point, mod );
return; return;
} }
@ -1516,8 +1519,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
//Elder: do shotgun report like AQ2 //Elder: do shotgun report like AQ2
int playernum = targ - g_entities; int playernum = targ - g_entities;
playernum--; //playernum--;
if (playernum >= 0 && playernum <= MAX_CLIENTS - 1) if (playernum >= 0 && playernum < MAX_CLIENTS)
tookShellHit[playernum] = 1; tookShellHit[playernum] = 1;
} }
else { else {
@ -1649,7 +1652,7 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker,
break; break;
case LOCATION_SHOULDER: case LOCATION_SHOULDER:
case LOCATION_CHEST: 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 (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)) //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 //Kevlar sound
tent = G_TempEntity2(targ->s.pos.trBase, EV_RQ3_SOUND, RQ3_SOUND_KEVLARHIT); 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 else
{ {

View file

@ -69,6 +69,8 @@ typedef enum {
#define SP_AUTOOPEN 4 // Elder: revert to Q3 behaviour #define SP_AUTOOPEN 4 // Elder: revert to Q3 behaviour
#define SP_DOORTOGGLE 8 // Elder: added to enable mover toggling #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; typedef struct gentity_s gentity_t;
@ -261,11 +263,33 @@ typedef struct {
int voteCount; // to prevent people from constantly calling votes int voteCount; // to prevent people from constantly calling votes
int teamVoteCount; // to prevent people from constantly calling votes int teamVoteCount; // to prevent people from constantly calling votes
qboolean teamInfo; // send team overlay updates? 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; } 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(), // this structure is cleared on each ClientSpawn(),
// except for 'client->pers' and 'client->sess' // except for 'client->pers' and 'client->sess'
struct gclient_s { struct gclient_s {
@ -329,7 +353,7 @@ struct gclient_s {
int lasthurt_mod; // type of damage the client did int lasthurt_mod; // type of damage the client did
// Begin Duffman // Begin Duffman
int lasthurt_location; // Where the client was hit. int lasthurt_location; // Where the client was hit.
// End Duffman // End Duffman
// timers // timers
@ -345,15 +369,16 @@ struct gclient_s {
qboolean fireHeld; // used for hook qboolean fireHeld; // used for hook
gentity_t *hook; // grapple hook if out gentity_t *hook; // grapple hook if out
int switchTeamTime; // time the player switched teams int switchTeamTime; // time the player switched teams
// Begin Duffman // Begin Duffman
int numClips[MAX_WEAPONS]; // Number of clips each weapon has int numClips[MAX_WEAPONS]; // Number of clips each weapon has
// End Duffman // 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 // timeResidual is used to handle events that happen every second
// like health / armor countdowns and regeneration // like health / armor countdowns and regeneration
int timeResidual; int timeResidual;
//Elder: C3A laser tutorial //Elder: C3A laser tutorial
@ -374,25 +399,13 @@ struct gclient_s {
//qboolean semi; // hawkins (semiauto mode for m4, mp5, pistol) //qboolean semi; // hawkins (semiauto mode for m4, mp5, pistol)
int shots; //Blaze: Number of shots fired so far with this weapon 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 weaponfireNextTime; // for akimbos
int lastzoom; // Elder: save last zoom state when firing int lastzoom; // Elder: save last zoom state when firing
int fastReloads; // Elder: for queuing M3/SSG reloads int fastReloads; // Elder: for queuing M3/SSG reloads
int lastReloadTime; // Elder: for queuing M3/SSG reloads int lastReloadTime; // Elder: for queuing M3/SSG reloads
int reloadAttempts; // 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 consecutiveShots; // Elder: for M4 ride-up/kick
int uniqueWeapons; // Elder: formerly a stat, now just a server var int uniqueWeapons; // Elder: formerly a stat, now just a server var
@ -408,6 +421,7 @@ struct gclient_s {
char *areabits; char *areabits;
}; };
// Begin Duffman // Begin Duffman
int G_LocationDamage(vec3_t point, gentity_t* targ, gentity_t* attacker, int take); int G_LocationDamage(vec3_t point, gentity_t* targ, gentity_t* attacker, int take);
void Cmd_Reload( gentity_t *ent ); // reloads the current weapon void Cmd_Reload( gentity_t *ent ); // reloads the current weapon
@ -510,7 +524,7 @@ typedef struct {
void CheckBleeding(gentity_t *targ); void CheckBleeding(gentity_t *targ);
void StartBandage(gentity_t *ent); void StartBandage(gentity_t *ent);
void ThrowWeapon( gentity_t *ent ); int ThrowWeapon( gentity_t *ent, qboolean forceThrow );
void ThrowItem( gentity_t *ent ); void ThrowItem( gentity_t *ent );
gentity_t *dropWeapon( gentity_t *ent, gitem_t *item, float angle, int xr_flags ); // XRAY FMJ gentity_t *dropWeapon( gentity_t *ent, gitem_t *item, float angle, int xr_flags ); // XRAY FMJ
//Blaze Reaction knife stuff //Blaze Reaction knife stuff
@ -540,7 +554,8 @@ void Cmd_OpenDoor(gentity_t *ent);
//Elder: C3A laser tutorial //Elder: C3A laser tutorial
void Laser_Gen (gentity_t *ent, qboolean enabled); void Laser_Gen (gentity_t *ent, qboolean enabled);
void Laser_Think( gentity_t *self ); void Laser_Think( gentity_t *self );
//Elder: anti-spam stuff
int RQ3_ValidateSay ( gentity_t *ent );
//Elder: commented out for Homer //Elder: commented out for Homer
//void toggleSemi(gentity_t *ent); //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 //Once it's below 255, we can send a more appropriate event
//This way, the mappers can use a single func_breakable //This way, the mappers can use a single func_breakable
//while we process it on the server-side. //while we process it on the server-side.
//Places to stuff: eventParm, generic1 //Places to stuff: eventParm
if( ent->health <= 0 ) { if( ent->health <= 0 ) {
//G_Printf("Original eParm: %i \n", ent->s.eventParm); //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 //Elder: added
if ( !(ent->s.weapon == WP_KNIFE && other->s.eType == ET_BREAKABLE) ) { if ( !(ent->s.weapon == WP_KNIFE && other->s.eType == ET_BREAKABLE) ) {
G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity, G_Damage (other, ent, &g_entities[ent->r.ownerNum], velocity,
ent->s.origin, ent->damage, ent->s.origin, ent->damage, 0, ent->methodOfDeath);
0, ent->methodOfDeath);
} }
} }
} }
@ -753,12 +752,6 @@ gentity_t *fire_knife (gentity_t *self, vec3_t start, vec3_t dir)
gentity_t *bolt; gentity_t *bolt;
// vec3_t gVec;
// gVec[0] = 0;
// gVec[1] = g_gravity.value;
// gVec[2] = 0;
VectorNormalize (dir); VectorNormalize (dir);
bolt = G_Spawn(); 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->s.apos.trBase);
VectorCopy (dir, bolt->r.currentAngles); VectorCopy (dir, bolt->r.currentAngles);
//Elder: not needed anymore
//Saving stuff for Makro's knife equations //Saving stuff for Makro's knife equations
VectorCopy( start, bolt->s.origin2); //VectorCopy( start, bolt->s.origin2);
VectorCopy( dir, bolt->s.angles2); //VectorCopy( dir, bolt->s.angles2);
return bolt; 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"); //G_Printf("Using a door\n");
Use_BinaryMover( ent->parent, ent, other ); Use_BinaryMover( ent->parent, ent, other );
other->client->openDoor = qfalse; 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 Moved from g_active.c to g_weapon.c
Because it is a weapon! Because it is a weapon!
@ -54,18 +54,19 @@ qboolean JumpKick( gentity_t *ent )
// set aiming directions // set aiming directions
AngleVectors (ent->client->ps.viewangles, forward, right, up); AngleVectors (ent->client->ps.viewangles, forward, right, up);
CalcMuzzlePoint ( ent, forward, right, up, muzzle ); 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 ); //VectorCopy( ent->s.origin, muzzle );
//muzzle[2] += 32; //muzzle[2] += 32;
// the muzzle really isn't the right point to test the jumpkick from // 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, 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); //trap_Trace (&tr, ent->s.origin, NULL, NULL, end, ent->s.number, MASK_SHOT);
if ( tr.surfaceFlags & SURF_NOIMPACT ) { if ( tr.surfaceFlags & SURF_NOIMPACT ) {
return qfalse; return qfalse;
} }
@ -99,26 +100,41 @@ qboolean JumpKick( gentity_t *ent )
damage, DAMAGE_NO_LOCATIONAL, MOD_KICK ); damage, DAMAGE_NO_LOCATIONAL, MOD_KICK );
} }
// send blood impact // send blood impact + event stuff
/*
if ( traceEnt->takedamage && traceEnt->client ) { 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.otherEntityNum = traceEnt->s.number;
tent->s.eventParm = DirToByte( tr.plane.normal ); tent->s.eventParm = DirToByte( tr.plane.normal );
tent->s.weapon = ent->s.weapon; 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 tent = G_TempEntity( tr.endpos, EV_JUMPKICK );
//Todo: Need to make sure to cancel any reload attempts tent->s.otherEntityNum = traceEnt->s.number;
//Todo: need to send a message to attacker and target about weapon kick tent->s.otherEntityNum2 = ent->s.number;
Cmd_Unzoom(traceEnt); tent->s.eventParm = DirToByte( tr.plane.normal );
ThrowWeapon(traceEnt); tent->s.weapon = 0;
//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\""));
}
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 //Elder: Our set of locally called sounds
if (kickSuccess) if (kickSuccess)
{
G_AddEvent ( ent, EV_RQ3_SOUND, RQ3_SOUND_KICK); G_AddEvent ( ent, EV_RQ3_SOUND, RQ3_SOUND_KICK);
}
return qtrue; return qtrue;
} }
@ -1012,20 +1030,16 @@ void Knife_Attack ( gentity_t *self, int damage)
{ {
trace_t tr; trace_t tr;
vec3_t end; vec3_t end;
// vec3_t start;
// vec3_t aimdir;
gentity_t *hitent; gentity_t *hitent;
int passent; gentity_t *tent;
//VectorMA (start, 90, aimdir, end);
passent = self->s.number;
VectorMA( muzzle, KNIFE_RANGE, forward, end ); 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 ]; hitent = &g_entities[ tr.entityNum ];
// don't need to check for water // don't need to check for water
if (!((tr.surfaceFlags) && (tr.surfaceFlags & SURF_SKY))) //if (!((tr.surfaceFlags) && (tr.surfaceFlags & SURF_SKY)))
if (!(tr.surfaceFlags & SURF_SKY))
{ {
if (tr.fraction < 1.0) if (tr.fraction < 1.0)
{ {
@ -1033,19 +1047,24 @@ void Knife_Attack ( gentity_t *self, int damage)
{ {
//Elder: no knock-back on knife slashes //Elder: no knock-back on knife slashes
G_Damage (hitent, self, self, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_KNIFE ); G_Damage (hitent, self, self, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_KNIFE );
return; if (hitent->client)
//return -2; {
} 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 //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 // Homer: increment burst if needed
if ( (ent->client->ps.persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE ) 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; spread = M4_SPREAD * 0.7;
} }
else else
@ -1298,7 +1317,7 @@ void Weapon_MK23_Fire(gentity_t *ent)
if ( (ent->client->ps.persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE ) if ( (ent->client->ps.persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE )
{ {
spread = PISTOL_SPREAD * 0.7; spread = PISTOL_SPREAD * 0.7;
ent->client->ps.stats[STAT_BURST]++; //ent->client->ps.stats[STAT_BURST]++;
} }
else else
{ {
@ -1316,16 +1335,13 @@ SSG3000 Attack
void Weapon_SSG3000_FireOld(gentity_t *ent) void Weapon_SSG3000_FireOld(gentity_t *ent)
{ {
float spread; 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: changed to use RQ3_Spread as well
//Elder: using new stat if (RQ3_isZoomed(ent))
//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)) {
spread = 0; spread = 0;
} }
else { else
{
spread = RQ3_Spread(ent, SNIPER_SPREAD); spread = RQ3_Spread(ent, SNIPER_SPREAD);
} }
Bullet_Fire( ent, spread, SNIPER_DAMAGE, MOD_SNIPER); 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]; gentity_t *unlinkedEntities[MAX_SSG3000_HITS];
qboolean hitBreakable; qboolean hitBreakable;
qboolean hitKevlar;
float r; float r;
float u; float u;
float spread; float spread;
@ -1367,16 +1384,24 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
VectorMA (muzzle, 8192*16, forward, end); VectorMA (muzzle, 8192*16, forward, end);
//Elder: added to assist in zoom crap //Elder: added to assist in zoom crap
if (RQ3_isZoomed(ent)) { if (RQ3_isZoomed(ent))
{
spread = 0; spread = 0;
} }
else { else
spread = RQ3_Spread(ent, SNIPER_SPREAD); {
/*
r = random() * M_PI * 2.0f; r = random() * M_PI * 2.0f;
u = sin(r) * crandom() * spread * 16; u = sin(r) * crandom() * spread * 16;
r = cos(r) * crandom() * spread * 16; r = cos(r) * crandom() * spread * 16;
VectorMA (end, r, right, end); VectorMA (end, r, right, end);
VectorMA (end, u, up, 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 //Elder: need to store this flag because
//the entity may get wiped out in G_Damage //the entity may get wiped out in G_Damage
hitBreakable = qfalse; hitBreakable = qfalse;
hitKevlar = qfalse;
//G_Printf("(%d) SSG: Trapping trace\n", level.time); //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] = G_TempEntity( trace.endpos, EV_SSG3000_HIT_FLESH );
//tent[unlinked]->s.eventParm = DirToByte( trace.plane.normal ); //tent[unlinked]->s.eventParm = DirToByte( trace.plane.normal );
tent[unlinked]->s.eventParm = traceEnt->s.number; 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 else
{ {
@ -1440,7 +1470,7 @@ void Weapon_SSG3000_Fire (gentity_t *ent) {
//Elder: go through non-solids and breakables //Elder: go through non-solids and breakables
//If we ever wanted to "shoot through walls" we'd do stuff here //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); //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 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 ) if ( (ent->client->ps.persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE )
{ {
spread = MP5_SPREAD * 0.7; spread = MP5_SPREAD * 0.7;
ent->client->ps.stats[STAT_BURST]++; //ent->client->ps.stats[STAT_BURST]++;
} }
else else
{ {
@ -1620,51 +1650,60 @@ void RQ3_InitShotgunDamageReport( void )
memset(tookShellHit, 0, MAX_CLIENTS * sizeof(int)); 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) void RQ3_ProduceShotgunDamageReport(gentity_t *self)
{ {
int i;
int l; int totalNames = 0;
int total_to_print = 0;
int printed = 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]) if (tookShellHit[i])
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[l - 1]) //grammar set
{ if (printed == (totalNames - 1))
if (printed == (total_to_print - 1)) {
{ if (totalNames == 2)
if (total_to_print == 2) Q_strcat(textbuf, sizeof(textbuf), "^7 and ");
strcat(textbuf, " and "); else if (totalNames != 1)
else if (total_to_print != 1) Q_strcat(textbuf, sizeof(textbuf), "^7, and ");
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++;
} }
if (printed == total_to_print) else if (printed)
break; 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);
}
} }
/* /*