q3rally/engine/code/game/g_arenas.c
zturtleman 0081965385 Sync Engine and Game VM code to ioquake3
Mostly whitespace changes. No bug fixes.
Q3Rally doesn't change any botlib code so revert copyright in botlib headers that use to be in the Q3 SDK game source directory.
MD3_MAX_* defines (besides MD3_MAX_LOD) are not used so revert to ioq3 values.
2017-11-17 03:49:41 +00:00

390 lines
11 KiB
C

/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2002-2015 Q3Rally Team (Per Thormann - q3rally@gmail.com)
This file is part of q3rally source code.
q3rally source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
q3rally source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with q3rally; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
//
// g_arenas.c
//
#include "g_local.h"
gentity_t *podium1;
gentity_t *podium2;
gentity_t *podium3;
/*
==================
UpdateTournamentInfo
==================
*/
void UpdateTournamentInfo( void ) {
int i;
gentity_t *player;
int playerClientNum;
int n, accuracy, perfect, msglen;
#ifdef MISSIONPACK
int score1, score2;
qboolean won;
#endif
char buf[32];
char msg[MAX_STRING_CHARS];
// find the real player
player = NULL;
for (i = 0; i < level.maxclients; i++ ) {
player = &g_entities[i];
if ( !player->inuse ) {
continue;
}
if ( !( player->r.svFlags & SVF_BOT ) ) {
break;
}
}
// this should never happen!
if ( !player || i == level.maxclients ) {
return;
}
playerClientNum = i;
CalculateRanks();
if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR ) {
#ifdef MISSIONPACK
Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
#else
Com_sprintf( msg, sizeof(msg), "postgame %i %i 0 0 0 0 0 0", level.numNonSpectatorClients, playerClientNum );
#endif
}
else {
if( player->client->accuracy_shots ) {
accuracy = player->client->accuracy_hits * 100 / player->client->accuracy_shots;
}
else {
accuracy = 0;
}
#ifdef MISSIONPACK
won = qfalse;
if (g_gametype.integer >= GT_CTF) {
score1 = level.teamScores[TEAM_RED];
score2 = level.teamScores[TEAM_BLUE];
if (level.clients[playerClientNum].sess.sessionTeam == TEAM_RED) {
won = (level.teamScores[TEAM_RED] > level.teamScores[TEAM_BLUE]);
} else {
won = (level.teamScores[TEAM_BLUE] > level.teamScores[TEAM_RED]);
}
} else {
if (&level.clients[playerClientNum] == &level.clients[ level.sortedClients[0] ]) {
won = qtrue;
score1 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
score2 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
} else {
score2 = level.clients[ level.sortedClients[0] ].ps.persistant[PERS_SCORE];
score1 = level.clients[ level.sortedClients[1] ].ps.persistant[PERS_SCORE];
}
}
if (won && player->client->ps.persistant[PERS_KILLED] == 0) {
perfect = 1;
} else {
perfect = 0;
}
Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],player->client->ps.persistant[PERS_DEFEND_COUNT],
player->client->ps.persistant[PERS_ASSIST_COUNT], player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
perfect, score1, score2, level.time, player->client->ps.persistant[PERS_CAPTURES] );
#else
perfect = ( level.clients[playerClientNum].ps.persistant[PERS_RANK] == 0 && player->client->ps.persistant[PERS_KILLED] == 0 ) ? 1 : 0;
Com_sprintf( msg, sizeof(msg), "postgame %i %i %i %i %i %i %i %i", level.numNonSpectatorClients, playerClientNum, accuracy,
player->client->ps.persistant[PERS_IMPRESSIVE_COUNT], player->client->ps.persistant[PERS_EXCELLENT_COUNT],
player->client->ps.persistant[PERS_GAUNTLET_FRAG_COUNT], player->client->ps.persistant[PERS_SCORE],
perfect );
#endif
}
msglen = strlen( msg );
for( i = 0; i < level.numNonSpectatorClients; i++ ) {
n = level.sortedClients[i];
Com_sprintf( buf, sizeof(buf), " %i %i %i", n, level.clients[n].ps.persistant[PERS_RANK], level.clients[n].ps.persistant[PERS_SCORE] );
msglen += strlen( buf );
if( msglen >= sizeof(msg) ) {
break;
}
strcat( msg, buf );
}
trap_SendConsoleCommand( EXEC_APPEND, msg );
}
static gentity_t *SpawnModelOnVictoryPad( gentity_t *pad, vec3_t offset, gentity_t *ent, int place ) {
gentity_t *body;
vec3_t vec;
vec3_t f, r, u;
body = G_Spawn();
if ( !body ) {
G_Printf( S_COLOR_RED "ERROR: out of gentities\n" );
return NULL;
}
body->classname = ent->client->pers.netname;
body->client = ent->client;
body->s = ent->s;
body->s.eType = ET_PLAYER; // could be ET_INVISIBLE
body->s.eFlags = 0; // clear EF_TALK, etc
body->s.powerups = 0; // clear powerups
body->s.loopSound = 0; // clear lava burning
body->s.number = body - g_entities;
body->timestamp = level.time;
body->physicsObject = qtrue;
body->physicsBounce = 0; // don't bounce
body->s.event = 0;
body->s.pos.trType = TR_STATIONARY;
body->s.groundEntityNum = ENTITYNUM_WORLD;
// STONELANCE
/*
body->s.legsAnim = LEGS_IDLE;
body->s.torsoAnim = TORSO_STAND;
*/
// END
if( body->s.weapon == WP_NONE ) {
body->s.weapon = WP_MACHINEGUN;
}
// STONELANCE
/*
if( body->s.weapon == WP_GAUNTLET) {
body->s.torsoAnim = TORSO_STAND2;
}
*/
// END
body->s.event = 0;
body->r.svFlags = ent->r.svFlags;
VectorCopy (ent->r.mins, body->r.mins);
VectorCopy (ent->r.maxs, body->r.maxs);
VectorCopy (ent->r.absmin, body->r.absmin);
VectorCopy (ent->r.absmax, body->r.absmax);
body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
body->r.contents = CONTENTS_BODY;
body->r.ownerNum = ent->r.ownerNum;
body->takedamage = qfalse;
VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );
vectoangles( vec, body->s.apos.trBase );
body->s.apos.trBase[PITCH] = 0;
body->s.apos.trBase[ROLL] = 0;
AngleVectors( body->s.apos.trBase, f, r, u );
VectorMA( pad->r.currentOrigin, offset[0], f, vec );
VectorMA( vec, offset[1], r, vec );
VectorMA( vec, offset[2], u, vec );
G_SetOrigin( body, vec );
trap_LinkEntity (body);
body->count = place;
return body;
}
static void CelebrateStop( gentity_t *player ) {
// STONELANCE
/*
int anim;
if( player->s.weapon == WP_GAUNTLET) {
anim = TORSO_STAND2;
}
else {
anim = TORSO_STAND;
}
player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
*/
// END
}
#define TIMER_GESTURE (34*66+50)
static void CelebrateStart( gentity_t *player ) {
// STONELANCE
// player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_GESTURE;
// END
player->nextthink = level.time + TIMER_GESTURE;
player->think = CelebrateStop;
/*
player->client->ps.events[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = EV_TAUNT;
player->client->ps.eventParms[player->client->ps.eventSequence & (MAX_PS_EVENTS-1)] = 0;
player->client->ps.eventSequence++;
*/
G_AddEvent(player, EV_TAUNT, 0);
}
static vec3_t offsetFirst = {0, 0, 74};
static vec3_t offsetSecond = {-10, 60, 54};
static vec3_t offsetThird = {-19, -60, 45};
static void PodiumPlacementThink( gentity_t *podium ) {
vec3_t vec;
vec3_t origin;
vec3_t f, r, u;
podium->nextthink = level.time + 100;
AngleVectors( level.intermission_angle, vec, NULL, NULL );
VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
G_SetOrigin( podium, origin );
if( podium1 ) {
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
vectoangles( vec, podium1->s.apos.trBase );
podium1->s.apos.trBase[PITCH] = 0;
podium1->s.apos.trBase[ROLL] = 0;
AngleVectors( podium1->s.apos.trBase, f, r, u );
VectorMA( podium->r.currentOrigin, offsetFirst[0], f, vec );
VectorMA( vec, offsetFirst[1], r, vec );
VectorMA( vec, offsetFirst[2], u, vec );
G_SetOrigin( podium1, vec );
}
if( podium2 ) {
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
vectoangles( vec, podium2->s.apos.trBase );
podium2->s.apos.trBase[PITCH] = 0;
podium2->s.apos.trBase[ROLL] = 0;
AngleVectors( podium2->s.apos.trBase, f, r, u );
VectorMA( podium->r.currentOrigin, offsetSecond[0], f, vec );
VectorMA( vec, offsetSecond[1], r, vec );
VectorMA( vec, offsetSecond[2], u, vec );
G_SetOrigin( podium2, vec );
}
if( podium3 ) {
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
vectoangles( vec, podium3->s.apos.trBase );
podium3->s.apos.trBase[PITCH] = 0;
podium3->s.apos.trBase[ROLL] = 0;
AngleVectors( podium3->s.apos.trBase, f, r, u );
VectorMA( podium->r.currentOrigin, offsetThird[0], f, vec );
VectorMA( vec, offsetThird[1], r, vec );
VectorMA( vec, offsetThird[2], u, vec );
G_SetOrigin( podium3, vec );
}
}
static gentity_t *SpawnPodium( void ) {
gentity_t *podium;
vec3_t vec;
vec3_t origin;
podium = G_Spawn();
if ( !podium ) {
return NULL;
}
podium->classname = "podium";
podium->s.eType = ET_GENERAL;
podium->s.number = podium - g_entities;
podium->clipmask = CONTENTS_SOLID;
podium->r.contents = CONTENTS_SOLID;
podium->s.modelindex = G_ModelIndex( SP_PODIUM_MODEL );
AngleVectors( level.intermission_angle, vec, NULL, NULL );
VectorMA( level.intermission_origin, trap_Cvar_VariableIntegerValue( "g_podiumDist" ), vec, origin );
origin[2] -= trap_Cvar_VariableIntegerValue( "g_podiumDrop" );
G_SetOrigin( podium, origin );
VectorSubtract( level.intermission_origin, podium->r.currentOrigin, vec );
podium->s.apos.trBase[YAW] = vectoyaw( vec );
trap_LinkEntity (podium);
podium->think = PodiumPlacementThink;
podium->nextthink = level.time + 100;
return podium;
}
/*
==================
SpawnModelsOnVictoryPads
==================
*/
void SpawnModelsOnVictoryPads( void ) {
gentity_t *player;
gentity_t *podium;
podium1 = NULL;
podium2 = NULL;
podium3 = NULL;
podium = SpawnPodium();
player = SpawnModelOnVictoryPad( podium, offsetFirst, &g_entities[level.sortedClients[0]],
level.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
if ( player ) {
player->nextthink = level.time + 2000;
player->think = CelebrateStart;
podium1 = player;
}
player = SpawnModelOnVictoryPad( podium, offsetSecond, &g_entities[level.sortedClients[1]],
level.clients[ level.sortedClients[1] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
if ( player ) {
podium2 = player;
}
if ( level.numNonSpectatorClients > 2 ) {
player = SpawnModelOnVictoryPad( podium, offsetThird, &g_entities[level.sortedClients[2]],
level.clients[ level.sortedClients[2] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
if ( player ) {
podium3 = player;
}
}
}
/*
===============
Svcmd_AbortPodium_f
===============
*/
void Svcmd_AbortPodium_f( void ) {
if( g_gametype.integer != GT_SINGLE_PLAYER ) {
return;
}
if( podium1 ) {
podium1->nextthink = level.time;
podium1->think = CelebrateStop;
}
}