381 lines
8 KiB
C
381 lines
8 KiB
C
|
#include "g_local.h"
|
||
|
#include "bg_saga.h"
|
||
|
|
||
|
char saga_info[MAX_SAGA_INFO_SIZE];
|
||
|
int saga_valid;
|
||
|
int saga_round_over;
|
||
|
|
||
|
int imperial_goals_required;
|
||
|
int imperial_goals_completed;
|
||
|
int rebel_goals_required;
|
||
|
int rebel_goals_completed;
|
||
|
|
||
|
int rebel_attackers;
|
||
|
int imperial_attackers;
|
||
|
|
||
|
void LogExit( const char *string );
|
||
|
|
||
|
int GetValueGroup(char *buf, char *group, char *outbuf);
|
||
|
int GetPairedValue(char *buf, char *key, char *outbuf);
|
||
|
//Using the bot parsing functions on saga ini's, at least for now.
|
||
|
|
||
|
void InitSagaMode(void)
|
||
|
{
|
||
|
vmCvar_t mapname;
|
||
|
char levelname[512];
|
||
|
char goalreq[64];
|
||
|
char objectives[MAX_SAGA_INFO_SIZE];
|
||
|
int len = 0;
|
||
|
fileHandle_t f;
|
||
|
|
||
|
if (g_gametype.integer != GT_SAGA)
|
||
|
{
|
||
|
goto failure;
|
||
|
}
|
||
|
|
||
|
imperial_goals_completed = 0;
|
||
|
rebel_goals_completed = 0;
|
||
|
|
||
|
saga_round_over = 0;
|
||
|
|
||
|
trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM );
|
||
|
|
||
|
Com_sprintf(levelname, sizeof(levelname), "maps/%s.saga\0", mapname.string);
|
||
|
|
||
|
if (!levelname || !levelname[0])
|
||
|
{
|
||
|
goto failure;
|
||
|
}
|
||
|
|
||
|
len = trap_FS_FOpenFile(levelname, &f, FS_READ);
|
||
|
|
||
|
if (!f || len >= MAX_SAGA_INFO_SIZE)
|
||
|
{
|
||
|
goto failure;
|
||
|
}
|
||
|
|
||
|
trap_FS_Read(saga_info, len, f);
|
||
|
|
||
|
saga_valid = 1;
|
||
|
|
||
|
if (GetValueGroup(saga_info, "Rebel", objectives))
|
||
|
{
|
||
|
if (GetPairedValue(objectives, "RequiredObjectives", goalreq))
|
||
|
{
|
||
|
rebel_goals_required = atoi(goalreq);
|
||
|
}
|
||
|
if (GetPairedValue(objectives, "attackers", goalreq))
|
||
|
{
|
||
|
rebel_attackers = atoi(goalreq);
|
||
|
}
|
||
|
}
|
||
|
if (GetValueGroup(saga_info, "Imperial", objectives))
|
||
|
{
|
||
|
if (GetPairedValue(objectives, "RequiredObjectives", goalreq))
|
||
|
{
|
||
|
imperial_goals_required = atoi(goalreq);
|
||
|
}
|
||
|
if (GetPairedValue(objectives, "attackers", goalreq))
|
||
|
{
|
||
|
imperial_attackers = atoi(goalreq);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
|
||
|
failure:
|
||
|
saga_valid = 0;
|
||
|
}
|
||
|
|
||
|
void UseSagaTarget(gentity_t *other, gentity_t *en, char *target)
|
||
|
{ //actually use the player which triggered the object which triggered the saga objective to trigger the target
|
||
|
gentity_t *t;
|
||
|
gentity_t *ent;
|
||
|
|
||
|
if ( !en || !en->client )
|
||
|
{ //looks like we don't have access to a player, so just use the activating entity
|
||
|
ent = other;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ent = en;
|
||
|
}
|
||
|
|
||
|
if (!en)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !target )
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
t = NULL;
|
||
|
while ( (t = G_Find (t, FOFS(targetname), target)) != NULL )
|
||
|
{
|
||
|
if ( t == ent )
|
||
|
{
|
||
|
G_Printf ("WARNING: Entity used itself.\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( t->use )
|
||
|
{
|
||
|
t->use (t, ent, ent);
|
||
|
}
|
||
|
}
|
||
|
if ( !ent->inuse )
|
||
|
{
|
||
|
G_Printf("entity was removed while using targets\n");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SagaBroadcast_OBJECTIVECOMPLETE(int team, int client, int objective)
|
||
|
{
|
||
|
gentity_t *te;
|
||
|
vec3_t nomatter;
|
||
|
|
||
|
VectorClear(nomatter);
|
||
|
|
||
|
te = G_TempEntity( nomatter, EV_SAGA_OBJECTIVECOMPLETE );
|
||
|
te->r.svFlags |= SVF_BROADCAST;
|
||
|
te->s.eventParm = team;
|
||
|
te->s.weapon = client;
|
||
|
te->s.trickedentindex = objective;
|
||
|
}
|
||
|
|
||
|
void SagaBroadcast_ROUNDOVER(int winningteam, int winningclient)
|
||
|
{
|
||
|
gentity_t *te;
|
||
|
vec3_t nomatter;
|
||
|
|
||
|
VectorClear(nomatter);
|
||
|
|
||
|
te = G_TempEntity( nomatter, EV_SAGA_ROUNDOVER );
|
||
|
te->r.svFlags |= SVF_BROADCAST;
|
||
|
te->s.eventParm = winningteam;
|
||
|
te->s.weapon = winningclient;
|
||
|
}
|
||
|
|
||
|
void BroadcastObjectiveCompletion(int team, int objective, int final, int client)
|
||
|
{
|
||
|
if (client != ENTITYNUM_NONE && g_entities[client].client && g_entities[client].client->sess.sessionTeam == team)
|
||
|
{ //guy who completed this objective gets points, providing he's on the opposing team
|
||
|
AddScore(&g_entities[client], g_entities[client].client->ps.origin, SAGA_POINTS_OBJECTIVECOMPLETED);
|
||
|
}
|
||
|
|
||
|
SagaBroadcast_OBJECTIVECOMPLETE(team, client, objective);
|
||
|
//G_Printf("Broadcast goal completion team %i objective %i final %i\n", team, objective, final);
|
||
|
}
|
||
|
|
||
|
void AddSagaWinningTeamPoints(int team, int winner)
|
||
|
{
|
||
|
int i = 0;
|
||
|
gentity_t *ent;
|
||
|
|
||
|
while (i < MAX_CLIENTS)
|
||
|
{
|
||
|
ent = &g_entities[i];
|
||
|
|
||
|
if (ent && ent->client && ent->client->sess.sessionTeam == team)
|
||
|
{
|
||
|
if (i == winner)
|
||
|
{
|
||
|
AddScore(ent, ent->client->ps.origin, SAGA_POINTS_TEAMWONROUND+SAGA_POINTS_FINALOBJECTIVECOMPLETED);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
AddScore(ent, ent->client->ps.origin, SAGA_POINTS_TEAMWONROUND);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SagaRoundComplete(int winningteam, int winningclient)
|
||
|
{
|
||
|
vec3_t nomatter;
|
||
|
|
||
|
saga_round_over = 1;
|
||
|
|
||
|
//G_Printf("Team %i won\n", winningteam);
|
||
|
|
||
|
if (winningclient != ENTITYNUM_NONE && g_entities[winningclient].client &&
|
||
|
g_entities[winningclient].client->sess.sessionTeam != winningteam)
|
||
|
{ //this person just won the round for the other team..
|
||
|
winningclient = ENTITYNUM_NONE;
|
||
|
}
|
||
|
|
||
|
VectorClear(nomatter);
|
||
|
|
||
|
SagaBroadcast_ROUNDOVER(winningteam, winningclient);
|
||
|
|
||
|
AddSagaWinningTeamPoints(winningteam, winningclient);
|
||
|
|
||
|
if (winningteam == SAGATEAM_IMPERIAL)
|
||
|
{
|
||
|
LogExit( "The Imperials completed their final objective." );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LogExit( "The Rebels completed their final objective." );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SagaObjectiveCompleted(int team, int objective, int final, int client)
|
||
|
{
|
||
|
int goals_completed, goals_required;
|
||
|
|
||
|
if (saga_round_over)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (final != -1)
|
||
|
{
|
||
|
if (team == SAGATEAM_IMPERIAL)
|
||
|
{
|
||
|
imperial_goals_completed++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
rebel_goals_completed++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (team == SAGATEAM_IMPERIAL)
|
||
|
{
|
||
|
goals_completed = imperial_goals_completed;
|
||
|
goals_required = imperial_goals_required;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
goals_completed = rebel_goals_completed;
|
||
|
goals_required = rebel_goals_required;
|
||
|
}
|
||
|
|
||
|
if (final == 1 || goals_completed >= goals_required)
|
||
|
{
|
||
|
SagaRoundComplete(team, client);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BroadcastObjectiveCompletion(team, objective, final, client);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void StripTabs(char *buf)
|
||
|
{
|
||
|
int i = 0;
|
||
|
int i_r = 0;
|
||
|
|
||
|
while (buf[i])
|
||
|
{
|
||
|
if (buf[i] != 9)
|
||
|
{
|
||
|
buf[i_r] = buf[i];
|
||
|
i_r++;
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
buf[i_r] = '\0';
|
||
|
}
|
||
|
|
||
|
void sagaTriggerUse(gentity_t *ent, gentity_t *other, gentity_t *activator)
|
||
|
{
|
||
|
char teamstr[64];
|
||
|
char objectivestr[64];
|
||
|
char objectives[MAX_SAGA_INFO_SIZE];
|
||
|
char desiredobjective[MAX_SAGA_INFO_SIZE];
|
||
|
int clUser = ENTITYNUM_NONE;
|
||
|
int final = 0;
|
||
|
int i = 0;
|
||
|
|
||
|
if (!saga_valid)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (activator && activator->client)
|
||
|
{ //activator will hopefully be the person who triggered this event
|
||
|
clUser = activator->s.number;
|
||
|
}
|
||
|
|
||
|
if (ent->side == SAGATEAM_IMPERIAL)
|
||
|
{
|
||
|
Com_sprintf(teamstr, sizeof(teamstr), "Imperial");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Com_sprintf(teamstr, sizeof(teamstr), "Rebel");
|
||
|
}
|
||
|
|
||
|
if (GetValueGroup(saga_info, teamstr, objectives))
|
||
|
{
|
||
|
Com_sprintf(objectivestr, sizeof(objectivestr), "Objective%i", ent->objective);
|
||
|
|
||
|
StripTabs(objectives); //tabs confuse the parsing function
|
||
|
|
||
|
if (GetValueGroup(objectives, objectivestr, desiredobjective))
|
||
|
{
|
||
|
if (GetPairedValue(desiredobjective, "final", teamstr))
|
||
|
{
|
||
|
final = atoi(teamstr);
|
||
|
}
|
||
|
|
||
|
if (GetPairedValue(desiredobjective, "target", teamstr))
|
||
|
{
|
||
|
while (teamstr[i])
|
||
|
{
|
||
|
if (teamstr[i] == '\r' ||
|
||
|
teamstr[i] == '\n')
|
||
|
{
|
||
|
teamstr[i] = '\0';
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
UseSagaTarget(other, activator, teamstr);
|
||
|
}
|
||
|
|
||
|
if (ent->target && ent->target[0])
|
||
|
{ //use this too
|
||
|
UseSagaTarget(other, activator, ent->target);
|
||
|
}
|
||
|
|
||
|
SagaObjectiveCompleted(ent->side, ent->objective, final, clUser);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*QUAKED info_saga_objective (1 0 1) (-16 -16 -24) (16 16 32)
|
||
|
"objective" - specifies the objective to complete upon activation
|
||
|
"side" - set to 1 to specify an imperial goal, 2 to specify rebels
|
||
|
*/
|
||
|
void SP_info_saga_objective (gentity_t *ent)
|
||
|
{
|
||
|
if (!saga_valid || g_gametype.integer != GT_SAGA)
|
||
|
{
|
||
|
G_FreeEntity(ent);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
ent->use = sagaTriggerUse;
|
||
|
G_SpawnInt( "objective", "0", &ent->objective);
|
||
|
G_SpawnInt( "side", "0", &ent->side);
|
||
|
|
||
|
if (!ent->objective || !ent->side)
|
||
|
{ //j00 fux0red something up
|
||
|
G_FreeEntity(ent);
|
||
|
G_Printf("ERROR: info_saga_objective without an objective or side value\n");
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|