//spycams.c void drawGrenadeCam() { vec3_t angles, forward, viewpos; trajectory_t grenadeTrajectory; grenadeTrajectory.trType = TR_GRAVITY; grenadeTrajectory.trTime = eth.cg_time; VectorCopy(eth.muzzle, grenadeTrajectory.trBase); VectorCopy(grenadeTrajectory.trBase, viewpos); VectorCopy(eth.cg_snap->ps.viewangles, angles); AngleVectors(angles, forward, NULL,NULL); viewpos[2] += eth.cg_snap->ps.viewheight; VectorMA(viewpos, 32, forward, viewpos); VectorScale(forward, 2000, forward); VectorCopy(forward, grenadeTrajectory.trDelta); SnapVector(grenadeTrajectory.trDelta); // Calculate Gre impact int timeOffset = 0; trace_t grenadeTrace; vec3_t grenadeImpact; VectorCopy(grenadeTrajectory.trBase, grenadeImpact); #define TIME_STEPP 50 int maxTime = 2000; int totalFly = 0; while (timeOffset < maxTime) { vec3_t nextPos; timeOffset += TIME_STEPP; totalFly += TIME_STEPP; eth.BG_EvaluateTrajectory(&grenadeTrajectory, eth.cg_time + timeOffset, nextPos, qfalse, 0); eth.CG_Trace(&grenadeTrace, grenadeImpact, 0, 0, nextPos, eth.cg_snap->ps.clientNum, MASK_MISSILESHOT); // check for hit if (grenadeTrace.startsolid || grenadeTrace.fraction != 1) { // When a nade flies for over 750ms and hits something, it'll explode if (totalFly > 350) break; // calculate reflect angle (forward axis) int hitTime = eth.cg_time + totalFly - TIME_STEPP + TIME_STEPP * grenadeTrace.fraction; eth_BG_EvaluateTrajectoryDelta(&grenadeTrajectory, hitTime, grenadeTrajectory.trDelta, qfalse, 0); float dot = DotProduct(grenadeTrajectory.trDelta, grenadeTrace.plane.normal); VectorMA(grenadeTrajectory.trDelta, -2*dot, grenadeTrace.plane.normal, grenadeTrajectory.trDelta); VectorScale(grenadeTrajectory.trDelta, 0.15, grenadeTrajectory.trDelta); if (grenadeTrace.surfaceFlags == 0) VectorScale(grenadeTrajectory.trDelta, 0.5, grenadeTrajectory.trDelta); // calc new max time and reset trTime maxTime -= timeOffset; timeOffset = 0; grenadeTrajectory.trTime = eth.cg_time; // new base origins VectorCopy(grenadeTrace.endpos, grenadeTrajectory.trBase); SnapVector(grenadeTrajectory.trDelta); SnapVector(grenadeTrajectory.trBase); } else { VectorCopy(nextPos, grenadeImpact); #define POINT_SIZE 2 int x, y; if (worldToScreen(nextPos, &x, &y)) { if (isVisible(nextPos)) drawFillRect(x - (POINT_SIZE / 2), y - (POINT_SIZE / 2), POINT_SIZE, POINT_SIZE, colorGreen); else drawFillRect(x - (POINT_SIZE / 2), y - (POINT_SIZE / 2), POINT_SIZE, POINT_SIZE, colorBlue); } } } // Set the view refdef_t camRefDef; // fov camRefDef.fov_x = 80; camRefDef.fov_y = 80; // origin VectorCopy(grenadeImpact, camRefDef.vieworg); camRefDef.vieworg[ROLL] += seth.value[VAR_GRENADECAM_H]; // Up the cam // angle vec3_t camAngle; VectorCopy(eth.cg_refdefViewAngles, camAngle); camAngle[PITCH] = 80; // Look down AnglesToAxis(camAngle, camRefDef.viewaxis); // Draw the grenadecam drawSpyCam(10, 10, 180, 200, &camRefDef, eth.enemyMortarShader, eth.friendMortarShader, qtrue); // Draw impact time char str[128]; sprintf(str, "^2%.1f ^3s", (float)totalFly / 1000.0f); drawText(10 + (250 - sizeTextWidth(0.19f, str, ð.fontVariable)) / 2, 10 + 250 - 15, 0.19f, str, colorWhite, qfalse, qtrue, ð.fontVariable); } //engine.c case WP_GRENADE_PINEAPPLE: case WP_GRENADE_LAUNCHER: if (seth.value[VAR_GRENADECAM]) drawGrenadeCam(); break; //menu.h VAR_GRENADECAM, VAR_GRENADECAM_H, //menu.c seth.vars[VAR_GRENADECAM] = (ethVars_t) { "Show grenade cam", qfalse, "grenadecam", CAT_SPYCAM, qfalse, { { "Off", qfalse }, { "On", qtrue } } }; seth.vars[VAR_GRENADECAM_H] = (ethVars_t) { "Grenade cam height", 500.0f, "grenadecam_h", CAT_SPYCAM, qfalse, { { "300", 300.0f }, { "400", 400.0f }, { "500", 500.0f }, { "600", 600.0f }, { "800", 800.0f }, { "900", 900.0f }, { "1000", 1000.0f } } };