void SelectNextItem (edict_t *ent, int itflags) { gclient_t *cl; int i, index; gitem_t *it; cl = ent->client; if (cl->chase_target) { ChaseNext(ent); return; } // scan for the next valid one for (i=1 ; i<=MAX_ITEMS ; i++) { index = (cl->pers.selected_item + i)%MAX_ITEMS; if (!cl->pers.inventory[index]) continue; it = &itemlist[index]; if (!it->use) continue; if (!(it->flags & itflags)) continue; cl->pers.selected_item = index; return; } cl->pers.selected_item = -1; }
static void SelectNextItem(edict_t *ent, int itflags) { gclient_t *cl; int i, index; const gitem_t *it; cl = ent->client; if (cl->layout == LAYOUT_MENU) { PMenu_Next(ent); return; } if (cl->chase_target) { ChaseNext(ent); cl->chase_mode = CHASE_NONE; return; } // scan for the next valid one for (i = 1; i <= ITEM_TOTAL; i++) { index = (cl->selected_item + i) % ITEM_TOTAL; if (!cl->inventory[index]) continue; it = INDEX_ITEM(index); if (!it->use) continue; if (!(it->flags & itflags)) continue; cl->selected_item = index; return; } cl->selected_item = -1; }
int ChaseTargetGone( edict_t * ent ) { edict_t *targ = ent->client->chase_target; // is our chase target gone? if (!targ || !targ->inuse || (targ->solid == SOLID_NOT && targ->deadflag != DEAD_DEAD)) { ChaseNext( ent ); if (ent->client->chase_target == targ) { DisableChaseCam( ent ); return 1; } } return 0; }
int ChaseTargetGone(edict_t *ent) { // is our chase target gone? if (!ent->client->chase_target->inuse || (ent->client->chase_target->solid == SOLID_NOT && ent->client->chase_target->deadflag != DEAD_DEAD)) { edict_t *old = ent->client->chase_target; ChaseNext(ent); if (ent->client->chase_target == old) { ent->client->chase_target = NULL; ent->client->desired_fov = 90; ent->client->ps.fov = 90; ent->client->chase_mode = 0; ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; return 1; } } return 0; }
void UpdateChaseCam(edict_t *ent) { vec3_t o, ownerv, goal; edict_t *targ; vec3_t forward, right; trace_t trace; int i; vec3_t oldgoal; vec3_t angles; // is our chase target gone? if (!ent->client->chase_target->inuse || ent->client->chase_target->client->resp.spectator) { edict_t *old = ent->client->chase_target; ChaseNext(ent); if (ent->client->chase_target == old) { ent->client->chase_target = NULL; ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; return; } } targ = ent->client->chase_target; VectorCopy(targ->s.origin, ownerv); VectorCopy(ent->s.origin, oldgoal); ownerv[2] += targ->viewheight; VectorCopy(targ->client->v_angle, angles); if (angles[PITCH] > 56) angles[PITCH] = 56; AngleVectors (angles, forward, right, NULL); VectorNormalize(forward); VectorMA(ownerv, -30, forward, o); if (o[2] < targ->s.origin[2] + 20) o[2] = targ->s.origin[2] + 20; // jump animation lifts if (!targ->groundentity) o[2] += 16; trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID); VectorCopy(trace.endpos, goal); VectorMA(goal, 2, forward, goal); // pad for floors and ceilings VectorCopy(goal, o); o[2] += 6; trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID); if (trace.fraction < 1) { VectorCopy(trace.endpos, goal); goal[2] -= 6; } VectorCopy(goal, o); o[2] -= 6; trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID); if (trace.fraction < 1) { VectorCopy(trace.endpos, goal); goal[2] += 6; } if (targ->deadflag) ent->client->ps.pmove.pm_type = PM_DEAD; else ent->client->ps.pmove.pm_type = PM_FREEZE; VectorCopy(goal, ent->s.origin); for (i=0 ; i<3 ; i++) ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]); if (targ->deadflag) { ent->client->ps.viewangles[ROLL] = 40; ent->client->ps.viewangles[PITCH] = -15; ent->client->ps.viewangles[YAW] = targ->client->killer_yaw; } else { VectorCopy(targ->client->v_angle, ent->client->ps.viewangles); VectorCopy(targ->client->v_angle, ent->client->v_angle); } ent->viewheight = 0; ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; gi.linkentity(ent); }
/* ============== ClientThink This will be called once for each client frame, which will usually be a couple times for each server frame. ============== */ void ClientThink (edict_t *ent, usercmd_t *ucmd) { gclient_t *client; edict_t *other; int i, j; pmove_t pm; level.current_entity = ent; client = ent->client; if (level.intermissiontime) { client->ps.pmove.pm_type = PM_FREEZE; // can exit intermission after five seconds if (level.time > level.intermissiontime + 5.0 && (ucmd->buttons & BUTTON_ANY) ) level.exitintermission = true; return; } pm_passent = ent; if (ent->client->chase_target) { client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); } else { // set up for pmove memset (&pm, 0, sizeof(pm)); if (ent->movetype == MOVETYPE_NOCLIP) client->ps.pmove.pm_type = PM_SPECTATOR; else if (ent->s.modelindex != 255) client->ps.pmove.pm_type = PM_GIB; else if (ent->deadflag) client->ps.pmove.pm_type = PM_DEAD; else client->ps.pmove.pm_type = PM_NORMAL; client->ps.pmove.gravity = sv_gravity->value; pm.s = client->ps.pmove; for (i=0 ; i<3 ; i++) { pm.s.origin[i] = ent->s.origin[i]*8; pm.s.velocity[i] = ent->velocity[i]*8; } if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s))) { pm.snapinitial = true; // gi.dprintf ("pmove changed!\n"); } pm.cmd = *ucmd; pm.trace = PM_trace; // adds default parms pm.pointcontents = gi.pointcontents; // perform a pmove gi.Pmove (&pm); // save results of pmove client->ps.pmove = pm.s; client->old_pmove = pm.s; for (i=0 ; i<3 ; i++) { ent->s.origin[i] = pm.s.origin[i]*0.125; ent->velocity[i] = pm.s.velocity[i]*0.125; } VectorCopy (pm.mins, ent->mins); VectorCopy (pm.maxs, ent->maxs); client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0)) { gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0); PlayerNoise(ent, ent->s.origin, PNOISE_SELF); } ent->viewheight = pm.viewheight; ent->waterlevel = pm.waterlevel; ent->watertype = pm.watertype; ent->groundentity = pm.groundentity; if (pm.groundentity) ent->groundentity_linkcount = pm.groundentity->linkcount; if (ent->deadflag) { client->ps.viewangles[ROLL] = 40; client->ps.viewangles[PITCH] = -15; client->ps.viewangles[YAW] = client->killer_yaw; } else { VectorCopy (pm.viewangles, client->v_angle); VectorCopy (pm.viewangles, client->ps.viewangles); } gi.linkentity (ent); if (ent->movetype != MOVETYPE_NOCLIP) G_TouchTriggers (ent); // touch other objects for (i=0 ; i<pm.numtouch ; i++) { other = pm.touchents[i]; for (j=0 ; j<i ; j++) if (pm.touchents[j] == other) break; if (j != i) continue; // duplicated if (!other->touch) continue; other->touch (other, ent, NULL, NULL); } } client->oldbuttons = client->buttons; client->buttons = ucmd->buttons; client->latched_buttons |= client->buttons & ~client->oldbuttons; // save light level the player is standing on for // monster sighting AI ent->light_level = ucmd->lightlevel; // fire weapon from final position if needed if (client->latched_buttons & BUTTON_ATTACK) { if (client->resp.spectator) { client->latched_buttons = 0; if (client->chase_target) { client->chase_target = NULL; client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; } else GetChaseTarget(ent); } else if (!client->weapon_thunk) { client->weapon_thunk = true; Think_Weapon (ent); } } if (client->resp.spectator) { if (ucmd->upmove >= 10) { if (!(client->ps.pmove.pm_flags & PMF_JUMP_HELD)) { client->ps.pmove.pm_flags |= PMF_JUMP_HELD; if (client->chase_target) ChaseNext(ent); else GetChaseTarget(ent); } } else client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD; } // update chase cam if being followed for (i = 1; i <= maxclients->value; i++) { other = g_edicts + i; if (other->inuse && other->client->chase_target == ent) UpdateChaseCam(other); } }
void UpdateChaseCam (edict_t *ent) { int i; edict_t *old, *targ; vec3_t start, goal; vec3_t angles, forward, right; trace_t tr; qboolean eyecam=false; if (!ent->client->chase_target) return; if (!G_IsSpectator(ent)) return; //gi.dprintf("updating chase for %s\n", ent->client->pers.netname); // is our chase target no longer valid? if (!IsValidChaseTarget(ent->client->chase_target)) { old = ent->client->chase_target; ChaseNext(ent); // try to find a new chase target if (ent->client->chase_target == old) { // switch out of chase-cam mode ent->client->chase_target = NULL; ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; ent->client->ps.pmove.pm_flags &= ~PMF_DUCKED; // quit ducked. return; } } targ = ent->client->chase_target; if (PM_MonsterHasPilot(targ)) targ = targ->owner; VectorCopy(targ->s.origin, start); // use client's viewing angle if (targ->client) VectorCopy(targ->client->v_angle, angles); // use pilot's viewing angle /* else if (PM_MonsterHasPilot(targ)) { VectorCopy(targ->owner->s.origin, start); VectorCopy(targ->owner->client->v_angle, angles); } */ // use non-client's angles else VectorCopy(targ->s.angles, angles); if (ent->client->chasecam_mode) eyecam = true; // if we're chasing a non-client entity that has a valid enemy // within our sights, then modify our viewing pitch if (eyecam && !targ->client && G_ValidTarget(targ, targ->enemy, true) && infov(targ, targ->enemy, 90)) { VectorSubtract(targ->enemy->s.origin, targ->s.origin, forward); vectoangles(forward, forward); angles[PITCH] = forward[PITCH]; //gi.dprintf("pitch %d\n", (int)forward[PITCH]); } if (!eyecam) { if (angles[PITCH] > 56) angles[PITCH] = 56; if (angles[PITCH] < -56) angles[PITCH] = -56; } AngleVectors (angles, forward, right, NULL); VectorNormalize(forward); if (eyecam) { // save current player fov float fov = ent->client->ps.fov; if (targ->viewheight) start[2] += targ->viewheight; else start[2] = targ->absmax[2]-8; VectorMA(start, targ->maxs[1]+16, forward, start); // update HUD if (targ->client) ent->client->ps = targ->client->ps; else ent->client->ps.gunindex = 0; // restore player's fov (don't use target's fov) ent->client->ps.fov = fov; } else { ent->client->ps.gunindex = 0; // special conditions for upside-down minisentry if (targ->owner && (targ->mtype == M_MINISENTRY) && (targ->owner->style == SENTRY_FLIPPED)) { start[2] = targ->absmin[2]-16; } else { if (targ->viewheight) start[2] += targ->viewheight; else start[2] = targ->absmax[2]-8; VectorMA(start, targ->mins[1]-16, forward, start); } } // jump animation lifts if (!targ->groundentity) start[2] += 16; tr = gi.trace(targ->s.origin, NULL, NULL, start, targ, MASK_SOLID); VectorCopy(tr.endpos, start); if (tr.fraction < 1) { if (eyecam) VectorMA(start, -12, forward, start); else VectorMA(start, 12, forward, start); } VectorCopy(start, goal); // pad for floors and ceilings VectorCopy(goal, start); start[2] += 6; tr = gi.trace(goal, vec3_origin, vec3_origin, start, targ, MASK_SOLID); if (tr.fraction < 1) { VectorCopy(tr.endpos, goal); goal[2] -= 6; } VectorCopy(goal, start); start[2] -= 6; tr = gi.trace(goal, vec3_origin, vec3_origin, start, targ, MASK_SOLID); if (tr.fraction < 1) { VectorCopy(tr.endpos, goal); goal[2] += 6; } if (targ->deadflag) ent->client->ps.pmove.pm_type = PM_DEAD; else ent->client->ps.pmove.pm_type = PM_FREEZE; VectorCopy(goal, ent->s.origin); for (i=0 ; i<3 ; i++) { ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(angles[i] - ent->client->resp.cmd_angles[i]); } if (targ->deadflag) { ent->client->ps.viewangles[ROLL] = 40; ent->client->ps.viewangles[PITCH] = -15; if (targ->client) ent->client->ps.viewangles[YAW] = targ->client->killer_yaw; else ent->client->ps.viewangles[YAW] = 0; } else { VectorCopy(angles, ent->client->ps.viewangles); VectorCopy(angles, ent->client->v_angle); } ent->viewheight = 0; ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; gi.linkentity(ent); }