From 0d3a1a70092301c8b628434f9fe8ca31e086ce47 Mon Sep 17 00:00:00 2001 From: Victor Chow Date: Tue, 24 Jul 2001 01:49:02 +0000 Subject: [PATCH] Elder: Updates for 0-05-xx + stuff to be released in 0-05-01 Client portion has adjusted HUD, small fixes here and there --- reaction/cgame/cg_consolecmds.c | 115 ++++++++++++++++++++++-- reaction/cgame/cg_draw.c | 74 ++++++++++++--- reaction/cgame/cg_effects.c | 153 +++++++++++++++++++++----------- reaction/cgame/cg_event.c | 16 +++- reaction/cgame/cg_local.h | 12 ++- reaction/cgame/cg_main.c | 6 +- reaction/cgame/cg_predict.c | 25 +++++- reaction/cgame/cg_weapons.c | 148 +++++++++++++++++++++++------- 8 files changed, 439 insertions(+), 110 deletions(-) diff --git a/reaction/cgame/cg_consolecmds.c b/reaction/cgame/cg_consolecmds.c index 66d1d38f..0e47e7a7 100644 --- a/reaction/cgame/cg_consolecmds.c +++ b/reaction/cgame/cg_consolecmds.c @@ -33,6 +33,7 @@ Elder: reset local zoom, then proceed with server action */ static void CG_DropWeapon_f (void) { if ( !cg.snap ) { + //CG_Printf("No snapshot: normally exiting\n"); return; } @@ -45,7 +46,11 @@ static void CG_DropWeapon_f (void) { if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { return; } - + + //Elder: don't allow weapon dropping when in the middle of bursts + if (cg.snap->ps.stats[STAT_BURST] > 0) + return; + CG_RQ3_Zoom1x(); trap_SendClientCommand("dropweapon"); } @@ -61,6 +66,7 @@ the client command to reduce bandwidth use slightly */ static void CG_Bandage_f (void) { if ( !cg.snap ) { + //CG_Printf("No snapshot: normally exiting\n"); return; } @@ -80,7 +86,6 @@ static void CG_Bandage_f (void) { return; } - //if (cg.snap->ps.stats[STAT_BANDAGE]) { if ( (cg.snap->ps.stats[STAT_RQ3] & RQ3_BANDAGE_WORK) == RQ3_BANDAGE_WORK) { CG_Printf("You are already bandaging!\n"); //cg.zoomed = 0; @@ -88,6 +93,10 @@ static void CG_Bandage_f (void) { return; } + //Elder: don't allow bandaging when in the middle of bursts + if (cg.snap->ps.stats[STAT_BURST] > 0) + return; + //Elder: added to prevent bandaging while reloading or firing //Moved below "already-bandaging" case and removed message //if ( cg.snap->ps.weaponTime > 0 || cg.snap->ps.weaponstate == WEAPON_COCKED) { @@ -109,6 +118,7 @@ Elder: reset reload depressed flag ================= */ static void CG_ReloadReset_f (void) { + //CG_Printf("Releasing Reload\n"); cg.rq3_reloadDown = qfalse; } @@ -118,6 +128,7 @@ static void CG_ReloadReset_f (void) { CG_Reload_f Elder: reset local zoom, then proceed with server action +Note: most of this doesn't work if it's a +button style ================= */ static void CG_Reload_f (void) { @@ -125,6 +136,7 @@ static void CG_Reload_f (void) { cent = &cg_entities[cg.snap->ps.clientNum]; if ( !cg.snap ) { + //CG_Printf("No snapshot: normally exiting\n"); return; } @@ -138,18 +150,23 @@ static void CG_Reload_f (void) { return; } - if (cg.rq3_reloadDown) + //Elder: don't allow reloading when in the middle of bursts + if (cg.snap->ps.stats[STAT_BURST] > 0) return; - cg.rq3_reloadDown = qtrue; - - //Elder: prevent "reloading" when dead hehe - if ( cg.snap->ps.stats[STAT_HEALTH] < 0 ) { - CG_Printf("Nothing to reload - you are dead.\n"); + if (cg.rq3_reloadDown == qtrue) + { + //CG_Printf("Reload down... exiting\n"); return; } - + //cg.rq3_reloadDown = qtrue; + + //Elder: prevent "reloading" when dead hehe + if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) { + CG_Printf("Nothing to reload - you are dead.\n"); + return; + } //Elder: don't allow reloading until the weapon is free //Don't cut-off here because we want to check for fast-reloads @@ -174,6 +191,7 @@ static void CG_Reload_f (void) { if (cg.snap->ps.weapon == WP_SSG3000 && cg.zoomFirstReturn == -1) cg.zoomFirstReturn = 0; + //CG_Printf("Sending reload command to server\n"); trap_SendClientCommand("reload"); } @@ -214,6 +232,18 @@ static void CG_Viewpos_f (void) { (int)cg.refdefViewAngles[YAW]); } +/* +============= +CG_PlayerOrigin_f + +Debugging command to print player's origin +============= +*/ +static void CG_PlayerOrigin_f (void) { + CG_Printf("(%i %i %i)\n", (int)cg.snap->ps.origin[0], + (int)cg.snap->ps.origin[1], (int)cg.snap->ps.origin[2]); +} + static void CG_ScoresDown_f( void ) { @@ -555,6 +585,64 @@ static void CG_StartOrbit_f( void ) { } +/* +================== +CG_Say_f + +Elder: Pre-validate say command to avoid text flooding +================== +*/ + +static void CG_Say_f ( void ) { + + if (cg.time - cg.sayTime > 2000) + cg.sayCount = 0; + + if (cg.sayCount == 0) + cg.sayTime = cg.time; + + cg.sayCount++; + + CG_Printf("sayCount: %i sayTime: %i\n", cg.sayCount, cg.sayTime); + + if (cg.sayCount > 4 && cg.time - cg.sayTime < 2000) + { + CG_Printf("Cannot send messages.\n"); + return; + } + + trap_SendClientCommand("say"); +} + + +/* +================== +CG_SayTeam_f + +Elder: Pre-validate say_team command to avoid text flooding +================== +*/ + +static void CG_SayTeam_f ( void ) { + + if (cg.time - cg.sayTime > 2000) + cg.sayCount = 0; + + if (cg.sayCount == 0) + cg.sayTime = cg.time; + + cg.sayCount++; + + CG_Printf("sayCount: %i sayTime: %i\n", cg.sayCount, cg.sayTime); + + if (cg.sayCount > 4 && cg.time - cg.sayTime < 2000) + { + CG_Printf("Cannot send messages.\n"); + return; + } + + trap_SendClientCommand("say_team"); +} typedef struct { @@ -570,6 +658,7 @@ static consoleCommand_t commands[] = { { "nextskin", CG_TestModelNextSkin_f }, { "prevskin", CG_TestModelPrevSkin_f }, { "viewpos", CG_Viewpos_f }, + { "playerorigin", CG_PlayerOrigin_f }, { "+scores", CG_ScoresDown_f }, { "-scores", CG_ScoresUp_f }, /* { "+zoom", CG_ZoomDown_f }, // hawkins not needed in Reaction @@ -584,6 +673,11 @@ static consoleCommand_t commands[] = { { "+reload", CG_Reload_f }, // Elder: added to reset zoom then goto server { "-reload", CG_ReloadReset_f}, // Elder: added to stop auto-throttle { "specialweapon", CG_SpecialWeapon_f }, // Elder: select special weapon + //Elder: added for manual sv_floodProtect check + { "messagemode", CG_Say_f }, + { "messagemode2", CG_SayTeam_f }, + { "say", CG_Say_f }, + { "say_team", CG_SayTeam_f }, { "tell_target", CG_TellTarget_f }, { "tell_attacker", CG_TellAttacker_f }, { "vtell_target", CG_VoiceTellTarget_f }, @@ -699,4 +793,7 @@ void CG_InitConsoleCommands( void ) { //Elder: try this trap_AddCommand ("weapon"); trap_AddCommand ("specialweapon"); + trap_AddCommand ("messagemode"); + trap_AddCommand ("messagemode2"); + trap_AddCommand ("playerorigin"); } diff --git a/reaction/cgame/cg_draw.c b/reaction/cgame/cg_draw.c index b1f191ba..d2931bc4 100644 --- a/reaction/cgame/cg_draw.c +++ b/reaction/cgame/cg_draw.c @@ -501,7 +501,7 @@ static void CG_DrawStatusBar( void ) { int style; centity_t *cent; playerState_t *ps; - int value, value2; + int value;//, value2; vec4_t hcolor; vec3_t angles; vec3_t origin; @@ -510,6 +510,7 @@ static void CG_DrawStatusBar( void ) { //#ifdef MISSIONPACK // qhandle_t handle; //#endif + int i; static float colors [4][4] = { { 0.0f, 1.0f, 0.0f, 1.0f } , //full green @@ -543,7 +544,7 @@ static void CG_DrawStatusBar( void ) { hcolor[2] = 0; hcolor[3] = (value <= 25) * (0.01 * value + 0.75) + (value > 25) * 1; - /* Elder: Old clamp routine for reference + /* Elder: Old clamp routine for reference -- more efficient since less stack usage? for (i = 0; i < 4; i++) { if (hcolor[i] > 1.0) { CG_Printf ("Over one on %i\n",i); @@ -555,23 +556,72 @@ static void CG_DrawStatusBar( void ) { } }*/ - CG_DrawPic(8, 440, 32, 32, hicon); + CG_DrawPic(8, 440, SMICON_SIZE, SMICON_SIZE, hicon); UI_DrawProportionalString(44, 444, va("%d", value), style, hcolor); //Elder: Draw weapon ammo and clips style = UI_LEFT|UI_DROPSHADOW; - icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon; + + icon = cg_weapons[ cg.predictedPlayerState.weapon ].weaponIcon; if (icon) - CG_DrawPic(152, 440, 32, 32, icon); + CG_DrawPic(152, 440, SMICON_SIZE, SMICON_SIZE, icon); + + icon = cg_weapons[ cg.predictedPlayerState.weapon ].ammoIcon; + //Don't draw ammo icon if holding grenade or knife + if (icon && + cg.predictedPlayerState.weapon != WP_KNIFE && + cg.predictedPlayerState.weapon != WP_GRENADE) + CG_DrawPic(252, 440, SMICON_SIZE, SMICON_SIZE, icon); - if ( cent->currentState.weapon ) { + if ( cent->currentState.weapon ) + { value = ps->ammo[cent->currentState.weapon]; - value2 = ps->stats[STAT_CLIPS]; - if ( value > -1 ) { - UI_DrawProportionalString(188, 444, va("%d / %d", value, value2), style, colors[0]); + + if ( value > -1 ) + UI_DrawProportionalString(188, 444, va("%d", value), style, colors[0]); + + //UI_DrawProportionalString(188, 444, "/"), style, colors[0]); + + value = ps->stats[STAT_CLIPS]; + if ( value > -1 && + cg.predictedPlayerState.weapon != WP_KNIFE && + cg.predictedPlayerState.weapon != WP_GRENADE) + UI_DrawProportionalString(288, 444, va("%d", value), style, colors[0]); + } + + //Elder: draw grenades, if any, on the side + if (cg.snap->ps.ammo[ WP_GRENADE ] > 0) + { + icon = cg_weapons[ WP_GRENADE ].weaponIcon; + if (icon) + CG_DrawPic(640-SMICON_SIZE, 360, SMICON_SIZE, SMICON_SIZE, icon); + UI_DrawProportionalString(580, 364, va("%d", cg.snap->ps.ammo[WP_GRENADE]), style, colors[0]); + } + + //Elder: draw special weapons, if any, on the side + if (cg.snap->ps.stats[STAT_UNIQUEWEAPONS]) + { + for (i = 1; i < MAX_WEAPONS; i++) + { + if (i == WP_KNIFE || + i == WP_PISTOL || + i == WP_GRENADE || + i == WP_AKIMBO) + continue; + + if ( (1 << i) == ((1 << i) & cg.snap->ps.stats[STAT_WEAPONS])) + break; + } + + if (i < MAX_WEAPONS) + { + icon = cg_weapons[i].weaponIcon; + if (icon) + CG_DrawPic(640-SMICON_SIZE, 400, SMICON_SIZE, SMICON_SIZE, icon); } } + } /* Elder: old stuff @@ -1392,7 +1442,8 @@ CG_DrawLowerRight static void CG_DrawLowerRight( void ) { float y; - y = 480 - ICON_SIZE; + //y = 480 - ICON_SIZE; + y = 320 + SMICON_SIZE; if ( cgs.gametype >= GT_TEAM && cg_drawTeamOverlay.integer == 2 ) { y = CG_DrawTeamOverlay( y, qtrue, qfalse ); @@ -1544,7 +1595,8 @@ static void CG_DrawHoldableItem( void ) { value = cg.snap->ps.stats[STAT_HOLDABLE_ITEM]; if ( value ) { CG_RegisterItemVisuals( value ); - CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); + //CG_DrawPic( 640-ICON_SIZE, (SCREEN_HEIGHT-ICON_SIZE)/2, ICON_SIZE, ICON_SIZE, cg_items[ value ].icon ); + CG_DrawPic( 640-SMICON_SIZE, 440, SMICON_SIZE, SMICON_SIZE, cg_items[ value ].icon ); } } diff --git a/reaction/cgame/cg_effects.c b/reaction/cgame/cg_effects.c index 2b74562f..607e5ab0 100644 --- a/reaction/cgame/cg_effects.c +++ b/reaction/cgame/cg_effects.c @@ -693,16 +693,15 @@ void CG_BigExplode( vec3_t playerOrigin ) { CG_LaunchExplode( origin, velocity, cgs.media.smoke2 ); } - #define GLASS_VELOCITY 175 - #define GLASS_JUMP 125 - - /* - ================== - CG_LaunchGlass - ================== - */ - //Elder: might want to rotate the model randomly or do it in break glass - void CG_LaunchGlass( vec3_t origin, vec3_t velocity, vec3_t rotation, qhandle_t hModel ) { +#define GLASS_VELOCITY 175 +#define GLASS_JUMP 125 +/* +================== +CG_LaunchGlass +================== +*/ +void CG_LaunchGlass( vec3_t origin, vec3_t velocity, vec3_t rotation, + float bounce, qhandle_t hModel ) { localEntity_t *le; refEntity_t *re; @@ -711,9 +710,8 @@ void CG_BigExplode( vec3_t playerOrigin ) { le->leType = LE_FRAGMENT; le->startTime = cg.time; - le->endTime = le->startTime + (random() * 3000)+ cg_RQ3_glasstime.integer;// + 30000; + le->endTime = le->startTime + (random() * 3000)+ cg_RQ3_glasstime.integer; // + 30000; - VectorCopy( origin, re->origin ); AxisCopy( axisDefault, re->axis ); re->hModel = hModel; @@ -722,7 +720,7 @@ void CG_BigExplode( vec3_t playerOrigin ) { VectorCopy( origin, le->pos.trBase ); VectorCopy( velocity, le->pos.trDelta ); le->pos.trTime = cg.time; - + //Elder: added //VectorCopy( origin, le->angles.trBase ); VectorCopy( velocity, le->angles.trBase ); @@ -730,101 +728,147 @@ void CG_BigExplode( vec3_t playerOrigin ) { VectorCopy( rotation, le->angles.trDelta ); le->angles.trTime = cg.time; - le->bounceFactor = 0.3f; + le->bounceFactor = bounce; le->leFlags = LEF_TUMBLE; le->leBounceSoundType = LEBS_BRASS; le->leMarkType = LEMT_NONE; } - /* - =================== - CG_BreakGlass +/* +=================== +CG_BreakGlass + +Generated a bunch of glass shards launching out from the glass location +Elder: don't be mislead by the name - this breaks more than glass +=================== +*/ - Generated a bunch of glass shards launching out from the glass location - =================== - */ - -void CG_BreakGlass( vec3_t playerOrigin, int glassParm ) { +void CG_BreakGlass( vec3_t playerOrigin, int glassParm, int type ) { vec3_t origin, velocity, rotation; int value; - int count = 40; // How many shards to generate - int states[] = {1,2,3}; // The array of possible numbers + int count; + int states[] = {1,2,3}; // Select model variations // Get the size of the array int numstates = sizeof(states)/sizeof(states[0]); - // Elder: The handles to our debris models - qhandle_t debris1, debris2, debris3; - - //Elder: check bit amount - if ( (glassParm & RQ3_DEBRIS_SMALL) == RQ3_DEBRIS_SMALL) { - count = 8 + rand() % 5; - } - //else if ( (glassParm & RQ3_DEBRIS_MEDIUM) == RQ3_DEBRIS_MEDIUM) { - else if ( (glassParm & RQ3_DEBRIS_LARGE) == RQ3_DEBRIS_LARGE) { - count = 40 + rand() % 15; - } - else if ( (glassParm & RQ3_DEBRIS_TONS) == RQ3_DEBRIS_TONS) { + // Elder: debris model handles + qhandle_t debris1; + qhandle_t debris2; + qhandle_t debris3; + int bounceFactor; + int newParm; + + if ( (glassParm & RQ3_DEBRIS_MEDIUM) == RQ3_DEBRIS_MEDIUM && + (glassParm & RQ3_DEBRIS_HIGH) == RQ3_DEBRIS_HIGH) + { + //Tons count = 65 + rand() % 25; } - else { - //medium is default - count = 22 + rand() % 7; + else if ( (glassParm & RQ3_DEBRIS_HIGH) == RQ3_DEBRIS_HIGH) + { + //Large + count = 40 + rand() % 15; + } + else if ( (glassParm & RQ3_DEBRIS_MEDIUM) == RQ3_DEBRIS_MEDIUM) + { + //Medium + count = 22 + rand() % 7; + } + else + { + //Small + count = 8 + rand() % 5; } - CG_Printf("glassParm: %d\n", glassParm); + /* + =============================== + TODO: Utilize variation bits! + ============================== + */ + + //Strip off amount info and revert eParm back to server-side size + newParm = glassParm & 15; + glassParm &= ~newParm; + glassParm = glassParm << (type * 4); + + CG_Printf("glassParm: %i\n", glassParm); //Elder: check debris type and assign debris models - //Using bit-op check b/c I will be stuffing the amount in there too - if ( (glassParm & RQ3_DEBRIS_WOOD) == RQ3_DEBRIS_WOOD) { + if ( (glassParm & RQ3_DEBRIS_WOOD) == RQ3_DEBRIS_WOOD) + { CG_Printf("Launching wood\n"); debris1 = cgs.media.wood01; debris2 = cgs.media.wood02; debris3 = cgs.media.wood03; + bounceFactor = 0.8f; } - else if ( (glassParm & RQ3_DEBRIS_METAL) == RQ3_DEBRIS_METAL) { + else if ( (glassParm & RQ3_DEBRIS_METAL) == RQ3_DEBRIS_METAL) + { CG_Printf("Launching metal\n"); debris1 = cgs.media.metal01; debris2 = cgs.media.metal02; debris3 = cgs.media.metal03; + bounceFactor = 0.7f; } - else if ( (glassParm & RQ3_DEBRIS_CERAMIC) == RQ3_DEBRIS_CERAMIC) { + else if ( (glassParm & RQ3_DEBRIS_CERAMIC) == RQ3_DEBRIS_CERAMIC) + { CG_Printf("Launching ceramic\n"); debris1 = cgs.media.ceramic01; debris2 = cgs.media.ceramic02; debris3 = cgs.media.ceramic03; + bounceFactor = 0.7f; } - else if ( (glassParm & RQ3_DEBRIS_PAPER) == RQ3_DEBRIS_PAPER) { + else if ( (glassParm & RQ3_DEBRIS_PAPER) == RQ3_DEBRIS_PAPER) + { CG_Printf("Launching paper\n"); debris1 = cgs.media.paper01; debris2 = cgs.media.paper02; debris3 = cgs.media.paper03; + bounceFactor = 0.2f; } - else if ( (glassParm & RQ3_DEBRIS_BRICK) == RQ3_DEBRIS_BRICK) { + else if ( (glassParm & RQ3_DEBRIS_BRICK) == RQ3_DEBRIS_BRICK) + { CG_Printf("Launching brick\n"); debris1 = cgs.media.brick01; debris2 = cgs.media.brick02; debris3 = cgs.media.brick03; + bounceFactor = 0.4f; } - else if ( (glassParm & RQ3_DEBRIS_CONCRETE) == RQ3_DEBRIS_CONCRETE) { + else if ( (glassParm & RQ3_DEBRIS_CONCRETE) == RQ3_DEBRIS_CONCRETE) + { CG_Printf("Launching concrete\n"); debris1 = cgs.media.concrete01; debris2 = cgs.media.concrete02; debris3 = cgs.media.concrete03; + bounceFactor = 0.5f; } - else { + /* + else if ( (glassParm & RQ3_DEBRIS_POPCAN) == RQ3_DEBRIS_POPCAN) + { + CG_Printf("Launching pop cans\n"); + debris1 = cgs.media.popcan01; + debris2 = cgs.media.popcan02; + debris3 = cgs.media.popcan03; + } + */ + else + { //glass is default CG_Printf("Launching glass\n"); debris1 = cgs.media.glass01; debris2 = cgs.media.glass02; debris3 = cgs.media.glass03; + bounceFactor = 0.7f; } + //launch loop while ( count-- ) { // Generate the random number every count so every shard is a // of the three. If this is placed above it only gets a random // number every time a piece of glass is broken. value = states[rand()%numstates]; - VectorCopy( playerOrigin, origin ); + + VectorCopy( playerOrigin, origin ); velocity[0] = crandom() * GLASS_VELOCITY; velocity[1] = crandom() * GLASS_VELOCITY; velocity[2] = GLASS_JUMP + crandom() * GLASS_VELOCITY; @@ -832,16 +876,17 @@ void CG_BreakGlass( vec3_t playerOrigin, int glassParm ) { rotation[0] = crandom() * GLASS_VELOCITY; rotation[1] = crandom() * GLASS_VELOCITY; rotation[2] = crandom() * GLASS_VELOCITY; - switch (value) { + + switch (value) + { case 1: - // If our random number was 1, generate the 1st shard piece - CG_LaunchGlass( origin, velocity, rotation, debris1 ); + CG_LaunchGlass( origin, velocity, rotation, bounceFactor, debris1 ); break; case 2: - CG_LaunchGlass( origin, velocity, rotation, debris2 ); + CG_LaunchGlass( origin, velocity, rotation, bounceFactor, debris2 ); break; case 3: - CG_LaunchGlass( origin, velocity, rotation, debris3 ); + CG_LaunchGlass( origin, velocity, rotation, bounceFactor, debris3 ); break; } } diff --git a/reaction/cgame/cg_event.c b/reaction/cgame/cg_event.c index 1f14f79d..e2651e09 100644 --- a/reaction/cgame/cg_event.c +++ b/reaction/cgame/cg_event.c @@ -2120,14 +2120,24 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { } CG_GibPlayer( cent->lerpOrigin ); break; - case EV_BREAK_GLASS: - DEBUGNAME("EV_BREAK_GLASS"); + case EV_BREAK_GLASS1: + DEBUGNAME("EV_BREAK_GLASS1"); // Change cgs.media.gibSound to whatever sound you want it to use // I think the gib sound sounds pretty good //Elder: gonna move this into the function trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.glassSound ); //Elder: modified - CG_BreakGlass( cent->lerpOrigin, es->eventParm ); + CG_BreakGlass( cent->lerpOrigin, es->eventParm, 0 ); + break; + case EV_BREAK_GLASS2: + DEBUGNAME("EV_BREAK_GLASS2"); + trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.glassSound ); + CG_BreakGlass( cent->lerpOrigin, es->eventParm, 1 ); + break; + case EV_BREAK_GLASS3: + DEBUGNAME("EV_BREAK_GLASS3"); + trap_S_StartSound( NULL, es->number, CHAN_BODY, cgs.media.glassSound ); + CG_BreakGlass( cent->lerpOrigin, es->eventParm, 2 ); break; case EV_STOPLOOPINGSOUND: DEBUGNAME("EV_STOPLOOPINGSOUND"); diff --git a/reaction/cgame/cg_local.h b/reaction/cgame/cg_local.h index 2e9a447a..ff759fce 100644 --- a/reaction/cgame/cg_local.h +++ b/reaction/cgame/cg_local.h @@ -47,6 +47,8 @@ #define STAT_MINUS 10 // num frame for '-' stats digit #define ICON_SIZE 48 +//Elder: small icon size added +#define SMICON_SIZE 32 #define CHAR_WIDTH 32 #define CHAR_HEIGHT 48 #define TEXT_ICON_SPACE 4 @@ -629,6 +631,11 @@ typedef struct { char testModelName[MAX_QPATH]; qboolean testGun; + // Elder: for message flooding protection + int sayTime; + int sayCount; + + } cg_t; @@ -1194,6 +1201,8 @@ extern vmCvar_t cg_RQ3_ssgColorR; extern vmCvar_t cg_RQ3_ssgColorG; extern vmCvar_t cg_RQ3_ssgColorB; extern vmCvar_t cg_RQ3_ssgColorA; +//Elder: smoke puffs, sparks, etc. +extern vmCvar_t cg_RQ3_impactEffects; extern vmCvar_t cg_drawFriend; extern vmCvar_t cg_teamChatsOnly; @@ -1463,7 +1472,8 @@ void CG_ScorePlum( int client, vec3_t org, int score ); void CG_GibPlayer( vec3_t playerOrigin ); void CG_BigExplode( vec3_t playerOrigin ); -void CG_BreakGlass( vec3_t playerOrigin, int glassParm );// Blaze: Breakable glass Elder: modified +// Blaze: Breakable glass Elder: modified +void CG_BreakGlass( vec3_t playerOrigin, int glassParm, int type ); void CG_Bleed( vec3_t origin, int entityNum ); localEntity_t *CG_MakeExplosion( vec3_t origin, vec3_t dir, diff --git a/reaction/cgame/cg_main.c b/reaction/cgame/cg_main.c index e3a2a856..9f85bc1c 100644 --- a/reaction/cgame/cg_main.c +++ b/reaction/cgame/cg_main.c @@ -151,6 +151,8 @@ vmCvar_t cg_RQ3_ssgColorR; vmCvar_t cg_RQ3_ssgColorG; vmCvar_t cg_RQ3_ssgColorB; vmCvar_t cg_RQ3_ssgColorA; +//Elder: smoke puffs, sparks, etc. +vmCvar_t cg_RQ3_impactEffects; vmCvar_t cg_drawFriend; vmCvar_t cg_teamChatsOnly; vmCvar_t cg_noVoiceChats; @@ -310,7 +312,8 @@ cvarTable_t cvarTable[] = { { &cg_RQ3_ssgColorR, "cg_RQ3_ssgColorR", "0.0", CVAR_ARCHIVE }, { &cg_RQ3_ssgColorG, "cg_RQ3_ssgColorG", "1.0", CVAR_ARCHIVE }, { &cg_RQ3_ssgColorB, "cg_RQ3_ssgColorB", "0.0", CVAR_ARCHIVE }, - { &cg_RQ3_ssgColorA, "cg_RQ3_ssgColorA", "0.75", CVAR_ARCHIVE } + { &cg_RQ3_ssgColorA, "cg_RQ3_ssgColorA", "0.75", CVAR_ARCHIVE }, + { &cg_RQ3_impactEffects, "cg_RQ3_impactEffects", "1", CVAR_ARCHIVE } // { &cg_pmove_fixed, "cg_pmove_fixed", "0", CVAR_USERINFO | CVAR_ARCHIVE } }; @@ -963,6 +966,7 @@ static void CG_RegisterGraphics( void ) { cgs.media.glass03 = trap_R_RegisterModel( "models/breakables/glass03.md3" ); //Elder: additional debris + //Todo: load only if in the level cgs.media.wood01 = trap_R_RegisterModel( "models/breakables/wood01.md3" ); cgs.media.wood02 = trap_R_RegisterModel( "models/breakables/wood02.md3" ); cgs.media.wood03 = trap_R_RegisterModel( "models/breakables/wood03.md3" ); diff --git a/reaction/cgame/cg_predict.c b/reaction/cgame/cg_predict.c index c81455c7..f8752958 100644 --- a/reaction/cgame/cg_predict.c +++ b/reaction/cgame/cg_predict.c @@ -561,8 +561,31 @@ void CG_PredictPlayerState( void ) { cg_pmove.cmd.serverTime = ((cg_pmove.cmd.serverTime + pmove_msec.integer-1) / pmove_msec.integer) * pmove_msec.integer; } + //Elder: predict bursting here + /* + if ( (cg.snap->ps.weapon == WP_M4 && + (cg.snap->ps.persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE) || + (cg.snap->ps.weapon == WP_MP5 && + (cg.snap->ps.persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE)) + { + if (cg_pmove.cmd.buttons & BUTTON_ATTACK)// && client->ps.stats[STAT_BURST] > 0) + { + if ( cg.snap->ps.stats[STAT_BURST] >= 0 && cg.snap->ps.stats[STAT_BURST] < 3) + cg_pmove.cmd.buttons |= BUTTON_ATTACK; + else + cg_pmove.cmd.buttons &= ~BUTTON_ATTACK; + } + else if (cg.snap->ps.stats[STAT_BURST] > 2) + { + cg.snap->ps.stats[STAT_BURST] = 0; + cg.snap->ps.weaponTime += 500; + } + else if (cg.snap->ps.stats[STAT_BURST] > 0) + cg_pmove.cmd.buttons |= BUTTON_ATTACK; + }*/ + Pmove (&cg_pmove); - + moved = qtrue; // add push trigger movement effects diff --git a/reaction/cgame/cg_weapons.c b/reaction/cgame/cg_weapons.c index 020aa83a..13bba73a 100644 --- a/reaction/cgame/cg_weapons.c +++ b/reaction/cgame/cg_weapons.c @@ -471,6 +471,7 @@ void CG_RegisterWeapon( int weaponNum ) { break; } } + if ( !item->classname ) { CG_Error( "Couldn't find weapon %i", weaponNum ); } @@ -492,9 +493,21 @@ void CG_RegisterWeapon( int weaponNum ) { if ( ammo->giType == IT_AMMO && ammo->giTag == weaponNum ) { break; } + //Elder: hack for handcannon to use M3 ammo icon + else if (weaponNum == WP_HANDCANNON && ammo->giType == IT_AMMO && ammo->giTag == WP_M3) + { + break; + } + //Elder: hack for akimbos to use MK23 ammo icon + else if (weaponNum == WP_AKIMBO && ammo->giType == IT_AMMO && ammo->giTag == WP_PISTOL) + { + break; + } } if ( ammo->classname && ammo->world_model[0] ) { weaponInfo->ammoModel = trap_R_RegisterModel( ammo->world_model[0] ); + //Elder: added + weaponInfo->ammoIcon = trap_R_RegisterShader( ammo->icon ); } strcpy( path, item->world_model[0] ); @@ -1236,20 +1249,6 @@ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent } */ - //Elder: added to supress burst mode flashes + sounds when 'predicting' - // M4 - if ( ps->weapon == WP_M4 && ps->stats[STAT_BURST] > 2 ) { - return; - } - // MP5 - if ( ps->weapon == WP_MP5 && ps->stats[STAT_BURST] > 2 ) { - return; - } - // MK23 - if ( ps->weapon == WP_PISTOL && ps->stats[STAT_BURST] > 0 ) { - return; - } - //Elder: re-added to fix loss of muzzle flashes! // impulse flash if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) { @@ -1608,6 +1607,10 @@ void CG_NextWeapon_f( void ) { return; } + //Elder: don't allow weapon switching when in the middle of bursts + if (cg.snap->ps.stats[STAT_BURST] > 0) + return; + //Elder: in the middle of firing, reloading or weapon-switching //cg.snap->ps.weaponstate == WEAPON_RELOADING when it's in if (cg.snap->ps.weaponstate == WEAPON_DROPPING && cg.snap->ps.weaponTime > 0) { @@ -1640,6 +1643,7 @@ void CG_NextWeapon_f( void ) { } else { CG_RQ3_Zoom1x(); + trap_SendClientCommand("unzoom"); } } @@ -1670,6 +1674,10 @@ void CG_PrevWeapon_f( void ) { return; } + //Elder: don't allow weapon switching when in the middle of bursts + if (cg.snap->ps.stats[STAT_BURST] > 0) + return; + //Elder: in the middle of firing, reloading or weapon-switching //cg.snap->ps.weaponstate == WEAPON_RELOADING when it's in if (cg.snap->ps.weaponstate == WEAPON_DROPPING && cg.snap->ps.weaponTime > 0) { @@ -1701,6 +1709,7 @@ void CG_PrevWeapon_f( void ) { } else { CG_RQ3_Zoom1x(); + trap_SendClientCommand("unzoom"); } } @@ -1717,8 +1726,10 @@ void CG_SpecialWeapon_f( void ) { int original; if ( !cg.snap ) { + //CG_Printf("No snapshot: normally exiting\n"); return; } + if ( cg.snap->ps.pm_flags & PMF_FOLLOW ) { return; } @@ -1733,6 +1744,10 @@ void CG_SpecialWeapon_f( void ) { CG_Printf("You are too busy bandaging...\n"); return; } + + //Elder: don't allow weapon switching when in the middle of bursts + if (cg.snap->ps.stats[STAT_BURST] > 0) + return; //Elder: in the middle of firing, reloading or weapon-switching //cg.snap->ps.weaponstate == WEAPON_RELOADING when it's in @@ -1767,6 +1782,7 @@ void CG_SpecialWeapon_f( void ) { } else { CG_RQ3_Zoom1x(); + trap_SendClientCommand("unzoom"); } } @@ -1790,7 +1806,6 @@ void CG_RQ3_SyncZoom ( void ) { //CG_Printf("Zoomed out\n"); cg.zoomLevel = 0; } - } //Elder: save zoom level and do any other necessary housekeeping @@ -1877,7 +1892,7 @@ void CG_RQ3_Zoom1x () { cg.zoomLevel = 0; cg.zoomTime = cg.time; } - trap_SendClientCommand("unzoom"); + //trap_SendClientCommand("unzoom"); } int CG_RQ3_GetGrenadeMode() @@ -1924,6 +1939,7 @@ void CG_Weapon_f( void ) { int num; if ( !cg.snap ) { + //CG_Printf("No snapshot: normally exiting\n"); return; } @@ -1938,6 +1954,10 @@ void CG_Weapon_f( void ) { return; } + //Elder: don't allow weapon switching when in the middle of bursts + if (cg.snap->ps.stats[STAT_BURST] > 0) + return; + //Elder: in the middle of firing, reloading or weapon-switching if (cg.snap->ps.weaponTime > 0) { return; @@ -1966,6 +1986,8 @@ void CG_Weapon_f( void ) { //do weapon select sound } trap_SendClientCommand("weapon"); + //Elder: added to get out of function at this point + return; } num = atoi( CG_Argv( 1 ) ); @@ -1992,6 +2014,7 @@ void CG_Weapon_f( void ) { //cg.zoomLevel = 0; CG_RQ3_Zoom1x(); + trap_SendClientCommand("unzoom"); cg.weaponSelect = num; } @@ -2065,6 +2088,27 @@ void CG_FireWeapon( centity_t *cent ) { weap = &cg_weapons[ ent->weapon ]; + //Elder: added to supress burst mode flashes + sounds when 'predicting' + // M4 + if ( cg.snap->ps.weapon == WP_M4 && + (cg.snap->ps.persistant[PERS_WEAPONMODES] & RQ3_M4MODE) == RQ3_M4MODE && + cg.snap->ps.stats[STAT_BURST] > 2 ) + { + return; + } + // MP5 + if ( cg.snap->ps.weapon == WP_MP5 && + (cg.snap->ps.persistant[PERS_WEAPONMODES] & RQ3_MP5MODE) == RQ3_MP5MODE && + cg.snap->ps.stats[STAT_BURST] > 2 ) { + return; + } + // MK23 + if ( cg.snap->ps.weapon == WP_PISTOL && + (cg.snap->ps.persistant[PERS_WEAPONMODES] & RQ3_MK23MODE) == RQ3_MK23MODE && + cg.snap->ps.stats[STAT_BURST] > 0 ) { + return; + } + // mark the entity as muzzle flashing, so when it is added it will // append the flash to the weapon model cent->muzzleFlashTime = cg.time; @@ -2125,6 +2169,14 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im qboolean alphaFade; qboolean isSprite; int duration; + + //Elder: for impact smoke marks + localEntity_t *smokePuff; + vec3_t puffOrigin; + vec3_t puffOffset; + vec3_t puffDir; + + int i; mark = 0; radius = 32; @@ -2353,8 +2405,8 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im shader = cgs.media.grenadeExplosionShader; sfx = cgs.media.sfx_rockexp; mark = cgs.media.burnMarkShader; - radius = 64; - light = 300; + radius = 96; //64 + light = 450; //300 isSprite = qtrue; break; @@ -2380,7 +2432,9 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im break; } - if ( sfx ) { + //Elder: 75% of the time render a bullet ricochet sound + i = (int)(random() * 35) % 4; + if ( sfx && i < 3) { trap_S_StartSound( origin, ENTITYNUM_WORLD, CHAN_AUTO, sfx ); } @@ -2416,6 +2470,35 @@ void CG_MissileHitWall( int weapon, int clientNum, vec3_t origin, vec3_t dir, im //} else { CG_ImpactMark( mark, origin, dir, random()*360, 1,1,1,1, alphaFade, radius, qfalse ); //} + + + //Elder: 75% of the time render a smoke puff + i = (int)(random() * 100) % 4; + if (cg_RQ3_impactEffects.integer && i < 3) + { + switch ( weapon ) { + case WP_MP5: + case WP_M4: + case WP_PISTOL: + puffDir[0] = 0; + puffDir[1] = 0; + puffDir[2] = 16; + + VectorCopy(dir, puffOffset); + VectorNormalize(puffOffset); + VectorNegate(puffOffset, puffOffset); + VectorScale(puffOffset, 13, puffOffset); + VectorSubtract(origin, puffOffset, puffOrigin); + smokePuff = CG_SmokePuff( puffOrigin, puffDir, + (int)(random() * 100) % 4 + 13, + 1, 1, 1, 0.25f, + 650, + cg.time, 0, + LEF_PUFF_DONT_SCALE, + cgs.media.smokePuffShader ); + break; + } + } } @@ -2529,10 +2612,11 @@ static void CG_ShotgunPellet( vec3_t start, vec3_t end, int skipNum, int shellWe CG_ShotgunPattern Perform the same traces the server did to locate the -hit splashes (FIXME: ranom seed isn't synce anymore) +hit splashes (FIXME: random seed isn't synce anymore) +Elder: hopefully fixed the seed problem ================ */ -static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int otherEntNum, int shotType ) { +static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int otherEntNum, int shotType, int seed ) { int i; float r, u; vec3_t end; @@ -2565,8 +2649,10 @@ static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int otherEntNum, i for ( i = 0 ; i < count ; i++ ) { if (shotType == WP_M3) { - r = crandom() * DEFAULT_M3_HSPREAD * 16; - u = crandom() * DEFAULT_M3_VSPREAD * 16; + r = Q_crandom(&seed) * DEFAULT_M3_HSPREAD * 16; + u = Q_crandom(&seed) * DEFAULT_M3_VSPREAD * 16; + //r = crandom() * DEFAULT_M3_HSPREAD * 16; + //u = crandom() * DEFAULT_M3_VSPREAD * 16; //r = crandom() * DEFAULT_SHOTGUN_SPREAD * 16; //u = crandom() * DEFAULT_SHOTGUN_SPREAD * 16; } @@ -2574,11 +2660,12 @@ static void CG_ShotgunPattern( vec3_t origin, vec3_t origin2, int otherEntNum, i { //Elder: fill in shotType shotType = WP_HANDCANNON; - r = crandom() * DEFAULT_SHOTGUN_HSPREAD * 16 * 4; - u = crandom() * DEFAULT_SHOTGUN_VSPREAD * 16 * hc_multipler; + r = Q_crandom(&seed) * DEFAULT_SHOTGUN_HSPREAD * 16 * 4; + u = Q_crandom(&seed) * DEFAULT_SHOTGUN_VSPREAD * 16 * hc_multipler; // r = crandom() * DEFAULT_HANDCANNON_SPREAD * 16 * 4; // u = crandom() * DEFAULT_HANDCANNON_SPREAD * 16 * 4; - } VectorMA( origin, 8192 * 16, forward, end); + } + VectorMA( origin, 8192 * 16, forward, end); VectorMA (end, r, right, end); VectorMA (end, u, up, end); @@ -2612,13 +2699,14 @@ void CG_ShotgunFire( entityState_t *es, qboolean ism3) { //Elder: note param changes if (ism3) { - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum, WP_M3); + CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum, WP_M3, es->eventParm); } else { - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum, WP_HANDCANNON); - es->origin2[1] += 5; - CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum, -1 ); + CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum, WP_HANDCANNON, es->eventParm); + es->angles2[1] += 20; + //es->origin2[1] += 5; + CG_ShotgunPattern( es->pos.trBase, es->origin2, es->otherEntityNum, -1, es->eventParm); } }