/* ================ R_StoreEfrags // FIXME: a lot of this goes away with edge-based ================ */ void R_StoreEfrags (efrag_t **ppefrag) { entity_t *pent; model_t *model; efrag_t *pefrag; for (pefrag = *ppefrag ; pefrag ; pefrag = pefrag->leafnext) { pent = pefrag->entity; model = pent->model; if (model->modhint == MOD_FLAME && !r_drawflame.value) continue; switch (model->type) { case mod_alias: case mod_brush: case mod_sprite: if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS)) { V_AddEntity (pent); // mark that we've recorded this entity for this frame pent->visframe = r_framecount; } break; default: Sys_Error ("R_StoreEfrags: Bad entity type %d", model->type); } } }
void CL_UpdateExplosions (void) { int f; explosion_t *ex; explosion_t *next, *hnode; entity_t ent; memset (&ent, 0, sizeof(entity_t)); ent.colormap = 0; hnode = &cl_explosions_headnode; for (ex = hnode->next; ex != hnode; ex = next) { next = ex->next; f = 10 * (cl.time - ex->start); if (f >= EXPLOSION_FRAMES) { CL_FreeExplosion (ex); continue; } VectorCopy (ex->origin, ent.origin); ent.model = ex->model; ent.frame = f; V_AddEntity (&ent); } }
void CL_AddViewLocs (void) { int index = CL_LocIndex(cl.frame.playerstate.pmove.origin); int i; int num = 0; if (!cl_drawlocs->value) return; for (i = 0; i < MAX_LOCATIONS; i++) { int dist; entity_t ent; if (locations[i].used == false) continue; dist = (cl.frame.playerstate.pmove.origin[0] - locations[i].origin[0]) * (cl.frame.playerstate.pmove.origin[0] - locations[i].origin[0]) + (cl.frame.playerstate.pmove.origin[1] - locations[i].origin[1]) * (cl.frame.playerstate.pmove.origin[1] - locations[i].origin[1]) + (cl.frame.playerstate.pmove.origin[2] - locations[i].origin[2]) * (cl.frame.playerstate.pmove.origin[2] - locations[i].origin[2]); if (dist > 4000 * 4000) continue; memset(&ent, 0, sizeof(entity_t)); ent.origin[0] = locations[i].origin[0] * 0.125f; ent.origin[1] = locations[i].origin[1] * 0.125f; ent.origin[2] = locations[i].origin[2] * 0.125f; ent.skinnum = 0; // ent.skin = NULL; memset(ent.skins, 0, sizeof(ent.skins)); ent.model = NULL; if (i == index) ent.origin[2] += sin(cl.time * 0.01f) * 10.0f; V_AddEntity(&ent); num++; } }
/* ================ R_StoreEfrags FIXME: a lot of this goes away with edge-based ================ */ void R_StoreEfrags (efrag_t **ppefrag) { entity_t *pent; efrag_t *pefrag; while ((pefrag = *ppefrag) != NULL) { pent = pefrag->entity; if ((pent->visframe != r_framecount) && (cl_numvisedicts < MAX_VISEDICTS)) { V_AddEntity (pent); // mark that we've recorded this entity for this frame pent->visframe = r_framecount; } ppefrag = &pefrag->leafnext; } }
/* ================= CL_UpdateBeams ================= */ void CL_UpdateBeams (void) { int i; beam_t *b; vec3_t dist, org; float d, dec; entity_t ent; vec3_t angles; dec = 30; memset (&ent, 0, sizeof(entity_t)); ent.colormap = 0; // update lightning for (i = 0, b = cl_beams; i < MAX_BEAMS; i++, b++) { if (!b->model || b->endtime < cl.time) continue; // if coming from the player, update the start position if (b->entity == Cam_PlayerNum() + 1 && !cl.intermission) { VectorCopy (cl.simorg, b->start); b->start[2] += cl.crouch; if (cl_fakeshaft.value && cl.allow_fakeshaft) { vec3_t forward; vec3_t v, org; vec3_t ang; float f, delta; trace_t trace; f = max(0, min(1, cl_fakeshaft.value)); VectorSubtract (playerbeam_end, cl.simorg, v); v[2] -= 22; // adjust for view height vectoangles (v, ang); // lerp pitch ang[0] = -ang[0]; if (ang[0] < -180) ang[0] += 360; ang[0] += (cl.simangles[0] - ang[0]) * f; // lerp yaw delta = cl.simangles[1] - ang[1]; if (delta > 180) delta -= 360; if (delta < -180) delta += 360; ang[1] += delta*f; ang[2] = 0; AngleVectors (ang, forward, NULL, NULL); VectorScale (forward, 600, forward); VectorCopy (cl.simorg, org); org[2] += 16; VectorAdd (org, forward, b->end); trace = PM_TraceLine (&cl.pmove, org, b->end); if (trace.fraction < 1) VectorCopy (trace.endpos, b->end); } } // calculate pitch and yaw VectorSubtract (b->end, b->start, dist); vectoangles (dist, angles); // add new entities for the lightning VectorCopy (b->start, org); d = VectorNormalize (dist); VectorScale (dist, dec, dist); while (d > 0) { VectorCopy (org, ent.origin); ent.model = b->model; ent.angles[PITCH] = angles[PITCH]; ent.angles[YAW] = angles[YAW]; ent.angles[ROLL] = rand() % 360; if (b->model == cl_bolt2_mod) ent.alpha = r_shaftalpha.value; V_AddEntity (&ent); d -= dec; VectorAdd (org, dist, org); } } }
/* ================= ROGUE - draw player locked beams CL_AddPlayerBeams ================= */ void CL_AddPlayerBeams (void) { int32_t i,j; beam_t *b; vec3_t dist, org; float d; entity_t ent; float yaw, pitch; float forward; float len, steps; int32_t framenum; float model_length; float hand_multiplier; frame_t *oldframe; player_state_t *ps, *ops; qboolean firstperson, chasecam; int32_t newhandmult; vec3_t thirdp_pbeam_offset; vec3_t pbeam_offset_dir; //PMM if (hand) { if (hand->value == 2) hand_multiplier = 0; else if (hand->value == 1) hand_multiplier = -1; else hand_multiplier = 1; } else { hand_multiplier = 1; } //PMM // chasecam beam offset stuff newhandmult = hand_multiplier; if (newhandmult == 0) newhandmult = 1; VectorSet(thirdp_pbeam_offset, 6.5, 0, 12); // end chasecam beam offset stuff // update beams for (i=0, b=cl_playerbeams; i< MAX_BEAMS; i++, b++) { vec3_t f,r,u; if (!b->model || b->endtime < cl.time) continue; firstperson = ((b->entity == cl.playernum+1) && !cg_thirdperson->value); chasecam = ((b->entity == cl.playernum+1) && cg_thirdperson->value); if(clMedia.mod_heatbeam && (b->model == clMedia.mod_heatbeam)) { // if coming from the player, update the start position if (firstperson || chasecam) { // set up gun position // code straight out of CL_AddViewWeapon ps = &cl.frame.playerstate; j = (cl.frame.serverframe - 1) & UPDATE_MASK; oldframe = &cl.frames[j]; if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid) oldframe = &cl.frame; // previous frame was dropped or involid ops = &oldframe->playerstate; // lerp for chasecam mode if (chasecam) { // use player's original viewangles AngleVectors(cl.refdef.aimangles, f, r, u); VectorClear (pbeam_offset_dir); for (j=0; j<3; j++) { pbeam_offset_dir[j] += f[j]*thirdp_pbeam_offset[1]; pbeam_offset_dir[j] += r[j]*thirdp_pbeam_offset[0]*newhandmult; pbeam_offset_dir[j] += u[j]*(-thirdp_pbeam_offset[2]); } for (j=0; j<3; j++) b->start[j] = cl.predicted_origin[j] + ops->viewoffset[j] + cl.lerpfrac * (ps->viewoffset[j] - ops->viewoffset[j]) + pbeam_offset_dir[j]; // Com_Printf("%f, %f, %f\n", pbeam_offset_dir[0], pbeam_offset_dir[1], pbeam_offset_dir[2]); VectorMA (b->start, (newhandmult * b->offset[0]), r, org); VectorMA ( org, b->offset[1], f, org); VectorMA ( org, b->offset[2], u, org); } else // firstperson { AngleVectors(cl.refdef.aimangles,f,r,u); for (j=0; j<3; j++) { b->start[j] = cl.refdef.vieworg[j] + ops->gunoffset[j] + cl.lerpfrac * (ps->gunoffset[j] - ops->gunoffset[j]); } VectorMA (b->start, (hand_multiplier * b->offset[0]), r, org); VectorMA ( org, b->offset[1], f, org); VectorMA ( org, b->offset[2], u, org); if ((hand) && (hand->value == 2)) { VectorMA (org, -1, u, org); } } } else // some other player or monster VectorCopy (b->start, org); } else // some other beam model { // if coming from the player, update the start position // skip for chasecam mode if (firstperson) { VectorCopy (cl.refdef.aimstart, b->start); b->start[2] -= 22; // adjust for view height } VectorAdd (b->start, b->offset, org); } // calculate pitch and yaw VectorSubtract (b->end, org, dist); //PMM if (clMedia.mod_heatbeam && (b->model == clMedia.mod_heatbeam) && (firstperson||chasecam)) { vec_t len; vec3_t forward, right, up; AngleVectors(cl.refdef.aimangles,forward,right,up); len = VectorLength (dist); VectorScale (forward, len, dist); if (chasecam) VectorMA (dist, (newhandmult * b->offset[0]), right, dist); else VectorMA (dist, (hand_multiplier * b->offset[0]), right, dist); VectorMA (dist, b->offset[1], forward, dist); VectorMA (dist, b->offset[2], up, dist); if (chasecam) { VectorMA (dist, -(newhandmult * thirdp_pbeam_offset[0]), right, dist); VectorMA (dist, thirdp_pbeam_offset[1], forward, dist); VectorMA (dist, thirdp_pbeam_offset[2], up, dist); } if ((hand) && (hand->value == 2) && !chasecam) VectorMA (org, -1, up, org); } //PMM if (dist[1] == 0 && dist[0] == 0) { yaw = 0; if (dist[2] > 0) pitch = 90; else pitch = 270; } else { // PMM - fixed to correct for pitch of 0 if (dist[0]) yaw = (atan2(dist[1], dist[0]) * 180 / M_PI); else if (dist[1] > 0) yaw = 90; else yaw = 270; if (yaw < 0) yaw += 360; forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); pitch = (atan2(dist[2], forward) * -180.0 / M_PI); if (pitch < 0) pitch += 360.0; } if (clMedia.mod_heatbeam && (b->model == clMedia.mod_heatbeam) ) { if (!firstperson) { framenum = 2; ent.angles[0] = -pitch; ent.angles[1] = yaw + 180.0; ent.angles[2] = 0; // skip this for chasecam mode if (!chasecam) { // Com_Printf ("%f %f - %f %f %f\n", -pitch, yaw+180.0, b->offset[0], b->offset[1], b->offset[2]); AngleVectors(ent.angles, f, r, u); // if it's a non-origin offset, it's a player, so use the hardcoded player offset if (!VectorCompare (b->offset, vec3_origin)) { VectorMA (org, -(b->offset[0])+1, r, org); VectorMA (org, -(b->offset[1])+12, f, org); //was 0 VectorMA (org, -(b->offset[2])-5, u, org); //was -10 } else { // if it's a monster, do the particle effect CL_MonsterPlasma_Shell(b->start); } } } else { framenum = 1; } } // if it's the heatbeam, draw the particle effect // also do this in chasecam mode if ((clMedia.mod_heatbeam && (b->model == clMedia.mod_heatbeam) && (firstperson||chasecam))) { CL_HeatbeamParticles (org, dist); } // add new entities for the beams d = VectorNormalize(dist); memset (&ent, 0, sizeof(ent)); if (b->model == clMedia.mod_heatbeam) { model_length = 32.0; } else if (b->model == clMedia.mod_lightning) { model_length = 35.0; d-= 20.0; // correction so it doesn't end in middle of tesla } else { model_length = 30.0; } steps = ceil(d/model_length); len = (d-model_length)/(steps-1); // PMM - special case for lightning model .. if the real length is shorter than the model, // flip it around & draw it from the end to the start. This prevents the model from going // through the tesla mine (instead it goes through the target) if ((b->model == clMedia.mod_lightning) && (d <= model_length)) { // Com_Printf ("special case\n"); VectorCopy (b->end, ent.origin); // offset to push beam outside of tesla model (negative because dist is from end to start // for this beam) // for (j=0 ; j<3 ; j++) // ent.origin[j] -= dist[j]*10.0; ent.model = b->model; ent.flags |= RF_FULLBRIGHT; ent.angles[0] = pitch; ent.angles[1] = yaw; ent.angles[2] = rand()%360; //AnglesToAxis(ent.angles, ent.axis); ent.flags |= RF_NOSHADOW; // beams don't cast shadows V_AddEntity (&ent); return; } while (d > 0) { VectorCopy (org, ent.origin); ent.model = b->model; if (clMedia.mod_heatbeam && (b->model == clMedia.mod_heatbeam)) { // ent.flags |= RF_FULLBRIGHT|RF_TRANSLUCENT; // ent.alpha = 0.6; ent.flags |= RF_FULLBRIGHT; ent.angles[0] = -pitch; ent.angles[1] = yaw + 180.0; ent.angles[2] = (cl.time) % 360; // ent.angles[2] = rand()%360; ent.frame = framenum; } else if (b->model == clMedia.mod_lightning) { ent.flags |= RF_FULLBRIGHT; ent.angles[0] = -pitch; ent.angles[1] = yaw + 180.0; ent.angles[2] = rand()%360; } else { ent.angles[0] = pitch; ent.angles[1] = yaw; ent.angles[2] = rand()%360; } //AnglesToAxis(ent.angles, ent.axis); ent.flags |= RF_NOSHADOW; // beams don't cast shadows // Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity); V_AddEntity (&ent); for (j=0 ; j<3 ; j++) org[j] += dist[j]*len; d -= model_length; } } }
void CL_AddBeams (void) { int32_t i,j; beam_t *b; vec3_t dist, org; float d; entity_t ent; float yaw, pitch; float forward; float len, steps; float model_length; frame_t *oldframe; // added player_state_t *ps, *ops; qboolean firstperson, chasecam; int32_t handmult; vec3_t thirdp_grapple_offset; vec3_t grapple_offset_dir; // chasecam grapple offset stuff if (hand) { if (hand->value == 2) handmult = 1; else if (hand->value == 1) handmult = -1; else handmult = 1; } else handmult = 1; VectorSet(thirdp_grapple_offset, 6, 16, 16); // end third person grapple // update beams for (i=0, b=cl_beams; i< MAX_BEAMS; i++, b++) { if (!b->model || b->endtime < cl.time) continue; firstperson = ((b->entity == cl.playernum+1) && !cg_thirdperson->value); chasecam = ((b->entity == cl.playernum+1) && cg_thirdperson->value); // if coming from the player, update the start position if (firstperson) // entity 0 is the world { VectorCopy (cl.refdef.vieworg, b->start); b->start[2] -= 22; // adjust for view height } else if (chasecam) { vec3_t f,r,u; ps = &cl.frame.playerstate; j = (cl.frame.serverframe - 1) & UPDATE_MASK; oldframe = &cl.frames[j]; if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid) oldframe = &cl.frame; ops = &oldframe->playerstate; AngleVectors(old_viewangles, f, r, u); VectorClear (grapple_offset_dir); for (j=0; j<3; j++) { grapple_offset_dir[j] += f[j]*thirdp_grapple_offset[1]; grapple_offset_dir[j] += r[j]*thirdp_grapple_offset[0]*handmult; grapple_offset_dir[j] += u[j]*(-thirdp_grapple_offset[2]); } for (j=0; j<3; j++) b->start[j] = cl.predicted_origin[j] + ops->viewoffset[j] + cl.lerpfrac * (ps->viewoffset[j] - ops->viewoffset[j]) + grapple_offset_dir[j]; // Com_Printf("%f, %f, %f\n", grapple_offset_dir[0], grapple_offset_dir[1], grapple_offset_dir[2]); } if (chasecam) VectorCopy (b->start, org); else VectorAdd (b->start, b->offset, org); // calculate pitch and yaw VectorSubtract (b->end, org, dist); if (dist[1] == 0 && dist[0] == 0) { yaw = 0; if (dist[2] > 0) pitch = 90; else pitch = 270; } else { // PMM - fixed to correct for pitch of 0 if (dist[0]) yaw = (atan2(dist[1], dist[0]) * 180 / M_PI); else if (dist[1] > 0) yaw = 90; else yaw = 270; if (yaw < 0) yaw += 360; forward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]); pitch = (atan2(dist[2], forward) * -180.0 / M_PI); if (pitch < 0) pitch += 360.0; } // add new entities for the beams d = VectorNormalize(dist); memset (&ent, 0, sizeof(ent)); if (b->model == clMedia.mod_lightning) { model_length = 35.0; d-= 20.0; // correction so it doesn't end in middle of tesla } else { model_length = 30.0; } steps = ceil(d/model_length); len = (d-model_length)/(steps-1); // PMM - special case for lightning model .. if the real length is shorter than the model, // flip it around & draw it from the end to the start. This prevents the model from going // through the tesla mine (instead it goes through the target) if ((b->model == clMedia.mod_lightning) && (d <= model_length)) { // Com_Printf ("special case\n"); VectorCopy (b->end, ent.origin); // offset to push beam outside of tesla model (negative because dist is from end to start // for this beam) // for (j=0 ; j<3 ; j++) // ent.origin[j] -= dist[j]*10.0; ent.model = b->model; ent.flags |= RF_FULLBRIGHT; ent.angles[0] = pitch; ent.angles[1] = yaw; ent.angles[2] = rand()%360; //AnglesToAxis(ent.angles, ent.axis); V_AddEntity (&ent); return; } while (d > 0) { VectorCopy (org, ent.origin); ent.model = b->model; if (b->model == clMedia.mod_lightning) { ent.flags |= RF_FULLBRIGHT; ent.angles[0] = -pitch; ent.angles[1] = yaw + 180.0; ent.angles[2] = rand()%360; } else { ent.angles[0] = pitch; ent.angles[1] = yaw; ent.angles[2] = rand()%360; } //AnglesToAxis(ent.angles, ent.axis); ent.flags |= RF_NOSHADOW; // beams don't cast shadows // Com_Printf("B: %d -> %d\n", b->entity, b->dest_entity); V_AddEntity (&ent); for (j=0 ; j<3 ; j++) org[j] += dist[j]*len; d -= model_length; } } }
void NQD_LinkEntities (void) { entity_t ent; centity_t *cent; entity_state_t *state; float f; struct model_s *model; int modelflags; vec3_t cur_origin; vec3_t old_origin; float autorotate; int i; int num; f = NQD_LerpPoint (); NQD_LerpPlayerinfo (f); autorotate = anglemod (100*cl.time); memset (&ent, 0, sizeof(ent)); for (num = 1; num < nq_num_entities; num++) { cent = &cl_entities[num]; state = ¢->current; if (cent->lastframe != cl_entframecount) continue; // not present in this frame MSG_UnpackOrigin (state->s_origin, cur_origin); if (state->effects & EF_BRIGHTFIELD) CL_EntityParticles (cur_origin); // spawn light flashes, even ones coming from invisible objects if (state->effects & EF_MUZZLEFLASH) { vec3_t angles, forward; cdlight_t *dl; dl = CL_AllocDlight (-num); MSG_UnpackAngles (state->s_angles, angles); AngleVectors (angles, forward, NULL, NULL); VectorMA (cur_origin, 18, forward, dl->origin); dl->origin[2] += 16; dl->radius = 200 + (rand()&31); dl->minlight = 32; dl->die = cl.time + 0.1; dl->type = lt_muzzleflash; } if (state->effects & EF_BRIGHTLIGHT) { if (state->modelindex != cl_playerindex || r_powerupglow.value) { vec3_t tmp; VectorCopy (cur_origin, tmp); tmp[2] += 16; V_AddDlight (state->number, tmp, 400 + (rand()&31), 0, lt_default); } } if (state->effects & EF_DIMLIGHT) if (state->modelindex != cl_playerindex || r_powerupglow.value) V_AddDlight (state->number, cur_origin, 200 + (rand()&31), 0, lt_default); // if set to invisible, skip if (!state->modelindex) continue; cent->current = *state; ent.model = model = cl.model_precache[state->modelindex]; if (!model) Host_Error ("CL_LinkPacketEntities: bad modelindex"); if (cl_r2g.value && cl_grenadeindex != -1) if (state->modelindex == cl_rocketindex) ent.model = cl.model_precache[cl_grenadeindex]; modelflags = R_ModelFlags (model); // rotate binary objects locally if (modelflags & MF_ROTATE) { ent.angles[0] = 0; ent.angles[1] = autorotate; ent.angles[2] = 0; } else { vec3_t old, cur; MSG_UnpackAngles (cent->current.s_angles, old); MSG_UnpackAngles (cent->previous.s_angles, cur); LerpAngles (old, cur, f, ent.angles); } if (num == nq_viewentity) { extern float nq_speed; float f; nq_speed = 0; for (i = 0; i < 3; i++) { f = (cent->current.s_origin[i] - cent->previous.s_origin[i]) * 0.125; nq_speed += f * f; } if (nq_speed) nq_speed = sqrt(nq_speed); nq_speed /= nq_mtime[0] - nq_mtime[1]; } // calculate origin for (i = 0; i < 3; i++) { if (abs(cent->current.s_origin[i] - cent->previous.s_origin[i]) > 128 * 8) { // teleport or something, don't lerp VectorCopy (cur_origin, ent.origin); if (num == nq_viewentity) nq_player_teleported = true; break; } ent.origin[i] = cent->previous.s_origin[i] * 0.125 + f * (cur_origin[i] - cent->previous.s_origin[i] * 0.125); } if (num == nq_viewentity) { VectorCopy (ent.origin, cent->trail_origin); // FIXME? continue; // player entity } if (cl_deadbodyfilter.value && state->modelindex == cl_playerindex && ( (i=state->frame)==49 || i==60 || i==69 || i==84 || i==93 || i==102) ) continue; if (cl_gibfilter.value && cl.modelinfos[state->modelindex] == mi_gib) continue; // set colormap if (state->colormap && state->colormap <= MAX_CLIENTS && state->modelindex == cl_playerindex ) ent.colormap = state->colormap; else ent.colormap = 0; // set skin ent.skinnum = state->skinnum; // set frame ent.frame = state->frame; // add automatic particle trails if ((modelflags & ~MF_ROTATE)) { if (false /*cl_entframecount == 1 || cent->lastframe != cl_entframecount-1*/) { // not in last message VectorCopy (ent.origin, old_origin); } else { VectorCopy (cent->trail_origin, old_origin); for (i=0 ; i<3 ; i++) if ( abs(old_origin[i] - ent.origin[i]) > 128) { // no trail if too far VectorCopy (ent.origin, old_origin); break; } } if (modelflags & MF_ROCKET) { if (r_rockettrail.value) { if (r_rockettrail.value == 2) CL_GrenadeTrail (old_origin, ent.origin, cent->trail_origin); else CL_RocketTrail (old_origin, ent.origin, cent->trail_origin); } else VectorCopy (ent.origin, cent->trail_origin); if (r_rocketlight.value) CL_NewDlight (state->number, ent.origin, 200, 0.1, lt_rocket); } else if (modelflags & MF_GRENADE && r_grenadetrail.value) CL_GrenadeTrail (old_origin, ent.origin, cent->trail_origin); else if (modelflags & MF_GIB) CL_BloodTrail (old_origin, ent.origin, cent->trail_origin); else if (modelflags & MF_ZOMGIB) CL_SlightBloodTrail (old_origin, ent.origin, cent->trail_origin); else if (modelflags & MF_TRACER) CL_TracerTrail (old_origin, ent.origin, cent->trail_origin, 52); else if (modelflags & MF_TRACER2) CL_TracerTrail (old_origin, ent.origin, cent->trail_origin, 230); else if (modelflags & MF_TRACER3) CL_VoorTrail (old_origin, ent.origin, cent->trail_origin); } cent->lastframe = cl_entframecount; V_AddEntity (&ent); } if (nq_viewentity == 0) Host_Error ("viewentity == 0"); VectorCopy (cl_entities[nq_viewentity].trail_origin, cl.simorg); }
/* ================== V_AddViewWeapon ================== */ void V_AddViewWeapon (float bob) { vec3_t forward, up; entity_t ent; extern cvar_t scr_fov; // FIXME, move the statics to a structure like cl static int oldweapon, curframe, oldframe; static double start_lerp_time; if (!cl_drawgun.value || (cl_drawgun.value == 2 && scr_fov.value > 90) || view_message.flags & (PF_GIB|PF_DEAD) || !Cam_DrawViewModel()) return; memset (&ent, 0, sizeof(ent)); if ((unsigned int)cl.stats[STAT_WEAPON] >= MAX_MODELS) Host_Error ("STAT_WEAPON >= MAX_MODELS"); ent.model = cl.model_precache[cl.stats[STAT_WEAPON]]; if (!ent.model) return; ent.frame = view_message.weaponframe; ent.colormap = 0; ent.renderfx = RF_WEAPONMODEL; if (cl.stats[STAT_WEAPON] != oldweapon) { oldweapon = cl.stats[STAT_WEAPON]; curframe = -1; start_lerp_time = -1; } if (ent.frame != curframe) { oldframe = curframe; curframe = ent.frame; start_lerp_time = cl.time; } ent.oldframe = oldframe; ent.backlerp = 1 - (cl.time - start_lerp_time)*10; ent.backlerp = bound (0, ent.backlerp, 1); // if (r_lerpmuzzlehack.value && cl.modelinfos[cl.stats[STAT_WEAPON]] != mi_no_lerp_hack) // ent.renderfx |= RF_LIMITLERP; if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) ent.alpha = 128; ent.angles[YAW] = r_refdef2.viewangles[YAW]; ent.angles[PITCH] = -r_refdef2.viewangles[PITCH]; ent.angles[ROLL] = r_refdef2.viewangles[ROLL]; AngleVectors (r_refdef2.viewangles, forward, NULL, up); VectorCopy (r_refdef2.vieworg, ent.origin); if (cl_bobmodel.value) { // calculate for swinging gun model // the gun bobs when running on the ground, but doesn't bob when you're in the air. // Sajt: I tried to smooth out the transitions between bob and no bob, which works // for the most part, but for some reason when you go through a message trigger or // pick up an item or anything like that it will momentarily jolt the gun. vec3_t forward, right, up; static double lastongroundtime = 0; double xyspeed; float bspeed; float s, t; xyspeed = sqrt(cl.simvel[0] * cl.simvel[0] + cl.simvel[1] * cl.simvel[1]); s = cl.time * cl_bobmodel_speed.value; if (cl.onground) { lastongroundtime = cl.time; if (cl.time - cl.landtime < 0.2) { // just hit the ground, speed the bob back up over the next 0.2 seconds t = cl.time - cl.landtime; t = bound(0, t, 0.2); t *= 5; } else { t = 1; } } else { // recently left the ground, slow the bob down over the next 0.2 seconds t = cl.time - lastongroundtime; t = 0.2 - bound(0, t, 0.2); t *= 5; } bspeed = bound (0, xyspeed, 400) * 0.01f; AngleVectors (r_refdef2.viewangles, forward, right, up); bob = bspeed * cl_bobmodel_side.value * sin (s) * t; VectorMA (ent.origin, bob, right, ent.origin); bob = bspeed * cl_bobmodel_up.value * cos (s * 2) * t; VectorMA (ent.origin, bob, up, ent.origin); } // fudge position around to keep amount of weapon visible // roughly equal with different FOV if (scr_viewsize.value == 110) VectorMA (ent.origin, 1, up, ent.origin); else if (scr_viewsize.value == 100) VectorMA (ent.origin, 2, up, ent.origin); else if (scr_viewsize.value == 90) VectorMA (ent.origin, 1, up, ent.origin); else if (scr_viewsize.value == 80) VectorMA (ent.origin, 0.5, up, ent.origin); V_AddEntity (&ent); }