mirror of
https://github.com/id-Software/quake2-rerelease-dll.git
synced 2025-03-14 12:20:45 +00:00
I think scope creep has set in, re-branching from here
This commit is contained in:
parent
9269c0eddf
commit
065e2edffe
19 changed files with 196 additions and 6744 deletions
|
@ -7,6 +7,12 @@ set(CMAKE_C_COMPILER "gcc")
|
|||
set(CMAKE_CXX_COMPILER "g++")
|
||||
|
||||
set(GAME_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/action/a_team.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/action/a_game.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/action/a_match.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/action/a_radio.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/action/cgf_sfx_glass.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bots/bot_debug.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bots/bot_exports.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bots/bot_think.cpp
|
||||
|
@ -45,10 +51,6 @@ set(GAME_SRC
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/p_weapon.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/q_std.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/a_team.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/a_game.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cgf_sfx_glass.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rogue/g_rogue_combat.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rogue/g_rogue_func.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rogue/g_rogue_items.cpp
|
||||
|
@ -94,7 +96,7 @@ set_target_properties(game PROPERTIES
|
|||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
set_target_properties(game PROPERTIES PREFIX "")
|
||||
set_target_properties(game PROPERTIES OUTPUT_NAME "gamex86")
|
||||
set_target_properties(game PROPERTIES OUTPUT_NAME "game")
|
||||
|
||||
# Fetch fmt locally
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,60 +0,0 @@
|
|||
// AQ2:TNG Deathwatch - Updated the Version variables to show TNG Stuff
|
||||
#ifndef VERSION
|
||||
#define VERSION "0.1"
|
||||
#endif
|
||||
#define TNG_TITLE "AQ2: The Next Generation Plus"
|
||||
// AQ2:TNG Deathwatch End
|
||||
//AQ2:TNG Slicer This is the max players writen on last killed target
|
||||
//SLIC2
|
||||
#define MAX_LAST_KILLED 8
|
||||
//AQ2:TNG END
|
||||
|
||||
extern char *map_rotation[];
|
||||
extern int num_maps, cur_map, rand_map, num_allvotes; // num_allvotes added by Igor[Rock]
|
||||
|
||||
void ReadConfigFile ();
|
||||
void ReadMOTDFile ();
|
||||
void PrintMOTD (edict_t *ent);
|
||||
void stuffcmd (edict_t *ent, char *s);
|
||||
void unicastSound(edict_t *ent, int soundIndex, float volume);
|
||||
|
||||
int KickDoor (trace_t * tr_old, edict_t * ent, vec3_t forward);
|
||||
|
||||
// Prototypes of base Q2 functions that weren't included in any Q2 header
|
||||
//bool loc_CanSee (edict_t *, edict_t *);
|
||||
void ParseSayText (edict_t *, char *, size_t size);
|
||||
|
||||
void AttachToEntity( edict_t *self, edict_t *onto );
|
||||
bool CanBeAttachedTo( const edict_t *ent );
|
||||
|
||||
//PG BUND - BEGIN
|
||||
//void ParseSayText(edict_t *, char *);
|
||||
void GetWeaponName (edict_t * ent, char *buf);
|
||||
void GetItemName (edict_t * ent, char *buf);
|
||||
void GetHealth (edict_t * ent, char *buf);
|
||||
void GetAmmo (edict_t * ent, char *buf);
|
||||
void GetNearbyTeammates (edict_t * self, char *buf);
|
||||
|
||||
void ResetScores (bool playerScores);
|
||||
void AddKilledPlayer (edict_t * self, edict_t * ent);
|
||||
void VideoCheckClient (edict_t * ent);
|
||||
//AQ2:TNG END
|
||||
//TempFile
|
||||
void GetLastLoss (edict_t * self, char *buf, char team);
|
||||
|
||||
// Firing styles (where shots originate from)
|
||||
#define ACTION_FIRING_CENTER 0
|
||||
#define ACTION_FIRING_CLASSIC 1
|
||||
#define ACTION_FIRING_CLASSIC_HIGH 2
|
||||
|
||||
// maxs[2] of a player when crouching (we modify it from the normal 4)
|
||||
// ...also the modified viewheight -FB 7/18/99
|
||||
#define CROUCHING_MAXS2 16
|
||||
#define CROUCHING_VIEWHEIGHT 8
|
||||
#define STANDING_VIEWHEIGHT 22
|
||||
|
||||
//a_team.c
|
||||
void MakeAllLivePlayersObservers( void );
|
||||
|
||||
//a_cmds.c
|
||||
void Cmd_NextMap_f( edict_t * ent );
|
|
@ -1,608 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#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);
|
|
@ -1,817 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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;
|
||||
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#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);
|
File diff suppressed because it is too large
Load diff
|
@ -1,112 +0,0 @@
|
|||
#include "g_local.h"
|
||||
|
||||
#define NOTEAM 0
|
||||
#define TEAM1 1
|
||||
#define TEAM2 2
|
||||
#define TEAM3 3
|
||||
|
||||
#define MAX_TEAMS 3
|
||||
#define TEAM_TOP (MAX_TEAMS+1)
|
||||
|
||||
#define WINNER_NONE NOTEAM
|
||||
#define WINNER_TIE TEAM_TOP
|
||||
|
||||
// Pre- and post-trace code for our teamplay anti-stick stuff. If there are
|
||||
// still "transparent" (SOLID_TRIGGER) players, they need to be set to
|
||||
// SOLID_BBOX before a trace is performed, then changed back again
|
||||
// afterwards. PRETRACE() and POSTTRACE() should be called before and after
|
||||
// traces in all places where combat is taking place (ie "transparent" players
|
||||
// should be detected), ie shots being traced etc.
|
||||
// FB 6/1/99: Now crouching players will have their bounding box adjusted here
|
||||
// too, for better shot areas. (there has to be a better way to do this?)
|
||||
|
||||
#define PRETRACE() \
|
||||
if (transparent_list && (((int)teamplay->value && !lights_camera_action))) \
|
||||
TransparentListSet(SOLID_BBOX)
|
||||
|
||||
#define POSTTRACE() \
|
||||
if (transparent_list && (((int)teamplay->value && !lights_camera_action))) \
|
||||
TransparentListSet(SOLID_TRIGGER)
|
||||
|
||||
edict_t *SelectTeamplaySpawnPoint (edict_t *);
|
||||
bool FallingDamageAmnesty (edict_t * targ);
|
||||
char * TeamName (int team);
|
||||
void UpdateJoinMenu( void );
|
||||
void OpenJoinMenu (edict_t *);
|
||||
void OpenWeaponMenu (edict_t *);
|
||||
void OpenItemMenu (edict_t * ent);
|
||||
void OpenItemKitMenu (edict_t * ent);
|
||||
void JoinTeam (edict_t * ent, int desired_team, int skip_menuclose);
|
||||
edict_t *FindOverlap (edict_t * ent, edict_t * last_overlap);
|
||||
int CheckTeamRules (void);
|
||||
void A_Scoreboard (edict_t * ent);
|
||||
void Team_f (edict_t * ent);
|
||||
void AssignSkin (edict_t * ent, const char *s, bool nickChanged);
|
||||
void TallyEndOfLevelTeamScores (void);
|
||||
void SetupTeamSpawnPoints ();
|
||||
int CheckTeamSpawnPoints ();
|
||||
void GetSpawnPoints ();
|
||||
void CleanBodies (); // from p_client.c, removes all current dead bodies from map
|
||||
|
||||
void LeaveTeam (edict_t *);
|
||||
int newrand (int top);
|
||||
void InitTransparentList ();
|
||||
void AddToTransparentList (edict_t *);
|
||||
void RemoveFromTransparentList (edict_t *);
|
||||
bool OnTransparentList( const edict_t *ent );
|
||||
void PrintTransparentList ();
|
||||
void CenterPrintAll (const char *msg);
|
||||
int TeamHasPlayers( int team );
|
||||
|
||||
//TNG:Freud - new spawning system
|
||||
void NS_GetSpawnPoints ();
|
||||
bool NS_SelectFarTeamplaySpawnPoint (int team, bool teams_assigned[]);
|
||||
void NS_SetupTeamSpawnPoints ();
|
||||
|
||||
int OtherTeam(int teamNum);
|
||||
|
||||
typedef struct spawn_distances_s
|
||||
{
|
||||
float distance;
|
||||
edict_t *s;
|
||||
}
|
||||
spawn_distances_t;
|
||||
|
||||
typedef struct transparent_list_s
|
||||
{
|
||||
edict_t *ent;
|
||||
struct transparent_list_s *next;
|
||||
}
|
||||
transparent_list_t;
|
||||
|
||||
|
||||
extern bool team_game_going;
|
||||
extern bool team_round_going;
|
||||
extern int lights_camera_action;
|
||||
extern int holding_on_tie_check;
|
||||
extern int team_round_countdown;
|
||||
extern int timewarning;
|
||||
extern int fragwarning;
|
||||
extern transparent_list_t *transparent_list;
|
||||
extern trace_t trace_t_temp;
|
||||
extern int current_round_length; // For RoundTimeLeft
|
||||
extern int day_cycle_at;
|
||||
extern int teamCount;
|
||||
extern int in_warmup;
|
||||
extern bool teams_changed;
|
||||
|
||||
typedef struct menu_list_weapon
|
||||
{
|
||||
int num;
|
||||
char sound[40];
|
||||
char name[40];
|
||||
}
|
||||
menu_list_weapon;
|
||||
|
||||
typedef struct menu_list_item
|
||||
{
|
||||
int num;
|
||||
char sound[40];
|
||||
char name[40];
|
||||
}
|
||||
menu_list_item;
|
|
@ -198,24 +198,28 @@ enum player_stat_t
|
|||
STAT_SPECTATOR = 17,
|
||||
|
||||
STAT_TEAM1_PIC = 18,
|
||||
STAT_CTF_TEAM1_CAPS = 19,
|
||||
STAT_TEAM2_PIC = 20,
|
||||
STAT_CTF_TEAM2_CAPS = 21,
|
||||
STAT_TEAM3_PIC = 21,
|
||||
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,
|
||||
STAT_CTF_ID_VIEW_COLOR = 30,
|
||||
STAT_CTF_TEAMINFO = 31,
|
||||
STAT_JOINED_TEAM3_PIC = 25,
|
||||
// Action: Consolidate team headers into level.pic_teamtag
|
||||
// STAT_TEAM1_HEADER = 25,
|
||||
// STAT_TEAM2_HEADER = 26,
|
||||
STAT_TEAM_HEADER = 26,
|
||||
STAT_CTF_TEAM1_CAPS = 27,
|
||||
STAT_CTF_TEAM2_CAPS = 28,
|
||||
STAT_CTF_TECH = 29,
|
||||
STAT_CTF_ID_VIEW = 30,
|
||||
STAT_CTF_MATCH = 31,
|
||||
STAT_CTF_ID_VIEW_COLOR = 32,
|
||||
STAT_CTF_TEAMINFO = 33,
|
||||
|
||||
// [Kex] More stats for weapon wheel
|
||||
STAT_WEAPONS_OWNED_1 = 32,
|
||||
STAT_WEAPONS_OWNED_2 = 33,
|
||||
STAT_AMMO_INFO_START = 34,
|
||||
STAT_WEAPONS_OWNED_1 = 34,
|
||||
STAT_WEAPONS_OWNED_2 = 35,
|
||||
STAT_AMMO_INFO_START = 36,
|
||||
STAT_AMMO_INFO_END = STAT_AMMO_INFO_START + NUM_AMMO_STATS - 1,
|
||||
STAT_POWERUP_INFO_START,
|
||||
STAT_POWERUP_INFO_END = STAT_POWERUP_INFO_START + NUM_POWERUP_STATS - 1,
|
||||
|
@ -247,18 +251,12 @@ enum player_stat_t
|
|||
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
|
||||
};
|
||||
|
|
|
@ -1,741 +0,0 @@
|
|||
/****************************************************************************/
|
||||
/* */
|
||||
/* project : CGF (c) 1999 William van der Sterren */
|
||||
/* parts (c) 1998 id software */
|
||||
/* */
|
||||
/* file : cgf_sfx_glass.cpp "special effects for glass entities" */
|
||||
/* author(s): William van der Sterren */
|
||||
/* version : 0.5 */
|
||||
/* */
|
||||
/* date (last revision): Jun 12, 99 */
|
||||
/* date (creation) : Jun 04, 99 */
|
||||
/* */
|
||||
/* */
|
||||
/* revision history */
|
||||
/* -- date ---- | -- revision ---------------------- | -- revisor -- */
|
||||
/* Jun 12, 1999 | fixed knife slash breaks glass | William */
|
||||
/* Jun 08, 1999 | improved fragment limit | William */
|
||||
/* */
|
||||
/******* http://www.botepidemic.com/aid/cgf for CGF for Action Quake2 *******/
|
||||
//
|
||||
// $Id: cgf_sfx_glass.c,v 1.2 2001/09/28 13:48:34 ra Exp $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: cgf_sfx_glass.c,v $
|
||||
// Revision 1.2 2001/09/28 13:48:34 ra
|
||||
// I ran indent over the sources. All .c and .h files reindented.
|
||||
//
|
||||
// Revision 1.1.1.1 2001/05/06 17:29:34 igor_rock
|
||||
// This is the PG Bund Edition V1.25 with all stuff laying around here...
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
// VC++, for CGF
|
||||
#include <cmath> // prevent problems between C and STL
|
||||
extern "C"
|
||||
{
|
||||
#include "g_local.h"
|
||||
#include "cgf_sfx_glass.h"
|
||||
}
|
||||
#else
|
||||
// C, for other AQ2 variants
|
||||
#include "g_local.h"
|
||||
#include "cgf_sfx_glass.h"
|
||||
#endif
|
||||
|
||||
|
||||
// cvar for breaking glass
|
||||
static cvar_t *breakableglass = 0;
|
||||
|
||||
// cvar for max glass fragment count
|
||||
static cvar_t *glassfragmentlimit = 0;
|
||||
|
||||
static int glassfragmentcount = 0;
|
||||
|
||||
|
||||
// additional functions - Q2 expects C calling convention
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void CGF_SFX_TouchGlass (edict_t * self, edict_t * other, cplane_t * plane,
|
||||
csurface_t * surf);
|
||||
// called whenever an entity hits the trigger spawned for the glass
|
||||
|
||||
void CGF_SFX_EmitGlass (edict_t * aGlassPane, edict_t * anInflictor,
|
||||
vec3_t aPoint);
|
||||
// emits glass fragments from aPoint, to show effects of firing thru window
|
||||
|
||||
void CGF_SFX_BreakGlass (edict_t * aGlassPane, edict_t * anOther,
|
||||
edict_t * anAttacker, int aDamage, vec3_t aPoint,
|
||||
vec_t aPaneDestructDelay);
|
||||
// breaks glass
|
||||
|
||||
void CGF_SFX_InstallBreakableGlass (edict_t * aGlassPane);
|
||||
// when working on a glass pane for the first time, just install trigger
|
||||
// when working on a glass pane again (after a game ended), move
|
||||
// glass back to original location
|
||||
|
||||
void CGF_SFX_HideBreakableGlass (edict_t * aGlassPane);
|
||||
// after being broken, the pane cannot be removed as it is needed in
|
||||
// subsequent missions/games, so hide it at about z = -1000
|
||||
|
||||
void CGF_SFX_ApplyGlassFragmentLimit (const char *aClassName);
|
||||
// updates glassfragmentcount and removes oldest glass fragement if
|
||||
// necessary to meet limit
|
||||
|
||||
void CGF_SFX_MiscGlassUse (edict_t * self, edict_t * other,
|
||||
edict_t * activator);
|
||||
// catches use from unforeseen objects (weapons, debris,
|
||||
// etc. touching the window)
|
||||
|
||||
void CGF_SFX_MiscGlassDie (edict_t * self, edict_t * inflictor,
|
||||
edict_t * attacker, int damage, vec3_t point);
|
||||
// catches die calls caused by unforeseen objects (weapons, debris,
|
||||
// etc. damaging the window)
|
||||
|
||||
void CGF_SFX_GlassThrowDebris (edict_t * self, char *modelname, float speed,
|
||||
vec3_t origin);
|
||||
// variant of id software's ThrowDebris, now numbering the entity (for later removal)
|
||||
|
||||
extern // from a_game.c
|
||||
edict_t *FindEdictByClassnum (char *classname, int classnum);
|
||||
|
||||
// declaration from g_misc.c
|
||||
extern // from g_misc.c
|
||||
void debris_die (edict_t * self, edict_t * inflictor, edict_t * attacker,
|
||||
int damage, vec3_t point);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_InstallGlassSupport ()
|
||||
{
|
||||
breakableglass = gi.cvar ("breakableglass", "0", 0);
|
||||
glassfragmentlimit = gi.cvar ("glassfragmentlimit", "30", 0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
CGF_SFX_IsBreakableGlassEnabled ()
|
||||
{
|
||||
// returns whether breakable glass is enabled (cvar) and allowed (dm mode)
|
||||
return breakableglass->value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think (edict_t *
|
||||
aPossibleGlassEntity)
|
||||
{
|
||||
// at level.time == 0.1 the entity has been introduced in the game,
|
||||
// and we can use gi.pointcontents and gi.trace to check the entity
|
||||
vec3_t origin;
|
||||
int breakingglass;
|
||||
trace_t trace;
|
||||
|
||||
// test for cvar
|
||||
if (!CGF_SFX_IsBreakableGlassEnabled ())
|
||||
{
|
||||
G_FreeEdict (aPossibleGlassEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
VectorAdd (aPossibleGlassEntity->absmax, aPossibleGlassEntity->absmin,
|
||||
origin);
|
||||
VectorScale (origin, 0.5, origin);
|
||||
|
||||
// detect glass (does not work for complex shapes,
|
||||
// for example, the glass window near the satellite
|
||||
// dish at Q2 base3
|
||||
breakingglass = (gi.pointcontents (origin) & CONTENTS_TRANSLUCENT);
|
||||
|
||||
if (!breakingglass)
|
||||
{
|
||||
// test for complex brushes that happen to be
|
||||
// hollow in their origin (for instance, the
|
||||
// window at Q2 base3, near the satellite dish
|
||||
trace =
|
||||
gi.trace (origin, vec3_origin, vec3_origin,
|
||||
aPossibleGlassEntity->absmax, 0, MASK_PLAYERSOLID);
|
||||
breakingglass = ((trace.ent == aPossibleGlassEntity)
|
||||
&& (trace.contents & CONTENTS_TRANSLUCENT));
|
||||
trace =
|
||||
gi.trace (origin, vec3_origin, vec3_origin,
|
||||
aPossibleGlassEntity->absmin, 0, MASK_PLAYERSOLID);
|
||||
breakingglass = ((breakingglass)
|
||||
|| ((trace.ent == aPossibleGlassEntity)
|
||||
&& (trace.contents & CONTENTS_TRANSLUCENT)));
|
||||
}
|
||||
|
||||
if (!breakingglass)
|
||||
{
|
||||
// do remove other func_explosives
|
||||
G_FreeEdict (aPossibleGlassEntity);
|
||||
return;
|
||||
}
|
||||
|
||||
// discovered some glass - now make store the origin
|
||||
// we need that after hiding the glass
|
||||
VectorCopy (aPossibleGlassEntity->s.origin, aPossibleGlassEntity->pos1); // IMPORTANT!
|
||||
|
||||
// make a backup of the health in light_level
|
||||
aPossibleGlassEntity->light_level = aPossibleGlassEntity->health;
|
||||
|
||||
// install the glass
|
||||
CGF_SFX_InstallBreakableGlass (aPossibleGlassEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_InstallBreakableGlass (edict_t * aGlassPane)
|
||||
{
|
||||
// when working on a glass pane for the first time, just install trigger
|
||||
// when working on a glass pane again (after a game ended), move
|
||||
// glass back to original location
|
||||
edict_t *trigger;
|
||||
vec3_t maxs;
|
||||
vec3_t mins;
|
||||
|
||||
// reset origin based on aGlassPane->pos1
|
||||
VectorCopy (aGlassPane->pos1, aGlassPane->s.origin);
|
||||
|
||||
// reset health based on aGlassPane->light_level
|
||||
aGlassPane->health = aGlassPane->light_level;
|
||||
|
||||
// replace die and use functions by glass specific ones
|
||||
aGlassPane->die = CGF_SFX_MiscGlassDie;
|
||||
aGlassPane->use = CGF_SFX_MiscGlassUse;
|
||||
|
||||
// reset some pane attributes
|
||||
aGlassPane->takedamage = DAMAGE_YES;
|
||||
aGlassPane->solid = SOLID_BSP;
|
||||
aGlassPane->movetype = MOVETYPE_FLYMISSILE;
|
||||
// for other movetypes, cannot move pane to hidden location and back
|
||||
|
||||
// try to establish size
|
||||
VectorCopy (aGlassPane->maxs, maxs);
|
||||
VectorCopy (aGlassPane->mins, mins);
|
||||
|
||||
// set up trigger, similar to triggers for doors
|
||||
// but with a smaller box
|
||||
mins[0] -= 24;
|
||||
mins[1] -= 24;
|
||||
mins[2] -= 24;
|
||||
maxs[0] += 24;
|
||||
maxs[1] += 24;
|
||||
maxs[2] += 24;
|
||||
|
||||
// adjust some settings
|
||||
trigger = G_Spawn ();
|
||||
trigger->classname = "breakableglass_trigger";
|
||||
VectorCopy (mins, trigger->mins);
|
||||
VectorCopy (maxs, trigger->maxs);
|
||||
trigger->owner = aGlassPane;
|
||||
trigger->solid = SOLID_TRIGGER;
|
||||
trigger->movetype = MOVETYPE_NONE;
|
||||
trigger->touch = CGF_SFX_TouchGlass;
|
||||
gi.linkentity (trigger);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_ShootBreakableGlass (edict_t * aGlassPane, edict_t * anAttacker,
|
||||
/*trace_t* */ void *tr,
|
||||
int mod)
|
||||
{
|
||||
// process gunshots thru glass
|
||||
edict_t *trigger;
|
||||
int destruct;
|
||||
|
||||
// depending on mod, destroy window or emit fragments
|
||||
switch (mod)
|
||||
{
|
||||
// break for ap, shotgun, handcannon, and kick, destory window
|
||||
case MOD_M3:
|
||||
case MOD_HC:
|
||||
case MOD_SNIPER:
|
||||
case MOD_KICK:
|
||||
case MOD_GRENADE:
|
||||
case MOD_G_SPLASH:
|
||||
case MOD_HANDGRENADE:
|
||||
case MOD_HG_SPLASH:
|
||||
case MOD_KNIFE: // slash damage
|
||||
destruct = true;
|
||||
break;
|
||||
default:
|
||||
destruct = (rand () % 3 == 0);
|
||||
break;
|
||||
};
|
||||
|
||||
if (destruct)
|
||||
{
|
||||
// break glass (and hurt if doing kick)
|
||||
CGF_SFX_BreakGlass (aGlassPane, anAttacker, 0, aGlassPane->health,
|
||||
vec3_origin, FRAMETIME);
|
||||
if (mod.id == MOD_KICK)
|
||||
{
|
||||
vec3_t bloodorigin;
|
||||
vec3_t dir;
|
||||
vec3_t normal;
|
||||
VectorAdd (aGlassPane->absmax, aGlassPane->absmin, bloodorigin);
|
||||
VectorScale (bloodorigin, 0.5, bloodorigin);
|
||||
VectorSubtract (bloodorigin, anAttacker->s.origin, dir);
|
||||
VectorNormalize (dir);
|
||||
VectorMA (anAttacker->s.origin, 32.0, dir, bloodorigin);
|
||||
VectorSet (normal, 0, 0, -1);
|
||||
T_Damage (anAttacker, aGlassPane, anAttacker, dir, bloodorigin,
|
||||
normal, 15.0, 0, 0, MOD_BREAKINGGLASS);
|
||||
}
|
||||
|
||||
// remove corresponding trigger
|
||||
trigger = 0;
|
||||
while ((trigger = G_Find (trigger, FOFS (classname), "breakableglass_trigger")) != NULL)
|
||||
{
|
||||
if (trigger->owner == aGlassPane)
|
||||
{
|
||||
// remove it
|
||||
G_FreeEdict (trigger);
|
||||
// only one to be found
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add decal (if not grenade)
|
||||
if ((mod != MOD_HANDGRENADE)
|
||||
&& (mod != MOD_HG_SPLASH)
|
||||
&& (mod != MOD_GRENADE) && (mod != MOD_G_SPLASH))
|
||||
{
|
||||
AddDecal (anAttacker, (trace_t *) tr);
|
||||
}
|
||||
// and emit glass
|
||||
CGF_SFX_EmitGlass (aGlassPane, anAttacker, ((trace_t *) tr)->endpos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_TouchGlass (edict_t * self, edict_t * other, cplane_t * plane,
|
||||
csurface_t * surf)
|
||||
{
|
||||
// called whenever an entity hits the trigger spawned for the glass
|
||||
|
||||
vec3_t origin;
|
||||
vec3_t normal;
|
||||
vec3_t spot;
|
||||
trace_t trace;
|
||||
edict_t *glass;
|
||||
vec3_t velocity;
|
||||
vec_t speed;
|
||||
vec_t projected_speed;
|
||||
int is_hgrenade;
|
||||
int is_knife;
|
||||
|
||||
is_hgrenade = is_knife = false;
|
||||
|
||||
// ignore non-clients-non-grenade-non-knife
|
||||
if (!other->client)
|
||||
{
|
||||
is_knife = (0 == Q_stricmp ("weapon_knife", other->classname));
|
||||
if (!is_knife)
|
||||
{
|
||||
is_hgrenade = (0 == Q_stricmp ("hgrenade", other->classname));
|
||||
}
|
||||
|
||||
if ((!is_knife) && (!is_hgrenade))
|
||||
return;
|
||||
if (is_knife)
|
||||
goto knife_and_grenade_handling;
|
||||
}
|
||||
|
||||
// test whether other really hits the glass - deal with
|
||||
// the special case that other hits some boundary close to the border of the glass pane
|
||||
//
|
||||
//
|
||||
// ....trigger.......
|
||||
// +++++++++ +++++++++++
|
||||
// .+---glass------+.
|
||||
// wall .+--------------+.wall
|
||||
// +++++++++ +++++++++++
|
||||
// ----->..................
|
||||
// wrong ^ ^
|
||||
// | |
|
||||
// wrong ok
|
||||
//
|
||||
glass = self->owner;
|
||||
// hack - set glass' movetype to MOVETYPE_PUSH as it is not
|
||||
// moving as long as the trigger is active
|
||||
glass->movetype = MOVETYPE_PUSH;
|
||||
|
||||
VectorAdd (glass->absmax, glass->absmin, origin);
|
||||
VectorScale (origin, 0.5, origin);
|
||||
|
||||
// other needs to be able to trace to glass origin
|
||||
trace = gi.trace (other->s.origin, vec3_origin, vec3_origin, origin, other,
|
||||
MASK_PLAYERSOLID);
|
||||
if (trace.ent != glass)
|
||||
return;
|
||||
|
||||
// we can reach the glass origin, so we have the normal of
|
||||
// the glass plane
|
||||
VectorCopy (trace.plane.normal, normal);
|
||||
|
||||
// we need to check if client is not running into wall next
|
||||
// to the glass (the trigger stretches into the wall)
|
||||
VectorScale (normal, -1000.0, spot);
|
||||
VectorAdd (spot, other->s.origin, spot);
|
||||
// line between other->s.origin and spot (perpendicular to glass
|
||||
// surface should not hit wall but glass instead
|
||||
trace = gi.trace (other->s.origin, vec3_origin, vec3_origin, spot, other,
|
||||
MASK_PLAYERSOLID);
|
||||
if (trace.ent != glass)
|
||||
return;
|
||||
|
||||
// now, we check if the client's speed perpendicular to
|
||||
// the glass plane, exceeds the required 175
|
||||
// (speed should be < -200, as the plane's normal
|
||||
// points towards the client
|
||||
VectorCopy (other->velocity, velocity);
|
||||
speed = VectorNormalize (velocity);
|
||||
projected_speed = speed * DotProduct (velocity, normal);
|
||||
|
||||
// bump projected speed for grenades - they should break
|
||||
// the window more easily
|
||||
if (is_hgrenade)
|
||||
projected_speed *= 1.5f;
|
||||
|
||||
// if hitting the glass with sufficient speed (project < -175),
|
||||
// being jumpkicked (speed > 700, project < -5) break the window
|
||||
if (!((projected_speed < -175.0) ||
|
||||
((projected_speed < -5) && (speed > 700))))
|
||||
goto knife_and_grenade_handling;
|
||||
|
||||
// break glass
|
||||
CGF_SFX_BreakGlass (glass, other, other, glass->health, vec3_origin,
|
||||
3.0f * FRAMETIME);
|
||||
// glass can take care of itself, but the trigger isn't needed anymore
|
||||
G_FreeEdict (self);
|
||||
|
||||
/* not needed
|
||||
// reduce momentum of the client (he just broke the window
|
||||
// so he should lose speed. in addition, it doesn't feel
|
||||
// right if he overtakes the glass fragments
|
||||
// VectorScale(normal, 200.0, velocity);
|
||||
// VectorAdd(other->velocity, velocity, other->velocity);
|
||||
*/
|
||||
|
||||
// make sure client takes damage
|
||||
T_Damage (other, glass, other, normal, other->s.origin, normal, 15.0, 0, 0,
|
||||
MOD_BREAKINGGLASS);
|
||||
return;
|
||||
|
||||
// goto label
|
||||
knife_and_grenade_handling:
|
||||
// if knife or grenade, bounce them
|
||||
if ((is_knife) || (is_hgrenade))
|
||||
{
|
||||
// change clipmask to bounce of glass
|
||||
other->clipmask = MASK_SOLID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_BreakGlass (edict_t * aGlassPane, edict_t * anInflictor,
|
||||
edict_t * anAttacker, int aDamage, vec3_t aPoint,
|
||||
vec_t aPaneDestructDelay)
|
||||
{
|
||||
// based on func_explode, but with lotsa subtle differences
|
||||
vec3_t origin;
|
||||
vec3_t old_origin;
|
||||
vec3_t chunkorigin;
|
||||
vec3_t size;
|
||||
int count;
|
||||
int mass;
|
||||
|
||||
// bmodel origins are (0 0 0), we need to adjust that here
|
||||
VectorCopy (aGlassPane->s.origin, old_origin);
|
||||
VectorScale (aGlassPane->size, 0.5, size);
|
||||
VectorAdd (aGlassPane->absmin, size, origin);
|
||||
VectorCopy (origin, aGlassPane->s.origin);
|
||||
|
||||
aGlassPane->takedamage = DAMAGE_NO;
|
||||
|
||||
VectorSubtract (aGlassPane->s.origin, anInflictor->s.origin,
|
||||
aGlassPane->velocity);
|
||||
VectorNormalize (aGlassPane->velocity);
|
||||
// use speed 250 instead of 150 for funkier glass spray
|
||||
VectorScale (aGlassPane->velocity, 250.0, aGlassPane->velocity);
|
||||
|
||||
// start chunks towards the center
|
||||
VectorScale (size, 0.75, size);
|
||||
|
||||
mass = aGlassPane->mass;
|
||||
if (!mass)
|
||||
mass = 75;
|
||||
|
||||
// big chunks
|
||||
if (mass >= 100)
|
||||
{
|
||||
count = mass / 100;
|
||||
if (count > 8)
|
||||
count = 8;
|
||||
while (count--)
|
||||
{
|
||||
CGF_SFX_ApplyGlassFragmentLimit ("debris");
|
||||
chunkorigin[0] = origin[0] + crandom () * size[0];
|
||||
chunkorigin[1] = origin[1] + crandom () * size[1];
|
||||
chunkorigin[2] = origin[2] + crandom () * size[2];
|
||||
CGF_SFX_GlassThrowDebris (aGlassPane,
|
||||
"models/objects/debris1/tris.md2", 1,
|
||||
chunkorigin);
|
||||
}
|
||||
}
|
||||
|
||||
// small chunks
|
||||
count = mass / 25;
|
||||
if (count > 16)
|
||||
count = 16;
|
||||
while (count--)
|
||||
{
|
||||
CGF_SFX_ApplyGlassFragmentLimit ("debris");
|
||||
chunkorigin[0] = origin[0] + crandom () * size[0];
|
||||
chunkorigin[1] = origin[1] + crandom () * size[1];
|
||||
chunkorigin[2] = origin[2] + crandom () * size[2];
|
||||
CGF_SFX_GlassThrowDebris (aGlassPane, "models/objects/debris2/tris.md2",
|
||||
2, chunkorigin);
|
||||
}
|
||||
|
||||
// clear velocity, reset origin (that has been abused in ThrowDebris)
|
||||
VectorClear (aGlassPane->velocity);
|
||||
VectorCopy (old_origin, aGlassPane->s.origin);
|
||||
|
||||
if (anAttacker)
|
||||
{
|
||||
// jumping thru
|
||||
G_UseTargets (aGlassPane, anAttacker);
|
||||
}
|
||||
else
|
||||
{
|
||||
// firing thru - the pane has no direct attacker to hurt,
|
||||
// but G_UseTargets expects one. So make it a DIY
|
||||
G_UseTargets (aGlassPane, aGlassPane);
|
||||
}
|
||||
|
||||
// have glass plane be visible for two more frames,
|
||||
// and have it self-destruct then
|
||||
// meanwhile, make sure the player can move thru
|
||||
aGlassPane->solid = SOLID_NOT;
|
||||
aGlassPane->think = CGF_SFX_HideBreakableGlass;
|
||||
aGlassPane->nextthink = level.framenum + aPaneDestructDelay * HZ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_EmitGlass (edict_t * aGlassPane, edict_t * anInflictor, vec3_t aPoint)
|
||||
{
|
||||
// based on func_explode, but with lotsa subtle differences
|
||||
vec3_t old_origin;
|
||||
vec3_t chunkorigin;
|
||||
vec3_t size;
|
||||
int count;
|
||||
|
||||
// bmodel origins are (0 0 0), we need to adjust that here
|
||||
VectorCopy (aGlassPane->s.origin, old_origin);
|
||||
VectorCopy (aPoint, aGlassPane->s.origin);
|
||||
|
||||
VectorSubtract (aGlassPane->s.origin, anInflictor->s.origin,
|
||||
aGlassPane->velocity);
|
||||
VectorNormalize (aGlassPane->velocity);
|
||||
// use speed 250 instead of 150 for funkier glass spray
|
||||
VectorScale (aGlassPane->velocity, 250.0, aGlassPane->velocity);
|
||||
|
||||
// start chunks towards the center
|
||||
VectorScale (aGlassPane->size, 0.25, size);
|
||||
|
||||
count = 4;
|
||||
while (count--)
|
||||
{
|
||||
CGF_SFX_ApplyGlassFragmentLimit ("debris");
|
||||
chunkorigin[0] = aPoint[0] + crandom () * size[0];
|
||||
chunkorigin[1] = aPoint[1] + crandom () * size[1];
|
||||
chunkorigin[2] = aPoint[2] + crandom () * size[2];
|
||||
CGF_SFX_GlassThrowDebris (aGlassPane, "models/objects/debris2/tris.md2",
|
||||
2, chunkorigin);
|
||||
}
|
||||
|
||||
// clear velocity, reset origin (that has been abused in ThrowDebris)
|
||||
VectorClear (aGlassPane->velocity);
|
||||
VectorCopy (old_origin, aGlassPane->s.origin);
|
||||
|
||||
// firing thru - the pane has no direct attacker to hurt,
|
||||
// but G_UseTargets expects one. So make it a DIY
|
||||
G_UseTargets (aGlassPane, aGlassPane);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_HideBreakableGlass (edict_t * aGlassPane)
|
||||
{
|
||||
// remove all attached decals
|
||||
edict_t *decal;
|
||||
decal = 0;
|
||||
while ((decal = G_Find (decal, FOFS (classname), "decal")) != NULL)
|
||||
{
|
||||
if (decal->owner == aGlassPane)
|
||||
{
|
||||
// make it goaway in the next frame
|
||||
decal->think = G_FreeEdict;
|
||||
decal->nextthink = level.framenum + 1;
|
||||
}
|
||||
}
|
||||
|
||||
while ((decal = G_Find (decal, FOFS (classname), "splat")) != NULL)
|
||||
{
|
||||
if (decal->owner == aGlassPane)
|
||||
{
|
||||
// make it goaway in the next frame
|
||||
decal->think = G_FreeEdict;
|
||||
decal->nextthink = level.framenum + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// after being broken, the pane cannot be freed as it is needed in
|
||||
// subsequent missions/games, so hide it at about z = -1000 lower
|
||||
aGlassPane->movetype = MOVETYPE_FLYMISSILE;
|
||||
VectorCopy (aGlassPane->s.origin, aGlassPane->pos1);
|
||||
aGlassPane->s.origin[2] -= 1000.0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_AttachDecalToGlass (edict_t * aGlassPane, edict_t * aDecal)
|
||||
{
|
||||
// just set aDecal's owner to be the glass pane
|
||||
aDecal->owner = aGlassPane;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_RebuildAllBrokenGlass ()
|
||||
{
|
||||
// iterate over all func_explosives
|
||||
edict_t *glass;
|
||||
glass = 0;
|
||||
while ((glass = G_Find (glass, FOFS (classname), "func_explosive")) != NULL)
|
||||
{
|
||||
// glass is broken if solid != SOLID_BSP
|
||||
if (glass->solid != SOLID_BSP)
|
||||
{
|
||||
CGF_SFX_InstallBreakableGlass (glass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_ApplyGlassFragmentLimit (const char *aClassName)
|
||||
{
|
||||
edict_t *oldfragment;
|
||||
|
||||
glassfragmentcount++;
|
||||
if (glassfragmentcount > glassfragmentlimit->value)
|
||||
glassfragmentcount = 1;
|
||||
|
||||
// remove fragment with corresponding number if any
|
||||
oldfragment = FindEdictByClassnum ((char *) aClassName, glassfragmentcount);
|
||||
|
||||
if (oldfragment)
|
||||
{
|
||||
// oldfragment->nextthink = level.framenum + 1;
|
||||
G_FreeEdict (oldfragment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_MiscGlassUse (edict_t * self, edict_t * other, edict_t * activator)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
const char *classname;
|
||||
classname = other->classname;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
CGF_SFX_MiscGlassDie (edict_t * self, edict_t * inflictor, edict_t * attacker,
|
||||
int damage, vec3_t point)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
const char *classname;
|
||||
classname = inflictor->classname;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
static vec_t previous_throw_time = 0;
|
||||
static int this_throw_count = 0;
|
||||
|
||||
void
|
||||
CGF_SFX_GlassThrowDebris (edict_t * self, char *modelname, float speed,
|
||||
vec3_t origin)
|
||||
{
|
||||
// based on ThrowDebris from id software - now returns debris created
|
||||
edict_t *chunk;
|
||||
vec3_t v;
|
||||
|
||||
if (level.time != previous_throw_time)
|
||||
{
|
||||
previous_throw_time = level.time;
|
||||
this_throw_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this_throw_count++;
|
||||
if (this_throw_count > glassfragmentlimit->value)
|
||||
return;
|
||||
}
|
||||
|
||||
chunk = G_Spawn ();
|
||||
VectorCopy (origin, chunk->s.origin);
|
||||
gi.setmodel (chunk, modelname);
|
||||
v[0] = 100 * crandom ();
|
||||
v[1] = 100 * crandom ();
|
||||
v[2] = 100 + 100 * crandom ();
|
||||
VectorMA (self->velocity, speed, v, chunk->velocity);
|
||||
chunk->movetype = MOVETYPE_BOUNCE;
|
||||
chunk->solid = SOLID_NOT;
|
||||
chunk->avelocity[0] = random () * 600;
|
||||
chunk->avelocity[1] = random () * 600;
|
||||
chunk->avelocity[2] = random () * 600;
|
||||
chunk->think = G_FreeEdict;
|
||||
chunk->nextthink = level.framenum + (5 + random() * 5) * HZ;
|
||||
chunk->s.frame = 0;
|
||||
chunk->flags = 0;
|
||||
chunk->classname = "debris";
|
||||
chunk->takedamage = DAMAGE_YES;
|
||||
chunk->die = debris_die;
|
||||
gi.linkentity (chunk);
|
||||
|
||||
// number chunk
|
||||
chunk->classnum = glassfragmentcount;
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/****************************************************************************/
|
||||
/* */
|
||||
/* project : CGF (c) 1999 William van der Sterren */
|
||||
/* parts (c) 1998 id software */
|
||||
/* */
|
||||
/* file : cgf_sfx_glass.h "special effects for glass entities" */
|
||||
/* author(s): William van der Sterren */
|
||||
/* version : 0.5 */
|
||||
/* */
|
||||
/* date (last revision): Jun 12, 99 */
|
||||
/* date (creation) : Jun 04, 99 */
|
||||
/* */
|
||||
/* */
|
||||
/* revision history */
|
||||
/* -- date ---- | -- revision ---------------------- | -- revisor -- */
|
||||
/* Jun 12, 1999 | fixed knife slash breaks glass | William */
|
||||
/* */
|
||||
/******* http://www.botepidemic.com/aid/cgf for CGF for Action Quake2 *******/
|
||||
//
|
||||
// $Id: cgf_sfx_glass.h,v 1.2 2001/09/28 13:48:34 ra Exp $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: cgf_sfx_glass.h,v $
|
||||
// Revision 1.2 2001/09/28 13:48:34 ra
|
||||
// I ran indent over the sources. All .c and .h files reindented.
|
||||
//
|
||||
// Revision 1.1.1.1 2001/05/06 17:29:34 igor_rock
|
||||
// This is the PG Bund Edition V1.25 with all stuff laying around here...
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __CGF_SFX_GLASS_H_
|
||||
#define __CGF_SFX_GLASS_H_
|
||||
|
||||
|
||||
// defines (should be consistent with other weapon defs in g_local.h)
|
||||
#define MOD_BREAKINGGLASS 46
|
||||
|
||||
/*
|
||||
// forward definitions
|
||||
typedef struct edict_s edict_t;
|
||||
*/
|
||||
|
||||
|
||||
// export a number of functions to g_func.c:
|
||||
//
|
||||
//
|
||||
|
||||
void CGF_SFX_InstallGlassSupport ();
|
||||
// registers cvar breakableglass (default 0)
|
||||
// registers cvar glassfragmentlimit (default 30)
|
||||
|
||||
|
||||
void CGF_SFX_RebuildAllBrokenGlass ();
|
||||
// upon starting a new team play game, reconstruct any
|
||||
// broken glass because we like to break it again
|
||||
|
||||
|
||||
int CGF_SFX_IsBreakableGlassEnabled ();
|
||||
// returns whether breakable glass is enabled (cvar breakableglass)
|
||||
|
||||
|
||||
void CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think (edict_t *
|
||||
aPossibleGlassEntity);
|
||||
// initial think function for all func_explosives
|
||||
// because we cannot verify the contents of the entity unless the entity
|
||||
// has been spawned, we need to first introduce the entity, and remove
|
||||
// it later (level.time == 0.1) if required
|
||||
|
||||
|
||||
void CGF_SFX_ShootBreakableGlass (edict_t * aGlassPane, edict_t * anAttacker,
|
||||
/*trace_t */ void *tr,
|
||||
int mod);
|
||||
// shoot thru glass - depending on bullet types and
|
||||
// random effects, glass just emits fragments, or breaks
|
||||
|
||||
|
||||
void CGF_SFX_AttachDecalToGlass (edict_t * aGlassPane, edict_t * aDecal);
|
||||
// a glass that breaks will remove all decals (blood splashes, bullet
|
||||
// holes) if they are attached
|
||||
|
||||
|
||||
#endif
|
|
@ -5,52 +5,15 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
enum match_t
|
||||
{
|
||||
MATCH_NONE,
|
||||
MATCH_SETUP,
|
||||
MATCH_PREGAME,
|
||||
MATCH_GAME,
|
||||
MATCH_POST
|
||||
};
|
||||
|
||||
enum elect_t
|
||||
{
|
||||
ELECT_NONE,
|
||||
ELECT_MATCH,
|
||||
ELECT_ADMIN,
|
||||
ELECT_MAP
|
||||
};
|
||||
|
||||
struct ctfgame_t
|
||||
{
|
||||
int team1, team2;
|
||||
int total1, total2; // these are only set when going into intermission except in teamplay
|
||||
gtime_t last_flag_capture;
|
||||
int last_capture_team;
|
||||
|
||||
match_t match; // match state
|
||||
gtime_t matchtime; // time for match start/end (depends on state)
|
||||
int lasttime; // last time update, explicitly truncated to seconds
|
||||
bool countdown; // has audio countdown started?
|
||||
|
||||
elect_t election; // election type
|
||||
edict_t *etarget; // for admin election, who's being elected
|
||||
char elevel[32]; // for map election, target level
|
||||
int evotes; // votes so far
|
||||
int needvotes; // votes needed
|
||||
gtime_t electtime; // remaining time until election times out
|
||||
char emsg[256]; // election name
|
||||
int warnactive; // true if stat string 30 is active
|
||||
|
||||
ghost_t ghosts[MAX_CLIENTS]; // ghost codes
|
||||
};
|
||||
|
||||
ctfgame_t ctfgame;
|
||||
|
||||
cvar_t *ctf;
|
||||
cvar_t *teamplay;
|
||||
cvar_t *g_teamplay_force_join;
|
||||
cvar_t *ctf_mode = NULL;
|
||||
cvar_t *ctf_dropflag = NULL;
|
||||
cvar_t *ctf_respawn = NULL;
|
||||
cvar_t *ctf_model = NULL;
|
||||
|
||||
// [Paril-KEX]
|
||||
bool G_TeamplayEnabled()
|
||||
|
|
|
@ -38,6 +38,50 @@ struct ghost_t
|
|||
edict_t *ent;
|
||||
};
|
||||
|
||||
enum match_t
|
||||
{
|
||||
MATCH_NONE,
|
||||
MATCH_SETUP,
|
||||
MATCH_PREGAME,
|
||||
MATCH_GAME,
|
||||
MATCH_POST
|
||||
};
|
||||
|
||||
enum elect_t
|
||||
{
|
||||
ELECT_NONE,
|
||||
ELECT_MATCH,
|
||||
ELECT_ADMIN,
|
||||
ELECT_MAP
|
||||
};
|
||||
|
||||
struct ctfgame_t
|
||||
{
|
||||
int team1, team2;
|
||||
int total1, total2; // these are only set when going into intermission except in teamplay
|
||||
gtime_t last_flag_capture;
|
||||
int last_capture_team;
|
||||
|
||||
match_t match; // match state
|
||||
gtime_t matchtime; // time for match start/end (depends on state)
|
||||
int lasttime; // last time update, explicitly truncated to seconds
|
||||
bool countdown; // has audio countdown started?
|
||||
|
||||
elect_t election; // election type
|
||||
edict_t *etarget; // for admin election, who's being elected
|
||||
char elevel[32]; // for map election, target level
|
||||
int evotes; // votes so far
|
||||
int needvotes; // votes needed
|
||||
gtime_t electtime; // remaining time until election times out
|
||||
char emsg[256]; // election name
|
||||
int warnactive; // true if stat string 30 is active
|
||||
|
||||
ghost_t ghosts[MAX_CLIENTS]; // ghost codes
|
||||
|
||||
// Action
|
||||
int32_t halftime;
|
||||
};
|
||||
|
||||
extern cvar_t *ctf;
|
||||
extern cvar_t *g_teamplay_force_join;
|
||||
extern cvar_t *teamplay;
|
||||
|
|
|
@ -120,6 +120,91 @@ void LaserSightThink(edict_t * self)
|
|||
self->nextthink = level.time + 1_ms;
|
||||
}
|
||||
|
||||
|
||||
// sets variable to toggle nearby door status
|
||||
void Cmd_OpenDoor_f(edict_t * ent)
|
||||
{
|
||||
ent->client->doortoggle = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
void Cmd_Bandage_f(edict_t *ent)
|
||||
{
|
||||
if (!IS_ALIVE(ent))
|
||||
return;
|
||||
|
||||
if (ent->client->bandaging) {
|
||||
gi.LocClient_Print(ent, PRINT_HIGH, "Already bandaging\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool can_use_medkit = (ent->client->medkit > 0) && (ent->health < ent->max_health);
|
||||
|
||||
// No need to bandage if enhanced slippers are enabled and you only have fall damage
|
||||
// but you can still use the medkit to regain health
|
||||
if (ent->client->bleeding == 0 && e_enhancedSlippers->value && ! can_use_medkit){
|
||||
gi.LocClient_Print(ent, PRINT_HIGH, "No need to bandage\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ent->client->bleeding == 0 && ent->client->leg_damage == 0 && ! can_use_medkit) {
|
||||
gi.LocClient_Print(ent, PRINT_HIGH, "No need to bandage\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ent->client->reload_attempts = 0; // prevent any further reloading
|
||||
|
||||
if (ent->client->weaponstate != WEAPON_READY && ent->client->weaponstate != WEAPON_END_MAG) {
|
||||
gi.LocClient_Print(ent, PRINT_HIGH, "Can't bandage now\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// zucc - check if they have a primed grenade
|
||||
if (ent->client->pers.weapon->id == IT_WEAPON_GRENADES
|
||||
&& ((ent->client->ps.gunframe >= GRENADE_IDLE_FIRST
|
||||
&& ent->client->ps.gunframe <= GRENADE_IDLE_LAST)
|
||||
|| (ent->client->ps.gunframe >= GRENADE_THROW_FIRST
|
||||
&& ent->client->ps.gunframe <= GRENADE_THROW_LAST)))
|
||||
{
|
||||
int damage;
|
||||
|
||||
ent->client->ps.gunframe = 0;
|
||||
|
||||
damage = GRENADE_DAMRAD;
|
||||
|
||||
fire_grenade2(ent, ent->s.origin, vec3_origin, damage, 0, 80_ms, damage * 2, false);
|
||||
|
||||
INV_AMMO(ent, IT_WEAPON_GRENADES)--;
|
||||
if (INV_AMMO(ent, IT_WEAPON_GRENADES) <= 0) {
|
||||
ent->client->newweapon = GetItemByIndex(IT_WEAPON_MK23);
|
||||
}
|
||||
}
|
||||
|
||||
ent->client->bandaging = 1;
|
||||
ent->client->resp.sniper_mode = SNIPER_1X;
|
||||
ent->client->ps.fov = 90;
|
||||
ent->client->desired_fov = 90;
|
||||
if (ent->client->pers.weapon)
|
||||
ent->client->ps.gunindex = gi.modelindex(ent->client->pers.weapon->view_model);
|
||||
gi.LocClient_Print(ent, PRINT_HIGH, "You've started bandaging\n");
|
||||
}
|
||||
|
||||
// function called in generic_weapon function that does the bandaging
|
||||
|
||||
void Bandage(edict_t * ent)
|
||||
{
|
||||
ClientFixLegs(ent);
|
||||
ent->client->bleeding = 0;
|
||||
ent->client->bleed_remain = 0;
|
||||
ent->client->bandaging = 0;
|
||||
ent->client->attacker = NULL;
|
||||
ent->client->bandage_stopped = 1;
|
||||
if (esp->value && esp_leaderenhance->value)
|
||||
ent->client->idle_weapon = ENHANCED_BANDAGE_TIME;
|
||||
else
|
||||
ent->client->idle_weapon = BANDAGE_TIME;
|
||||
}
|
||||
|
||||
void Cmd_New_Reload_f(edict_t * ent)
|
||||
{
|
||||
//FB 6/1/99 - refuse to reload during LCA
|
||||
|
|
|
@ -6,9 +6,16 @@
|
|||
|
||||
#include "bg_local.h"
|
||||
|
||||
#include "a_team.h"
|
||||
#include "a_game.h"
|
||||
#include "cgf_sfx_glass.h"
|
||||
// Action includes
|
||||
#include "action/a_team.h"
|
||||
#include "action/a_game.h"
|
||||
#include "action/cgf_sfx_glass.h"
|
||||
#include "action/a_match.h"
|
||||
#include "action/a_radio.h"
|
||||
#include "action/a_ini.h"
|
||||
#include "action/a_stats.h"
|
||||
#include "action/a_balancer.h"
|
||||
|
||||
|
||||
// the "gameversion" client command will print this plus compile date
|
||||
constexpr const char *GAMEVERSION = "action";
|
||||
|
@ -1995,6 +2002,8 @@ extern cvar_t *radio_ban;
|
|||
extern cvar_t *radio_repeat;
|
||||
//SLIC2
|
||||
extern cvar_t *radio_repeat_time;
|
||||
extern cvar_t *warmup;
|
||||
extern cvar_t *round_begin;
|
||||
|
||||
void LaserSightThink (edict_t * self);
|
||||
void SP_LaserSight (edict_t * self, gitem_t * item);
|
||||
|
@ -2961,6 +2970,7 @@ struct client_respawn_t
|
|||
gtime_t ctf_lastreturnedflag;
|
||||
gtime_t ctf_flagsince;
|
||||
gtime_t ctf_lastfraggedcarrier;
|
||||
int32_t ctf_caps;
|
||||
int32_t ctf_capstreak;
|
||||
bool id_state;
|
||||
gtime_t lastidtime;
|
||||
|
@ -2971,12 +2981,17 @@ struct client_respawn_t
|
|||
// ZOID
|
||||
|
||||
// Action Add
|
||||
int32_t joined_team; // last frame # at which the player joined a team
|
||||
int32_t lastWave; //last time used wave
|
||||
|
||||
radio_t radio;
|
||||
|
||||
int32_t motd_refreshes;
|
||||
int32_t last_motd_refresh;
|
||||
edict_t *last_chase_target; // last person they chased, to resume at the same place later...
|
||||
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_wounds;
|
||||
int32_t team;
|
||||
int32_t subteam;
|
||||
int32_t sniper_mode;
|
||||
|
@ -3041,7 +3056,15 @@ struct team_t
|
|||
};
|
||||
extern team_t teams[TEAM_TOP];
|
||||
|
||||
// Action Add
|
||||
#ifndef max
|
||||
# define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef min
|
||||
# define min(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
// Action Add End
|
||||
|
||||
// [Paril-KEX] seconds until we are fully invisible after
|
||||
// making a racket
|
||||
|
|
|
@ -170,6 +170,8 @@ cvar_t *respawn_effect;
|
|||
cvar_t *use_warnings;
|
||||
cvar_t *use_killcounts;
|
||||
cvar_t *use_rewards;
|
||||
cvar_t *warmup;
|
||||
cvar_t *round_begin;
|
||||
|
||||
// UI / Menu / Messaging Settings
|
||||
cvar_t *motd_time;
|
||||
|
|
|
@ -1323,9 +1323,9 @@ static void G_InitStatusbar()
|
|||
.yb(-84)
|
||||
.endifstat()
|
||||
.endifstat();
|
||||
sb.ifstat(STAT_KEY_A).xv(296).pic(STAT_KEY_A).endifstat();
|
||||
sb.ifstat(STAT_KEY_B).xv(272).pic(STAT_KEY_B).endifstat();
|
||||
sb.ifstat(STAT_KEY_C).xv(248).pic(STAT_KEY_C).endifstat();
|
||||
// sb.ifstat(STAT_KEY_A).xv(296).pic(STAT_KEY_A).endifstat();
|
||||
// sb.ifstat(STAT_KEY_B).xv(272).pic(STAT_KEY_B).endifstat();
|
||||
// sb.ifstat(STAT_KEY_C).xv(248).pic(STAT_KEY_C).endifstat();
|
||||
|
||||
if (coop->integer)
|
||||
{
|
||||
|
|
|
@ -973,11 +973,11 @@ void G_SetStats(edict_t *ent)
|
|||
if (!deathmatch->integer)
|
||||
{
|
||||
int32_t key_offset = 0;
|
||||
player_stat_t stat = STAT_KEY_A;
|
||||
// player_stat_t stat = STAT_KEY_A;
|
||||
|
||||
ent->client->ps.stats[STAT_KEY_A] =
|
||||
ent->client->ps.stats[STAT_KEY_B] =
|
||||
ent->client->ps.stats[STAT_KEY_C] = 0;
|
||||
// ent->client->ps.stats[STAT_KEY_A] =
|
||||
// ent->client->ps.stats[STAT_KEY_B] =
|
||||
// ent->client->ps.stats[STAT_KEY_C] = 0;
|
||||
|
||||
// there's probably a way to do this in one pass but
|
||||
// I'm lazy
|
||||
|
|
Loading…
Reference in a new issue