Added match and radio

This commit is contained in:
Aaron Dean 2023-09-05 12:47:49 -04:00
parent 931b33bca2
commit 9269c0eddf
10 changed files with 1600 additions and 61 deletions

608
actionlite/a_match.cpp Normal file
View file

@ -0,0 +1,608 @@
#include "g_local.h"
#include "a_match.h"
void SendScores(void)
{
unsigned int mins, secs, gametime = level.matchTime;
mins = gametime / 60;
secs = gametime % 60;
if(teamCount == 3) {
gi.bprintf(PRINT_HIGH, "\x9D\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9F\n");
gi.bprintf(PRINT_HIGH, " Team 1 Score - Team 2 Score - Team 3 Score\n");
gi.bprintf(PRINT_HIGH, " [%d] [%d] [%d]\n", teams[TEAM1].score, teams[TEAM2].score, teams[TEAM3].score);
gi.bprintf(PRINT_HIGH, " Total Played Time: %d:%02d\n", mins, secs);
gi.bprintf(PRINT_HIGH, "\x9D\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9F\n");
} else {
int team1score = 0, team2score = 0;
if(ctf->value) {
GetCTFScores(&team1score, &team2score);
} else {
team1score = teams[TEAM1].score;
team2score = teams[TEAM2].score;
}
gi.bprintf(PRINT_HIGH, "\x9D\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9F\n");
gi.bprintf(PRINT_HIGH, " Team 1 Score - Team 2 Score\n");
gi.bprintf(PRINT_HIGH, " [%d] [%d]\n", team1score, team2score);
gi.bprintf(PRINT_HIGH, " Total Played Time: %d:%02d\n", mins, secs);
gi.bprintf(PRINT_HIGH, "\x9D\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9E\x9F\n");
}
gi.bprintf(PRINT_HIGH, "Match is over, waiting for next map, please vote a new one..\n");
#if USE_AQTION
// Needed to add this here because Matchmode does not call BeginIntermission, but other teamplay modes do call it
if (stat_logs->value) {
LogMatch(); // Generates end of game stats
LogEndMatchStats(); // Generates end of match stats
}
#endif
// Stats: Reset roundNum
game.roundNum = 0;
// Stats end
#ifndef NO_BOTS
// Clear LTK bot names
LTKClearBotNames();
#endif
}
void Cmd_Sub_f(edict_t * ent)
{
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
if (ent->client->resp.team == NOTEAM) {
gi.cprintf(ent, PRINT_HIGH, "You need to be on a team for that...\n");
return;
}
if (!ent->client->resp.subteam) {
killPlayer(ent, true); // lets kill em.
gi.bprintf(PRINT_HIGH, "%s is now a substitute for %s\n", ent->client->pers.netname, teams[ent->client->resp.team].name);
ent->client->resp.subteam = ent->client->resp.team;
return;
}
gi.bprintf(PRINT_HIGH, "%s is no longer a substitute for %s\n", ent->client->pers.netname, teams[ent->client->resp.team].name);
ent->client->resp.subteam = 0;
if (team_round_going && !(gameSettings & GS_ROUNDBASED))
{
PutClientInServer (ent);
AddToTransparentList (ent);
}
}
/*
==============
MM_SetCaptain
==============
Set ent to be a captain of team, ent can be NULL to remove captain
*/
void MM_SetCaptain( int teamNum, edict_t *ent )
{
int i;
edict_t *oldCaptain = teams[teamNum].captain;
if (teamNum == NOTEAM)
ent = NULL;
teams[teamNum].captain = ent;
if (esp->value) {
EspSetLeader(teamNum, ent);
}
if (!ent) {
if (!team_round_going || (gameSettings & GS_ROUNDBASED)) {
if (teams[teamNum].ready) {
char temp[128];
Com_sprintf( temp, sizeof( temp ), "%s is no longer ready to play!", teams[teamNum].name );
CenterPrintAll( temp );
}
teams[teamNum].ready = 0;
}
if (oldCaptain) {
gi.bprintf( PRINT_HIGH, "%s is no longer %s's captain\n", oldCaptain->client->pers.netname, teams[teamNum].name );
}
teams[teamNum].locked = 0;
return;
}
if (ent != oldCaptain) {
gi.bprintf( PRINT_HIGH, "%s is now %s's captain\n", ent->client->pers.netname, teams[teamNum].name );
gi.cprintf( ent, PRINT_CHAT, "You are the captain of '%s'\n", teams[teamNum].name );
gi.sound( &g_edicts[0], CHAN_VOICE | CHAN_NO_PHS_ADD, gi.soundindex( "misc/comp_up.wav" ), 1.0, ATTN_NONE, 0.0 );
for (i = TEAM1; i <= teamCount; i++) {
if (i != teamNum && teams[i].wantReset)
gi.cprintf( ent, PRINT_HIGH, "Team %i wants to reset scores, type 'resetscores' to accept\n", i );
}
}
}
void MM_LeftTeam( edict_t *ent )
{
int teamNum = ent->client->resp.team;
if (teams[teamNum].captain == ent) {
MM_SetCaptain( teamNum, NULL );
}
ent->client->resp.subteam = 0;
}
qboolean TeamsReady( void )
{
int i, ready = 0;
for( i = TEAM1; i <= teamCount; i++ )
{
if( teams[i].ready )
ready ++;
else if( TeamHasPlayers(i) )
return false;
}
return (ready >= 2);
}
void Cmd_Captain_f(edict_t * ent)
{
int teamNum;
edict_t *oldCaptain;
// Aliases `captain` command to `volunteer` if Espionage is enabled
if (esp->value && !matchmode->value) {
Cmd_Volunteer_f(ent);
return;
}
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
teamNum = ent->client->resp.team;
if (teamNum == NOTEAM) {
gi.cprintf(ent, PRINT_HIGH, "You need to be on a team for that...\n");
return;
}
oldCaptain = teams[teamNum].captain;
if (oldCaptain == ent) {
MM_SetCaptain( teamNum, NULL );
if (esp->value) {
EspSetLeader(teamNum, NULL);
}
return;
}
if (oldCaptain) {
gi.cprintf( ent, PRINT_HIGH, "Your team already has a captain\n" );
return;
}
MM_SetCaptain( teamNum, ent );
if (esp->value) {
EspSetLeader( teamNum, ent );
}
}
//extern int started; // AQ2:M - Matchmode - Used for ready command
void Cmd_Ready_f(edict_t * ent)
{
char temp[128];
int teamNum;
team_t *team;
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
teamNum = ent->client->resp.team;
if (teamNum == NOTEAM) {
gi.cprintf( ent, PRINT_HIGH, "You need to be on a team for that...\n" );
return;
}
team = &teams[teamNum];
if (team->captain != ent) {
gi.cprintf( ent, PRINT_HIGH, "You need to be a captain for that\n" );
return;
}
if (!(gameSettings & GS_ROUNDBASED) && team_round_going) {
if(teamdm->value)
gi.cprintf(ent, PRINT_HIGH, "You can't unready in teamdm, use 'pausegame' instead\n");
else
gi.cprintf(ent, PRINT_HIGH, "You can't unready in ctf, use 'pausegame' instead\n");
return;
}
team->ready = !team->ready;
Com_sprintf( temp, sizeof( temp ), "%s %s ready to play!", team->name, (team->ready) ? "is" : "is no longer" );
CenterPrintAll( temp );
}
void Cmd_Teamname_f(edict_t * ent)
{
int i, argc, teamNum;
char temp[32];
team_t *team;
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
if(ctf->value) {
gi.cprintf(ent, PRINT_HIGH, "You can't change teamnames in CTF mode\n");
return;
}
if(esp->value) {
gi.cprintf(ent, PRINT_HIGH, "You can't change teamnames in Espionage mode\n");
return;
}
teamNum = ent->client->resp.team;
if (teamNum == NOTEAM) {
gi.cprintf( ent, PRINT_HIGH, "You need to be on a team for that...\n" );
return;
}
team = &teams[teamNum];
if (team->captain != ent) {
gi.cprintf( ent, PRINT_HIGH, "You need to be a captain for that\n" );
return;
}
if (team->ready) {
gi.cprintf( ent, PRINT_HIGH, "You can't use this while 'ready'\n" );
return;
}
if (team_round_going || team_game_going) {
gi.cprintf(ent, PRINT_HIGH, "You can't use this while playing\n");
return;
}
argc = gi.argc();
if (argc < 2) {
gi.cprintf( ent, PRINT_HIGH, "Your team name is %s\n", team->name );
return;
}
Q_strncpyz(temp, gi.argv(1), sizeof(temp));
for (i = 2; i < argc; i++) {
Q_strncatz(temp, " ", sizeof(temp));
Q_strncatz(temp, gi.argv(i), sizeof(temp));
}
temp[18] = 0;
if (!temp[0])
strcpy( temp, "noname" );
gi.dprintf("%s (team %i) is now known as %s\n", team->name, teamNum, temp);
IRC_printf(IRC_T_GAME, "%n (team %k) is now known as %n", team->name, teamNum, temp);
strcpy(team->name, temp);
gi.cprintf(ent, PRINT_HIGH, "New team name: %s\n", team->name);
}
void Cmd_Teamskin_f(edict_t * ent)
{
char *s, newskin[32];
int i, teamNum;
team_t *team;
edict_t *e;
if (!esp->value) {
gi.cprintf(ent, PRINT_HIGH, "Espionage skins are set in the .esp file\n");
return;
}
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
teamNum = ent->client->resp.team;
if (teamNum == NOTEAM) {
gi.cprintf(ent, PRINT_HIGH, "You need to be on a team for that...\n");
return;
}
team = &teams[teamNum];
if (team->captain != ent) {
gi.cprintf(ent, PRINT_HIGH, "You need to be a captain for that\n");
return;
}
if (team->ready) {
gi.cprintf(ent, PRINT_HIGH, "You can't use this while 'Ready'\n");
return;
}
if (team_round_going || team_game_going) {
gi.cprintf(ent, PRINT_HIGH, "You can't use this while playing\n");
return;
}
if (gi.argc() < 2) {
gi.cprintf(ent, PRINT_HIGH, "Your team skin is %s\n", team->skin);
return;
}
s = gi.argv(1);
Q_strncpyz(newskin, s, sizeof(newskin));
if(ctf->value) {
s = strchr(newskin, '/');
if(s)
s[1] = 0;
else
strcpy(newskin, "male/");
Q_strncatz(newskin, teamNum == 1 ? CTF_TEAM1_SKIN : CTF_TEAM2_SKIN, sizeof(newskin));
}
if (!strcmp(newskin, team->skin)) {
gi.cprintf(ent, PRINT_HIGH, "Your team skin is already %s\n", newskin);
return;
}
Q_strncpyz(team->skin, newskin, sizeof(team->skin));
Com_sprintf(team->skin_index, sizeof(team->skin_index), "../players/%s_i", team->skin );
level.pic_teamskin[teamNum] = gi.imageindex(team->skin_index);
for (i = 0, e = &g_edicts[1]; i < game.maxclients; i++, e++) { //lets update players skin
if (!e->inuse || !e->client)
continue;
if (e->client->resp.team == teamNum)
AssignSkin(e, team->skin, false);
}
gi.cprintf(ent, PRINT_HIGH, "New team skin: %s\n", team->skin);
}
void Cmd_TeamLock_f(edict_t *ent, int a_switch)
{
char msg[128], *s;
int teamNum, i;
team_t *team;
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
if (!mm_allowlock->value) {
gi.cprintf(ent, PRINT_HIGH, "Team locking is disabled on this server\n");
return;
}
//Admin can lock teams
if (ent->client->pers.admin && gi.argc() > 1)
{
s = gi.argv(1);
teamNum = TP_GetTeamFromArg(s);
if (teamNum < 1) {
gi.cprintf(ent, PRINT_HIGH, "Unknown team '%s'.\n", s);
return;
}
team = &teams[teamNum];
if (a_switch == team->locked) {
gi.cprintf(ent, PRINT_HIGH, "Team %s locked\n", (a_switch) ? "is already" : "isn't");
return;
}
if (a_switch) {
gclient_t *client;
for (i = 0, client = game.clients; i < game.maxclients; i++, client++) {
if (client->pers.connected && client->resp.team == teamNum)
break;
}
if (i == game.maxclients) {
gi.cprintf(ent, PRINT_HIGH, "You can't lock teams without players\n");
return;
}
}
}
else
{
teamNum = ent->client->resp.team;
if (teamNum == NOTEAM) {
gi.cprintf(ent, PRINT_HIGH, "You are not on a team\n");
return;
}
team = &teams[teamNum];
if (team->captain != ent) {
gi.cprintf(ent, PRINT_HIGH, "You are not the captain of your team\n");
return;
}
if (a_switch == team->locked) {
gi.cprintf(ent, PRINT_HIGH, "Your team %s locked\n", (a_switch) ? "is already" : "isn't");
return;
}
}
team->locked = a_switch;
Com_sprintf( msg, sizeof( msg ), "%s is now %s", team->name, (a_switch) ? "locked" : "unlocked" );
CenterPrintAll(msg);
}
void Cmd_SetAdmin_f (edict_t * ent)
{
if (ent->client->pers.admin) {
gi.cprintf( ent, PRINT_HIGH, "You are no longer a match admin.\n" );
gi.dprintf( "%s is no longer a match admin\n", ent->client->pers.netname );
ent->client->pers.admin = 0;
}
if(!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "Matchmode is not enabled on this server.\n");
return;
}
if (strcmp( mm_adminpwd->string, "0" ) == 0) {
gi.cprintf( ent, PRINT_HIGH, "Match admin mode is not enabled on this server..\n" );
return;
}
if (gi.argc() < 2) {
gi.cprintf (ent, PRINT_HIGH, "Usage: matchadmin <password>\n");
return;
}
if (strcmp( mm_adminpwd->string, gi.argv(1) )) {
gi.cprintf( ent, PRINT_HIGH, "Wrong password\n" );
return;
}
gi.cprintf (ent, PRINT_HIGH, "You are now a match admin.\n");
gi.dprintf ("%s is now a match admin\n", ent->client->pers.netname);
IRC_printf (IRC_T_GAME, "%n is now a match admin", ent->client->pers.netname);
ent->client->pers.admin = 1;
}
void Cmd_ResetScores_f(edict_t * ent)
{
int i, teamNum, otherCaptain = 0;
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
if (ent->client->pers.admin) //Admins can resetscores
{
ResetScores(true);
gi.bprintf(PRINT_HIGH, "Scores and time were reset by match admin %s\n", ent->client->pers.netname);
return;
}
teamNum = ent->client->resp.team;
if (teamNum == NOTEAM) {
gi.cprintf(ent, PRINT_HIGH, "You need to be on a team for that...\n");
return;
}
if (teams[teamNum].captain != ent) {
gi.cprintf(ent, PRINT_HIGH, "You need to be a captain for that\n");
return;
}
if (teams[teamNum].wantReset)
{
teams[teamNum].wantReset = 0;
for (i = TEAM1; i<teamCount + 1; i++) {
if (i != teamNum && teams[i].captain) {
gi.cprintf(teams[i].captain, PRINT_HIGH, "Team %i doesn't want to reset afterall", teamNum);
}
}
gi.cprintf(ent, PRINT_HIGH, "Your score reset request cancelled\n");
return;
}
teams[teamNum].wantReset = 1;
for(i = TEAM1; i<teamCount+1; i++) {
if(!teams[i].wantReset)
break;
}
if(i == teamCount+1)
{
ResetScores(true);
gi.bprintf(PRINT_HIGH, "Scores and time were reset by request of captains\n");
return;
}
for (; i<teamCount + 1; i++) {
if (!teams[i].wantReset && teams[i].captain) {
gi.cprintf(teams[i].captain, PRINT_HIGH, "Team %i wants to reset scores, type 'resetscores' to accept\n", teamNum);
otherCaptain = 1;
}
}
if(otherCaptain)
gi.cprintf(ent, PRINT_HIGH, "Your score reset request was sent to the other team captain\n");
else
gi.cprintf(ent, PRINT_HIGH, "Other team needs a captain and his acceptance to reset the scores\n");
}
void Cmd_TogglePause_f(edict_t * ent, qboolean pause)
{
static int lastPaused = 0;
int teamNum;
if (!matchmode->value) {
gi.cprintf(ent, PRINT_HIGH, "This command needs matchmode to be enabled\n");
return;
}
if ((int)mm_pausecount->value < 1) {
gi.cprintf(ent, PRINT_HIGH, "Pause is disabled, mm_pausecount is 0\n");
return;
}
if (mm_pausetime->value < FRAMETIME) {
gi.cprintf( ent, PRINT_HIGH, "Pause is disabled, mm_pausetime is 0\n" );
return;
}
teamNum = ent->client->resp.team;
if (teamNum == NOTEAM) {
gi.cprintf(ent, PRINT_HIGH, "You need to be on a team for that...\n");
return;
}
if (!team_round_going) {
gi.cprintf(ent, PRINT_HIGH, "No match running, so why pause?\n");
//return;
}
if (ent->client->resp.subteam) {
gi.cprintf(ent, PRINT_HIGH, "You can't pause when substitute\n");
return;
}
if(pause)
{
if(level.pauseFrames > 0)
{
gi.cprintf(ent, PRINT_HIGH, "Game is already paused you silly\n");
return;
}
if (level.intermission_framenum) {
gi.cprintf(ent, PRINT_HIGH, "Can't pause in an intermission.\n");
return;
}
if(teams[teamNum].pauses_used >= (int)mm_pausecount->value)
{
gi.cprintf(ent, PRINT_HIGH, "Your team doesn't have any pauses left.\n");
return;
}
teams[teamNum].pauses_used++;
CenterPrintAll (va("Game paused by %s\nTeam %i has %i pauses left", ent->client->pers.netname, ent->client->resp.team, (int)mm_pausecount->value - teams[ent->client->resp.team].pauses_used));
level.pauseFrames = (int)(mm_pausetime->value * 60.0f * HZ);
lastPaused = teamNum;
}
else
{
if (!level.pauseFrames)
{
gi.cprintf(ent, PRINT_HIGH, "Game is not paused\n");
return;
}
if(!lastPaused)
{
gi.cprintf(ent, PRINT_HIGH, "Already unpausing\n");
return;
}
if(lastPaused != teamNum)
{
gi.cprintf(ent, PRINT_HIGH, "You can't unpause when paused by the other team\n");
return;
}
level.pauseFrames = 10 * HZ;
lastPaused = 0;
}
}

17
actionlite/a_match.h Normal file
View file

@ -0,0 +1,17 @@
#define IS_CAPTAIN(ent) (teams[(ent)->client->resp.team].captain == (ent))
#define HAVE_CAPTAIN(teamNum) (teams[(teamNum)].captain)
void SendScores (void);
bool TeamsReady( void );
void MM_LeftTeam( edict_t * ent );
void Cmd_Captain_f (edict_t * ent);
void Cmd_Ready_f (edict_t * ent);
void Cmd_Sub_f (edict_t * ent);
void Cmd_Teamname_f (edict_t * ent);
void Cmd_Teamskin_f (edict_t * ent);
void Cmd_TeamLock_f (edict_t * ent, int a_switch);
int CheckForCaptains (int cteam);
void Cmd_SetAdmin_f (edict_t * ent);
void Cmd_TogglePause_f(edict_t * ent, bool pause);
void Cmd_ResetScores_f(edict_t * ent);

817
actionlite/a_radio.cpp Normal file
View file

@ -0,0 +1,817 @@
//-----------------------------------------------------------------------------
// Radio-related code for Action (formerly Axshun)
//
// -Fireblade
//
// $Id: a_radio.c,v 1.6 2004/04/08 23:19:51 slicerdw Exp $
//
//-----------------------------------------------------------------------------
// $Log: a_radio.c,v $
// Revision 1.6 2004/04/08 23:19:51 slicerdw
// Optimized some code, added a couple of features and fixed minor bugs
//
// Revision 1.5 2002/03/26 21:49:01 ra
// Bufferoverflow fixes
//
// Revision 1.4 2001/09/28 13:48:34 ra
// I ran indent over the sources. All .c and .h files reindented.
//
// Revision 1.3 2001/09/05 14:33:57 slicerdw
// Added Fix's from the 2.1 release
//
// Revision 1.2 2001/08/15 14:50:48 slicerdw
// Added Flood protections to Radio & Voice, Fixed the sniper bug AGAIN
//
// Revision 1.1.1.1 2001/05/06 17:24:29 igor_rock
// This is the PG Bund Edition V1.25 with all stuff laying around here...
//
//-----------------------------------------------------------------------------
#include "g_local.h"
void Cmd_Say_f (edict_t * ent, qboolean team, qboolean arg0,
qboolean partner_msg);
// Each of the possible radio messages and their length
typedef struct radio_msg_s
{
char *msg; // the msg name
int length; // length in server frames (ie tenths of a second), rounded up
int sndIndex;
} radio_msg_t;
static radio_msg_t male_radio_msgs[] = {
{"1", 6, 0},
{"2", 6, 0},
{"3", 8, 0},
{"4", 7, 0},
{"5", 8, 0},
{"6", 9, 0},
{"7", 8, 0},
{"8", 7, 0},
{"9", 7, 0},
{"10", 6, 0},
{"back", 6, 0},
{"cover", 7, 0},
{"down", 13, 0},
{"enemyd", 10, 0},
{"enemys", 9, 0},
{"forward", 6, 0},
{"go", 6, 0},
{"im_hit", 7, 0},
{"left", 7, 0},
{"reportin", 9, 0},
{"right", 6, 0},
{"taking_f", 22, 0},
{"teamdown", 13, 0},
{"treport", 12, 0},
{"up", 4, 0}
//{"END", 0, 0} // end of list delimiter
};
static radio_msg_t female_radio_msgs[] = {
{"1", 5, 0},
{"2", 5, 0},
{"3", 5, 0},
{"4", 5, 0},
{"5", 5, 0},
{"6", 8, 0},
{"7", 7, 0},
{"8", 5, 0},
{"9", 5, 0},
{"10", 5, 0},
{"back", 6, 0},
{"cover", 5, 0},
{"down", 6, 0},
{"enemyd", 9, 0},
{"enemys", 9, 0},
{"forward", 8, 0},
{"go", 6, 0},
{"im_hit", 7, 0},
{"left", 8, 0},
{"reportin", 9, 0},
{"right", 5, 0},
{"taking_f", 22, 0},
{"teamdown", 10, 0},
{"treport", 12, 0},
{"up", 6, 0}
//{"END", 0, 0}, // end of list delimiter
};
static const int numMaleSnds = ( sizeof( male_radio_msgs ) / sizeof( male_radio_msgs[0] ) );
static const int numFemaleSnds = ( sizeof( female_radio_msgs ) / sizeof( female_radio_msgs[0] ) );
#define RADIO_MALE_DIR "radio/male/"
#define RADIO_FEMALE_DIR "radio/female/"
#define RADIO_CLICK 0
#define RADIO_DEATH_MALE 1
#define RADIO_DEATH_FEMALE 2
radio_msg_t globalRadio[] = {
{"radio/click.wav", 2, 0},
{"radio/male/rdeath.wav", 27, 0},
{"radio/female/rdeath.wav", 30, 0}
};
void PrecacheRadioSounds ()
{
int i;
char path[MAX_QPATH];
globalRadio[RADIO_CLICK].sndIndex = gi.soundindex(globalRadio[RADIO_CLICK].msg);
globalRadio[RADIO_DEATH_MALE].sndIndex = gi.soundindex(globalRadio[RADIO_DEATH_MALE].msg);
globalRadio[RADIO_DEATH_FEMALE].sndIndex = gi.soundindex(globalRadio[RADIO_DEATH_FEMALE].msg);
//male
for(i = 0; i < numMaleSnds; i++)
{
Com_sprintf (path, sizeof(path), "%s%s.wav", RADIO_MALE_DIR, male_radio_msgs[i].msg);
male_radio_msgs[i].sndIndex = gi.soundindex(path);
}
//female
for(i = 0; i < numFemaleSnds; i++)
{
Com_sprintf (path, sizeof(path), "%s%s.wav", RADIO_FEMALE_DIR, female_radio_msgs[i].msg);
female_radio_msgs[i].sndIndex = gi.soundindex(path);
}
}
static void DeleteRadioQueueEntry( radio_t *radio, int entry_num )
{
int i;
if (radio->queue_size <= entry_num)
{
gi.dprintf("DeleteRadioQueueEntry: attempt to delete out of range queue entry: %i\n", entry_num);
return;
}
for (i = entry_num + 1; i < radio->queue_size; i++)
{
memcpy(&radio->queue[i - 1], &radio->queue[i], sizeof(radio_queue_entry_t));
}
radio->queue_size--;
}
// RadioThink should be called once on each player per server frame.
void RadioThink (edict_t * ent)
{
radio_t *radio = &ent->client->resp.radio;
// Try to clean things up, a bit....
if (radio->partner)
{
if (!radio->partner->inuse ||
radio->partner->client->resp.radio.partner != ent)
{
radio->partner = NULL;
}
}
if (radio->partner_last_offered_to)
{
if (!radio->partner_last_offered_to->inuse ||
radio->partner_last_offered_to->solid == SOLID_NOT)
{
radio->partner_last_offered_to = NULL;
}
}
if (radio->partner_last_denied_from)
{
if (!radio->partner_last_denied_from->inuse ||
radio->partner_last_denied_from->solid == SOLID_NOT)
{
radio->partner_last_denied_from = NULL;
}
}
// ................................
if (radio->power_off)
{
radio->queue_size = 0;
return;
}
if (radio->delay > 0)
{
radio->delay--;
if (radio->delay)
return;
}
if (radio->queue_size)
{
edict_t *from;
int check;
from = radio->queue[0].from_player;
if (!radio->queue[0].click && (!from->inuse || !IS_ALIVE(from)))
{
if (radio->queue[0].from_gender)
{
radio->queue[0].sndIndex = globalRadio[RADIO_DEATH_FEMALE].sndIndex;
radio->queue[0].length = globalRadio[RADIO_DEATH_FEMALE].length;
}
else
{
radio->queue[0].sndIndex = globalRadio[RADIO_DEATH_MALE].sndIndex;
radio->queue[0].length = globalRadio[RADIO_DEATH_MALE].length;
}
for (check = 1; check < radio->queue_size; check++)
{
if (!radio->queue[check].click && radio->queue[check].from_player == from)
{
DeleteRadioQueueEntry( radio, check );
check--;
}
}
}
if( ! IsInIgnoreList( ent, from ) )
{
unicastSound( ent, radio->queue[0].sndIndex, 1.0 );
radio->delay = radio->queue[0].length;
}
DeleteRadioQueueEntry( radio, 0 ); //We can remove it here?
}
}
static void AppendRadioMsgToQueue( radio_t *radio, int sndIndex, int len, int click, edict_t *from_player )
{
radio_queue_entry_t *newentry;
if (radio->queue_size >= MAX_RADIO_QUEUE_SIZE)
{
gi.dprintf("AppendRadioMsgToQueue: Maximum radio queue size exceeded\n");
return;
}
newentry = &radio->queue[radio->queue_size];
newentry->sndIndex = sndIndex;
newentry->from_player = from_player;
newentry->from_gender = from_player->client->resp.radio.gender;
newentry->length = len;
newentry->click = click;
radio->queue_size++;
}
static void InsertRadioMsgInQueueBeforeClick( radio_t *radio, int sndIndex, int len, edict_t *from_player )
{
radio_queue_entry_t *newentry;
if (radio->queue_size >= MAX_RADIO_QUEUE_SIZE)
{
gi.dprintf("InsertRadioMsgInQueueBeforeClick: Maximum radio queue size exceeded\n");
return;
}
newentry = &radio->queue[radio->queue_size - 1];
memcpy( &radio->queue[radio->queue_size], newentry, sizeof(radio_queue_entry_t));
newentry->sndIndex = sndIndex;
newentry->from_player = from_player;
newentry->from_gender = from_player->client->resp.radio.gender;
newentry->length = len;
newentry->click = 0;
radio->queue_size++;
}
static void AddRadioMsg( radio_t *radio, int sndIndex, int len, edict_t *from_player )
{
if (radio->queue_size == 0)
{
AppendRadioMsgToQueue( radio, globalRadio[RADIO_CLICK].sndIndex, globalRadio[RADIO_CLICK].length, 1, from_player );
AppendRadioMsgToQueue( radio, sndIndex, len, 0, from_player );
AppendRadioMsgToQueue( radio, globalRadio[RADIO_CLICK].sndIndex, globalRadio[RADIO_CLICK].length, 1, from_player );
}
else // we have some msgs in it already...
{
if (radio->queue_size < MAX_RADIO_QUEUE_SIZE)
InsertRadioMsgInQueueBeforeClick( radio, sndIndex, len, from_player );
// else ignore the message...
}
}
void RadioBroadcast (edict_t * ent, int partner, char *msg)
{
int j, i, msg_len, numSnds;
edict_t *other;
radio_msg_t *radio_msgs;
int msg_soundIndex = 0;
char msgname_num[8], filteredmsg[48];
qboolean found = false;
radio_t *radio;
if (!IS_ALIVE(ent))
return;
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
radio = &ent->client->resp.radio;
if (radio->power_off)
{
gi.centerprintf (ent, "Your radio is off!");
return;
}
if (partner && radio->partner == NULL)
{
gi.cprintf (ent, PRINT_HIGH, "You don't have a partner.\n");
return;
}
if (radio->gender)
{
radio_msgs = female_radio_msgs;
numSnds = numFemaleSnds;
}
else
{
radio_msgs = male_radio_msgs;
numSnds = numMaleSnds;
}
i = found = 0;
msg_len = 0;
Q_strncpyz(filteredmsg, msg, sizeof(filteredmsg));
for(i = 0; i < numSnds; i++)
{
if (!Q_stricmp(radio_msgs[i].msg, filteredmsg))
{
found = true;
msg_soundIndex = radio_msgs[i].sndIndex;
msg_len = radio_msgs[i].length;
break;
}
}
if (!found)
{
gi.centerprintf (ent, "'%s' is not a valid radio message", filteredmsg);
return;
}
if (radiolog->value)
{
gi.cprintf (NULL, PRINT_CHAT, "[%s RADIO] %s: %s\n",
partner ? "PARTNER" : "TEAM", ent->client->pers.netname, filteredmsg);
}
//TempFile BEGIN
if (Q_stricmp (filteredmsg, "enemyd") == 0)
{
if (ent->client->radio_num_kills > 1 && ent->client->radio_num_kills <= 10)
{
// If we are reporting enemy down, add the number of kills.
sprintf( msgname_num, "%i", ent->client->radio_num_kills );
ent->client->radio_num_kills = 0; // prevent from getting into an endless loop
RadioBroadcast(ent, partner, msgname_num); // Now THAT'S recursion! =)
}
ent->client->radio_num_kills = 0;
}
//TempFile END
//AQ2:TNG Slicer
if (radio_repeat->value)
{ //SLIC2 Optimization
if (CheckForRepeat (ent, i) == false)
return;
}
if (radio_max->value)
{
if (CheckForFlood (ent) == false)
return;
}
//AQ2:TNG END
for (j = 1; j <= game.maxclients; j++)
{
other = &g_edicts[j];
if (!other->inuse)
continue;
if (!other->client)
continue;
if (!OnSameTeam(ent, other))
continue;
if (partner && other != radio->partner)
continue;
AddRadioMsg( &other->client->resp.radio, msg_soundIndex, msg_len, ent );
}
}
void Cmd_Radio_f (edict_t * ent)
{
RadioBroadcast(ent, ent->client->resp.radio.partner_mode, gi.args());
}
void Cmd_Radiopartner_f (edict_t * ent)
{
RadioBroadcast(ent, 1, gi.args());
}
void Cmd_Radioteam_f (edict_t * ent)
{
RadioBroadcast(ent, 0, gi.args());
}
void Cmd_Radiogender_f (edict_t * ent)
{
char *arg;
radio_t *radio;
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
radio = &ent->client->resp.radio;
arg = gi.args();
if (arg == NULL || !*arg)
{
if (radio->gender)
gi.cprintf (ent, PRINT_HIGH, "Radio gender currently set to female\n");
else
gi.cprintf (ent, PRINT_HIGH, "Radio gender currently set to male\n");
return;
}
if (!Q_stricmp(arg, "male"))
{
gi.cprintf (ent, PRINT_HIGH, "Radio gender set to male\n");
radio->gender = 0;
}
else if (!Q_stricmp(arg, "female"))
{
gi.cprintf (ent, PRINT_HIGH, "Radio gender set to female\n");
radio->gender = 1;
}
else
{
gi.cprintf (ent, PRINT_HIGH, "Invalid gender selection, try 'male' or 'female'\n");
}
}
void Cmd_Radio_power_f (edict_t * ent)
{
radio_t *radio;
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
radio = &ent->client->resp.radio;
radio->power_off = !radio->power_off;
gi.centerprintf(ent, "Radio switched %s", (radio->power_off) ? "off" : "on");
unicastSound(ent, globalRadio[RADIO_CLICK].sndIndex, 1.0);
}
void Cmd_Channel_f (edict_t * ent)
{
radio_t *radio;
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
radio = &ent->client->resp.radio;
radio->partner_mode = !radio->partner_mode;
if (radio->partner_mode)
{
gi.centerprintf (ent, "Channel set to 1, partner channel");
}
else
{
gi.centerprintf (ent, "Channel set to 0, team channel");
}
}
edict_t *DetermineViewedPlayer(edict_t *ent, qboolean teammate);
void Cmd_Partner_f (edict_t * ent)
{
edict_t *target;
char *genderstr;
radio_t *radio, *tRadio;
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
if (!IS_ALIVE(ent))
return;
radio = &ent->client->resp.radio;
if (radio->partner) {
if (radio->partner->inuse) {
gi.centerprintf( ent, "You already have a partner, %s", radio->partner->client->pers.netname );
return;
}
// just in case RadioThink hasn't caught it yet... avoid any problems
radio->partner = NULL;
}
target = DetermineViewedPlayer(ent, true);
if (target == NULL) {
gi.centerprintf (ent, "No potential partner selected");
return;
}
tRadio = &target->client->resp.radio;
if (tRadio->partner) {
gi.centerprintf (ent, "%s already has a partner", target->client->pers.netname);
return;
}
if (tRadio->partner_last_offered_to == ent &&
radio->partner_last_offered_from == target)
{
gi.centerprintf (ent, "%s is now your partner", target->client->pers.netname);
gi.centerprintf (target, "%s is now your partner", ent->client->pers.netname);
radio->partner = target;
tRadio->partner = ent;
radio->partner_last_offered_from = NULL;
tRadio->partner_last_offered_to = NULL;
return;
}
if (tRadio->partner_last_denied_from == ent)
{
gi.centerprintf (ent, "%s has already denied you", target->client->pers.netname);
return;
}
if (target == radio->partner_last_offered_to)
{
genderstr = GENDER_STR(target, "him", "her", "it");
gi.centerprintf (ent, "Already awaiting confirmation from %s", genderstr);
return;
}
genderstr = GENDER_STR(ent, "him", "her", "it");
gi.centerprintf (ent, "Awaiting confirmation from %s", target->client->pers.netname);
gi.centerprintf (target,
"%s offers to be your partner\n"
"To accept:\nView %s and use the 'partner' command\n"
"To deny:\nUse the 'deny' command",
ent->client->pers.netname, genderstr);
radio->partner_last_offered_to = target;
tRadio->partner_last_offered_from = ent;
}
void Cmd_Unpartner_f (edict_t * ent)
{
edict_t *target;
radio_t *radio;
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
radio = &ent->client->resp.radio;
if (radio->partner && !radio->partner->inuse)
{ // just in case RadioThink hasn't caught it yet... avoid any problems
radio->partner = NULL;
}
target = radio->partner;
if (target == NULL) {
gi.centerprintf (ent, "You don't have a partner");
return;
}
if (target->client->resp.radio.partner == ent)
{
gi.centerprintf (target, "%s broke your partnership", ent->client->pers.netname);
target->client->resp.radio.partner = NULL;
}
gi.centerprintf (ent, "You broke your partnership with %s", target->client->pers.netname);
radio->partner = NULL;
}
void Cmd_Deny_f (edict_t * ent)
{
edict_t *target;
radio_t *radio;
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
if (!IS_ALIVE(ent))
return;
radio = &ent->client->resp.radio;
target = radio->partner_last_offered_from;
if (target && target->inuse)
{
gi.centerprintf (ent, "You denied %s", target->client->pers.netname);
gi.centerprintf (target, "%s has denied you", ent->client->pers.netname);
radio->partner_last_denied_from = target;
radio->partner_last_offered_from = NULL;
if (target->client->resp.radio.partner_last_offered_to == ent)
target->client->resp.radio.partner_last_offered_to = NULL;
}
else
{
gi.centerprintf (ent, "No one has offered to be your partner");
return;
}
}
void Cmd_Say_partner_f (edict_t * ent)
{
if (!teamplay->value)
{
if (!DMFLAGS( (DF_MODELTEAMS | DF_SKINTEAMS) ))
return; // don't allow in a non-team setup...
}
if (ent->client->resp.radio.partner == NULL)
{
gi.cprintf (ent, PRINT_HIGH, "You don't have a partner.\n");
return;
}
Cmd_Say_f (ent, false, false, true);
}
//SLIC2 Redesigned and optimized these two functions
qboolean CheckForFlood( edict_t * ent )
{
radio_t *radio = &ent->client->resp.radio;
//If he's muted..
if (radio->rd_mute) {
if (radio->rd_mute > level.framenum) // Still muted..
return false;
radio->rd_mute = 0; // No longer muted..
}
if (!radio->rd_Count) {
radio->rd_time = level.framenum;
radio->rd_Count++;
}
else {
if (level.framenum - radio->rd_time < (int)(radio_time->value * HZ)) {
if (++radio->rd_Count >= (int)radio_max->value) {
gi.cprintf( ent, PRINT_HIGH,
"[RADIO FLOOD PROTECTION]: Flood Detected, you are silenced for %d secs\n", (int)radio_ban->value );
radio->rd_mute = level.framenum + (int)(radio_ban->value * HZ);
return false;
}
}
else {
radio->rd_Count = 0;
}
}
return true;
}
qboolean CheckForRepeat( edict_t * ent, int radioCode )
{
radio_t *radio = &ent->client->resp.radio;
//If he's muted..
if (radio->rd_mute) {
if (radio->rd_mute > level.framenum) // Still muted..
return false;
radio->rd_mute = 0; // No longer muted..
}
if (radio->rd_lastRadio == radioCode) { //He's trying to repeat it..
if (level.framenum - radio->rd_repTime < (int)(radio_repeat_time->value * HZ)) {
if (++radio->rd_repCount == (int)radio_repeat->value) { //Busted
gi.cprintf( ent, PRINT_HIGH, "[RADIO FLOOD PROTECTION]: Repeat Flood Detected, you are silenced for %d secs\n", (int)radio_ban->value );
radio->rd_mute = level.framenum + (int)(radio_ban->value * HZ);
return false;
}
}
else {
radio->rd_repCount = 0;
}
}
else {
radio->rd_lastRadio = radioCode;
radio->rd_repCount = 0;
}
radio->rd_repTime = level.framenum;
return true;
}

55
actionlite/a_radio.h Normal file
View file

@ -0,0 +1,55 @@
#define MAX_SOUNDFILE_PATH_LEN 32 // max length of a sound file path
#define MAX_RADIO_MSG_QUEUE_SIZE 4
#define MAX_RADIO_QUEUE_SIZE 6 // this must be at least 2 greater than the above
typedef struct radio_queue_entry_s
{
int sndIndex;
edict_t *from_player;
int from_gender; // true if female
int length;
bool click;
} radio_queue_entry_t;
typedef struct radio_s
{
int delay;
radio_queue_entry_t queue[MAX_RADIO_QUEUE_SIZE];
int queue_size;
bool gender; // radiogender
bool power_off; // radio_power
// Partners stuff
bool partner_mode; // 'radio' command using team or partner
edict_t *partner; // current partner
edict_t *partner_last_offered_to; // last person I offered a partnership to
edict_t *partner_last_offered_from; // last person I received a partnership offer from
edict_t *partner_last_denied_from; // last person I denied a partnership offer from
//Flood & Repeat
int rd_mute; //Time to be muted
int rd_Count; //Counter for the last msgs in "xx" secs allowed
int rd_time; //Frame for the first radio message of the ones to follow
int rd_lastRadio; //Code of the last radio used
int rd_repCount; //Counter for the number of repeated radio msgs
int rd_repTime; //Frame for the last repeated radio msg
} radio_t;
void RadioThink (edict_t *);
void Cmd_Radio_f (edict_t *);
void Cmd_Radiogender_f (edict_t *);
void Cmd_Radio_power_f (edict_t *);
void Cmd_Radiopartner_f (edict_t *);
void Cmd_Radioteam_f (edict_t *);
void Cmd_Channel_f (edict_t *);
void Cmd_Say_partner_f (edict_t *);
void Cmd_Partner_f (edict_t *);
void Cmd_Deny_f (edict_t *);
void Cmd_Unpartner_f (edict_t *);
void PrecacheRadioSounds ();
bool CheckForFlood (edict_t * ent);
bool CheckForRepeat (edict_t * ent, int radioCode);

View file

@ -1858,10 +1858,6 @@ int CheckTeamRules (void)
if (!team_round_going)
{
RunWarmup();
if (!AllTeamsHaveLeaders())
return 1;
if (CheckTimelimit())
return 1;
@ -2061,7 +2057,7 @@ int G_SortedClients( gclient_t **sortedList )
gclient_t *client;
for (i = 0, client = game.clients; i < game.maxclients; i++, client++) {
if (!client->pers.connected || client->pers.mvdspec)
if (!client->pers.connected)
continue;
sortedList[total++] = client;
@ -2078,7 +2074,7 @@ int G_NotSortedClients( gclient_t **sortedList )
gclient_t *client;
for (i = 0, client = game.clients; i < game.maxclients; i++, client++) {
if (!client->pers.connected || client->pers.mvdspec)
if (!client->pers.connected)
continue;
sortedList[total++] = client;
@ -2290,14 +2286,14 @@ void A_ScoreboardMessage (edict_t * ent, edict_t * killer)
//Add team tag img
if (!ctf->value) {
Q_strncatz(string, "if 22 ", sizeof(string));
Q_strlcat(string, "if 22 ", sizeof(string));
len = strlen(string);
for (i = TEAM1, line_x = base_x + headerOffset; i <= teamCount; i++, line_x += rowWidth)
{
sprintf(string + len, "xv %i pic 22 ", line_x + 32);
len = strlen(string);
}
Q_strncatz(string, "endif ", sizeof(string));
Q_strlcat(string, "endif ", sizeof(string));
len = strlen(string);
}
@ -2421,11 +2417,11 @@ void A_ScoreboardMessage (edict_t * ent, edict_t * killer)
totalaliveprinted++;
playername[0] = 0;
if (IS_CAPTAIN(cl_ent) || IS_LEADER(cl_ent)) {
if (IS_CAPTAIN(cl_ent)) {
playername[0] = '@';
playername[1] = 0;
}
Q_strncatz(playername, cl->pers.netname, sizeof(playername));
Q_strlcat(playername, cl->pers.netname, sizeof(playername));
if (showExtra) {
sprintf( string + len,
"yv %d string%s \"%-15s %3d %3d %3d\" ",
@ -2764,7 +2760,6 @@ void GetSpawnPoints (void)
potential_spawns[num_potential_spawns] = spot;
num_potential_spawns++;
}
if ((spot = G_FindByString<&edict_t::classname>(spot, "info_player_team2") != nullptr))
{
potential_spawns[num_potential_spawns] = spot;

View file

@ -197,15 +197,15 @@ enum player_stat_t
STAT_CHASE = 16,
STAT_SPECTATOR = 17,
STAT_CTF_TEAM1_PIC = 18,
STAT_TEAM1_PIC = 18,
STAT_CTF_TEAM1_CAPS = 19,
STAT_CTF_TEAM2_PIC = 20,
STAT_TEAM2_PIC = 20,
STAT_CTF_TEAM2_CAPS = 21,
STAT_CTF_FLAG_PIC = 22,
STAT_CTF_JOINED_TEAM1_PIC = 23,
STAT_CTF_JOINED_TEAM2_PIC = 24,
STAT_CTF_TEAM1_HEADER = 25,
STAT_CTF_TEAM2_HEADER = 26,
STAT_FLAG_PIC = 22,
STAT_JOINED_TEAM1_PIC = 23,
STAT_JOINED_TEAM2_PIC = 24,
STAT_TEAM1_HEADER = 25,
STAT_TEAM2_HEADER = 26,
STAT_CTF_TECH = 27,
STAT_CTF_ID_VIEW = 28,
STAT_CTF_MATCH = 29,
@ -221,9 +221,10 @@ enum player_stat_t
STAT_POWERUP_INFO_END = STAT_POWERUP_INFO_START + NUM_POWERUP_STATS - 1,
// [Paril-KEX] Key display
STAT_KEY_A,
STAT_KEY_B,
STAT_KEY_C,
// Not used in Action, freeing up stat numbers
// STAT_KEY_A,
// STAT_KEY_B,
// STAT_KEY_C,
// [Paril-KEX] currently active wheel weapon (or one we're switching to)
STAT_ACTIVE_WHEEL_WEAPON,
@ -239,6 +240,25 @@ enum player_stat_t
STAT_HEALTH_BARS, // two health bar values; 7 bits for value, 1 bit for active
// if active,
// Action
STAT_CLIP_ICON,
STAT_CLIP,
STAT_SNIPER_ICON,
STAT_ITEMS_ICON,
STAT_WEAPONS_ICON,
STAT_ID_VIEW,
STAT_TEAM_HEADER,
STAT_TEAM1_SCORE,
STAT_TEAM2_SCORE,
STAT_TEAM3_SCORE,
STAT_GRENADE_ICON,
STAT_GRENADES,
STAT_TEAM3_PIC,
// don't use; just for verification
STAT_LAST
};

View file

@ -1027,8 +1027,8 @@ void SetCTFStats(edict_t *ent)
}
// logo headers for the frag display
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = imageindex_ctfsb1;
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = imageindex_ctfsb2;
ent->client->ps.stats[STAT_TEAM1_HEADER] = imageindex_ctfsb1;
ent->client->ps.stats[STAT_TEAM2_HEADER] = imageindex_ctfsb2;
bool blink = (level.time.milliseconds() % 1000) < 500;
@ -1038,17 +1038,17 @@ void SetCTFStats(edict_t *ent)
// blink half second
// note that ctfgame.total[12] is set when we go to intermission
if (ctfgame.team1 > ctfgame.team2)
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
ent->client->ps.stats[STAT_TEAM1_HEADER] = 0;
else if (ctfgame.team2 > ctfgame.team1)
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
ent->client->ps.stats[STAT_TEAM2_HEADER] = 0;
else if (ctfgame.total1 > ctfgame.total2) // frag tie breaker
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
ent->client->ps.stats[STAT_TEAM1_HEADER] = 0;
else if (ctfgame.total2 > ctfgame.total1)
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
ent->client->ps.stats[STAT_TEAM2_HEADER] = 0;
else
{ // tie game!
ent->client->ps.stats[STAT_CTF_TEAM1_HEADER] = 0;
ent->client->ps.stats[STAT_CTF_TEAM2_HEADER] = 0;
ent->client->ps.stats[STAT_TEAM1_HEADER] = 0;
ent->client->ps.stats[STAT_TEAM2_HEADER] = 0;
}
}
@ -1114,51 +1114,51 @@ void SetCTFStats(edict_t *ent)
p2 = imageindex_i_ctf2d; // must be dropped
}
ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
ent->client->ps.stats[STAT_TEAM1_PIC] = p1;
ent->client->ps.stats[STAT_TEAM2_PIC] = p2;
if (ctfgame.last_flag_capture && level.time - ctfgame.last_flag_capture < 5_sec)
{
if (ctfgame.last_capture_team == CTF_TEAM1)
if (blink)
ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = p1;
ent->client->ps.stats[STAT_TEAM1_PIC] = p1;
else
ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = 0;
ent->client->ps.stats[STAT_TEAM1_PIC] = 0;
else if (blink)
ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = p2;
ent->client->ps.stats[STAT_TEAM2_PIC] = p2;
else
ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = 0;
ent->client->ps.stats[STAT_TEAM2_PIC] = 0;
}
ent->client->ps.stats[STAT_CTF_TEAM1_CAPS] = ctfgame.team1;
ent->client->ps.stats[STAT_CTF_TEAM2_CAPS] = ctfgame.team2;
ent->client->ps.stats[STAT_CTF_FLAG_PIC] = 0;
ent->client->ps.stats[STAT_FLAG_PIC] = 0;
if (ent->client->resp.ctf_team == CTF_TEAM1 &&
ent->client->pers.inventory[IT_FLAG2] &&
(blink))
ent->client->ps.stats[STAT_CTF_FLAG_PIC] = imageindex_i_ctf2;
ent->client->ps.stats[STAT_FLAG_PIC] = imageindex_i_ctf2;
else if (ent->client->resp.ctf_team == CTF_TEAM2 &&
ent->client->pers.inventory[IT_FLAG1] &&
(blink))
ent->client->ps.stats[STAT_CTF_FLAG_PIC] = imageindex_i_ctf1;
ent->client->ps.stats[STAT_FLAG_PIC] = imageindex_i_ctf1;
}
else
{
ent->client->ps.stats[STAT_CTF_TEAM1_PIC] = imageindex_i_ctf1;
ent->client->ps.stats[STAT_CTF_TEAM2_PIC] = imageindex_i_ctf2;
ent->client->ps.stats[STAT_TEAM1_PIC] = imageindex_i_ctf1;
ent->client->ps.stats[STAT_TEAM2_PIC] = imageindex_i_ctf2;
ent->client->ps.stats[STAT_CTF_TEAM1_CAPS] = ctfgame.total1;
ent->client->ps.stats[STAT_CTF_TEAM2_CAPS] = ctfgame.total2;
}
ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = 0;
ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = 0;
ent->client->ps.stats[STAT_JOINED_TEAM1_PIC] = 0;
ent->client->ps.stats[STAT_JOINED_TEAM2_PIC] = 0;
if (ent->client->resp.ctf_team == CTF_TEAM1)
ent->client->ps.stats[STAT_CTF_JOINED_TEAM1_PIC] = imageindex_i_ctfj;
ent->client->ps.stats[STAT_JOINED_TEAM1_PIC] = imageindex_i_ctfj;
else if (ent->client->resp.ctf_team == CTF_TEAM2)
ent->client->ps.stats[STAT_CTF_JOINED_TEAM2_PIC] = imageindex_i_ctfj;
ent->client->ps.stats[STAT_JOINED_TEAM2_PIC] = imageindex_i_ctfj;
if (ent->client->resp.id_state)
CTFSetIDView(ent);

View file

@ -1064,10 +1064,14 @@ struct game_locals_t
std::array<level_entry_t, MAX_LEVELS_PER_UNIT> level_entries;
int32_t max_lag_origins;
vec3_t *lag_origins; // maxclients * max_lag_origins
// Action
int32_t roundNum;
};
constexpr size_t MAX_HEALTH_BARS = 2;
#define ITEM_MAX_NUM WEAPON_MAX+ITEM_MAX+AMMO_MAX_ANUM
//
// this structure is cleared as each map is entered
// it is read/written to the level.sav file for savegames
@ -1171,6 +1175,18 @@ struct level_locals_t
gtime_t next_match_report;
// Action add
int32_t pic_items[ITEM_MAX_NUM];
int32_t pic_weapon_ammo[WEAPON_MAX];
int32_t pic_sniper_mode[SNIPER_MODE_MAX];
int32_t pic_teamskin[TEAM_TOP];
int32_t pic_teamtag;
int32_t pic_ctf_teamtag[TEAM_TOP];
int32_t pic_ctf_flagbase[TEAM_TOP];
int32_t pic_ctf_flagtaken[TEAM_TOP];
int32_t pic_ctf_flagdropped[TEAM_TOP];
int32_t snd_silencer;
int32_t snd_headshot;
int32_t snd_vesthit;
@ -1919,12 +1935,12 @@ extern gitem_t itemlist[IT_TOTAL];
#define GS_ROUNDBASED 8
#define GS_WEAPONCHOOSE 16
// sniper modes
#define SNIPER_1X 0
#define SNIPER_2X 1
#define SNIPER_4X 2
#define SNIPER_6X 3
#define SNIPER_MODE_MAX 4
// // sniper modes
// #define SNIPER_1X 0
// #define SNIPER_2X 1
// #define SNIPER_4X 2
// #define SNIPER_6X 3
// #define SNIPER_MODE_MAX 4
//TempFile sniper zoom moved to constants
#define SNIPER_FOV1 90
@ -1985,6 +2001,13 @@ void SP_LaserSight (edict_t * self, gitem_t * item);
void Cmd_Reload_f (edict_t * ent);
void Cmd_New_Reload_f (edict_t * ent);
enum layout_t{
LAYOUT_NONE,
LAYOUT_SCORES,
LAYOUT_SCORES2,
LAYOUT_MENU
};
enum action_sniper_modes_t
{
SNIPER_1X,
@ -2029,7 +2052,7 @@ enum action_ammo_num_t
M4_ANUM,
SHELL_ANUM,
SNIPER_ANUM,
AMMO_MAX
AMMO_MAX_ANUM
};
constexpr item_id_t weap_ids[] = {
@ -2948,8 +2971,11 @@ struct client_respawn_t
// ZOID
// Action Add
int32_t enterframe; // frame when player entered the game
int32_t team_kills;
int32_t team_wounds;
int32_t joined_team; // last frame # at which the player joined a team
int32_t lastWave; //last time used wave
int32_t team;
int32_t subteam;
@ -2977,6 +3003,7 @@ struct client_respawn_t
int32_t streakHS; //Headshots in a Row
int32_t streakKillsHighest; //Highest kills in a row
int32_t streakHSHighest; //Highest headshots in a Row
int32_t damage_dealt;
int32_t hitsLocations[LOC_MAX]; //Number of hits for different locations
gunStats_t gunstats[MOD_TOTAL]; //Number of shots/hits for different guns, adjusted to MOD_TOTAL to allow grenade, kick and punch stats
@ -3141,7 +3168,6 @@ struct gclient_t
gtime_t respawn_time; // can respawn when time > this
edict_t *chase_target; // player we are chasing
bool update_chase; // need to update chase info?
//=======
@ -3224,13 +3250,14 @@ struct gclient_t
gtime_t last_attacker_time;
// Action Add
layout_t layout; // set layout stat
int32_t unique_item_total;
int32_t unique_weapon_total;
int32_t inventory[MAX_ITEMS];
int32_t inventory[MAX_ITEMS];
edict_t *chase_target;
int32_t chase_mode;
int32_t chase_mode;
// ammo capacities
int32_t ammo_index;
int32_t max_pistolmags;

View file

@ -1344,19 +1344,19 @@ static void G_InitStatusbar()
// ctf/tdm
// red team
sb.yb(-110).ifstat(STAT_CTF_TEAM1_PIC).xr(-26).pic(STAT_CTF_TEAM1_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM1_CAPS);
sb.yb(-110).ifstat(STAT_TEAM1_PIC).xr(-26).pic(STAT_TEAM1_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM1_CAPS);
// joined overlay
sb.ifstat(STAT_CTF_JOINED_TEAM1_PIC).yb(-112).xr(-28).pic(STAT_CTF_JOINED_TEAM1_PIC).endifstat();
sb.ifstat(STAT_JOINED_TEAM1_PIC).yb(-112).xr(-28).pic(STAT_JOINED_TEAM1_PIC).endifstat();
// blue team
sb.yb(-83).ifstat(STAT_CTF_TEAM2_PIC).xr(-26).pic(STAT_CTF_TEAM2_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM2_CAPS);
sb.yb(-83).ifstat(STAT_TEAM2_PIC).xr(-26).pic(STAT_TEAM2_PIC).endifstat().xr(-78).num(3, STAT_CTF_TEAM2_CAPS);
// joined overlay
sb.ifstat(STAT_CTF_JOINED_TEAM2_PIC).yb(-85).xr(-28).pic(STAT_CTF_JOINED_TEAM2_PIC).endifstat();
sb.ifstat(STAT_JOINED_TEAM2_PIC).yb(-85).xr(-28).pic(STAT_JOINED_TEAM2_PIC).endifstat();
if (ctf->integer)
{
// have flag graph
sb.ifstat(STAT_CTF_FLAG_PIC).yt(26).xr(-24).pic(STAT_CTF_FLAG_PIC).endifstat();
sb.ifstat(STAT_FLAG_PIC).yt(26).xr(-24).pic(STAT_FLAG_PIC).endifstat();
}
// id view state

View file

@ -3977,13 +3977,13 @@ edict_t *FindSpecWeapSpawn(edict_t* ent)
edict_t* spot = NULL;
//gi.bprintf (PRINT_HIGH, "Calling the FindSpecWeapSpawn\n");
spot = G_FindByString<&edict_t::classname>(spot, classname);
spot = G_FindByString<&edict_t::classname>(spot, ent->classname);
//spot = G_Find(spot, FOFS(classname), ent->classname);
//gi.bprintf (PRINT_HIGH, "spot = %p and spot->think = %p and playerholder = %p, spot, (spot ? spot->think : 0), PlaceHolder\n");
while (spot && spot->think != PlaceHolder) //(spot->spawnflags & DROPPED_ITEM ) && spot->think != PlaceHolder )//spot->solid == SOLID_NOT )
{
// gi.bprintf (PRINT_HIGH, "Calling inside the loop FindSpecWeapSpawn\n");
spot = G_FindByString<&edict_t::classname>(spot, classname);
spot = G_FindByString<&edict_t::classname>(spot, ent->classname);
//spot = G_Find(spot, FOFS(classname), ent->classname);
}
return spot;