void SetChase( edict_t *ent, edict_t *target ) { if (!target) { DisableChaseCam( ent ); return; } if (target != ent->client->chase_target && ent->client->chase_mode == 2) { ent->client->clientNum = (target - g_edicts) - 1; } ent->client->chase_target = target; }
void NextChaseMode( edict_t *ent ) { ent->client->chase_mode = (ent->client->chase_mode + 1) % 3; if (ent->client->chase_mode == 1) { //going 3rd person, remove gun and invisible player ent->client->clientNum = (ent - g_edicts) - 1; ent->client->ps.gunindex = ent->client->ps.gunframe = 0; if (!ent->client->chase_target) { GetChaseTarget( ent ); if (!ent->client->chase_target) { ent->client->chase_mode = 0; return; } } if (ent->client->resp.team && teamplay->value && limchasecam->value == 2) { NextChaseMode( ent ); return; } } else if (ent->client->chase_mode == 2) { if (!ent->client->chase_target) { GetChaseTarget( ent ); if (!ent->client->chase_target) { ent->client->chase_mode = 0; return; } } //set clientnum to hide chased person on supported server ent->client->clientNum = (ent->client->chase_target - g_edicts) - 1; ent->client->ps.gunindex = ent->client->ps.gunframe = 0; } else// if (ent->client->chase_mode == CHASE_FREE) { if (ent->client->resp.team && teamplay->value && limchasecam->value) { if (limchasecam->value == 1) { NextChaseMode( ent ); } else { ent->client->chase_mode = 2; } return; } DisableChaseCam( ent ); } }
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; }
/* ============== ToggleChaseCam ============== Player hit Spectator menu option or used chase command. */ void ToggleChaseCam (edict_t *ent) { if (ent->client->pers.team) { TDM_LeftTeam (ent, true); TDM_TeamsChanged (); if (tdm_match_status == MM_TIMEOUT && teaminfo[TEAM_A].players == 0 && teaminfo[TEAM_B].players == 0) TDM_ResumeGame (); respawn (ent); } if (ent->client->chase_target) DisableChaseCam (ent); else GetChaseTarget(ent); PMenu_Close (ent); }
/* ============== TDM_ProcessJoinCode ============== Returns true if a player was set back on a team as a result of rejoining. */ qboolean TDM_ProcessJoinCode (edict_t *ent, unsigned value) { int i; const char *code; teamplayer_t *t; edict_t *ghost; edict_t new_entity; gclient_t new_client; gclient_t *saved_client; if (tdm_match_status < MM_PLAYING || tdm_match_status == MM_SCOREBOARD) return false; //if no value was passed, look up userinfo if (!value) { code = Info_ValueForKey (ent->client->pers.userinfo, "joincode"); if (!code[0]) return false; value = strtoul (code, NULL, 10); } //must be a disconnected client for this to work t = TDM_FindTeamplayerForJoinCode (value); if (!t || t->client || !t->saved_client || !t->saved_entity) return false; //0000201: Joincode rejoin. don't allow bypassing of max players setting. if (teaminfo[t->team].players >= current_matchinfo.max_players_per_team) return false; //could be using a joincode while chasing, need to fix it here before we possibly overwrite entity if (ent->client->chase_target) DisableChaseCam (ent); gi.unlinkentity (ent); ent->client->pers.team = t->team; JoinedTeam (ent, true, true); //we only preserve the whole client state in 1v1 mode, in TDM we simply respawn the player if (TDM_Is1V1()) { //remove ghost model for (ghost = g_edicts + game.maxclients + 1; ghost < g_edicts + globals.num_edicts; ghost++) { if (!ghost->inuse) continue; if (ghost->enttype != ENT_GHOST) continue; if (ghost->count == t->saved_entity->s.number) { G_FreeEdict (ghost); break; } } //take copies of the current (new) structures new_entity = *ent; new_client = *ent->client; //preserve new client pointer saved_client = ent->client; //restore all edict fields and preserve new client pointer *ent = *t->saved_entity; ent->client = saved_client; //restore all client fields *ent->client = *t->saved_client; //restore stuff that shouldn't be overwritten ent->inuse = true; ent->s.number = new_entity.s.number; ent->client->resp.vote = VOTE_HOLD; VectorCopy (new_client.resp.cmd_angles, ent->client->resp.cmd_angles); strcpy (ent->client->pers.userinfo, new_client.pers.userinfo); //aiee :E :E ent->linkcount = new_entity.linkcount; ent->area = new_entity.area; ent->num_clusters = new_entity.num_clusters; memcpy (ent->clusternums, new_entity.clusternums, sizeof(ent->clusternums)); ent->headnode = new_entity.headnode; ent->areanum = new_entity.areanum; ent->areanum2 = new_entity.areanum2; //set the delta angle for (i=0 ; i<3 ; i++) ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->v_angle[i] - ent->client->resp.cmd_angles[i]); } else { ent->client->resp.score = t->saved_client->resp.score; ent->client->resp.enterframe = t->saved_client->resp.enterframe; ent->client->resp.ready = t->saved_client->resp.ready; ent->client->pers.joinstate = t->saved_client->pers.joinstate; ent->client->pers.admin = t->saved_client->pers.admin; } //free the teamplayer saved info gi.TagFree (t->saved_entity); gi.TagFree (t->saved_client); t->saved_entity = NULL; t->saved_client = NULL; // wision: restore player's name G_StuffCmd (ent, "set name \"%s\"\n", t->name); //restore teamplayer links ent->client->resp.teamplayerinfo = t; t->client = ent; //no linkentity, we are called as part of PutClientInServer, linking here would telefrag ourselves! gi.unlinkentity (ent); return true; }