00001 // Copyright (C) 1999-2000 Id Software, Inc. 00002 // 00003 // 00004 // g_arenas.c 00005 // 00006 00007 #include "g_local.h" 00008 00009 00010 gentity_t *podium1; 00011 gentity_t *podium2; 00012 gentity_t *podium3; 00013 00014 00015 /* 00016 ================== 00017 UpdateTournamentInfo 00018 ================== 00019 */ 00020 void UpdateTournamentInfo( void ) { 00021 int i; 00022 gentity_t *player; 00023 int playerClientNum; 00024 int n, accuracy, perfect, msglen; 00025 int buflen; 00026 int score1, score2; 00027 qboolean won; 00028 char buf[32]; 00029 char msg[MAX_STRING_CHARS]; 00030 00031 // find the real player 00032 player = NULL; 00033 for (i = 0; i < level.maxclients; i++ ) { 00034 player = &g_entities[i]; 00035 if ( !player->inuse ) { 00036 continue; 00037 } 00038 if ( !( player->r.svFlags & SVF_BOT ) ) { 00039 break; 00040 } 00041 } 00042 // this should never happen! 00043 if ( !player || i == level.maxclients ) { 00044 return; 00045 } 00046 playerClientNum = i; 00047 00048 CalculateRanks(); 00049 00050 if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) { 00051 Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum ); 00052 } 00053 else { 00054 if( player->client->accuracy_shots ) { 00055 accuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots; 00056 } 00057 else { 00058 accuracy = 0; 00059 } 00060 won = qfalse; 00061 if (g_gametype.integer >= GT_CTF) { 00062 score1 = level.teamScores[TEAM_RED]; 00063 score2 = level.teamScores[TEAM_BLUE]; 00064 if (level.clients[playerClientNum].sess.sessionTeam == TEAM_RED) { 00065 won = (level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE]); 00066 } else { 00067 won = (level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED]); 00068 } 00069 } else { 00070 if (&level.clients[playerClientNum] == &level.clients[ level.sortedClients[0] ]) { 00071 won = qtrue; 00072 score1 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE]; 00073 score2 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE]; 00074 } else { 00075 score2 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE]; 00076 score1 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE]; 00077 } 00078 } 00079 if (won && player->client->ps.persistant[PERS_KILLED] == 0) { 00080 perfect = 1; 00081 } else { 00082 perfect = 0; 00083 } 00084 Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy, 00085 player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],player->client->ps.persistant[PERS_DEFEND_COUNT], 00086 player->client->ps.persistant[PERS_ASSIST_COUNT], player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE], 00087 perfect, score1, score2, level.time, player->client->ps.persistant[PERS_CAPTURES] ); 00088 } 00089 00090 msglen = strlen( msg ); 00091 for( i = 0; i < level.numNonSpectatorClients; i++ ) { 00092 n = level.sortedClients[i]; 00093 Com_sprintf( buf, sizeof(buf), " %i %i %i", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] ); 00094 buflen = strlen( buf ); 00095 if( msglen + buflen + 1 >= sizeof(msg) ) { 00096 break; 00097 } 00098 strcat( msg, buf ); 00099 } 00100 trap_SendConsoleCommand( EXEC_APPEND, msg ); 00101 } 00102 00103 00104 /* 00105 static gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) { 00106 gentity_t *body; 00107 vec3_t vec; 00108 vec3_t f, r, u; 00109 00110 body = G_Spawn(); 00111 if ( !body ) { 00112 G_Printf( S_COLOR_RED "ERROR: out of gentities\n" ); 00113 return NULL; 00114 } 00115 00116 body->classname = ent->client->pers.netname; 00117 body->client = ent->client; 00118 body->s = ent->s; 00119 body->s.eType = ET_PLAYER; // could be ET_INVISIBLE 00120 body->s.eFlags = 0; // clear EF_TALK, etc 00121 body->s.powerups = 0; // clear powerups 00122 body->s.loopSound = 0; // clear lava burning 00123 body->s.number = body - g_entities; 00124 body->timestamp = level.time; 00125 body->physicsObject = qtrue; 00126 body->physicsBounce = 0; // don't bounce 00127 body->s.event = 0; 00128 body->s.pos.trType = TR_STATIONARY; 00129 body->s.groundEntityNum = ENTITYNUM_WORLD; 00130 body->s.legsAnim = WeaponReadyAnim[ent->s.weapon]; 00131 body->s.torsoAnim = WeaponReadyAnim[ent->s.weapon]; 00132 if( body->s.weapon == WP_NONE ) { 00133 body->s.weapon = WP_BRYAR_PISTOL; 00134 } 00135 if( body->s.weapon == WP_SABER) { 00136 body->s.torsoAnim = BOTH_STAND2; 00137 } 00138 body->s.event = 0; 00139 body->r.svFlags = ent->r.svFlags; 00140 VectorCopy (ent->r.mins, body->r.mins); 00141 VectorCopy (ent->r.maxs, body->r.maxs); 00142 VectorCopy (ent->r.absmin, body->r.absmin); 00143 VectorCopy (ent->r.absmax, body->r.absmax); 00144 body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP; 00145 body->r.contents = CONTENTS_BODY; 00146 body->r.ownerNum = ent->r.ownerNum; 00147 body->takedamage = qfalse; 00148 00149 VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec ); 00150 vectoangles( vec, body->s.apos.trBase ); 00151 body->s.apos.trBase[PITCH] = 0; 00152 body->s.apos.trBase[ROLL] = 0; 00153 00154 AngleVectors( body->s.apos.trBase, f, r, u ); 00155 VectorMA( pad->r.currentOrigin, offset[0], f, vec ); 00156 VectorMA( vec, offset[1], r, vec ); 00157 VectorMA( vec, offset[2], u, vec ); 00158 00159 G_SetOrigin( body, vec ); 00160 00161 trap_LinkEntity (body); 00162 00163 body->count = place; 00164 00165 return body; 00166 } 00167 00168 00169 static void CelebrateStop( gentity_t *player ) { 00170 int anim; 00171 00172 if( player->s.weapon == WP_SABER) { 00173 anim = BOTH_STAND2; 00174 } 00175 else { 00176 anim = WeaponReadyAnim[player->s.weapon]; 00177 } 00178 player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim; 00179 } 00180 00181 00182 #define TIMER_GESTURE (34*66+50) 00183 static void CelebrateStart( gentity_t *player ) { 00184 player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | BOTH_TALKGESTURE1; 00185 player->nextthink = level.time + TIMER_GESTURE; 00186 player->think = CelebrateStop; 00187 00188 00189 // player->client->ps.events[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = EV_TAUNT; 00190 // player->client->ps.eventParms[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = 0; 00191 // player->client->ps.eventSequence++; 00192 00193 G_AddEvent(player, EV_TAUNT, 0); 00194 } 00195 00196 00197 static vec3_t offsetFirst = {0, 0, 74}; 00198 static vec3_t offsetSecond = {-10, 60, 54}; 00199 static vec3_t offsetThird = {-19, -60, 45}; 00200 00201 static void PodiumPlacementThink( gentity_t *podium ) { 00202 vec3_t vec; 00203 vec3_t origin; 00204 vec3_t f, r, u; 00205 00206 podium->nextthink = level.time + 100; 00207 00208 AngleVectors( level.intermission_angle, vec, NULL, NULL ); 00209 VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin ); 00210 origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" ); 00211 G_SetOrigin( podium, origin ); 00212 00213 if( podium1 ) { 00214 VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec ); 00215 vectoangles( vec, podium1->s.apos.trBase ); 00216 podium1->s.apos.trBase[PITCH] = 0; 00217 podium1->s.apos.trBase[ROLL] = 0; 00218 00219 AngleVectors( podium1->s.apos.trBase, f, r, u ); 00220 VectorMA( podium->r.currentOrigin, offsetFirst[0], f, vec ); 00221 VectorMA( vec, offsetFirst[1], r, vec ); 00222 VectorMA( vec, offsetFirst[2], u, vec ); 00223 00224 G_SetOrigin( podium1, vec ); 00225 } 00226 00227 if( podium2 ) { 00228 VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec ); 00229 vectoangles( vec, podium2->s.apos.trBase ); 00230 podium2->s.apos.trBase[PITCH] = 0; 00231 podium2->s.apos.trBase[ROLL] = 0; 00232 00233 AngleVectors( podium2->s.apos.trBase, f, r, u ); 00234 VectorMA( podium->r.currentOrigin, offsetSecond[0], f, vec ); 00235 VectorMA( vec, offsetSecond[1], r, vec ); 00236 VectorMA( vec, offsetSecond[2], u, vec ); 00237 00238 G_SetOrigin( podium2, vec ); 00239 } 00240 00241 if( podium3 ) { 00242 VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec ); 00243 vectoangles( vec, podium3->s.apos.trBase ); 00244 podium3->s.apos.trBase[PITCH] = 0; 00245 podium3->s.apos.trBase[ROLL] = 0; 00246 00247 AngleVectors( podium3->s.apos.trBase, f, r, u ); 00248 VectorMA( podium->r.currentOrigin, offsetThird[0], f, vec ); 00249 VectorMA( vec, offsetThird[1], r, vec ); 00250 VectorMA( vec, offsetThird[2], u, vec ); 00251 00252 G_SetOrigin( podium3, vec ); 00253 } 00254 } 00255 00256 00257 static gentity_t *SpawnPodium( void ) { 00258 gentity_t *podium; 00259 vec3_t vec; 00260 vec3_t origin; 00261 00262 podium = G_Spawn(); 00263 if ( !podium ) { 00264 return NULL; 00265 } 00266 00267 podium->classname = "podium"; 00268 podium->s.eType = ET_GENERAL; 00269 podium->s.number = podium - g_entities; 00270 podium->clipmask = CONTENTS_SOLID; 00271 podium->r.contents = CONTENTS_SOLID; 00272 podium->s.modelindex = G_ModelIndex( SP_PODIUM_MODEL ); 00273 00274 AngleVectors( level.intermission_angle, vec, NULL, NULL ); 00275 VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin ); 00276 origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" ); 00277 G_SetOrigin( podium, origin ); 00278 00279 VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec ); 00280 podium->s.apos.trBase[YAW] = vectoyaw( vec ); 00281 trap_LinkEntity (podium); 00282 00283 podium->think = PodiumPlacementThink; 00284 podium->nextthink = level.time + 100; 00285 return podium; 00286 } 00287 00288 00289 00290 //================== 00291 //SpawnModelsOnVictoryPads 00292 //================== 00293 00294 void SpawnModelsOnVictoryPads( void ) { 00295 gentity_t *player; 00296 gentity_t *podium; 00297 00298 podium1 = NULL; 00299 podium2 = NULL; 00300 podium3 = NULL; 00301 00302 podium = SpawnPodium(); 00303 00304 player = SpawnModelOnVictoryPad( podium, offsetFirst, &g_entities[level.sortedClients[0]], 00305 level.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG ); 00306 if ( player ) { 00307 player->nextthink = level.time + 2000; 00308 player->think = CelebrateStart; 00309 podium1 = player; 00310 } 00311 00312 player = SpawnModelOnVictoryPad( podium, offsetSecond, &g_entities[level.sortedClients[1]], 00313 level.clients[ level.sortedClients[1] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG ); 00314 if ( player ) { 00315 podium2 = player; 00316 } 00317 00318 if ( level.numNonSpectatorClients > 2 ) { 00319 player = SpawnModelOnVictoryPad( podium, offsetThird, &g_entities[level.sortedClients[2]], 00320 level.clients[ level.sortedClients[2] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG ); 00321 if ( player ) { 00322 podium3 = player; 00323 } 00324 } 00325 } 00326 00327 00328 00329 //=============== 00330 //Svcmd_AbortPodium_f 00331 //=============== 00332 00333 void Svcmd_AbortPodium_f( void ) { 00334 if( g_gametype.integer != GT_SINGLE_PLAYER ) { 00335 return; 00336 } 00337 00338 if( podium1 ) { 00339 podium1->nextthink = level.time; 00340 podium1->think = CelebrateStop; 00341 } 00342 } 00343 */