rpgxef/code/game/g_arenas.c
Walter Julius Hennecke a39565b783 Integrated RPG-X2 rpgxEF edition into the rpgxEF repo
... not quite content with where the project files lie but it is ok for
now.
... compiling works fine so far (only tested mingw32 right now)
2012-08-04 12:54:37 +02:00

463 lines
13 KiB
C

// Copyright (C) 1999-2000 Id Software, Inc.
//
//
// g_arenas.c
//
#include "g_local.h"
#ifndef min
#define min(a, b) (a) < (b) ? a : b
#endif
gentity_t *podium1;
gentity_t *podium2;
gentity_t *podium3;
/*
==================
UpdateTournamentInfo
==================
*/
void UpdateTournamentInfo( void ) {
int i = 0, j = 0, k = 0;
gentity_t *player = NULL, *ent = NULL;
int playerClientNum;
int n;
char msg[AWARDS_MSG_LENGTH], msg2[AWARDS_MSG_LENGTH];
int playerRank=level.numNonSpectatorClients-1, highestTiedRank = 0;
gentity_t *MVP = NULL;
int mvpNum = -1, mvpPoints = 0, winningCaptures = 0, winningPoints = 0;
int winningTeam=0;
int loseCaptures = 0, losePoints = 0;
char *mvpName = "";
gclient_t *cl = NULL;
gclient_t *cl2= NULL;
int secondPlaceTied=0;
memset(msg, 0, AWARDS_MSG_LENGTH);
memset(msg2, 0, AWARDS_MSG_LENGTH);
player = NULL;
// Was there a tie for second place on the podium?
cl = &level.clients[level.sortedClients[1]];
cl2= &level.clients[level.sortedClients[2]];
if (cl->ps.persistant[PERS_SCORE] == cl2->ps.persistant[PERS_SCORE])
secondPlaceTied=1;
winningTeam = level.clients[0].ps.persistant[PERS_RANK]+1;
if ( winningTeam != TEAM_BLUE && winningTeam != TEAM_RED )
{//tie or not a team game
winningTeam = 0;
}
// In team game, we want to represent the highest scored client from the WINNING team.
for (i = 0; i < level.maxclients; i++)
{
ent = &g_entities[i];
if (ent && ent->client &&
(ent->client->sess.sessionTeam != TEAM_SPECTATOR) &&
CalculateTeamMVPByRank(ent))
{
// found the winning team's MVP
mvpNum = i;
break;
}
}
if (mvpNum < 0)
{//ah, crap no MVP, pick the first player on the winning team
for (i = 0; i < level.maxclients; i++ )
{
if ( !&g_entities[i] ) continue;
if ( !(&g_entities[i])->client) continue;
if ( g_entities[i].client->ps.persistant[PERS_TEAM] == winningTeam )
{
mvpNum = i;
break;
}
}
}
if (mvpNum >= 0)
{//still no MVP, so skip it
MVP = &g_entities[mvpNum];
mvpName = MVP->client->pers.netname;
mvpPoints = MVP->client->ps.persistant[PERS_SCORE];
winningTeam = MVP->client->ps.persistant[PERS_TEAM];
}
if ( winningTeam )
{//one of the teams won
winningCaptures = level.teamScores[winningTeam];
if (winningTeam == TEAM_RED)
loseCaptures = level.teamScores[TEAM_BLUE];
else
loseCaptures = level.teamScores[TEAM_RED];
for (i = 0; i < level.maxclients; i++ )
{
if ( !&g_entities[i] ) continue;
if ( !(&g_entities[i])->client ) continue;
if ( g_entities[i].client->ps.persistant[PERS_TEAM] == winningTeam )
winningPoints += g_entities[i].client->ps.persistant[PERS_SCORE];
else
losePoints += g_entities[i].client->ps.persistant[PERS_SCORE];
}
}
for (i = 0; i < level.maxclients; i++ )
{
player = &g_entities[i];
if ( !player->inuse || (player->r.svFlags & SVF_BOT))
{
continue;
}
playerClientNum = i;
CalculateRanks( qfalse );
// put info for the top three players into the msg
Com_sprintf(msg, AWARDS_MSG_LENGTH, "awards %d", level.numNonSpectatorClients);
for( j = 0; j < level.numNonSpectatorClients; j++ )
{
if (j > 2)
{
break;
}
n = level.sortedClients[j];
strcpy(msg2, msg);
Com_sprintf(msg, AWARDS_MSG_LENGTH, "%s %d", msg2, n);
}
// put this guy's awards into the msg
if ( level.clients[playerClientNum].sess.sessionTeam == TEAM_SPECTATOR )
{
strcpy(msg2, msg);
Com_sprintf( msg, sizeof(msg), "%s 0", msg2);
}
else
{
CalculateAwards(player, msg);
}
// now supply...
//
// 1) winning team's MVP's name
// 2) winning team's MVP's score
// 3) winning team's total captures
// 4) winning team's total points
// 5) this player's rank
// 6) the highest rank for which this player tied
// 7) losing team's total captures
// 8) losing team's total points
// 9) if second place was tied
// 10) intermission point
// 11) intermission angles
//
for (k = 0; k < level.numNonSpectatorClients; k++)
{
if (level.sortedClients[k] == playerClientNum)
{
playerRank = k;
break;
}
}
highestTiedRank = 0;
for (k = playerRank-1; k >= 0; k--)
{
cl = &level.clients[level.sortedClients[k]];
if (cl->ps.persistant[PERS_SCORE] > level.clients[level.sortedClients[playerRank]].ps.persistant[PERS_SCORE])
{
break;
}
highestTiedRank = k+1;
}
strcpy(msg2, msg);
Com_sprintf(msg, AWARDS_MSG_LENGTH, "%s \"%s\" %d %d %d %d %d %d %d %d %f %f %f %f %f %f",
msg2, mvpName, mvpPoints, winningCaptures, winningPoints, playerRank, highestTiedRank,
loseCaptures, losePoints, secondPlaceTied, level.intermission_origin[0], level.intermission_origin[1],
level.intermission_origin[2], level.intermission_angle[0], level.intermission_angle[1],
level.intermission_angle[2]);
trap_SendServerCommand(player-g_entities, msg);
}
if (g_gametype.integer == GT_SINGLE_PLAYER)
{
Com_sprintf( msg, sizeof(msg), "postgame %i", playerRank);
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;
entityState_t *eState;
entityShared_t *eShared;
body = G_Spawn();
if ( !body ) {
G_Printf( S_COLOR_RED "ERROR: out of gentities\n" );
return NULL;
}
eState = &body->s;
eShared = &body->r;
body->classname = ent->client->pers.netname;
body->client = ent->client;
eState = &ent->s;
eState->eType = ET_PLAYER; // could be ET_INVISIBLE
eState->eFlags = 0; // clear EF_TALK, etc
eState->powerups = 0; // clear powerups
eState->loopSound = 0; // clear lava burning
eState->number = body - g_entities;
body->timestamp = level.time;
body->physicsObject = qtrue;
body->physicsBounce = 0; // don't bounce
eState->event = 0;
eState->pos.trType = TR_STATIONARY;
eState->groundEntityNum = ENTITYNUM_WORLD;
eState->legsAnim = BOTH_STAND1; //TORSO_STAND
eState->torsoAnim = BOTH_STAND1;
// fix up some weapon holding / shooting issues
if (eState->weapon==WP_5 || eState->weapon==WP_13 || eState->weapon == WP_0 )
eState->weapon = WP_6;
eState->event = 0;
eShared->svFlags = ent->r.svFlags;
VectorCopy (ent->r.mins, eShared->mins);
VectorCopy (ent->r.maxs, eShared->maxs);
VectorCopy (ent->r.absmin, eShared->absmin);
VectorCopy (ent->r.absmax, eShared->absmax);
body->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP;
eShared->contents = CONTENTS_BODY;
eShared->ownerNum = ent->r.ownerNum;
body->takedamage = qfalse;
VectorSubtract( level.intermission_origin, pad->r.currentOrigin, vec );
vectoangles( vec, eState->apos.trBase );
eState->apos.trBase[PITCH] = 0;
eState->apos.trBase[ROLL] = 0;
AngleVectors( eState->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 ) {
int anim;
anim = BOTH_STAND1; //TORSO_STAND
player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
}
#define TIMER_GESTURE (34*66+50)
extern void BG_AddPredictableEventToPlayerstate( int newEvent, int eventParm, playerState_t *ps );
static void CelebrateStart( gentity_t *player )
{
/*player->s.torsoAnim = ( ( player->s.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | TORSO_GESTURE;
player->nextthink = level.time + TIMER_GESTURE;
player->think = CelebrateStop;*/
// We don't want the taunt sound effect because it interfears with the computer voice giving awards
// FIXME: just get timing right?
//FIXME: why does this get lost now?
BG_AddPredictableEventToPlayerstate( EV_TAUNT, 0, &player->client->ps );
}
static vec3_t offsetFirst = {0, 0, 64};
static vec3_t offsetSecond = {-10, 60, 44};
static vec3_t offsetThird = {-19, -60, 35};
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;
if (g_gametype.integer > GT_SINGLE_PLAYER)
podium->s.modelindex = G_ModelIndex( TEAM_PODIUM_MODEL );
else
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;
int i = 0;
gentity_t *ent = &g_entities[0];
podium1 = NULL;
podium2 = NULL;
podium3 = NULL;
podium = SpawnPodium();
// SPAWN PLAYER ON TOP MOST PODIUM
if (g_gametype.integer > GT_SINGLE_PLAYER)
{
// In team game, we want to represent the highest scored client from the WINNING team.
for (i = 0; i < level.maxclients; i++)
{
ent = &g_entities[i];
if (ent->client && CalculateTeamMVPByRank(ent))
{
// found the winning team's MVP
break;
}
}
player = SpawnModelOnVictoryPad( podium, offsetFirst, ent,
level.clients[ level.sortedClients[0] ].ps.persistant[PERS_RANK] &~ RANK_TIED_FLAG );
}
else
{
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;
}
// For non team game types, we want to spawn 3 characters on the victory pad
// For team games (GT_TEAM, GT_CTF) we want to have only a single player on the pad
if (( g_gametype.integer == GT_FFA ) || (g_gametype.integer == GT_TOURNAMENT) || (g_gametype.integer == GT_SINGLE_PLAYER))
{
if ( level.numNonSpectatorClients > 1 ) {
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;
}
}