void demoEffectMove( void ) { float *origin, *angles, *size, *color; demoEffectParent_t *parent; if (!demo.effect.active) return; parent = demo.effect.active; if (!parent->locked ) { origin = parent->origin; angles = parent->angles; color = parent->color; size = &parent->size; } else { demoEffectPoint_t * point = demoEffectPointSynch( parent, demo.play.time ); if ( !point || point->time != demo.play.time || demo.play.fraction) return; origin = point->origin; angles = point->angles; color = point->color; size = &point->size; } if (demo.cmd.buttons & BUTTON_ATTACK) { vec3_t moveAngles; /* First clear some related values */ if (!(demo.oldcmd.buttons & BUTTON_ATTACK)) { VectorClear( parent->velocity ); } if (demo.cmd.upmove > 0) { angles[ROLL] -= demo.cmd.angles[YAW]; AnglesNormalize180( angles ); return; } VectorAdd( angles, demo.cmdDeltaAngles, angles ); AnglesNormalize180( angles ); VectorCopy( angles, moveAngles ); moveAngles[ROLL] = 0; demoMovePoint( origin, parent->velocity, moveAngles ); } else if (demo.cmd.upmove > 0) { *size -= demo.serverDeltaTime * 700 * demo.cmdDeltaAngles[YAW]; if (*size < 0) *size = 0; } else if ( (demo.cmd.upmove < 0) || (demo.cmd.forwardmove < 0) || (demo.cmd.rightmove < 0) ) { vec3_t moveAngles; VectorCopy( angles, moveAngles ); moveAngles[ROLL] = 0; demoMoveDirection( origin, moveAngles ); } }
void demoMoveAddDeltaAngles( vec3_t angles ) { if (demo.cmd.buttons & BUTTON_NEGATIVE) { angles[ROLL] -= demo.cmdDeltaAngles[YAW]; } else { VectorAdd( angles, demo.cmdDeltaAngles, angles); } AnglesNormalize180( angles ); }
void demoMoveChaseDirect( void ) { if (demo.chase.locked) return; if (!(demo.oldcmd.buttons & BUTTON_ATTACK)) { VectorClear( demo.chase.velocity ); } VectorAdd( demo.chase.angles, demo.cmdDeltaAngles, demo.chase.angles ); AnglesNormalize180( demo.chase.angles ); demoMovePoint( demo.chase.origin, demo.chase.velocity, demo.chase.angles ); }
void demoMoveChase(void) { float *origin; float *distance; float *angles; int *target; if (demo.chase.locked) { demoChasePoint_t * point = chasePointSynch( demo.play.time ); if ( point && point->time == demo.play.time && !demo.play.fraction) { origin = point->origin; angles = point->angles; distance = &point->distance; target = &point->target; } else return; } else { origin = demo.chase.origin; angles = demo.chase.angles; distance = &demo.chase.distance; target = &demo.chase.target; } if (demo.cmd.buttons & BUTTON_ATTACK) { /* First clear some related values */ if (!(demo.oldcmd.buttons & BUTTON_ATTACK)) { VectorClear( demo.chase.velocity ); } VectorAdd( angles, demo.cmdDeltaAngles, angles ); AnglesNormalize180( angles ); demoMovePoint( origin, demo.chase.velocity, angles ); } else if (demo.cmd.buttons & BUTTON_AFFIRMATIVE && !(demo.oldcmd.buttons & BUTTON_AFFIRMATIVE)) { VectorCopy( demo.viewOrigin, origin ); VectorCopy( demo.viewAngles, angles ); CG_DemosAddLog("Chase position synced to current view"); } else if ( demo.cmd.upmove > 0) { *distance -= demo.serverDeltaTime * 700 * demo.cmdDeltaAngles[YAW]; if (*distance < 0) *distance = 0; } else if ( (demo.cmd.upmove < 0) || (demo.cmd.forwardmove < 0) || (demo.cmd.rightmove < 0) ) { demoMoveDirection( origin, angles ); } else if (demo.cmd.rightmove < 0) { int shift; demo.chase.timeShift -= demo.serverDeltaTime * 1000 * demo.cmdDeltaAngles[YAW]; shift = (int)demo.chase.timeShift; demo.chase.timeShift -= shift; chasePointShift( shift ); } }
void demoChaseCommand_f(void) { const char *cmd = CG_Argv(1); if (!Q_stricmp(cmd, "lock")) { demo.chase.locked = !demo.chase.locked; if (demo.chase.locked) CG_DemosAddLog("Chase view locked"); else CG_DemosAddLog("Chase view unlocked"); } else if (!Q_stricmp(cmd, "add")) { if (chasePointAdd( demo.play.time, demo.chase.angles, demo.chase.distance, demo.chase.target, demo.chase.origin )) { CG_DemosAddLog("Added chase point" ); } else { CG_DemosAddLog("Failed to add chase point" ); } } else if (!Q_stricmp(cmd, "del")) { if (chasePointDel( demo.play.time) ) { CG_DemosAddLog("Deleted chase chase point" ); } else { CG_DemosAddLog("Failed to add delete chase point" ); } } else if (!Q_stricmp(cmd, "start")) { demo.chase.start = demo.play.time; if (demo.chase.start > demo.chase.end) demo.chase.start = demo.chase.end; if (demo.chase.end == demo.chase.start) CG_DemosAddLog( "Cleared chase selection"); else CG_DemosAddLog( "Chase selection start at %d.%03d", demo.chase.start / 1000, demo.chase.start % 1000 ); } else if (!Q_stricmp(cmd, "end")) { demo.chase.end = demo.play.time; if (demo.chase.end < demo.chase.start) demo.chase.end = demo.chase.start; if (demo.chase.end == demo.chase.start) CG_DemosAddLog( "Cleared chase selection"); else CG_DemosAddLog( "Chase selection end at %d.%03d", demo.chase.end / 1000, demo.chase.end % 1000 ); } else if (!Q_stricmp(cmd, "next")) { demoChasePoint_t *point = chasePointSynch( demo.play.time ); if ( demo.cmd.upmove > 0) { if ( demo.chase.locked ) { CG_DemosAddLog( "Can't change target when locked"); } else { chaseNextTarget( &demo.chase.target ); } return; } if (!point) return; if (point->next) point = point->next; demo.play.time = point->time; demo.play.fraction = 0; } else if (!Q_stricmp(cmd, "prev")) { demoChasePoint_t *point = chasePointSynch( demo.play.time ); if ( demo.cmd.upmove > 0 ) { if ( demo.chase.locked ) { CG_DemosAddLog( "Can't change target when locked"); } else { chasePrevTarget( &demo.chase.target ); } return; } if (!point) return; if (point->prev) point = point->prev; demo.play.time = point->time; demo.play.fraction = 0; } else if (!Q_stricmp(cmd, "clear")) { chaseClear(); } else if (!Q_stricmp(cmd, "targetPrev")) { chasePrevTarget( &demo.chase.target ); } else if (!Q_stricmp(cmd, "targetNext")) { chaseNextTarget( &demo.chase.target ); } else if (!Q_stricmp(cmd, "target")) { float *angles, *origin, *distance; int *target; if (demo.chase.locked) { demoChasePoint_t *point = chasePointSynch( demo.play.time ); if (!point || point->time != demo.play.time || demo.play.fraction ) { Com_Printf("Can't synch when not synched to a point\n"); return; } origin = point->origin; angles = point->angles; target = &point->target; distance = &point->distance; } else { origin = demo.chase.origin; angles = demo.chase.angles; target = &demo.chase.target; distance = &demo.chase.distance; } if ( demo.cmd.buttons & BUTTON_ATTACK ) { if (*target>=0) { CG_DemosAddLog("Cleared target %d", *target ); *target = -1; } else { vec3_t forward; AngleVectors( demo.viewAngles, forward, 0, 0 ); *target = demoHitEntities( demo.viewOrigin, forward ); if (*target >= 0) { vec3_t targetAngles; chaseEntityOrigin( &cg_entities[*target], origin); *distance = VectorDistance( demo.viewOrigin, origin ); VectorSubtract( origin, demo.viewOrigin, forward ); vectoangles( forward, targetAngles ); angles[PITCH] = targetAngles[PITCH]; angles[YAW] = targetAngles[YAW]; CG_DemosAddLog("Target set to %d", *target ); } else { CG_DemosAddLog("Unable to hit any target" ); } } } else { CG_DemosAddLog( "Chase synched to current view" ); *target = -1; *distance = 128; VectorCopy( demo.viewOrigin, origin ); VectorCopy( demo.viewAngles, angles ); } } else if (!Q_stricmp(cmd, "pos")) { float *oldOrigin; if (demo.chase.locked) { demoChasePoint_t *point = chasePointSynch( demo.play.time ); if (!point || point->time != demo.play.time || demo.play.fraction ) { Com_Printf("Can't change position when not synched to a point\n"); return; } oldOrigin = point->origin; } else { oldOrigin = demo.chase.origin; } demoCommandValue( CG_Argv(2), oldOrigin ); demoCommandValue( CG_Argv(3), oldOrigin+1 ); demoCommandValue( CG_Argv(4), oldOrigin+2 ); } else if (!Q_stricmp(cmd, "angles")) { float *oldAngles; if (demo.chase.locked) { demoChasePoint_t *point = chasePointSynch( demo.play.time ); if (!point || point->time != demo.play.time || demo.play.fraction ) { Com_Printf("Can't change angles when not synched to a point\n"); return; } oldAngles = point->angles; } else { oldAngles = demo.chase.angles; } demoCommandValue( CG_Argv(2), oldAngles ); demoCommandValue( CG_Argv(3), oldAngles+1 ); demoCommandValue( CG_Argv(4), oldAngles+2 ); AnglesNormalize180( oldAngles ); } else if (!Q_stricmp(cmd, "dist") || !Q_stricmp(cmd, "distance")) { if (demo.chase.locked) { demoChasePoint_t *point = chasePointSynch( demo.play.time ); if (!point || point->time != demo.play.time || demo.play.fraction ) { Com_Printf("Can't change distance when not synched to a point\n"); return; } demoCommandValue( CG_Argv(2), &point->distance ); } else { demoCommandValue( CG_Argv(2), &demo.chase.distance ); } } else if (!Q_stricmp(cmd, "shift")) { int shift = 1000 * atof(CG_Argv(2)); demo.chase.shiftWarn = 0; if (chasePointShift( shift )) { CG_DemosAddLog( "Shifted %d.%03d seconds", shift / 1000, shift % 1000); } } else { Com_Printf("chase usage:\n" ); Com_Printf("chase add/del, add/del a chase point at current viewpoint and time.\n" ); Com_Printf("chase clear, clear all chase points. (Use with caution...)\n" ); Com_Printf("chase lock, lock the view to chase track or free moving.\n" ); Com_Printf("chase target, Clear/Set the target currently being aimed at.\n" ); Com_Printf("chase targetNext/Prev, Go the next or previous player.\n" ); Com_Printf("chase shift time, move time indexes of chase points by certain amount.\n" ); Com_Printf("chase next/prev, go to time index of next or previous point.\n" ); Com_Printf("chase start/end, current time with be set as start/end of selection.\n" ); Com_Printf("chase pos/angles (a)0 (a)0 (a)0, Directly control position/angles, optional a before number to add to current value\n" ); } }
/* * Tests whether the player entity ent is visible from the point origin. */ qboolean SV_IsPlayerVisibleFromPoint( vec3_t origin, clientSnapshot_t *frame, sharedEntity_t *ent, vec3_t diff) { int i,contents_mask,goal_ent,viewer_clnum,ent_clnum,tries; trace_t tr; vec3_t start,end,dir,entangles,angles,temp,forward; sharedEntity_t *viewer_ent; client_t *viewer_cl; // client_t *ent_cl; playerState_t *viewer_ps, *ent_ps; float pitch; viewer_clnum = frame->ps.clientNum; // get the client number of the viewer ent_clnum = ent->s.clientNum; // get the client number of the other player if (viewer_clnum == ent_clnum) { // in case the viewer is the player entity return qtrue; // we don't need to hide us from ourselves } viewer_ps = &frame->ps; ent_ps = SV_GameClientNum(ent_clnum); if (viewer_ps->pm_type != PM_NORMAL) { // if the viewer is dead or spectating return qtrue; // let every entity be visible } if (ent_ps->pm_type != PM_NORMAL || (ent->s.weapon == WP_NONE)) { // if the player entity is dead or spectating return qtrue; } viewer_cl = svs.clients+viewer_clnum; // get the client of the viewer // ent_cl = svs.clients+ent_clnum; // get the client of the other player // if (viewer_clnum > ent_clnum) { // if viewer_clnum > ent_clnum, we have already tested whether ent_clnum is able to see viewer_clnum. // if (ent_cl->tracetimer[viewer_clnum] > sv.time) return qtrue; // and we could assume symmetry of SV_IsPlayerVisibleFromPoint // } if (viewer_cl->tracetimer[ent_clnum] > sv.time+MEMORY+10) { // if the sv.time has been reset viewer_cl->tracetimer[ent_clnum] = sv.time; // reset the tracetimer } else if (viewer_cl->tracetimer[ent_clnum] > (sv.time+MEMORY-10)) { // if we have recently seen this entity, we are lazy and assume it is still visible // Com_Printf(va("client: %i, seen: %i\n", ent_clnum, viewer_cl->tracetimer[ent_clnum])); return qtrue; } goal_ent = SV_NumForGentity(ent); // this might always be the same as ent_clnum viewer_ent = SV_GentityNum(viewer_clnum); contents_mask = CONTENTS_SOLID;// |CONTENTS_BODY will work for doors, but also for windows |CONTENTS_PLAYERCLIP|CONTENTS_SOLID|CONTENTS_MOVER|CONTENTS_PLAYERCLIP // if (seen->v.movetype == MOVETYPE_PUSH ) { //don't cull doors and plats :( // return false; // } // if (sv_antiwallhack.value == 1) //1 only check player models, 2 = check all ents // if (strcmp(pr_strings + seen->v.classname, "player")) // return qfalse; // get camera origin (according to \cg_drawdebug 1) start[0] = origin[0]; start[1] = origin[1]; start[2] = origin[2]+3.0f; VectorCopy(viewer_ps->viewangles, angles); AnglesNormalize180(angles); pitch = angles[PITCH]; angles[PITCH] = 0; angles[ROLL] = 0; AngleVectors(angles, forward, NULL, NULL); VectorScale(forward, (pitch/3.5f), temp); VectorAdd( start, temp, start); // if there is sufficient distance between viewer and player entity, check if player entity is within viewer's field of vision VectorSubtract(ent->r.currentOrigin, start, dir); // VectorAdd(ent->r.currentOrigin,dir,diff);// fill diff VectorCopy(viewer_ent->s.pos.trBase,diff);// fill diff vectoangles(dir, entangles); dir[2]=0; // pretend, players are on the same level (the height should no be taken into account) if (VectorLength(dir) > 1024) {// if it is not within close range (x,y-wise, not z-wise) if (!InFieldOfVision(viewer_ps->viewangles, 60.f, entangles, ent_clnum)) {// If the player entity is not in the field of vision of the viewer // Com_Printf( va("behind: %i vorg: %f,%f,%f vang: %f,%f,%f eorg: %f,%f,%f dir: %f,%f,%f eang: %f,%f,%f ent: %i\n", viewer_clnum,origin[0],origin[1],origin[2],viewer_ps->viewangles[0],viewer_ps->viewangles[1],viewer_ps->viewangles[2],ent->r.currentOrigin[0],ent->r.currentOrigin[1],ent->r.currentOrigin[2],dir[0],dir[1],dir[2],entangles[0],entangles[1],entangles[2],ent_clnum)); return qtrue; // if the player entity is behind the viewer, abstain from any computations (and transmit the entity to hear sounds) // } else { // Com_Printf( va("front: %i vorg: %f,%f,%f vang: %f,%f,%f eorg: %f,%f,%f dir: %f,%f,%f eang: %f,%f,%f ent: %i\n", viewer_clnum,origin[0],origin[1],origin[2],viewer_ps->viewangles[0],viewer_ps->viewangles[1],viewer_ps->viewangles[2],ent->r.currentOrigin[0],ent->r.currentOrigin[1],ent->r.currentOrigin[2],dir[0],dir[1],dir[2],entangles[0],entangles[1],entangles[2],ent_clnum)); } } // aim straight at the head of the entity from our eyes end[0] = ent->r.currentOrigin[0]; end[1] = ent->r.currentOrigin[1]; end[2] = ent->r.currentOrigin[2]+ent->r.maxs[2];// "+3.0f" doesn't do it. "+ent->r.maxs[2]" is at the top of the BBox VectorCopy(ent_ps->viewangles, angles); AnglesNormalize180(angles); pitch = angles[PITCH]; angles[PITCH] = 0; angles[ROLL] = 0; AngleVectors(angles, forward, NULL, NULL); VectorScale(forward, (pitch/3.5f), temp); VectorAdd( end, temp, end); memset (&tr, 0, sizeof(tr)); tr.fraction = 1; // check the head SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse); // Com_Printf(va("client: %i, trace: %f\n", ent->s.clientNum, tr.fraction)); if (tr.fraction == 1 || tr.entityNum==goal_ent) {// tr.fraction == 1 || if there is a line of sight to the entity viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units return qtrue;// and signal the entity is visible } // Com_Printf(va("origin(%f %f %f) min(%f %f %f) max(%f %f %f)\n", start[0], start[1], start[2], mins[0],mins[1],mins[2],maxs[0],maxs[1],maxs[2])); // check the last good offset VectorAdd(ent->r.currentOrigin,viewer_cl->lasttrace[ent_clnum],end); SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse); // Com_Printf(va("client: %i, trace: %f\n", ent->s.clientNum, tr.fraction)); if (tr.fraction == 1 || tr.entityNum==goal_ent) {// tr.fraction == 1 || if there is a line of sight to the entity viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units return qtrue;// and signal the entity is visible } // random tries = (viewer_cl->tracetimer[ent_clnum]+(MEMORY*20) > sv.time)?8:2;// if we have seen an entity recently, we try hard to locate it again for (i=0; i<tries; i++) {// Even if the head is not visible, other body parts might be. Let's check a few randomly selected points end[0] = ent->r.currentOrigin[0] + offsetrandom(ent->r.mins[0], ent->r.maxs[0]); end[1] = ent->r.currentOrigin[1] + offsetrandom(ent->r.mins[1], ent->r.maxs[1]); end[2] = ent->r.currentOrigin[2] + offsetrandom(ent->r.mins[2], ent->r.maxs[2]+3.f); SV_Trace(&tr, start, NULL, NULL, end, viewer_clnum, contents_mask, qfalse); if (tr.fraction == 1 || tr.entityNum==goal_ent) {// if there is a line of sight to the entity // Com_Printf(va("found ent in %i hits\n", i)); viewer_cl->tracetimer[ent_clnum] = sv.time + MEMORY;// update the trace timer so the entity will be visible the next 200 time units VectorSubtract(end, ent->r.currentOrigin, viewer_cl->lasttrace[ent_clnum]);// remember the offset return qtrue;// and signal the entity is visible } } viewer_cl->lasttrace[ent_clnum][0] = offsetrandom(ent->r.mins[0], ent->r.maxs[0]); viewer_cl->lasttrace[ent_clnum][1] = offsetrandom(ent->r.mins[1], ent->r.maxs[1]); viewer_cl->lasttrace[ent_clnum][2] = offsetrandom(ent->r.mins[2], ent->r.maxs[2]+3.f); return (viewer_cl->tracetimer[ent_clnum] > sv.time);// returns true if the entity was visible within the last 200 time units }