mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2024-11-23 04:32:28 +00:00
Elder:
Code updates for VM 0-08-00 Server-side
This commit is contained in:
parent
3408381bf7
commit
f4cf1c8a3b
12 changed files with 373 additions and 156 deletions
|
@ -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",
|
||||
|
|
|
@ -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) )
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -868,6 +868,29 @@ void G_Say( gentity_t *ent, gentity_t *target, int mode, const char *chatText )
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
VectorMA (muzzle, 32, forward, end);
|
||||
// Elder: AQ2 offset
|
||||
muzzle[2] -= (ent->client->ps.viewheight - 20);
|
||||
VectorMA (muzzle, 25, 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,29 +100,44 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//Elder: for the kick
|
||||
// do our special form of knockback here
|
||||
/*
|
||||
|
@ -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])
|
||||
//grammar set
|
||||
if (printed == (totalNames - 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++;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue