// GPL License - see http://opensource.org/licenses/gpl-license.php // Copyright 2006 *nixCoders team - don't forget to credit us #include "eth.h" // to get info about windowchanging vec4_t colorCam = {0.0f,0.0f,0.0f,0.0f}; void drawSpyCam(float x, float y, float width, float height, refdef_t *refDef, qhandle_t enemyShader, qhandle_t friendShader, qboolean crosshair) { // Add all backuped refEntities to the scene int count = 0; for (; count < eth.refEntitiesCount; count++) { refEntity_t* refEnt = ð.refEntities[count]; int entityNum = refEnt->entityNum ; // If valid player if ((eth.cg_entities[entityNum].currentState->eType == ET_PLAYER) && (entityNum < MAX_CLIENTS) && eth.clientInfo[entityNum].infoValid && (entityNum != eth.cg_snap->ps.clientNum) // If not dead && !(eth.cg_entities[entityNum].currentState->eFlags & EF_DEAD) // If not vulnerable && (!(eth.cg_entities[entityNum].currentState->powerups & (1 << PW_INVULNERABLE))) // If body && refEnt->torsoFrameModel) { if (IS_PLAYER_ENEMY(entityNum)) refEnt->customShader = enemyShader; else refEnt->customShader = friendShader; refEnt->renderfx |= RF_DEPTHHACK | RF_NOSHADOW; } orig_syscall(CG_R_ADDREFENTITYTOSCENE, refEnt); } // Adjust refDef from 640 refDef->x = x * eth.cgs_screenXScale; refDef->y = y * eth.cgs_screenYScale; refDef->width = width * eth.cgs_screenXScale; refDef->height = height * eth.cgs_screenYScale; // Draw the spycam scene drawFillRect(x, y, width, height, colorBlack); orig_syscall(CG_R_RENDERSCENE, refDef); // Draw border drawRect(x, y, width, height, colorBlack, 1); if(colorCam[3] != 0.0f) drawFillRect(x,y,width,height,colorCam); // Draw the crosshair #define CROSSHAIR_SIZE 4 if (crosshair) drawRect(x + (width / 2) - (CROSSHAIR_SIZE / 2), y + (height / 2) - (CROSSHAIR_SIZE / 2) , CROSSHAIR_SIZE, CROSSHAIR_SIZE, colorRed, 1); } void drawSatchelCam() { int satchelEntityNum = findSatchel(); // If don't find satchel if (satchelEntityNum == -1) return; // Set the view refdef_t camRefDef; memcpy(&camRefDef, ð.cg_refdef, sizeof(refdef_t)); // fov camRefDef.fov_x = 60; camRefDef.fov_y = 60; // origin VectorCopy(eth.entities[satchelEntityNum].origin, camRefDef.vieworg); camRefDef.vieworg[ROLL] += seth.value[VAR_SATCHELCAM_H]; // Up the cam // view angle vec3_t camAngle; VectorCopy(eth.cg_refdefViewAngles, camAngle); camAngle[PITCH] = 90; // Look down AnglesToAxis(camAngle, camRefDef.viewaxis); // Draw the spycam drawSpyCam(10, 10, 240, 240, &camRefDef, eth.enemyVisibleShader, eth.friendVisibleShader, qfalse); } // windowed mortarcam eth_window_t mortarwin; void drawMortarCam() { // Set mortar trajectory from current view vec3_t angles, forward; VectorCopy(eth.cg_refdef.viewaxis[ROLL], forward); // TODO: seems not need VectorCopy(eth.cg_snap->ps.viewangles, angles); angles[PITCH] -= 60.f; AngleVectors(angles, forward, NULL, NULL); forward[0] *= 3000 * 1.1f; forward[1] *= 3000 * 1.1f; forward[2] *= 1500 * 1.1f; trajectory_t mortarTrajectory; mortarTrajectory.trType = TR_GRAVITY; mortarTrajectory.trTime = eth.cg_time; VectorCopy(eth.cg_refdef.vieworg, mortarTrajectory.trBase); // TODO: Not precise need some muzzle VectorCopy(forward, mortarTrajectory.trDelta); // Calculate mortar impact int timeOffset = 0; trace_t mortarTrace; vec3_t mortarImpact; VectorCopy(mortarTrajectory.trBase, mortarImpact); #define TIME_STEP 20 while (timeOffset < 10000) { vec3_t nextPos; timeOffset += TIME_STEP; eth.BG_EvaluateTrajectory(&mortarTrajectory, eth.cg_time + timeOffset, nextPos, qfalse, 0); eth.CG_Trace(&mortarTrace, mortarImpact, 0, 0, nextPos, eth.cg_snap->ps.clientNum, MASK_MISSILESHOT); if ((mortarTrace.fraction != 1) // Check for don't hit sky && !((mortarTrace.surfaceFlags & SURF_NODRAW) || (mortarTrace.surfaceFlags & SURF_NOIMPACT)) && (mortarTrace.contents != 0)) { break; } VectorCopy(nextPos, mortarImpact); } // kobject: add some math to allow for cam pitch angle vec3_t dpos; //x,y vector from mortar impact to us vec3_t campos; //position of camera viewing on mortarimpact vec3_t zaxis; float angle = seth.value[VAR_CAM_PITCH]; // pitch angle, make menu option :P zaxis[0] = 0.0; zaxis[1] = 0.0; zaxis[2] = 1.0; dpos[0] = eth.cg_refdef.vieworg[0]-mortarImpact[0]; dpos[1] = eth.cg_refdef.vieworg[1]-mortarImpact[1]; dpos[2] = 0.0f; VectorNormalize2( dpos, dpos ); VectorCopy( mortarImpact, campos ); VectorMA( campos, seth.value[VAR_MORTARCAM_H]*sinf(angle*M_PI/180.0), zaxis, campos ); VectorMA( campos, seth.value[VAR_MORTARCAM_H]*cosf(angle*M_PI/180.0), dpos, campos ); // Set the view refdef_t camRefDef; memcpy(&camRefDef, ð.cg_refdef, sizeof(refdef_t)); // fov camRefDef.fov_x = 90; camRefDef.fov_y = 90; // origin VectorCopy(campos, camRefDef.vieworg); // angle vec3_t camAngle; VectorCopy(eth.cg_refdefViewAngles, camAngle); camAngle[PITCH] = angle; // Look down AnglesToAxis(camAngle, camRefDef.viewaxis); //initialize window if(!mortarwin.posX) { mortarwin.posX = 10; mortarwin.posY = 10; mortarwin.windowW = 320; mortarwin.windowH = 320; } getWindowStatus(&mortarwin); //clear it anyway memset(&colorCam,0,sizeof(vec4_t)); if (mortarwin.isMouseOn) { colorCam[3]=5.0f; if(mortarwin.isSticked) { int i=0; for (; i < 3 ; i++) colorCam[i] += 0.5f; } } // Draw the mortarcam drawSpyCam(mortarwin.posX, mortarwin.posY, mortarwin.windowW, mortarwin.windowH, &camRefDef, eth.enemyMortarShader, eth.friendMortarShader, qtrue); // Draw impact time char str[128]; sprintf(str, "^0[ ^3Impact in:^2 %.1f ^3seconds ^0]", (float)timeOffset / 1000.0f); drawText(mortarwin.posX + (mortarwin.windowW - sizeTextWidth(0.19f, str, ð.fontVariable)) / 2, mortarwin.posY + mortarwin.windowH - 15, 0.19f, str, colorWhite, qfalse, qtrue, ð.fontVariable); } void drawPanzerCam() { // Set panzer direction vec3_t forward; AngleVectors(eth.cg_snap->ps.viewangles, forward, NULL, NULL ); // Set a far away end point vec3_t aheadPos; VectorMA(eth.muzzle, 65536.0f, forward, aheadPos); // Find panzer impact trace_t panzerTrace; eth.CG_Trace(&panzerTrace, eth.muzzle, NULL, NULL, aheadPos, eth.cg_snap->ps.clientNum, MASK_MISSILESHOT); // If no impact or hit sky don't draw cam if ((panzerTrace.fraction == 1.0f) || (panzerTrace.surfaceFlags & SURF_NOIMPACT)) return; // Set the view refdef_t camRefDef; memcpy(&camRefDef, ð.cg_refdef, sizeof(refdef_t)); // fov camRefDef.fov_x = 30; camRefDef.fov_y = 30; // angle AnglesToAxis(eth.cg_refdefViewAngles, camRefDef.viewaxis); VectorCopy(panzerTrace.endpos, camRefDef.vieworg); // origin vec3_t stepBack; VectorMA(vec3_origin, 400, forward, stepBack); VectorSubtract(camRefDef.vieworg, stepBack, camRefDef.vieworg); // Draw the panzer cam drawSpyCam(10, 10, 160, 160, &camRefDef, eth.enemyVisibleShader, eth.friendVisibleShader, qtrue); } void drawMirrorCam() { #define MIRRORCAM_WIDTH 640.0f #define MIRRORCAM_HEIGHT 100.0f // Set the view refdef_t camRefDef; memcpy(&camRefDef, ð.cg_refdef, sizeof(refdef_t)); // fov camRefDef.fov_x = 90.0f; camRefDef.fov_y = 90.0f * (MIRRORCAM_HEIGHT / MIRRORCAM_WIDTH); // view angle vec3_t camAngle; VectorCopy(eth.cg_refdefViewAngles, camAngle); camAngle[YAW] -= 180.0f; // Look behind AnglesToAxis(camAngle, camRefDef.viewaxis); // Draw the spycam drawSpyCam(0, 0, MIRRORCAM_WIDTH - 1, MIRRORCAM_HEIGHT - 1, &camRefDef, eth.enemyVisibleShader, eth.friendVisibleShader, qfalse); } void drawRiffleCam() { vec3_t angles, forward, viewpos; trajectory_t riffleTrajectory; riffleTrajectory.trType = TR_GRAVITY; riffleTrajectory.trTime = eth.cg_time; VectorCopy(eth.muzzle, riffleTrajectory.trBase); VectorCopy(riffleTrajectory.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, riffleTrajectory.trDelta); SnapVector(riffleTrajectory.trDelta); // Calculate riffle impact int timeOffset = 0; trace_t riffleTrace; vec3_t riffleImpact; VectorCopy(riffleTrajectory.trBase, riffleImpact); #define TIME_STEPP 50 int maxTime = 3250; int totalFly = 0; while (timeOffset < maxTime) { vec3_t nextPos; timeOffset += TIME_STEPP; totalFly += TIME_STEPP; eth.BG_EvaluateTrajectory(&riffleTrajectory, eth.cg_time + timeOffset, nextPos, qfalse, 0); eth.CG_Trace(&riffleTrace, riffleImpact, 0, 0, nextPos, eth.cg_snap->ps.clientNum, MASK_MISSILESHOT); // check for hit if (riffleTrace.startsolid || riffleTrace.fraction != 1) { // When a nade flies for over 750ms and hits something, it'll explode if (totalFly > 750) break; // calculate reflect angle (forward axis) int hitTime = eth.cg_time + totalFly - TIME_STEPP + TIME_STEPP * riffleTrace.fraction; eth_BG_EvaluateTrajectoryDelta(&riffleTrajectory, hitTime, riffleTrajectory.trDelta, qfalse, 0); float dot = DotProduct(riffleTrajectory.trDelta, riffleTrace.plane.normal); VectorMA(riffleTrajectory.trDelta, -2*dot, riffleTrace.plane.normal, riffleTrajectory.trDelta); VectorScale(riffleTrajectory.trDelta, 0.35, riffleTrajectory.trDelta); if (riffleTrace.surfaceFlags == 0) VectorScale(riffleTrajectory.trDelta, 0.5, riffleTrajectory.trDelta); // calc new max time and reset trTime maxTime -= timeOffset; timeOffset = 0; riffleTrajectory.trTime = eth.cg_time; // new base origins VectorCopy(riffleTrace.endpos, riffleTrajectory.trBase); SnapVector(riffleTrajectory.trDelta); SnapVector(riffleTrajectory.trBase); } else { VectorCopy(nextPos, riffleImpact); #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, colorYellow); else drawFillRect(x - (POINT_SIZE / 2), y - (POINT_SIZE / 2), POINT_SIZE, POINT_SIZE, colorRed); } } } // Set the view refdef_t camRefDef = eth.cg_refdef; // fov camRefDef.fov_x = 90; camRefDef.fov_y = 90; // origin VectorCopy(riffleImpact, camRefDef.vieworg); camRefDef.vieworg[ROLL] += seth.value[VAR_RIFLECAM_H]; // Up the cam // angle vec3_t camAngle; VectorCopy(eth.cg_refdefViewAngles, camAngle); camAngle[PITCH] = 90; // Look down AnglesToAxis(camAngle, camRefDef.viewaxis); // Draw the rifflecam drawSpyCam(10, 10, 250, 250, &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); }