mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2025-03-22 02:21:25 +00:00
Update to ioquake3 2018-12-21 part 4 (CGame/Game code)
This commit is contained in:
parent
a4be4e4a37
commit
ac4155327b
42 changed files with 661 additions and 501 deletions
|
@ -1283,12 +1283,18 @@ static float CG_DrawPowerups(float y)
|
|||
if (!ps->powerups[i]) {
|
||||
continue;
|
||||
}
|
||||
t = ps->powerups[i] - cg.time;
|
||||
// ZOID--don't draw if the power up has unlimited time (999 seconds)
|
||||
|
||||
// ZOID--don't draw if the power up has unlimited time
|
||||
// This is true of the CTF flags
|
||||
if (t < 0 || t > 999000) {
|
||||
if (ps->powerups[i] == INT_MAX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
t = ps->powerups[i] - cg.time;
|
||||
if (t <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// insert into the list
|
||||
for (j = 0; j < active; j++) {
|
||||
if (sortedTime[j] >= t) {
|
||||
|
@ -2722,11 +2728,6 @@ static void CG_Draw2D(void)
|
|||
CG_DrawWeaponStats();
|
||||
}
|
||||
|
||||
static void CG_DrawTourneyScoreboard( void )
|
||||
{
|
||||
CG_DrawOldTourneyScoreboard();
|
||||
}
|
||||
|
||||
/*
|
||||
=====================
|
||||
CG_DrawDamageBlend
|
||||
|
|
|
@ -131,7 +131,7 @@ void CG_DrawRect(float x, float y, float width, float height, float size, const
|
|||
trap_R_SetColor(color);
|
||||
|
||||
CG_DrawTopBottom(x, y, width, height, size);
|
||||
CG_DrawSides(x, y, width, height, size);
|
||||
CG_DrawSides(x, y + size, width, height - size * 2, size);
|
||||
|
||||
trap_R_SetColor(NULL);
|
||||
}
|
||||
|
|
|
@ -641,7 +641,7 @@ typedef struct centity_s {
|
|||
//======================================================================
|
||||
|
||||
// local entities are created as a result of events or predicted actions,
|
||||
// and live independantly from all server transmitted entities
|
||||
// and live independently from all server transmitted entities
|
||||
|
||||
typedef struct markPoly_s {
|
||||
struct markPoly_s *prevMark, *nextMark;
|
||||
|
@ -942,7 +942,7 @@ typedef struct {
|
|||
qboolean loading; // don't defer players at initial startup
|
||||
qboolean intermissionStarted; // don't play voice rewards, because game will end shortly
|
||||
|
||||
// there are only one or two snapshot_t that are relevent at a time
|
||||
// there are only one or two snapshot_t that are relevant at a time
|
||||
int latestSnapshotNum; // the number of snapshots the client system has received
|
||||
int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet
|
||||
|
||||
|
@ -1101,7 +1101,7 @@ typedef struct {
|
|||
|
||||
int itemPickup;
|
||||
int itemPickupTime;
|
||||
int itemPickupBlendTime; // the pulse around the crosshair is timed seperately
|
||||
int itemPickupBlendTime; // the pulse around the crosshair is timed separately
|
||||
|
||||
int weaponSelectTime;
|
||||
int weaponAnimation;
|
||||
|
@ -2385,7 +2385,7 @@ void CG_DrawInformation(void);
|
|||
// cg_scoreboard.c
|
||||
//
|
||||
qboolean CG_DrawOldScoreboard(void);
|
||||
void CG_DrawOldTourneyScoreboard(void);
|
||||
void CG_DrawTourneyScoreboard(void);
|
||||
|
||||
//
|
||||
// cg_players.c
|
||||
|
@ -2555,7 +2555,7 @@ void trap_GetGlconfig(glconfig_t * glconfig);
|
|||
void trap_GetGameState(gameState_t * gamestate);
|
||||
|
||||
// cgame will poll each frame to see if a newer snapshot has arrived
|
||||
// that it is interested in. The time is returned seperately so that
|
||||
// that it is interested in. The time is returned separately so that
|
||||
// snapshot latency can be calculated.
|
||||
void trap_GetCurrentSnapshotNumber(int *snapshotNumber, int *serverTime);
|
||||
|
||||
|
|
|
@ -1372,7 +1372,7 @@ static void CG_RegisterItemSounds(int itemNum)
|
|||
if (item->pickup_sound) {
|
||||
trap_S_RegisterSound(item->pickup_sound, qfalse);
|
||||
}
|
||||
// parse the space seperated precache string for other media
|
||||
// parse the space separated precache string for other media
|
||||
s = item->sounds;
|
||||
if (!s || !s[0])
|
||||
return;
|
||||
|
|
|
@ -947,10 +947,6 @@ void CG_ParticleSnowFlurry(qhandle_t pshader, centity_t * cent)
|
|||
|
||||
VectorCopy(cent->currentState.origin, p->org);
|
||||
|
||||
p->org[0] = p->org[0];
|
||||
p->org[1] = p->org[1];
|
||||
p->org[2] = p->org[2];
|
||||
|
||||
p->vel[0] = p->vel[1] = 0;
|
||||
|
||||
p->accel[0] = p->accel[1] = p->accel[2] = 0;
|
||||
|
|
|
@ -276,12 +276,12 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t * ci)
|
|||
while (1) {
|
||||
prev = text_p; // so we can unget
|
||||
token = COM_Parse(&text_p);
|
||||
if (!token) {
|
||||
if (!token[0]) {
|
||||
break;
|
||||
}
|
||||
if (!Q_stricmp(token, "footsteps")) {
|
||||
token = COM_Parse(&text_p);
|
||||
if (!token) {
|
||||
if (!token[0]) {
|
||||
break;
|
||||
}
|
||||
if (!Q_stricmp(token, "default") || !Q_stricmp(token, "normal")) {
|
||||
|
@ -306,7 +306,7 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t * ci)
|
|||
} else if (!Q_stricmp(token, "headoffset")) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
token = COM_Parse(&text_p);
|
||||
if (!token) {
|
||||
if (!token[0]) {
|
||||
break;
|
||||
}
|
||||
ci->headOffset[i] = atof(token);
|
||||
|
@ -314,7 +314,7 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t * ci)
|
|||
continue;
|
||||
} else if (!Q_stricmp(token, "sex")) {
|
||||
token = COM_Parse(&text_p);
|
||||
if (!token) {
|
||||
if (!token[0]) {
|
||||
break;
|
||||
}
|
||||
if (token[0] == 'f' || token[0] == 'F') {
|
||||
|
@ -344,7 +344,7 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t * ci)
|
|||
for (i = 0; i < MAX_ANIMATIONS; i++) {
|
||||
|
||||
token = COM_Parse(&text_p);
|
||||
if (!*token) {
|
||||
if (!token[0]) {
|
||||
if (i >= TORSO_GETFLAG && i <= TORSO_NEGATIVE) {
|
||||
animations[i].firstFrame = animations[TORSO_GESTURE].firstFrame;
|
||||
animations[i].frameLerp = animations[TORSO_GESTURE].frameLerp;
|
||||
|
@ -367,7 +367,7 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t * ci)
|
|||
}
|
||||
|
||||
token = COM_Parse(&text_p);
|
||||
if (!*token) {
|
||||
if (!token[0]) {
|
||||
break;
|
||||
}
|
||||
animations[i].numFrames = atoi(token);
|
||||
|
@ -381,13 +381,13 @@ static qboolean CG_ParseAnimationFile(const char *filename, clientInfo_t * ci)
|
|||
}
|
||||
|
||||
token = COM_Parse(&text_p);
|
||||
if (!*token) {
|
||||
if (!token[0]) {
|
||||
break;
|
||||
}
|
||||
animations[i].loopFrames = atoi(token);
|
||||
|
||||
token = COM_Parse(&text_p);
|
||||
if (!*token) {
|
||||
if (!token[0]) {
|
||||
break;
|
||||
}
|
||||
fps = atof(token);
|
||||
|
@ -1719,7 +1719,7 @@ static void CG_AddPainTwitch(centity_t * cent, vec3_t torsoAngles)
|
|||
===============
|
||||
CG_PlayerAngles
|
||||
|
||||
Handles seperate torso motion
|
||||
Handles separate torso motion
|
||||
|
||||
legs pivot based on direction of movement
|
||||
|
||||
|
|
|
@ -83,6 +83,9 @@ void CG_CheckAmmo(void)
|
|||
//if ( ! ( weapons & ( 1 << i ) ) ) {
|
||||
//continue;
|
||||
//}
|
||||
//if ( cg.snap->ps.ammo[i] < 0 ) {
|
||||
//continue;
|
||||
//}
|
||||
//Blaze: Dont need this
|
||||
/*
|
||||
switch ( i ) {
|
||||
|
|
|
@ -670,8 +670,10 @@ void CG_PredictPlayerState(void)
|
|||
|
||||
if (pmove_msec.integer < 8) {
|
||||
trap_Cvar_Set("pmove_msec", "8");
|
||||
trap_Cvar_Update(&pmove_msec);
|
||||
} else if (pmove_msec.integer > 33) {
|
||||
trap_Cvar_Set("pmove_msec", "33");
|
||||
trap_Cvar_Update(&pmove_msec);
|
||||
}
|
||||
|
||||
cg_pmove.pmove_fixed = pmove_fixed.integer; // | cg_pmove_fixed.integer;
|
||||
|
|
|
@ -206,7 +206,7 @@ typedef enum {
|
|||
|
||||
CG_SHUTDOWN,
|
||||
// void (*CG_Shutdown)( void );
|
||||
// oportunity to flush and close any open files
|
||||
// opportunity to flush and close any open files
|
||||
|
||||
CG_CONSOLE_COMMAND,
|
||||
// qboolean (*CG_ConsoleCommand)( void );
|
||||
|
|
|
@ -791,7 +791,7 @@ Draw the oversize scoreboard for tournements
|
|||
=================
|
||||
*/
|
||||
|
||||
void CG_DrawOldTourneyScoreboard(void)
|
||||
void CG_DrawTourneyScoreboard(void)
|
||||
{
|
||||
const char *s;
|
||||
vec4_t color;
|
||||
|
|
|
@ -222,7 +222,7 @@
|
|||
// Copyright (C) 1999-2000 Id Software, Inc.
|
||||
//
|
||||
// cg_servercmds.c -- reliably sequenced text commands sent by the server
|
||||
// these are processed at snapshot transition time, so there will definately
|
||||
// these are processed at snapshot transition time, so there will definitely
|
||||
// be a valid snapshot this frame
|
||||
|
||||
#include "cg_local.h"
|
||||
|
@ -899,7 +899,7 @@ int CG_ParseVoiceChats(const char *filename, voiceChatList_t * voiceChatList, in
|
|||
voiceChats[i].id[0] = 0;
|
||||
}
|
||||
token = COM_ParseExt(p, qtrue);
|
||||
if (!token || token[0] == 0) {
|
||||
if (!token[0]) {
|
||||
return qtrue;
|
||||
}
|
||||
if (!Q_stricmp(token, "female")) {
|
||||
|
@ -916,7 +916,7 @@ int CG_ParseVoiceChats(const char *filename, voiceChatList_t * voiceChatList, in
|
|||
voiceChatList->numVoiceChats = 0;
|
||||
while (1) {
|
||||
token = COM_ParseExt(p, qtrue);
|
||||
if (!token || token[0] == 0) {
|
||||
if (!token[0]) {
|
||||
return qtrue;
|
||||
}
|
||||
Com_sprintf(voiceChats[voiceChatList->numVoiceChats].id,
|
||||
|
@ -929,7 +929,7 @@ int CG_ParseVoiceChats(const char *filename, voiceChatList_t * voiceChatList, in
|
|||
voiceChats[voiceChatList->numVoiceChats].numSounds = 0;
|
||||
while (1) {
|
||||
token = COM_ParseExt(p, qtrue);
|
||||
if (!token || token[0] == 0) {
|
||||
if (!token[0]) {
|
||||
return qtrue;
|
||||
}
|
||||
if (!Q_stricmp(token, "}"))
|
||||
|
@ -938,7 +938,7 @@ int CG_ParseVoiceChats(const char *filename, voiceChatList_t * voiceChatList, in
|
|||
voiceChats[voiceChatList->numVoiceChats].sounds[voiceChats[voiceChatList->numVoiceChats].
|
||||
numSounds] = sound;
|
||||
token = COM_ParseExt(p, qtrue);
|
||||
if (!token || token[0] == 0) {
|
||||
if (!token[0]) {
|
||||
return qtrue;
|
||||
}
|
||||
Com_sprintf(voiceChats[voiceChatList->numVoiceChats].
|
||||
|
@ -1011,7 +1011,7 @@ int CG_HeadModelVoiceChats(char *filename)
|
|||
p = &ptr;
|
||||
|
||||
token = COM_ParseExt(p, qtrue);
|
||||
if (!token || token[0] == 0) {
|
||||
if (!token[0]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1561,12 +1561,14 @@ static void CG_ServerCommand(void)
|
|||
}
|
||||
|
||||
if (!strcmp(cmd, "chat")) {
|
||||
if (!cg_teamChatsOnly.integer) {
|
||||
trap_S_StartLocalSound(cgs.media.talkSound, CHAN_LOCAL_SOUND);
|
||||
Q_strncpyz(text, CG_Argv(1), sizeof(text));
|
||||
CG_RemoveChatEscapeChar(text);
|
||||
CG_AddMessage(text);
|
||||
if (cgs.gametype >= GT_TEAM && cg_teamChatsOnly.integer) {
|
||||
return;
|
||||
}
|
||||
|
||||
trap_S_StartLocalSound(cgs.media.talkSound, CHAN_LOCAL_SOUND);
|
||||
Q_strncpyz(text, CG_Argv(1), sizeof(text));
|
||||
CG_RemoveChatEscapeChar(text);
|
||||
CG_AddMessage(text);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,11 +121,8 @@ static void CG_CheckVidRestart(void)
|
|||
==================
|
||||
CG_SetInitialSnapshot
|
||||
|
||||
This will only happen on the very first snapshot, or
|
||||
on tourney restarts. All other times will use
|
||||
CG_TransitionSnapshot instead.
|
||||
|
||||
FIXME: Also called by map_restart?
|
||||
This will only happen on the very first snapshot.
|
||||
All other times will use CG_TransitionSnapshot instead.
|
||||
==================
|
||||
*/
|
||||
void CG_SetInitialSnapshot(snapshot_t * snap)
|
||||
|
@ -189,9 +186,8 @@ static void CG_TransitionSnapshot(void)
|
|||
// execute any server string commands before transitioning entities
|
||||
CG_ExecuteNewServerCommands(cg.nextSnap->serverCommandSequence);
|
||||
|
||||
// if we had a map_restart, set everthing with initial
|
||||
if (!cg.snap) {
|
||||
return;
|
||||
// if we had a map_restart, set everything with initial
|
||||
if (cg.mapRestart) {
|
||||
}
|
||||
|
||||
// clear the currentValid flag for all entities in the existing snapshot
|
||||
|
|
|
@ -155,7 +155,7 @@ Testmodel will create a fake entity 100 units in front of the current view
|
|||
position, directly facing the viewer. It will remain immobile, so you can
|
||||
move around it to view it from different angles.
|
||||
|
||||
Testgun will cause the model to follow the player around and supress the real
|
||||
Testgun will cause the model to follow the player around and suppress the real
|
||||
view weapon model. The default frame 0 of most guns is completely off screen,
|
||||
so you will probably have to cycle a couple frames to see it.
|
||||
|
||||
|
@ -185,6 +185,7 @@ void CG_TestModel_f(void)
|
|||
{
|
||||
vec3_t angles;
|
||||
|
||||
cg.testGun = qfalse;
|
||||
memset(&cg.testModelEntity, 0, sizeof(cg.testModelEntity));
|
||||
if (trap_Argc() < 2) {
|
||||
return;
|
||||
|
@ -210,7 +211,6 @@ void CG_TestModel_f(void)
|
|||
angles[ROLL] = 0;
|
||||
|
||||
AnglesToAxis(angles, cg.testModelEntity.axis);
|
||||
cg.testGun = qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -223,6 +223,11 @@ Replaces the current view weapon with the given model
|
|||
void CG_TestGun_f(void)
|
||||
{
|
||||
CG_TestModel_f();
|
||||
|
||||
if ( !cg.testModelEntity.hModel ) {
|
||||
return;
|
||||
}
|
||||
|
||||
cg.testGun = qtrue;
|
||||
cg.testModelEntity.renderfx = RF_MINLIGHT | RF_DEPTHHACK | RF_FIRST_PERSON;
|
||||
}
|
||||
|
@ -1341,7 +1346,8 @@ void CG_DrawActiveFrame(int serverTime, stereoFrame_t stereoView, qboolean demoP
|
|||
|
||||
// decide on third person view
|
||||
// Elder: remove third-person death rendering
|
||||
cg.renderingThirdPerson = cg_thirdPerson.integer; //|| (cg.snap->ps.stats[STAT_HEALTH] <= 0);
|
||||
cg.renderingThirdPerson = cg.snap->ps.persistant[PERS_TEAM] != TEAM_SPECTATOR
|
||||
&& (cg_thirdPerson.integer); //|| (cg.snap->ps.stats[STAT_HEALTH] <= 0));
|
||||
|
||||
// build cg.refdef
|
||||
inwater = CG_CalcViewValues();
|
||||
|
|
|
@ -1444,7 +1444,7 @@ void CG_AddPlayerWeapon( refEntity_t * parent, playerState_t * ps, centity_t * c
|
|||
nonPredictedCent = &cg_entities[ cent->currentState.clientNum ];
|
||||
|
||||
// if the index of the nonPredictedCent is not the same as the clientNum
|
||||
// then this is a fake player (like on teh single player podiums), so
|
||||
// then this is a fake player (like on the single player podiums), so
|
||||
// go ahead and use the cent
|
||||
if ((nonPredictedCent - cg_entities) != cent->currentState.clientNum) {
|
||||
nonPredictedCent = cent;
|
||||
|
|
|
@ -77,13 +77,9 @@ int BotNumActivePlayers(void)
|
|||
{
|
||||
int i, num;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
num = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
@ -106,14 +102,10 @@ int BotIsFirstInRankings(bot_state_t * bs)
|
|||
{
|
||||
int i, score;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
playerState_t ps;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
score = bs->cur_ps.persistant[PERS_SCORE];
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
@ -122,8 +114,7 @@ int BotIsFirstInRankings(bot_state_t * bs)
|
|||
if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR)
|
||||
continue;
|
||||
//
|
||||
BotAI_GetClientState(i, &ps);
|
||||
if (score < ps.persistant[PERS_SCORE])
|
||||
if (BotAI_GetClientState(i, &ps) && score < ps.persistant[PERS_SCORE])
|
||||
return qfalse;
|
||||
}
|
||||
return qtrue;
|
||||
|
@ -138,14 +129,10 @@ int BotIsLastInRankings(bot_state_t * bs)
|
|||
{
|
||||
int i, score;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
playerState_t ps;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
score = bs->cur_ps.persistant[PERS_SCORE];
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
@ -154,8 +141,7 @@ int BotIsLastInRankings(bot_state_t * bs)
|
|||
if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR)
|
||||
continue;
|
||||
//
|
||||
BotAI_GetClientState(i, &ps);
|
||||
if (score > ps.persistant[PERS_SCORE])
|
||||
if (BotAI_GetClientState(i, &ps) && score > ps.persistant[PERS_SCORE])
|
||||
return qfalse;
|
||||
}
|
||||
return qtrue;
|
||||
|
@ -171,15 +157,11 @@ char *BotFirstClientInRankings(void)
|
|||
int i, bestscore, bestclient;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static char name[32];
|
||||
static int maxclients;
|
||||
playerState_t ps;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
bestscore = -999999;
|
||||
bestclient = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
@ -188,8 +170,7 @@ char *BotFirstClientInRankings(void)
|
|||
if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR)
|
||||
continue;
|
||||
//
|
||||
BotAI_GetClientState(i, &ps);
|
||||
if (ps.persistant[PERS_SCORE] > bestscore) {
|
||||
if (BotAI_GetClientState(i, &ps) && ps.persistant[PERS_SCORE] > bestscore) {
|
||||
bestscore = ps.persistant[PERS_SCORE];
|
||||
bestclient = i;
|
||||
}
|
||||
|
@ -208,15 +189,11 @@ char *BotLastClientInRankings(void)
|
|||
int i, worstscore, bestclient;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static char name[32];
|
||||
static int maxclients;
|
||||
playerState_t ps;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
worstscore = 999999;
|
||||
bestclient = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
@ -225,8 +202,7 @@ char *BotLastClientInRankings(void)
|
|||
if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR)
|
||||
continue;
|
||||
//
|
||||
BotAI_GetClientState(i, &ps);
|
||||
if (ps.persistant[PERS_SCORE] < worstscore) {
|
||||
if (BotAI_GetClientState(i, &ps) && ps.persistant[PERS_SCORE] < worstscore) {
|
||||
worstscore = ps.persistant[PERS_SCORE];
|
||||
bestclient = i;
|
||||
}
|
||||
|
@ -245,15 +221,11 @@ char *BotRandomOpponentName(bot_state_t * bs)
|
|||
int i, count;
|
||||
char buf[MAX_INFO_STRING];
|
||||
int opponents[MAX_CLIENTS], numopponents;
|
||||
static int maxclients;
|
||||
static char name[32];
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
numopponents = 0;
|
||||
opponents[0] = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (i == bs->client)
|
||||
continue;
|
||||
//
|
||||
|
|
|
@ -256,16 +256,13 @@ int FindClientByName(char *name)
|
|||
{
|
||||
int i;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
ClientName(i, buf, sizeof(buf));
|
||||
if (!Q_stricmp(buf, name))
|
||||
return i;
|
||||
}
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
ClientName(i, buf, sizeof(buf));
|
||||
if (stristr(buf, name))
|
||||
return i;
|
||||
|
@ -282,18 +279,15 @@ int FindEnemyByName(bot_state_t * bs, char *name)
|
|||
{
|
||||
int i;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (BotSameTeam(bs, i))
|
||||
continue;
|
||||
ClientName(i, buf, sizeof(buf));
|
||||
if (!Q_stricmp(buf, name))
|
||||
return i;
|
||||
}
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (BotSameTeam(bs, i))
|
||||
continue;
|
||||
ClientName(i, buf, sizeof(buf));
|
||||
|
@ -312,13 +306,9 @@ int NumPlayersOnSameTeam(bot_state_t * bs)
|
|||
{
|
||||
int i, num;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
num = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, MAX_INFO_STRING);
|
||||
if (strlen(buf)) {
|
||||
if (BotSameTeam(bs, i + 1))
|
||||
|
|
|
@ -657,7 +657,7 @@ int BotGetItemLongTermGoal(bot_state_t * bs, int tfl, bot_goal_t * goal)
|
|||
==================
|
||||
BotGetLongTermGoal
|
||||
|
||||
we could also create a seperate AI node for every long term goal type
|
||||
we could also create a separate AI node for every long term goal type
|
||||
however this saves us a lot of code
|
||||
==================
|
||||
*/
|
||||
|
@ -917,11 +917,10 @@ int BotGetLongTermGoal(bot_state_t * bs, int tfl, int retreat, bot_goal_t * goal
|
|||
bs->teammessage_time = 0;
|
||||
}
|
||||
//
|
||||
if (bs->lastkilledplayer == bs->teamgoal.entitynum) {
|
||||
if (bs->killedenemy_time > bs->teamgoal_time - TEAM_KILL_SOMEONE && bs->lastkilledplayer == bs->teamgoal.entitynum) {
|
||||
EasyClientName(bs->teamgoal.entitynum, buf, sizeof(buf));
|
||||
BotAI_BotInitialChat(bs, "kill_done", buf, NULL);
|
||||
trap_BotEnterChat(bs->cs, bs->decisionmaker, CHAT_TELL);
|
||||
bs->lastkilledplayer = -1;
|
||||
bs->ltgtype = 0;
|
||||
}
|
||||
//
|
||||
|
|
|
@ -237,7 +237,6 @@ bot_waypoint_t *botai_freewaypoints;
|
|||
|
||||
//NOTE: not using a cvars which can be updated because the game should be reloaded anyway
|
||||
int gametype; //game type
|
||||
int maxclients; //maximum number of clients
|
||||
|
||||
vmCvar_t bot_grapple;
|
||||
vmCvar_t bot_rocketjump;
|
||||
|
@ -755,7 +754,9 @@ qboolean EntityIsDead(aas_entityinfo_t * entinfo)
|
|||
|
||||
if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) {
|
||||
//retrieve the current client state
|
||||
BotAI_GetClientState(entinfo->number, &ps);
|
||||
if (!BotAI_GetClientState(entinfo->number, &ps)) {
|
||||
return qfalse;
|
||||
}
|
||||
//Makro - added health check
|
||||
if (ps.pm_type != PM_NORMAL || ps.stats[STAT_HEALTH] <= 0)
|
||||
return qtrue;
|
||||
|
@ -1393,11 +1394,8 @@ int ClientFromName(char *name)
|
|||
{
|
||||
int i;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
Q_CleanStr(buf);
|
||||
if (!Q_stricmp(Info_ValueForKey(buf, "n"), name))
|
||||
|
@ -1415,11 +1413,8 @@ int ClientOnSameTeamFromName(bot_state_t * bs, char *name)
|
|||
{
|
||||
int i;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (!BotSameTeam(bs, i))
|
||||
continue;
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
|
@ -2699,7 +2694,7 @@ bot_moveresult_t BotAttackMove(bot_state_t * bs, int tfl)
|
|||
bs->flags ^= BFL_STRAFERIGHT;
|
||||
bs->attackstrafe_time = 0;
|
||||
}
|
||||
//bot couldn't do any usefull movement
|
||||
//bot couldn't do any useful movement
|
||||
// bs->attackchase_time = AAS_Time() + 6;
|
||||
return moveresult;
|
||||
}
|
||||
|
@ -2779,8 +2774,12 @@ float BotEntityVisible(int viewer, vec3_t eye, vec3_t viewangles, float fov, int
|
|||
aas_entityinfo_t entinfo;
|
||||
vec3_t dir, entangles, start, end, middle;
|
||||
|
||||
//calculate middle of bounding box
|
||||
BotEntityInfo(ent, &entinfo);
|
||||
if (!entinfo.valid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//calculate middle of bounding box
|
||||
VectorAdd(entinfo.mins, entinfo.maxs, middle);
|
||||
VectorScale(middle, 0.5, middle);
|
||||
VectorAdd(entinfo.origin, middle, middle);
|
||||
|
@ -2903,13 +2902,17 @@ int BotFindEnemy(bot_state_t * bs, int curenemy)
|
|||
} else {
|
||||
cursquaredist = 0;
|
||||
}
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
|
||||
if (i == bs->client)
|
||||
continue;
|
||||
//if it's the current enemy
|
||||
if (i == curenemy)
|
||||
continue;
|
||||
//if the enemy has targeting disabled
|
||||
if (g_entities[i].flags & FL_NOTARGET) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
BotEntityInfo(i, &entinfo);
|
||||
//
|
||||
|
@ -2922,10 +2925,6 @@ int BotFindEnemy(bot_state_t * bs, int curenemy)
|
|||
if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
|
||||
continue;
|
||||
}
|
||||
// JBravo: unlagged
|
||||
if (g_entities[i].flags & FL_NOTARGET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//if not an easy fragger don't shoot at chatting players
|
||||
if (easyfragger < 0.5 && EntityIsChatting(&entinfo))
|
||||
|
@ -2999,7 +2998,7 @@ int BotTeamFlagCarrierVisible(bot_state_t * bs)
|
|||
float vis;
|
||||
aas_entityinfo_t entinfo;
|
||||
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (i == bs->client)
|
||||
continue;
|
||||
//
|
||||
|
@ -3033,7 +3032,7 @@ int BotTeamFlagCarrier(bot_state_t * bs)
|
|||
int i;
|
||||
aas_entityinfo_t entinfo;
|
||||
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (i == bs->client)
|
||||
continue;
|
||||
//
|
||||
|
@ -3064,7 +3063,7 @@ int BotEnemyFlagCarrierVisible(bot_state_t * bs)
|
|||
float vis;
|
||||
aas_entityinfo_t entinfo;
|
||||
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (i == bs->client)
|
||||
continue;
|
||||
//
|
||||
|
@ -3104,7 +3103,7 @@ void BotVisibleTeamMatesAndEnemies(bot_state_t * bs, int *teammates, int *enemie
|
|||
*teammates = 0;
|
||||
if (enemies)
|
||||
*enemies = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (i == bs->client)
|
||||
continue;
|
||||
//
|
||||
|
@ -3591,24 +3590,29 @@ void BotMapScripts(bot_state_t * bs)
|
|||
strncpy(mapname, Info_ValueForKey(info, "mapname"), sizeof(mapname) - 1);
|
||||
mapname[sizeof(mapname) - 1] = '\0';
|
||||
|
||||
if (!Q_stricmp(mapname, "q3tourney6")) {
|
||||
vec3_t mins = { 700, 204, 672 }, maxs = {
|
||||
964, 468, 680};
|
||||
if (!Q_stricmp(mapname, "q3tourney6") || !Q_stricmp(mapname, "q3tourney6_ctf") || !Q_stricmp(mapname, "mpq3tourney6")) {
|
||||
vec3_t mins = { 694, 200, 480 }, maxs = {
|
||||
968, 472, 680 };
|
||||
vec3_t buttonorg = { 304, 352, 920 };
|
||||
|
||||
//NOTE: NEVER use the func_bobbing in q3tourney6
|
||||
bs->tfl &= ~TFL_FUNCBOB;
|
||||
//if the bot is below the bounding box
|
||||
//crush area is higher in mpq3tourney6
|
||||
if (!Q_stricmp(mapname, "mpq3tourney6")) {
|
||||
mins[2] += 64;
|
||||
maxs[2] += 64;
|
||||
}
|
||||
//if the bot is in the bounding box of the crush area
|
||||
if (bs->origin[0] > mins[0] && bs->origin[0] < maxs[0]) {
|
||||
if (bs->origin[1] > mins[1] && bs->origin[1] < maxs[1]) {
|
||||
if (bs->origin[2] < mins[2]) {
|
||||
if (bs->origin[2] > mins[2] && bs->origin[2] < maxs[2]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
shootbutton = qfalse;
|
||||
//if an enemy is below this bounding box then shoot the button
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
//if an enemy is in the bounding box then shoot the button
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
|
||||
if (i == bs->client)
|
||||
continue;
|
||||
|
@ -3623,12 +3627,12 @@ void BotMapScripts(bot_state_t * bs)
|
|||
//
|
||||
if (entinfo.origin[0] > mins[0] && entinfo.origin[0] < maxs[0]) {
|
||||
if (entinfo.origin[1] > mins[1] && entinfo.origin[1] < maxs[1]) {
|
||||
if (entinfo.origin[2] < mins[2]) {
|
||||
if (entinfo.origin[2] > mins[2] && entinfo.origin[2] < maxs[2]) {
|
||||
//if there's a team mate below the crusher
|
||||
if (BotSameTeam(bs, i)) {
|
||||
shootbutton = qfalse;
|
||||
break;
|
||||
} else {
|
||||
} else if (bs->enemy == i) {
|
||||
shootbutton = qtrue;
|
||||
}
|
||||
}
|
||||
|
@ -3651,9 +3655,6 @@ void BotMapScripts(bot_state_t * bs)
|
|||
BotAttack(bs);
|
||||
}
|
||||
}
|
||||
} else if (!Q_stricmp(mapname, "mpq3tourney6")) {
|
||||
//NOTE: NEVER use the func_bobbing in mpq3tourney6
|
||||
bs->tfl &= ~TFL_FUNCBOB;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3744,7 +3745,6 @@ int BotFuncButtonActivateGoal(bot_state_t * bs, int bspent, bot_activategoal_t *
|
|||
modelindex = atoi(model + 1);
|
||||
if (!modelindex)
|
||||
return qfalse;
|
||||
VectorClear(angles);
|
||||
entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
|
||||
//get the lip of the button
|
||||
trap_AAS_FloatForBSPEpairKey(bspent, "lip", &lip);
|
||||
|
@ -3968,7 +3968,7 @@ int BotFuncDoorRotatingActivateGoal(bot_state_t * bs, int bspent, bot_activatego
|
|||
{
|
||||
int modelindex, entitynum;
|
||||
char model[MAX_INFO_STRING];
|
||||
vec3_t mins, maxs, origin, angles;
|
||||
vec3_t mins, maxs, origin;
|
||||
|
||||
trap_AAS_ValueForBSPEpairKey(bspent, "model", model, sizeof(model));
|
||||
if (!*model)
|
||||
|
@ -3976,7 +3976,6 @@ int BotFuncDoorRotatingActivateGoal(bot_state_t * bs, int bspent, bot_activatego
|
|||
modelindex = atoi(model + 1);
|
||||
if (!modelindex)
|
||||
return qfalse;
|
||||
VectorClear(angles);
|
||||
entitynum = BotModelMinsMaxs(modelindex, ET_MOVER, 0, mins, maxs);
|
||||
//door origin
|
||||
VectorAdd(mins, maxs, origin);
|
||||
|
@ -4003,7 +4002,7 @@ int BotTriggerMultipleActivateGoal(bot_state_t * bs, int bspent, bot_activategoa
|
|||
{
|
||||
int i, areas[10], numareas, modelindex, entitynum;
|
||||
char model[128];
|
||||
vec3_t start, end, mins, maxs, angles;
|
||||
vec3_t start, end, mins, maxs;
|
||||
vec3_t origin, goalorigin;
|
||||
|
||||
activategoal->shoot = qfalse;
|
||||
|
@ -4015,7 +4014,6 @@ int BotTriggerMultipleActivateGoal(bot_state_t * bs, int bspent, bot_activategoa
|
|||
modelindex = atoi(model + 1);
|
||||
if (!modelindex)
|
||||
return qfalse;
|
||||
VectorClear(angles);
|
||||
entitynum = BotModelMinsMaxs(modelindex, 0, CONTENTS_TRIGGER, mins, maxs);
|
||||
//trigger origin
|
||||
VectorAdd(mins, maxs, origin);
|
||||
|
@ -4169,7 +4167,7 @@ int BotGetActivateGoal(bot_state_t * bs, int entitynum, bot_activategoal_t * act
|
|||
char targetname[10][128];
|
||||
aas_entityinfo_t entinfo;
|
||||
aas_areainfo_t areainfo;
|
||||
vec3_t origin, angles, absmins, absmaxs;
|
||||
vec3_t origin, absmins, absmaxs;
|
||||
|
||||
memset(activategoal, 0, sizeof(bot_activategoal_t));
|
||||
BotEntityInfo(entitynum, &entinfo);
|
||||
|
@ -4226,7 +4224,6 @@ int BotGetActivateGoal(bot_state_t * bs, int entitynum, bot_activategoal_t * act
|
|||
if (*model) {
|
||||
modelindex = atoi(model + 1);
|
||||
if (modelindex) {
|
||||
VectorClear(angles);
|
||||
BotModelMinsMaxs(modelindex, ET_MOVER, 0, absmins, absmaxs);
|
||||
//
|
||||
numareas = trap_AAS_BBoxAreas(absmins, absmaxs, areas, MAX_ACTIVATEAREAS * 2);
|
||||
|
@ -4621,7 +4618,7 @@ int BotAIPredictObstacles(bot_state_t * bs, bot_goal_t * goal)
|
|||
bs->predictobstacles_goalareanum = goal->areanum;
|
||||
bs->predictobstacles_time = FloatTime();
|
||||
|
||||
// predict at most 100 areas or 10 seconds ahead
|
||||
// predict at most 100 areas or 1 second ahead
|
||||
trap_AAS_PredictRoute(&route, bs->areanum, bs->origin,
|
||||
goal->areanum, bs->tfl, 100, 1000,
|
||||
RSE_USETRAVELTYPE | RSE_ENTERCONTENTS, AREACONTENTS_MOVER, TFL_BRIDGE, 0);
|
||||
|
@ -5265,7 +5262,7 @@ BotDeathmatchAI
|
|||
*/
|
||||
void BotDeathmatchAI(bot_state_t * bs, float thinktime)
|
||||
{
|
||||
char gender[144], name[144], buf[144];
|
||||
char gender[144], name[144];
|
||||
char userinfo[MAX_INFO_STRING];
|
||||
int i;
|
||||
|
||||
|
@ -5280,11 +5277,6 @@ void BotDeathmatchAI(bot_state_t * bs, float thinktime)
|
|||
trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
|
||||
Info_SetValueForKey(userinfo, "sex", gender);
|
||||
trap_SetUserinfo(bs->client, userinfo);
|
||||
//set the team
|
||||
if (!bs->map_restart && g_gametype.integer != GT_TOURNAMENT) {
|
||||
Com_sprintf(buf, sizeof(buf), "team %s", bs->settings.team);
|
||||
trap_EA_Command(bs->client, buf);
|
||||
}
|
||||
//set the chat gender
|
||||
if (gender[0] == 'm')
|
||||
trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE);
|
||||
|
@ -5406,7 +5398,33 @@ void BotSetEntityNumForGoal(bot_goal_t * goal, char *classname)
|
|||
if (!ent->inuse) {
|
||||
continue;
|
||||
}
|
||||
if (!Q_stricmp(ent->classname, classname)) {
|
||||
if (Q_stricmp(ent->classname, classname) != 0) {
|
||||
continue;
|
||||
}
|
||||
VectorSubtract(goal->origin, ent->s.origin, dir);
|
||||
if (VectorLengthSquared(dir) < Square(10)) {
|
||||
goal->entitynum = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BotSetEntityNumForGoalWithActivator
|
||||
==================
|
||||
*/
|
||||
void BotSetEntityNumForGoalWithActivator(bot_goal_t *goal, char *classname) {
|
||||
gentity_t *ent;
|
||||
int i;
|
||||
vec3_t dir;
|
||||
|
||||
ent = &g_entities[0];
|
||||
for (i = 0; i < level.num_entities; i++, ent++) {
|
||||
if (!ent->inuse || !ent->activator) {
|
||||
continue;
|
||||
}
|
||||
if (Q_stricmp(ent->activator->classname, classname) != 0) {
|
||||
continue;
|
||||
}
|
||||
VectorSubtract(goal->origin, ent->s.origin, dir);
|
||||
|
@ -5461,7 +5479,6 @@ void BotSetupDeathmatchAI(void)
|
|||
char model[128];
|
||||
|
||||
gametype = trap_Cvar_VariableIntegerValue("g_gametype");
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
trap_Cvar_Register(&bot_rocketjump, "bot_rocketjump", "1", 0);
|
||||
trap_Cvar_Register(&bot_grapple, "bot_grapple", "0", 0);
|
||||
|
|
|
@ -201,7 +201,7 @@ void BotClearActivateGoalStack(bot_state_t * bs);
|
|||
//returns the team the bot is in
|
||||
int BotTeam(bot_state_t * bs);
|
||||
|
||||
//retuns the opposite team of the bot
|
||||
//returns the opposite team of the bot
|
||||
int BotOppositeTeam(bot_state_t * bs);
|
||||
|
||||
//returns the flag the bot is carrying (CTFFLAG_?)
|
||||
|
|
|
@ -76,8 +76,6 @@
|
|||
#include "inv.h"
|
||||
#include "syn.h"
|
||||
|
||||
#define MAX_PATH 144
|
||||
|
||||
//bot states
|
||||
bot_state_t *botstates[MAX_CLIENTS];
|
||||
|
||||
|
@ -294,7 +292,7 @@ void BotTestAAS(vec3_t origin)
|
|||
return;
|
||||
areanum = BotPointAreaNum(origin);
|
||||
if (areanum)
|
||||
BotAI_Print(PRT_MESSAGE, "\remtpy area");
|
||||
BotAI_Print(PRT_MESSAGE, "\rempty area");
|
||||
else
|
||||
BotAI_Print(PRT_MESSAGE, "\r^1SOLID area");
|
||||
} else if (bot_testclusters.integer) {
|
||||
|
@ -423,7 +421,7 @@ void BotTeamplayReport(void)
|
|||
char buf[MAX_INFO_STRING];
|
||||
|
||||
BotAI_Print(PRT_MESSAGE, S_COLOR_RED "RED\n");
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
//
|
||||
if (!botstates[i] || !botstates[i]->inuse)
|
||||
continue;
|
||||
|
@ -438,7 +436,7 @@ void BotTeamplayReport(void)
|
|||
}
|
||||
}
|
||||
BotAI_Print(PRT_MESSAGE, S_COLOR_BLUE "BLUE\n");
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
//
|
||||
if (!botstates[i] || !botstates[i]->inuse)
|
||||
continue;
|
||||
|
@ -570,7 +568,7 @@ void BotUpdateInfoConfigStrings(void)
|
|||
int i;
|
||||
char buf[MAX_INFO_STRING];
|
||||
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
//
|
||||
if (!botstates[i] || !botstates[i]->inuse)
|
||||
continue;
|
||||
|
@ -823,7 +821,7 @@ void BotChangeViewAngles(bot_state_t * bs, float thinktime)
|
|||
//
|
||||
if (bot_challenge.integer) {
|
||||
//smooth slowdown view model
|
||||
diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]));
|
||||
diff = fabs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]));
|
||||
anglespeed = diff * factor;
|
||||
if (anglespeed > maxchange)
|
||||
anglespeed = maxchange;
|
||||
|
@ -939,7 +937,7 @@ void BotInputToUserCommand(bot_input_t * bi, usercmd_t * ucmd, int delta_angles[
|
|||
//set the view independent movement
|
||||
f = DotProduct(forward, bi->dir);
|
||||
r = DotProduct(right, bi->dir);
|
||||
u = abs(forward[2]) * bi->dir[2];
|
||||
u = fabs(forward[2]) * bi->dir[2];
|
||||
m = fabs(f);
|
||||
|
||||
if (fabs(r) > m) {
|
||||
|
@ -1056,8 +1054,10 @@ int BotAI(int client, float thinktime)
|
|||
return qfalse;
|
||||
}
|
||||
//retrieve the current client state
|
||||
BotAI_GetClientState(client, &bs->cur_ps);
|
||||
|
||||
if (!BotAI_GetClientState(client, &bs->cur_ps)) {
|
||||
BotAI_Print(PRT_FATAL, "BotAI: failed to get player state for player %d\n", client);
|
||||
return qfalse;
|
||||
}
|
||||
//retrieve any waiting server commands
|
||||
while (trap_BotGetServerCommand(client, buf, sizeof(buf))) {
|
||||
//have buf point to the command and args to the command arguments
|
||||
|
@ -1225,7 +1225,7 @@ BotAISetupClient
|
|||
*/
|
||||
int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart)
|
||||
{
|
||||
char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH];
|
||||
char filename[144], name[144], gender[144];
|
||||
bot_state_t *bs;
|
||||
int errnum;
|
||||
|
||||
|
@ -1257,7 +1257,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta
|
|||
//allocate a goal state
|
||||
bs->gs = trap_BotAllocGoalState(client);
|
||||
//load the item weights
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH);
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, sizeof(filename));
|
||||
errnum = trap_BotLoadItemWeights(bs->gs, filename);
|
||||
if (errnum != BLERR_NOERROR) {
|
||||
trap_BotFreeGoalState(bs->gs);
|
||||
|
@ -1266,7 +1266,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta
|
|||
//allocate a weapon state
|
||||
bs->ws = trap_BotAllocWeaponState();
|
||||
//load the weapon weights
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH);
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, sizeof(filename));
|
||||
errnum = trap_BotLoadWeaponWeights(bs->ws, filename);
|
||||
if (errnum != BLERR_NOERROR) {
|
||||
trap_BotFreeGoalState(bs->gs);
|
||||
|
@ -1276,8 +1276,8 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta
|
|||
//allocate a chat state
|
||||
bs->cs = trap_BotAllocChatState();
|
||||
//load the chat file
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH);
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH);
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, sizeof(filename));
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, sizeof(name));
|
||||
errnum = trap_BotLoadChatFile(bs->cs, filename, name);
|
||||
if (errnum != BLERR_NOERROR) {
|
||||
trap_BotFreeChatState(bs->cs);
|
||||
|
@ -1286,7 +1286,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta
|
|||
return qfalse;
|
||||
}
|
||||
//get the gender characteristic
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH);
|
||||
trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender));
|
||||
//set the chat gender
|
||||
if (*gender == 'f' || *gender == 'F')
|
||||
trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE);
|
||||
|
@ -1318,7 +1318,7 @@ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean resta
|
|||
if (restart) {
|
||||
BotReadSessionData(bs);
|
||||
}
|
||||
//bot has been setup succesfully
|
||||
//bot has been setup successfully
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
@ -1663,9 +1663,7 @@ int BotInitLibrary(void)
|
|||
char buf[144];
|
||||
|
||||
//set the maxclients and maxentities library variables before calling BotSetupLibrary
|
||||
trap_Cvar_VariableStringBuffer("sv_maxclients", buf, sizeof(buf));
|
||||
if (!strlen(buf))
|
||||
strcpy(buf, "8");
|
||||
Com_sprintf(buf, sizeof(buf), "%d", level.maxclients);
|
||||
trap_BotLibVarSet("maxclients", buf);
|
||||
Com_sprintf(buf, sizeof(buf), "%d", MAX_GENTITIES);
|
||||
trap_BotLibVarSet("maxentities", buf);
|
||||
|
|
|
@ -105,13 +105,9 @@ int BotNumTeamMates(bot_state_t * bs)
|
|||
{
|
||||
int i, numplayers;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
numplayers = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
@ -137,8 +133,12 @@ int BotClientTravelTimeToGoal(int client, bot_goal_t * goal)
|
|||
playerState_t ps;
|
||||
int areanum;
|
||||
|
||||
BotAI_GetClientState(client, &ps);
|
||||
areanum = BotPointAreaNum(ps.origin);
|
||||
if (BotAI_GetClientState(client, &ps)) {
|
||||
areanum = BotPointAreaNum(ps.origin);
|
||||
} else {
|
||||
areanum = 0;
|
||||
}
|
||||
|
||||
if (!areanum)
|
||||
return 1;
|
||||
return trap_AAS_AreaTravelTimeToGoalArea(areanum, ps.origin, goal->areanum, TFL_DEFAULT);
|
||||
|
@ -154,7 +154,6 @@ int BotSortTeamMatesByBaseTravelTime(bot_state_t * bs, int *teammates, int maxte
|
|||
|
||||
int i, j, k, numteammates, traveltime;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
int traveltimes[MAX_CLIENTS];
|
||||
bot_goal_t *goal = NULL;
|
||||
|
||||
|
@ -164,11 +163,9 @@ int BotSortTeamMatesByBaseTravelTime(bot_state_t * bs, int *teammates, int maxte
|
|||
else
|
||||
goal = &ctf_blueflag;
|
||||
}
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
numteammates = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
@ -932,13 +929,9 @@ void BotTeamOrders(bot_state_t * bs)
|
|||
int teammates[MAX_CLIENTS];
|
||||
int numteammates, i;
|
||||
char buf[MAX_INFO_STRING];
|
||||
static int maxclients;
|
||||
|
||||
if (!maxclients)
|
||||
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
|
||||
|
||||
numteammates = 0;
|
||||
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
trap_GetConfigstring(CS_PLAYERS + i, buf, sizeof(buf));
|
||||
//if no config string or no name
|
||||
if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n")))
|
||||
|
|
|
@ -57,10 +57,10 @@ static void swapfunc(char *, char *, int, int);
|
|||
*/
|
||||
#define swapcode(TYPE, parmi, parmj, n) { \
|
||||
long i = (n) / sizeof (TYPE); \
|
||||
register TYPE *pi = (TYPE *) (parmi); \
|
||||
register TYPE *pj = (TYPE *) (parmj); \
|
||||
TYPE *pi = (TYPE *) (parmi); \
|
||||
TYPE *pj = (TYPE *) (parmj); \
|
||||
do { \
|
||||
register TYPE t = *pi; \
|
||||
TYPE t = *pi; \
|
||||
*pi++ = *pj; \
|
||||
*pj++ = t; \
|
||||
} while (--i > 0); \
|
||||
|
@ -1473,7 +1473,7 @@ double fabs( double x ) {
|
|||
* probably requires libm on most operating systems. Don't yet
|
||||
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
|
||||
* was pretty badly broken, it just wasn't being exercised in ways
|
||||
* which showed it, so that's been fixed. Also, formated the code
|
||||
* which showed it, so that's been fixed. Also, formatted the code
|
||||
* to mutt conventions, and removed dead code left over from the
|
||||
* original. Also, there is now a builtin-test, just compile with:
|
||||
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
|
||||
|
|
|
@ -1047,7 +1047,7 @@ static void PM_NoclipMove(void)
|
|||
================
|
||||
PM_FootstepForSurface
|
||||
|
||||
Returns an event number apropriate for the groundsurface
|
||||
Returns an event number appropriate for the groundsurface
|
||||
Makro - changed prototype so that we can use it for other surfaces, too
|
||||
(ladder footsteps)
|
||||
================
|
||||
|
@ -1614,7 +1614,7 @@ static void PM_Footsteps(void)
|
|||
old = pm->ps->bobCycle;
|
||||
pm->ps->bobCycle = (int) (old + bobmove * pml.msec) & 255;
|
||||
|
||||
// if we just crossed a cycle boundary, play an apropriate footstep event
|
||||
// if we just crossed a cycle boundary, play an appropriate footstep event
|
||||
if (((old + 64) ^ (pm->ps->bobCycle + 64)) & 128) {
|
||||
if (pm->waterlevel == 0) {
|
||||
//Elder: we can check for slippers here!
|
||||
|
|
|
@ -813,7 +813,7 @@ typedef enum {
|
|||
STAT_DEAD_YAW, // look this direction when dead (FIXME: get rid of?)
|
||||
|
||||
STAT_CLIENTS_READY, // bit mask of clients wishing to exit the intermission (FIXME: configstring?)
|
||||
//STAT_MAX_HEALTH, // health / armor limit, changable by handicap
|
||||
//STAT_MAX_HEALTH, // health / armor limit, changeable by handicap
|
||||
|
||||
//These are RQ3-related specific stats
|
||||
STAT_CLIPS, // Num Clips player currently has
|
||||
|
|
|
@ -465,8 +465,10 @@ qboolean PM_SlideMove(qboolean gravity)
|
|||
// slide along the plane
|
||||
PM_ClipVelocity(pm->ps->velocity, planes[i], clipVelocity, OVERCLIP);
|
||||
|
||||
// slide along the plane
|
||||
PM_ClipVelocity(endVelocity, planes[i], endClipVelocity, OVERCLIP);
|
||||
if (gravity) {
|
||||
// slide along the plane
|
||||
PM_ClipVelocity(endVelocity, planes[i], endClipVelocity, OVERCLIP);
|
||||
}
|
||||
|
||||
// see if there is a second plane that the new move enters
|
||||
for (j = 0; j < numplanes; j++) {
|
||||
|
@ -490,10 +492,12 @@ qboolean PM_SlideMove(qboolean gravity)
|
|||
d = DotProduct(dir, pm->ps->velocity);
|
||||
VectorScale(dir, d, clipVelocity);
|
||||
|
||||
CrossProduct(planes[i], planes[j], dir);
|
||||
VectorNormalize(dir);
|
||||
d = DotProduct(dir, endVelocity);
|
||||
VectorScale(dir, d, endClipVelocity);
|
||||
if (gravity) {
|
||||
CrossProduct(planes[i], planes[j], dir);
|
||||
VectorNormalize(dir);
|
||||
d = DotProduct(dir, endVelocity);
|
||||
VectorScale(dir, d, endClipVelocity);
|
||||
}
|
||||
|
||||
// see if there is a third plane the the new move enters
|
||||
for (k = 0; k < numplanes; k++) {
|
||||
|
@ -511,7 +515,11 @@ qboolean PM_SlideMove(qboolean gravity)
|
|||
|
||||
// if we have fixed all interactions, try another move
|
||||
VectorCopy(clipVelocity, pm->ps->velocity);
|
||||
VectorCopy(endClipVelocity, endVelocity);
|
||||
|
||||
if (gravity) {
|
||||
VectorCopy(endClipVelocity, endVelocity);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -483,7 +483,7 @@ void G_TouchTriggers(gentity_t * ent)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
// use seperate code for determining if an item is picked up
|
||||
// use separate code for determining if an item is picked up
|
||||
// so you don't have to actually contact its bounding box
|
||||
if (hit->s.eType == ET_ITEM) {
|
||||
if (!BG_PlayerTouchesItem(&ent->client->ps, &hit->s, level.time)) {
|
||||
|
@ -1127,8 +1127,10 @@ void ClientThink_real(gentity_t * ent)
|
|||
|
||||
if (pmove_msec.integer < 8) {
|
||||
trap_Cvar_Set("pmove_msec", "8");
|
||||
trap_Cvar_Update(&pmove_msec);
|
||||
} else if (pmove_msec.integer > 33) {
|
||||
trap_Cvar_Set("pmove_msec", "33");
|
||||
trap_Cvar_Update(&pmove_msec);
|
||||
}
|
||||
|
||||
if (pmove_fixed.integer || client->pers.pmoveFixed) {
|
||||
|
|
|
@ -250,78 +250,103 @@ static void PlayerIntroSound(const char *modelAndSkin)
|
|||
trap_SendConsoleCommand(EXEC_APPEND, va("play sound/player/announce/%s.wav\n", skin));
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_CountBotPlayersByName
|
||||
|
||||
Check connected and connecting (delay join) bots.
|
||||
|
||||
Returns number of bots with name on specified team or whole server if team is -1.
|
||||
===============
|
||||
*/
|
||||
int G_CountBotPlayersByName( const char *name, int team ) {
|
||||
int i, num;
|
||||
gclient_t *cl;
|
||||
|
||||
num = 0;
|
||||
for ( i=0 ; i< g_maxclients.integer ; i++ ) {
|
||||
cl = level.clients + i;
|
||||
if ( cl->pers.connected == CON_DISCONNECTED ) {
|
||||
continue;
|
||||
}
|
||||
if ( !(g_entities[i].r.svFlags & SVF_BOT) ) {
|
||||
continue;
|
||||
}
|
||||
if ( team >= 0 && cl->sess.sessionTeam != team ) {
|
||||
continue;
|
||||
}
|
||||
if ( name && Q_stricmp( name, cl->pers.netname ) ) {
|
||||
continue;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_SelectRandomBotInfo
|
||||
|
||||
Get random least used bot info on team or whole server if team is -1.
|
||||
===============
|
||||
*/
|
||||
int G_SelectRandomBotInfo( int team ) {
|
||||
int selection[MAX_BOTS];
|
||||
int n, num;
|
||||
int count, bestCount;
|
||||
char *value;
|
||||
|
||||
// don't add duplicate bots to the server if there are less bots than bot types
|
||||
if ( team != -1 && G_CountBotPlayersByName( NULL, -1 ) < g_numBots ) {
|
||||
team = -1;
|
||||
}
|
||||
|
||||
num = 0;
|
||||
bestCount = MAX_CLIENTS;
|
||||
for ( n = 0; n < g_numBots ; n++ ) {
|
||||
value = Info_ValueForKey( g_botInfos[n], "funname" );
|
||||
if ( !value[0] ) {
|
||||
value = Info_ValueForKey( g_botInfos[n], "name" );
|
||||
}
|
||||
//
|
||||
count = G_CountBotPlayersByName( value, team );
|
||||
|
||||
if ( count < bestCount ) {
|
||||
bestCount = count;
|
||||
num = 0;
|
||||
}
|
||||
|
||||
if ( count == bestCount ) {
|
||||
selection[num++] = n;
|
||||
|
||||
if ( num == MAX_BOTS ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( num > 0 ) {
|
||||
num = random() * ( num - 1 );
|
||||
return selection[num];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
G_AddRandomBot
|
||||
===============
|
||||
*/
|
||||
void G_AddRandomBot(int team)
|
||||
{
|
||||
int i, n, num;
|
||||
float skill;
|
||||
char *value, netname[36], *teamstr;
|
||||
gclient_t *cl;
|
||||
void G_AddRandomBot( int team ) {
|
||||
char *teamstr;
|
||||
float skill;
|
||||
|
||||
num = 0;
|
||||
for (n = 0; n < g_numBots; n++) {
|
||||
value = Info_ValueForKey(g_botInfos[n], "name");
|
||||
//
|
||||
for (i = 0; i < g_maxclients.integer; i++) {
|
||||
cl = level.clients + i;
|
||||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
if (!(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT)) {
|
||||
continue;
|
||||
}
|
||||
if (team >= 0 && cl->sess.sessionTeam != team) {
|
||||
continue;
|
||||
}
|
||||
if (!Q_stricmp(value, cl->pers.netname)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= g_maxclients.integer) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
num = random() * num;
|
||||
for (n = 0; n < g_numBots; n++) {
|
||||
value = Info_ValueForKey(g_botInfos[n], "name");
|
||||
//
|
||||
for (i = 0; i < g_maxclients.integer; i++) {
|
||||
cl = level.clients + i;
|
||||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
if (!(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT)) {
|
||||
continue;
|
||||
}
|
||||
if (team >= 0 && cl->sess.sessionTeam != team) {
|
||||
continue;
|
||||
}
|
||||
if (!Q_stricmp(value, cl->pers.netname)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= g_maxclients.integer) {
|
||||
num--;
|
||||
if (num <= 0) {
|
||||
skill = trap_Cvar_VariableValue("g_spSkill");
|
||||
if (team == TEAM_RED)
|
||||
teamstr = "red";
|
||||
else if (team == TEAM_BLUE)
|
||||
teamstr = "blue";
|
||||
else
|
||||
teamstr = "";
|
||||
Q_strncpyz(netname, value, sizeof(netname));
|
||||
Q_CleanStr(netname);
|
||||
trap_SendConsoleCommand(EXEC_INSERT,
|
||||
va("addbot %s %f %s %i\n", netname, skill, teamstr, 0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
skill = trap_Cvar_VariableValue( "g_spSkill" );
|
||||
if (team == TEAM_RED) teamstr = "red";
|
||||
else if (team == TEAM_BLUE) teamstr = "blue";
|
||||
else teamstr = "free";
|
||||
trap_SendConsoleCommand( EXEC_INSERT, va("addbot random %f %s %i\n", skill, teamstr, 0) );
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -339,13 +364,13 @@ int G_RemoveRandomBot(int team)
|
|||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
if (!(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT)) {
|
||||
if (!(g_entities[i].r.svFlags & SVF_BOT)) {
|
||||
continue;
|
||||
}
|
||||
if (team >= 0 && cl->sess.sessionTeam != team) {
|
||||
continue;
|
||||
}
|
||||
trap_SendConsoleCommand( EXEC_INSERT, va("clientkick %d\n", cl->ps.clientNum) );
|
||||
trap_SendConsoleCommand( EXEC_INSERT, va("clientkick %d\n", i) );
|
||||
return qtrue;
|
||||
}
|
||||
return qfalse;
|
||||
|
@ -367,7 +392,7 @@ int G_CountHumanPlayers(int team)
|
|||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
if (g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) {
|
||||
if (g_entities[i].r.svFlags & SVF_BOT) {
|
||||
continue;
|
||||
}
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
|
@ -385,20 +410,22 @@ int G_CountHumanPlayers(int team)
|
|||
/*
|
||||
===============
|
||||
G_CountBotPlayers
|
||||
|
||||
Check connected and connecting (delay join) bots.
|
||||
===============
|
||||
*/
|
||||
int G_CountBotPlayers(int team)
|
||||
{
|
||||
int i, n, num;
|
||||
int i, num;
|
||||
gclient_t *cl;
|
||||
|
||||
num = 0;
|
||||
for (i = 0; i < g_maxclients.integer; i++) {
|
||||
cl = level.clients + i;
|
||||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
if (cl->pers.connected == CON_DISCONNECTED) {
|
||||
continue;
|
||||
}
|
||||
if (!(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT)) {
|
||||
if (!(g_entities[i].r.svFlags & SVF_BOT)) {
|
||||
continue;
|
||||
}
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
|
@ -410,15 +437,6 @@ int G_CountBotPlayers(int team)
|
|||
}
|
||||
num++;
|
||||
}
|
||||
for (n = 0; n < BOT_SPAWN_QUEUE_DEPTH; n++) {
|
||||
if (!botSpawnQueue[n].spawnTime) {
|
||||
continue;
|
||||
}
|
||||
if (botSpawnQueue[n].spawnTime > level.time) {
|
||||
continue;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
|
@ -582,7 +600,6 @@ qboolean G_BotConnect(int clientNum, qboolean restart)
|
|||
|
||||
Q_strncpyz(settings.characterfile, Info_ValueForKey(userinfo, "characterfile"), sizeof(settings.characterfile));
|
||||
settings.skill = atof(Info_ValueForKey(userinfo, "skill"));
|
||||
Q_strncpyz(settings.team, Info_ValueForKey(userinfo, "team"), sizeof(settings.team));
|
||||
|
||||
if (!BotAISetupClient(clientNum, &settings, restart)) {
|
||||
trap_DropClient(clientNum, "BotAISetupClient failed");
|
||||
|
@ -600,6 +617,8 @@ G_AddBot
|
|||
static void G_AddBot(const char *name, float skill, const char *team, int delay, char *altname)
|
||||
{
|
||||
int clientNum;
|
||||
int teamNum;
|
||||
int botinfoNum;
|
||||
char *botinfo;
|
||||
gentity_t *bot;
|
||||
char *s;
|
||||
|
@ -610,12 +629,59 @@ static void G_AddBot(const char *name, float skill, const char *team, int delay,
|
|||
weapon_t tpWeapon = WP_M4;
|
||||
holdable_t tpItem = HI_LASER;
|
||||
|
||||
// get the botinfo from bots.txt
|
||||
botinfo = G_GetBotInfoByName(name);
|
||||
if (!botinfo) {
|
||||
G_Printf(S_COLOR_RED "Error: Bot '%s' not defined\n", name);
|
||||
// have the server allocate a client slot
|
||||
clientNum = trap_BotAllocateClient();
|
||||
if ( clientNum == -1 ) {
|
||||
G_Printf(S_COLOR_RED "Unable to add bot. All player slots are in use.\n");
|
||||
G_Printf(S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// set default team
|
||||
if (!team || !*team) {
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
if (PickTeam(clientNum) == TEAM_RED) {
|
||||
team = "red";
|
||||
} else {
|
||||
team = "blue";
|
||||
}
|
||||
} else {
|
||||
team = "free";
|
||||
}
|
||||
}
|
||||
|
||||
// get the botinfo from bots.txt
|
||||
if ( Q_stricmp( name, "random" ) == 0 ) {
|
||||
if (Q_stricmp(team, "red") == 0 || Q_stricmp(team, "r") == 0) {
|
||||
teamNum = TEAM_RED;
|
||||
} else if (Q_stricmp(team, "blue") == 0 || Q_stricmp(team, "b") == 0) {
|
||||
teamNum = TEAM_BLUE;
|
||||
} else if (!Q_stricmp(team, "spectator") || !Q_stricmp(team, "s")) {
|
||||
teamNum = TEAM_SPECTATOR;
|
||||
} else {
|
||||
teamNum = TEAM_FREE;
|
||||
}
|
||||
|
||||
botinfoNum = G_SelectRandomBotInfo(teamNum);
|
||||
|
||||
if (botinfoNum < 0) {
|
||||
G_Printf(S_COLOR_RED "Error: Cannot add random bot, no bot info available.\n" );
|
||||
trap_BotFreeClient(clientNum);
|
||||
return;
|
||||
}
|
||||
|
||||
botinfo = G_GetBotInfoByNumber(botinfoNum);
|
||||
}
|
||||
else {
|
||||
botinfo = G_GetBotInfoByName(name);
|
||||
}
|
||||
|
||||
if (!botinfo) {
|
||||
G_Printf(S_COLOR_RED "Error: Bot '%s' not defined\n", name);
|
||||
trap_BotFreeClient( clientNum );
|
||||
return;
|
||||
}
|
||||
|
||||
// create the bot's userinfo
|
||||
userinfo[0] = '\0';
|
||||
|
||||
|
@ -630,7 +696,8 @@ static void G_AddBot(const char *name, float skill, const char *team, int delay,
|
|||
Info_SetValueForKey(userinfo, "name", botname);
|
||||
Info_SetValueForKey(userinfo, "rate", "25000");
|
||||
Info_SetValueForKey(userinfo, "snaps", "20");
|
||||
Info_SetValueForKey(userinfo, "skill", va("%1.2f", skill));
|
||||
Info_SetValueForKey(userinfo, "skill", va("%.2f", skill));
|
||||
Info_SetValueForKey(userinfo, "teampref", team);
|
||||
|
||||
if (skill >= 1 && skill < 2) {
|
||||
Info_SetValueForKey(userinfo, "handicap", "50");
|
||||
|
@ -679,30 +746,13 @@ static void G_AddBot(const char *name, float skill, const char *team, int delay,
|
|||
s = Info_ValueForKey(botinfo, "aifile");
|
||||
if (!*s) {
|
||||
trap_Printf(S_COLOR_RED "Error: bot has no aifile specified\n");
|
||||
trap_BotFreeClient( clientNum );
|
||||
return;
|
||||
}
|
||||
// have the server allocate a client slot
|
||||
clientNum = trap_BotAllocateClient();
|
||||
if (clientNum == -1) {
|
||||
G_Printf(S_COLOR_RED "Unable to add bot. All player slots are in use.\n");
|
||||
G_Printf(S_COLOR_RED "Start server with more 'open' slots (or check setting of sv_maxclients cvar).\n");
|
||||
return;
|
||||
}
|
||||
// initialize the bot settings
|
||||
if (!team || !*team) {
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
if (PickTeam(clientNum) == TEAM_RED) {
|
||||
team = "red";
|
||||
} else {
|
||||
team = "blue";
|
||||
}
|
||||
} else {
|
||||
team = "red";
|
||||
}
|
||||
}
|
||||
Info_SetValueForKey(userinfo, "characterfile", Info_ValueForKey(botinfo, "aifile"));
|
||||
Info_SetValueForKey(userinfo, "skill", va("%5.2f", skill));
|
||||
Info_SetValueForKey(userinfo, "team", team);
|
||||
Info_SetValueForKey(userinfo, "characterfile", s);
|
||||
|
||||
// don't send tinfo to bots, they don't parse it
|
||||
Info_SetValueForKey( userinfo, "teamoverlay", "0" );
|
||||
|
||||
if (g_gametype.integer == GT_TEAMPLAY) {
|
||||
//Makro - load custom weapon/item from bot file
|
||||
|
@ -772,7 +822,7 @@ void Svcmd_AddBot_f(void)
|
|||
if (!string[0]) {
|
||||
skill = 4;
|
||||
} else {
|
||||
skill = atof(string);
|
||||
skill = Com_Clamp(1, 5, atof(string));
|
||||
}
|
||||
|
||||
// team
|
||||
|
@ -815,19 +865,19 @@ void Svcmd_BotList_f(void)
|
|||
|
||||
trap_Printf("^1name model aifile funname\n");
|
||||
for (i = 0; i < g_numBots; i++) {
|
||||
strcpy(name, Info_ValueForKey(g_botInfos[i], "name"));
|
||||
Q_strncpyz(name, Info_ValueForKey(g_botInfos[i], "name"), sizeof(name));
|
||||
if (!*name) {
|
||||
strcpy(name, "UnnamedPlayer");
|
||||
}
|
||||
strcpy(funname, Info_ValueForKey(g_botInfos[i], "funname"));
|
||||
Q_strncpyz(funname, Info_ValueForKey(g_botInfos[i], "funname"), sizeof(funname));
|
||||
if (!*funname) {
|
||||
strcpy(funname, "");
|
||||
}
|
||||
strcpy(model, Info_ValueForKey(g_botInfos[i], "model"));
|
||||
Q_strncpyz(model, Info_ValueForKey(g_botInfos[i], "model"), sizeof(model));
|
||||
if (!*model) {
|
||||
strcpy(model, "visor/default");
|
||||
}
|
||||
strcpy(aifile, Info_ValueForKey(g_botInfos[i], "aifile"));
|
||||
Q_strncpyz(aifile, Info_ValueForKey(g_botInfos[i], "aifile"), sizeof(aifile));
|
||||
if (!*aifile) {
|
||||
strcpy(aifile, "bots/default_c.c");
|
||||
}
|
||||
|
|
|
@ -402,7 +402,7 @@ void SP_info_player_deathmatch(gentity_t * ent)
|
|||
}
|
||||
|
||||
/*QUAKED info_player_start (1 0 0) (-16 -16 -24) (16 16 32)
|
||||
equivelant to info_player_deathmatch
|
||||
equivalent to info_player_deathmatch
|
||||
*/
|
||||
void SP_info_player_start(gentity_t * ent)
|
||||
{
|
||||
|
@ -703,7 +703,7 @@ void ClearBodyQue(void)
|
|||
=============
|
||||
BodySink
|
||||
|
||||
After sitting around for five seconds, fall into the ground and dissapear
|
||||
After sitting around for five seconds, fall into the ground and disappear
|
||||
=============
|
||||
*/
|
||||
void BodySink(gentity_t * ent)
|
||||
|
@ -994,7 +994,7 @@ void ClientUserinfoChanged(int clientNum)
|
|||
{
|
||||
gentity_t *ent;
|
||||
gclient_t *client;
|
||||
int teamTask, teamLeader, team, health, gender;
|
||||
int teamTask, teamLeader, health, gender;
|
||||
char *s, model[MAX_QPATH], headModel[MAX_QPATH], oldname[MAX_STRING_CHARS];
|
||||
char c1[MAX_INFO_STRING], c2[MAX_INFO_STRING], redTeam[MAX_INFO_STRING];
|
||||
char blueTeam[MAX_INFO_STRING], userinfo[MAX_INFO_STRING];
|
||||
|
@ -1011,11 +1011,7 @@ void ClientUserinfoChanged(int clientNum)
|
|||
// don't keep those clients and userinfo
|
||||
trap_DropClient(clientNum, "Invalid userinfo");
|
||||
}
|
||||
// check for local client
|
||||
s = Info_ValueForKey(userinfo, "ip");
|
||||
if (!strcmp(s, "localhost")) {
|
||||
client->pers.localClient = qtrue;
|
||||
}
|
||||
|
||||
// check the item prediction
|
||||
s = Info_ValueForKey(userinfo, "cg_predictItems");
|
||||
if (!atoi(s)) {
|
||||
|
@ -1144,20 +1140,6 @@ void ClientUserinfoChanged(int clientNum)
|
|||
} else if (gender != GENDER_NEUTER)
|
||||
client->radioGender = gender;
|
||||
}
|
||||
// bots set their team a few frames later
|
||||
if (g_gametype.integer >= GT_TEAM && g_entities[clientNum].r.svFlags & SVF_BOT) {
|
||||
s = Info_ValueForKey(userinfo, "team");
|
||||
if (!Q_stricmp(s, "red") || !Q_stricmp(s, "r") || !Q_stricmp(s, "1")) {
|
||||
team = TEAM_RED;
|
||||
} else if (!Q_stricmp(s, "blue") || !Q_stricmp(s, "b") || !Q_stricmp(s, "2")) {
|
||||
team = TEAM_BLUE;
|
||||
} else {
|
||||
// pick the team with the least number of players
|
||||
team = PickTeam(clientNum);
|
||||
}
|
||||
} else {
|
||||
team = client->sess.sessionTeam;
|
||||
}
|
||||
|
||||
// teamInfo
|
||||
s = Info_ValueForKey(userinfo, "teamoverlay");
|
||||
|
@ -1173,11 +1155,11 @@ void ClientUserinfoChanged(int clientNum)
|
|||
teamLeader = client->sess.teamLeader;
|
||||
|
||||
// colors
|
||||
strcpy(c1, Info_ValueForKey(userinfo, "color1"));
|
||||
strcpy(c2, Info_ValueForKey(userinfo, "color2"));
|
||||
Q_strncpyz(c1, Info_ValueForKey(userinfo, "color1"), sizeof(c1));
|
||||
Q_strncpyz(c2, Info_ValueForKey(userinfo, "color2"), sizeof(c2));
|
||||
|
||||
strcpy(redTeam, Info_ValueForKey(userinfo, "g_redteam"));
|
||||
strcpy(blueTeam, Info_ValueForKey(userinfo, "g_blueteam"));
|
||||
Q_strncpyz(redTeam, Info_ValueForKey(userinfo, "g_redteam"), sizeof(redTeam));
|
||||
Q_strncpyz(blueTeam, Info_ValueForKey(userinfo, "g_blueteam"), sizeof(blueTeam));
|
||||
|
||||
// send over a subset of the userinfo keys so other clients can
|
||||
// print scoreboards, display models, and play custom sounds
|
||||
|
@ -1185,7 +1167,7 @@ void ClientUserinfoChanged(int clientNum)
|
|||
//Makro - adding teamplay weapon/item info for bots
|
||||
s = va
|
||||
("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d\\tpw\\%s\\tpi\\%s",
|
||||
client->pers.netname, team, model, headModel, c1, c2, client->pers.maxHealth, client->sess.wins,
|
||||
client->pers.netname, client->sess.sessionTeam, model, headModel, c1, c2, client->pers.maxHealth, client->sess.wins,
|
||||
client->sess.losses,
|
||||
//Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader );
|
||||
Info_ValueForKey(userinfo, "skill"), teamTask, teamLeader, Info_ValueForKey(userinfo, "tpw"),
|
||||
|
@ -1339,11 +1321,11 @@ char *ClientConnect(int clientNum, qboolean firstTime, qboolean isBot)
|
|||
// JBravo: Clear zcam flag for cgame
|
||||
client->ps.stats[STAT_RQ3] &= ~RQ3_ZCAM;
|
||||
|
||||
// read or initialize the session data
|
||||
if (firstTime || level.newSession) {
|
||||
G_InitSessionData(client, userinfo);
|
||||
// check for local client
|
||||
value = Info_ValueForKey( userinfo, "ip" );
|
||||
if ( !strcmp( value, "localhost" ) ) {
|
||||
client->pers.localClient = qtrue;
|
||||
}
|
||||
G_ReadSessionData(client);
|
||||
|
||||
if (isBot) {
|
||||
ent->r.svFlags |= SVF_BOT;
|
||||
|
@ -1352,6 +1334,13 @@ char *ClientConnect(int clientNum, qboolean firstTime, qboolean isBot)
|
|||
return "BotConnectfailed";
|
||||
}
|
||||
}
|
||||
|
||||
// read or initialize the session data
|
||||
if (firstTime || level.newSession) {
|
||||
G_InitSessionData(client, userinfo);
|
||||
}
|
||||
G_ReadSessionData(client);
|
||||
|
||||
// slicer : make sessionTeam = to savedTeam for scoreboard on cgame
|
||||
// JBravo: only for teambased games. Could break DM
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
|
|
|
@ -505,8 +505,6 @@
|
|||
#include "../ui/menudef.h" // for the voice chats
|
||||
//Blaze for door code
|
||||
void Use_BinaryMover(gentity_t * ent, gentity_t * other, gentity_t * activator);
|
||||
// JBravo: for kicking code
|
||||
gentity_t *getEntByName(char *name);
|
||||
|
||||
/*
|
||||
==================
|
||||
|
@ -516,12 +514,17 @@ DeathmatchScoreboardMessage
|
|||
*/
|
||||
void DeathmatchScoreboardMessage(gentity_t * ent)
|
||||
{
|
||||
char entry[1024], string[1400];
|
||||
char entry[1024], string[1000];
|
||||
int stringlength, i, j;
|
||||
gclient_t *cl;
|
||||
int numSorted, scoreFlags, accuracy;
|
||||
int alive;
|
||||
|
||||
// don't send scores to bots, they don't parse it
|
||||
if ( ent->r.svFlags & SVF_BOT ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// send the latest information on all clients
|
||||
string[0] = 0;
|
||||
stringlength = 0;
|
||||
|
@ -705,6 +708,33 @@ char *ConcatArgs(int start)
|
|||
return line;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
StringIsInteger
|
||||
==================
|
||||
*/
|
||||
qboolean StringIsInteger(const char * s)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
qboolean foundDigit;
|
||||
|
||||
len = strlen(s);
|
||||
foundDigit = qfalse;
|
||||
|
||||
for (i=0 ; i < len ; i++) {
|
||||
if (!isdigit(s[i])) {
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
foundDigit = qtrue;
|
||||
}
|
||||
|
||||
return foundDigit;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
ClientNumberFromString
|
||||
|
@ -713,37 +743,36 @@ Returns a player number for either a number or name string
|
|||
Returns -1 if invalid
|
||||
==================
|
||||
*/
|
||||
int ClientNumberFromString(gentity_t * to, char *s)
|
||||
int ClientNumberFromString(gentity_t *to, char *s, qboolean checkNums, qboolean checkNames)
|
||||
{
|
||||
gclient_t *cl;
|
||||
int idnum;
|
||||
char s2[MAX_STRING_CHARS];
|
||||
char n2[MAX_STRING_CHARS];
|
||||
char cleanName[MAX_STRING_CHARS];
|
||||
|
||||
// numeric values are just slot numbers
|
||||
if (s[0] >= '0' && s[0] <= '9') {
|
||||
idnum = atoi(s);
|
||||
if (idnum < 0 || idnum >= level.maxclients) {
|
||||
trap_SendServerCommand(to - g_entities, va("print \"^1Bad client slot: %i\n\"", idnum));
|
||||
return -1;
|
||||
if ( checkNums ) {
|
||||
// numeric values could be slot numbers
|
||||
if (StringIsInteger(s)) {
|
||||
idnum = atoi(s);
|
||||
if (idnum >= 0 && idnum < level.maxclients) {
|
||||
cl = &level.clients[idnum];
|
||||
if (cl->pers.connected == CON_CONNECTED) {
|
||||
return idnum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cl = &level.clients[idnum];
|
||||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
trap_SendServerCommand(to - g_entities, va("print \"^1Client %i is not active\n\"", idnum));
|
||||
return -1;
|
||||
}
|
||||
return idnum;
|
||||
}
|
||||
// check for a name match
|
||||
SanitizeString(s, s2);
|
||||
for (idnum = 0, cl = level.clients; idnum < level.maxclients; idnum++, cl++) {
|
||||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
SanitizeString(cl->pers.netname, n2);
|
||||
if (!strcmp(n2, s2)) {
|
||||
return idnum;
|
||||
|
||||
if ( checkNames ) {
|
||||
// check for a name match
|
||||
for (idnum = 0, cl = level.clients; idnum < level.maxclients; idnum++, cl++) {
|
||||
if (cl->pers.connected != CON_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
Q_strncpyz(cleanName, cl->pers.netname, sizeof(cleanName));
|
||||
Q_CleanStr(cleanName);
|
||||
if (!Q_stricmp(cleanName, s)) {
|
||||
return idnum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1079,7 +1108,7 @@ void BroadcastTeamChange(gclient_t * client, int oldTeam)
|
|||
SetTeam
|
||||
=================
|
||||
*/
|
||||
void SetTeam(gentity_t * ent, char *s)
|
||||
void SetTeam(gentity_t * ent, const char *s)
|
||||
{
|
||||
int team, oldTeam, clientNum;
|
||||
gclient_t *client;
|
||||
|
@ -1131,7 +1160,7 @@ void SetTeam(gentity_t * ent, char *s)
|
|||
team = PickTeam(clientNum);
|
||||
}
|
||||
|
||||
if (g_teamForceBalance.integer) {
|
||||
if (g_teamForceBalance.integer && !client->pers.localClient && !(ent->r.svFlags & SVF_BOT)) {
|
||||
int counts[TEAM_NUM_TEAMS];
|
||||
|
||||
counts[TEAM_BLUE] = TeamCount( clientNum, TEAM_BLUE );
|
||||
|
@ -1185,10 +1214,11 @@ void SetTeam(gentity_t * ent, char *s)
|
|||
if(g_gametype.integer >= GT_TEAM && (oldTeam == TEAM_FREE || oldTeam == TEAM_SPECTATOR) && (team == TEAM_RED || team == TEAM_BLUE))
|
||||
ent->client->sess.refHear = qfalse;
|
||||
|
||||
// if the player was dead leave the body
|
||||
if (client->ps.stats[STAT_HEALTH] <= 0) {
|
||||
// if the player was dead leave the body, but only if they're actually in game
|
||||
if (client->ps.stats[STAT_HEALTH] <= 0 && client->pers.connected == CON_CONNECTED) {
|
||||
CopyToBodyQue(ent);
|
||||
}
|
||||
|
||||
// he starts at 'base'
|
||||
client->pers.teamState.state = TEAM_BEGIN;
|
||||
|
||||
|
@ -1242,9 +1272,8 @@ void SetTeam(gentity_t * ent, char *s)
|
|||
}
|
||||
|
||||
client->sess.teamLeader = qfalse;
|
||||
BroadcastTeamChange(client, oldTeam);
|
||||
|
||||
// get and distribute relevent paramters
|
||||
// get and distribute relevant parameters
|
||||
|
||||
// JBravo: save sessionTeam and then set it correctly for the call to ClientUserinfoChanged
|
||||
// so the scoreboard will be correct. Also check for uneven teams.
|
||||
|
@ -1269,8 +1298,19 @@ void SetTeam(gentity_t * ent, char *s)
|
|||
client->radioGender = level.team2gender;
|
||||
} else {
|
||||
ClientUserinfoChanged(clientNum);
|
||||
ClientBegin(clientNum);
|
||||
|
||||
if (client->pers.connected == CON_CONNECTED) {
|
||||
ClientBegin(clientNum);
|
||||
}
|
||||
}
|
||||
|
||||
BroadcastTeamChange(client, oldTeam);
|
||||
|
||||
// client hasn't spawned yet, they sent an early team command, teampref userinfo, or g_teamAutoJoin is enabled
|
||||
if (client->pers.connected != CON_CONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_gametype.integer == GT_CTF || (g_gametype.integer == GT_TEAM && client->sess.savedTeam == TEAM_SPECTATOR))
|
||||
MakeSpectator (ent);
|
||||
// JBravo: If the game is in progress, lets spawn players joining.
|
||||
|
@ -1423,7 +1463,7 @@ void Cmd_Follow_f(gentity_t * ent)
|
|||
}
|
||||
|
||||
trap_Argv(1, arg, sizeof(arg));
|
||||
i = ClientNumberFromString(ent, arg);
|
||||
i = ClientNumberFromString(ent, arg, qtrue, qtrue);
|
||||
if (i == -1) {
|
||||
return;
|
||||
}
|
||||
|
@ -1685,7 +1725,7 @@ void G_Say(gentity_t * ent, gentity_t * target, int mode, const char *chatText)
|
|||
// JBravo: Log it like AQ does
|
||||
G_LogPrintf("%s%s\n", name, text);
|
||||
|
||||
// send it to all the apropriate clients
|
||||
// send it to all the appropriate clients
|
||||
for (j = 0; j < level.maxclients; j++) {
|
||||
//Blaze: Prit out some Debug info
|
||||
if (&g_entities[j] == NULL) G_Printf("Ln 1532\n");
|
||||
|
@ -1695,6 +1735,18 @@ void G_Say(gentity_t * ent, gentity_t * target, int mode, const char *chatText)
|
|||
}
|
||||
}
|
||||
|
||||
static void SanitizeChatText(char *text)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; text[i]; i++) {
|
||||
if (text[i] == '\n' || text[i] == '\r') {
|
||||
text[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
Cmd_ay_f
|
||||
|
@ -1732,6 +1784,8 @@ static void Cmd_Say_f(gentity_t * ent, int mode, qboolean arg0)
|
|||
}
|
||||
}
|
||||
|
||||
SanitizeChatText( p );
|
||||
|
||||
G_Say(ent, NULL, mode, p);
|
||||
}
|
||||
|
||||
|
@ -1747,7 +1801,8 @@ static void Cmd_Tell_f(gentity_t * ent)
|
|||
char *p;
|
||||
char arg[MAX_TOKEN_CHARS];
|
||||
|
||||
if (trap_Argc() < 2) {
|
||||
if (trap_Argc () < 3) {
|
||||
trap_SendServerCommand( ent-g_entities, "print \"Usage: tell <player id> <message>\n\"" );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1756,20 +1811,22 @@ static void Cmd_Tell_f(gentity_t * ent)
|
|||
return;
|
||||
|
||||
trap_Argv(1, arg, sizeof(arg));
|
||||
targetNum = atoi(arg);
|
||||
if (targetNum < 0 || targetNum >= level.maxclients) {
|
||||
targetNum = ClientNumberFromString(ent, arg, qtrue, qtrue);
|
||||
if (targetNum == -1) {
|
||||
return;
|
||||
}
|
||||
//Blaze: Prit out some Debug info
|
||||
if (&g_entities[targetNum] == NULL) G_Printf("Ln 1608\n");
|
||||
|
||||
target = &g_entities[targetNum];
|
||||
if (!target || !target->inuse || !target->client) {
|
||||
if (!target->inuse || !target->client) {
|
||||
return;
|
||||
}
|
||||
|
||||
p = ConcatArgs(2);
|
||||
|
||||
SanitizeChatText(p);
|
||||
|
||||
G_LogPrintf("tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, p);
|
||||
G_Say(ent, target, SAY_TELL, p);
|
||||
// don't tell to the player self if it was already directed to this player
|
||||
|
@ -1832,7 +1889,7 @@ void G_Voice(gentity_t * ent, gentity_t * target, int mode, const char *id, qboo
|
|||
if (g_dedicated.integer) {
|
||||
G_Printf("voice: %s %s\n", ent->client->pers.netname, id);
|
||||
}
|
||||
// send it to all the apropriate clients
|
||||
// send it to all the appropriate clients
|
||||
for (j = 0; j < level.maxclients; j++) {
|
||||
//Blaze: Prit out some Debug info
|
||||
if (&g_entities[j] == NULL) G_Printf("Ln 1682\n");
|
||||
|
@ -1861,6 +1918,8 @@ static void Cmd_Voice_f(gentity_t * ent, int mode, qboolean arg0, qboolean voice
|
|||
p = ConcatArgs(1);
|
||||
}
|
||||
|
||||
SanitizeChatText(p);
|
||||
|
||||
G_Voice(ent, NULL, mode, p, voiceonly);
|
||||
}
|
||||
|
||||
|
@ -1876,25 +1935,28 @@ static void Cmd_VoiceTell_f(gentity_t * ent, qboolean voiceonly)
|
|||
char *id;
|
||||
char arg[MAX_TOKEN_CHARS];
|
||||
|
||||
if (trap_Argc() < 2) {
|
||||
if (trap_Argc () < 3) {
|
||||
trap_SendServerCommand(ent-g_entities, va("print \"Usage: %s <player id> <voice id>\n\"", voiceonly ? "votell" : "vtell"));
|
||||
return;
|
||||
}
|
||||
|
||||
trap_Argv(1, arg, sizeof(arg));
|
||||
targetNum = atoi(arg);
|
||||
if (targetNum < 0 || targetNum >= level.maxclients) {
|
||||
targetNum = ClientNumberFromString(ent, arg, qtrue, qtrue);
|
||||
if (targetNum == -1) {
|
||||
return;
|
||||
}
|
||||
//Blaze: Prit out some Debug info
|
||||
if (&g_entities[targetNum] == NULL) G_Printf("Ln 1733\n");
|
||||
|
||||
target = &g_entities[targetNum];
|
||||
if (!target || !target->inuse || !target->client) {
|
||||
if (!target->inuse || !target->client) {
|
||||
return;
|
||||
}
|
||||
|
||||
id = ConcatArgs(2);
|
||||
|
||||
SanitizeChatText(id);
|
||||
|
||||
G_LogPrintf("vtell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, id);
|
||||
G_Voice(ent, target, SAY_TELL, id, voiceonly);
|
||||
// don't tell to the player self if it was already directed to this player
|
||||
|
@ -1989,28 +2051,49 @@ static char *gc_orders[] = {
|
|||
"report"
|
||||
};
|
||||
|
||||
void Cmd_GameCommand_f(gentity_t * ent)
|
||||
static const int numgc_orders = ARRAY_LEN(gc_orders);
|
||||
|
||||
void Cmd_GameCommand_f(gentity_t *ent)
|
||||
{
|
||||
int player;
|
||||
int order;
|
||||
char str[MAX_TOKEN_CHARS];
|
||||
int targetNum;
|
||||
gentity_t *target;
|
||||
int order;
|
||||
char arg[MAX_TOKEN_CHARS];
|
||||
|
||||
trap_Argv(1, str, sizeof(str));
|
||||
player = atoi(str);
|
||||
trap_Argv(2, str, sizeof(str));
|
||||
order = atoi(str);
|
||||
|
||||
if (player < 0 || player >= MAX_CLIENTS) {
|
||||
if (trap_Argc() != 3) {
|
||||
trap_SendServerCommand(ent-g_entities, va("print \"Usage: gc <player id> <order 0-%d>\n\"", numgc_orders - 1));
|
||||
return;
|
||||
}
|
||||
if (order < 0 || order > ARRAY_LEN(gc_orders)) {
|
||||
|
||||
trap_Argv(2, arg, sizeof(arg));
|
||||
order = atoi(arg);
|
||||
|
||||
if (order < 0 || order >= numgc_orders) {
|
||||
trap_SendServerCommand(ent-g_entities, va("print \"Bad order: %i\n\"", order));
|
||||
return;
|
||||
}
|
||||
|
||||
trap_Argv(1, arg, sizeof(arg));
|
||||
targetNum = ClientNumberFromString(ent, arg, qtrue, qtrue);
|
||||
if (targetNum == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Blaze: Prit out some Debug info
|
||||
if (&g_entities[player] == NULL) G_Printf("Ln 1854\n");
|
||||
if (&g_entities[targetNum] == NULL) G_Printf("Ln 1854\n");
|
||||
|
||||
G_Say(ent, &g_entities[player], SAY_TELL, gc_orders[order]);
|
||||
G_Say(ent, ent, SAY_TELL, gc_orders[order]);
|
||||
target = &g_entities[targetNum];
|
||||
if (!target->inuse || !target->client) {
|
||||
return;
|
||||
}
|
||||
|
||||
G_LogPrintf( "tell: %s to %s: %s\n", ent->client->pers.netname, target->client->pers.netname, gc_orders[order]);
|
||||
G_Say(ent, target, SAY_TELL, gc_orders[order]);
|
||||
// don't tell to the player self if it was already directed to this player
|
||||
// also don't send the chat back to a bot
|
||||
if (ent != target && !(ent->r.svFlags & SVF_BOT)) {
|
||||
G_Say(ent, ent, SAY_TELL, gc_orders[order]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2044,12 +2127,12 @@ Cmd_CallVote_f
|
|||
*/
|
||||
void Cmd_CallVote_f(gentity_t * ent)
|
||||
{
|
||||
int i, kickNum;
|
||||
char *c;
|
||||
int i;
|
||||
float delay;
|
||||
char arg1[MAX_STRING_TOKENS];
|
||||
char arg2[MAX_STRING_TOKENS];
|
||||
char *v_gametype, *v_map;
|
||||
gentity_t *kicked;
|
||||
|
||||
if (!g_allowVote.integer) {
|
||||
trap_SendServerCommand(ent - g_entities, "print \"^1Voting not allowed here.\n\"");
|
||||
|
@ -2090,9 +2173,16 @@ void Cmd_CallVote_f(gentity_t * ent)
|
|||
trap_Argv(1, arg1, sizeof(arg1));
|
||||
trap_Argv(2, arg2, sizeof(arg2));
|
||||
|
||||
if (strchr(arg1, ';') || strchr(arg2, ';')) {
|
||||
trap_SendServerCommand(ent - g_entities, "print \"^1Invalid vote string.\n\"");
|
||||
return;
|
||||
// check for command separators in arg2
|
||||
for(c = arg2; *c; ++c) {
|
||||
switch(*c) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case ';':
|
||||
trap_SendServerCommand(ent-g_entities, "print \"^1Invalid vote string.\n\"");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Q_stricmp(arg1, "cyclemap")) {
|
||||
|
@ -2244,16 +2334,19 @@ void Cmd_CallVote_f(gentity_t * ent)
|
|||
} else if (!Q_stricmp(arg1, "cyclemap")) {
|
||||
Com_sprintf(level.voteString, sizeof(level.voteString), "cyclemap");
|
||||
Com_sprintf(level.voteDisplayString, sizeof(level.voteDisplayString), "%s", level.voteString);
|
||||
} else if (!Q_strncmp(arg1, "kick", 4)) {
|
||||
kicked = getEntByName(arg2);
|
||||
if (kicked && kicked->client) {
|
||||
kickNum = kicked->client - level.clients;
|
||||
Com_sprintf(level.voteString, sizeof(level.voteString), "clientkick \"%i\"", kickNum);
|
||||
Com_sprintf(level.voteDisplayString, sizeof(level.voteDisplayString), "%s \"%s\"", arg1, arg2);
|
||||
} else {
|
||||
Com_sprintf(level.voteString, sizeof(level.voteString), "%s \"%s\"", arg1, arg2);
|
||||
Com_sprintf(level.voteDisplayString, sizeof(level.voteDisplayString), "%s", level.voteString);
|
||||
} else if (!Q_stricmp(arg1, "clientkick") || !Q_stricmp(arg1, "kick")) {
|
||||
i = ClientNumberFromString(ent, arg2, !Q_stricmp(arg1, "clientkick"), !Q_stricmp(arg1, "kick"));
|
||||
if (i == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (level.clients[i].pers.localClient) {
|
||||
trap_SendServerCommand(ent - g_entities, "print \"Cannot kick host player.\n\"");
|
||||
return;
|
||||
}
|
||||
|
||||
Com_sprintf(level.voteString, sizeof(level.voteString), "clientkick %d", i);
|
||||
Com_sprintf(level.voteDisplayString, sizeof(level.voteDisplayString), "kick %s", level.clients[i].pers.netname);
|
||||
} else {
|
||||
Com_sprintf(level.voteString, sizeof(level.voteString), "%s \"%s\"", arg1, arg2);
|
||||
Com_sprintf(level.voteDisplayString, sizeof(level.voteDisplayString), "%s", level.voteString);
|
||||
|
@ -2331,6 +2424,7 @@ Cmd_CallTeamVote_f
|
|||
*/
|
||||
void Cmd_CallTeamVote_f(gentity_t * ent)
|
||||
{
|
||||
char *c;
|
||||
int i, team, cs_offset;
|
||||
char arg1[MAX_STRING_TOKENS];
|
||||
char arg2[MAX_STRING_TOKENS];
|
||||
|
@ -2376,9 +2470,16 @@ void Cmd_CallTeamVote_f(gentity_t * ent)
|
|||
trap_Argv(i, &arg2[strlen(arg2)], sizeof(arg2) - strlen(arg2));
|
||||
}
|
||||
|
||||
if (strchr(arg1, ';') || strchr(arg2, ';')) {
|
||||
trap_SendServerCommand(ent - g_entities, "print \"^1Invalid vote string.\n\"");
|
||||
// check for command separators in arg2
|
||||
for(c = arg2; *c; ++c) {
|
||||
switch(*c) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case ';':
|
||||
trap_SendServerCommand(ent - g_entities, "print \"^1Invalid vote string.\n\"");
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Q_stricmp(arg1, "leader")) {
|
||||
|
@ -3004,6 +3105,14 @@ void ClientCommand(int clientNum)
|
|||
|
||||
ent = g_entities + clientNum;
|
||||
if (!ent->client || ent->client->pers.connected != CON_CONNECTED) {
|
||||
if (ent->client && ent->client->pers.localClient) {
|
||||
// Handle early team command sent by UI when starting a local
|
||||
// team play game.
|
||||
trap_Argv( 0, cmd, sizeof( cmd ) );
|
||||
if (Q_stricmp (cmd, "team") == 0) {
|
||||
Cmd_Team_f (ent);
|
||||
}
|
||||
}
|
||||
return; // not fully in game yet
|
||||
}
|
||||
|
||||
|
|
|
@ -1806,7 +1806,7 @@ void G_Damage(gentity_t * targ, gentity_t * inflictor, gentity_t * attacker,
|
|||
}
|
||||
}
|
||||
|
||||
// the intermission has allready been qualified for, so don't
|
||||
// the intermission has already been qualified for, so don't
|
||||
// allow any extra scoring
|
||||
if (level.intermissionQueued) {
|
||||
return;
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
|
||||
Respawnable items don't actually go away when picked up, they are
|
||||
just made invisible and untouchable. This allows them to ride
|
||||
movers and respawn apropriately.
|
||||
movers and respawn appropriately.
|
||||
*/
|
||||
|
||||
#define RESPAWN_ARMOR 25
|
||||
|
|
|
@ -1032,7 +1032,7 @@ char *ConcatArgs(int start);
|
|||
void Cmd_Score_f(gentity_t * ent);
|
||||
void StopFollowing(gentity_t * ent);
|
||||
void BroadcastTeamChange(gclient_t * client, int oldTeam);
|
||||
void SetTeam(gentity_t * ent, char *s);
|
||||
void SetTeam(gentity_t * ent, const char *s);
|
||||
void Cmd_FollowCycle_f(gentity_t * ent, int dir);
|
||||
void Cmd_Unzoom(gentity_t * ent);
|
||||
void Cmd_OpenDoor(gentity_t * ent);
|
||||
|
@ -1389,7 +1389,6 @@ void BotInterbreedEndMatch(void);
|
|||
typedef struct bot_settings_s {
|
||||
char characterfile[MAX_FILEPATH];
|
||||
float skill;
|
||||
char team[MAX_FILEPATH];
|
||||
} bot_settings_t;
|
||||
|
||||
int BotAISetup(int restart);
|
||||
|
@ -1462,6 +1461,7 @@ extern vmCvar_t g_enableBreath;
|
|||
extern vmCvar_t g_enableFogLaser;
|
||||
extern vmCvar_t g_singlePlayer;
|
||||
extern vmCvar_t g_proxMineTimeout;
|
||||
extern vmCvar_t g_localTeamPref;
|
||||
|
||||
// JBravo: unlagged
|
||||
extern vmCvar_t g_delagHitscan;
|
||||
|
|
|
@ -514,6 +514,7 @@ vmCvar_t pmove_fixed;
|
|||
vmCvar_t pmove_msec;
|
||||
vmCvar_t g_rankings;
|
||||
vmCvar_t g_listEntity;
|
||||
vmCvar_t g_localTeamPref;
|
||||
|
||||
//Slicer: Matchmode
|
||||
vmCvar_t g_RQ3_matchmode;
|
||||
|
@ -614,7 +615,7 @@ static cvarTable_t gameCvarTable[] = {
|
|||
|
||||
// noset vars
|
||||
{NULL, "gamename", GAMEVERSION, CVAR_SERVERINFO | CVAR_ROM, 0, qfalse},
|
||||
{NULL, "gamedate", __DATE__, CVAR_ROM, 0, qfalse},
|
||||
{NULL, "gamedate", PRODUCT_DATE, CVAR_ROM, 0, qfalse},
|
||||
{&g_restarted, "g_restarted", "0", CVAR_ROM, 0, qfalse},
|
||||
|
||||
// latched vars
|
||||
|
@ -674,6 +675,7 @@ static cvarTable_t gameCvarTable[] = {
|
|||
{&g_unlaggedVersion, "g_unlaggedVersion", "2.0", CVAR_ROM | CVAR_SERVERINFO, 0, qfalse},
|
||||
{&sv_fps, "sv_fps", "20", CVAR_SYSTEMINFO | CVAR_ARCHIVE, 0, qfalse},
|
||||
{&g_rankings, "g_rankings", "0", 0, 0, qfalse},
|
||||
{&g_localTeamPref, "g_localTeamPref", "", 0, 0, qfalse},
|
||||
//Slicer: Matchmode
|
||||
{&g_RQ3_matchmode, "g_RQ3_matchmode", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_SYSTEMINFO, 0, qfalse},
|
||||
{&g_RQ3_forceteamtalk, "g_RQ3_forceteamtalk", "0", 0, 0, qtrue},
|
||||
|
@ -847,7 +849,7 @@ void G_FindTeams(void)
|
|||
|
||||
c = 0;
|
||||
c2 = 0;
|
||||
for (i = 1, e = g_entities + i; i < level.num_entities; i++, e++) {
|
||||
for (i = MAX_CLIENTS, e = g_entities + i; i < level.num_entities; i++, e++) {
|
||||
if (!e->inuse)
|
||||
continue;
|
||||
if (!e->team)
|
||||
|
@ -1251,7 +1253,7 @@ void G_InitGame(int levelTime, int randomSeed, int restart)
|
|||
|
||||
G_Printf("------- Game Initialization -------\n");
|
||||
G_Printf("gamename: %s\n", GAMEVERSION);
|
||||
G_Printf("gamedate: %s\n", __DATE__);
|
||||
G_Printf("gamedate: %s\n", PRODUCT_DATE);
|
||||
|
||||
srand(randomSeed);
|
||||
|
||||
|
@ -2284,6 +2286,12 @@ void CheckExitRules(void)
|
|||
//Slicer
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
//Let's check fraglimit here, everything else is on teamplay.c
|
||||
if ( g_fraglimit.integer < 0 ) {
|
||||
G_Printf( "fraglimit %i is out of range, defaulting to 0\n", g_fraglimit.integer );
|
||||
trap_Cvar_Set( "fraglimit", "0" );
|
||||
trap_Cvar_Update( &g_fraglimit );
|
||||
}
|
||||
|
||||
if (g_fraglimit.integer > 0) {
|
||||
for (i = 0; i < g_maxclients.integer; i++) {
|
||||
cl = level.clients + i;
|
||||
|
@ -2315,6 +2323,12 @@ void CheckExitRules(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if ( g_timelimit.integer < 0 || g_timelimit.integer > INT_MAX / 60000 ) {
|
||||
G_Printf( "timelimit %i is out of range, defaulting to 0\n", g_timelimit.integer );
|
||||
trap_Cvar_Set( "timelimit", "0" );
|
||||
trap_Cvar_Update( &g_timelimit );
|
||||
}
|
||||
|
||||
if (g_timelimit.integer && !level.warmupTime) {
|
||||
if (level.time - level.startTime >= g_timelimit.integer * 60000) {
|
||||
trap_SendServerCommand(-1, "print \"Timelimit hit.\n\"");
|
||||
|
@ -2327,6 +2341,12 @@ void CheckExitRules(void)
|
|||
return;
|
||||
} */
|
||||
|
||||
if ( g_fraglimit.integer < 0 ) {
|
||||
G_Printf( "fraglimit %i is out of range, defaulting to 0\n", g_fraglimit.integer );
|
||||
trap_Cvar_Set( "fraglimit", "0" );
|
||||
trap_Cvar_Update( &g_fraglimit );
|
||||
}
|
||||
|
||||
if (g_gametype.integer < GT_CTF && g_fraglimit.integer) {
|
||||
if (level.teamScores[TEAM_RED] >= g_fraglimit.integer) {
|
||||
trap_SendServerCommand(-1, "print \"Red hit the fraglimit.\n\"");
|
||||
|
@ -2358,6 +2378,12 @@ void CheckExitRules(void)
|
|||
}
|
||||
}
|
||||
|
||||
if ( g_capturelimit.integer < 0 ) {
|
||||
G_Printf( "capturelimit %i is out of range, defaulting to 0\n", g_capturelimit.integer );
|
||||
trap_Cvar_Set( "capturelimit", "0" );
|
||||
trap_Cvar_Update( &g_capturelimit );
|
||||
}
|
||||
|
||||
if (g_gametype.integer >= GT_CTF && g_capturelimit.integer) {
|
||||
|
||||
if (level.teamScores[TEAM_RED] >= g_capturelimit.integer) {
|
||||
|
@ -2442,7 +2468,7 @@ void CheckTournament(void)
|
|||
int counts[TEAM_NUM_TEAMS];
|
||||
qboolean notEnough = qfalse;
|
||||
|
||||
if (g_gametype.integer > GT_TEAM) {
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
counts[TEAM_BLUE] = TeamCount(-1, TEAM_BLUE);
|
||||
counts[TEAM_RED] = TeamCount(-1, TEAM_RED);
|
||||
|
||||
|
|
|
@ -372,7 +372,7 @@ qboolean G_TryPushingEntity(gentity_t * check, gentity_t * pusher, vec3_t move,
|
|||
return qtrue;
|
||||
}
|
||||
// if it is ok to leave in the old position, do it
|
||||
// this is only relevent for riding entities, not pushed
|
||||
// this is only relevant for riding entities, not pushed
|
||||
// Sliding trapdoors can cause this.
|
||||
VectorCopy((pushed_p - 1)->origin, check->s.pos.trBase);
|
||||
if (check->client) {
|
||||
|
@ -626,7 +626,7 @@ void G_MoverTeam(gentity_t * ent)
|
|||
|
||||
obstacle = NULL;
|
||||
|
||||
// make sure all team slaves can move before commiting
|
||||
// make sure all team slaves can move before committing
|
||||
// any moves or calling any think functions
|
||||
// if the move is blocked, all moved objects will be backed out
|
||||
pushed_p = pushed;
|
||||
|
@ -1214,7 +1214,7 @@ void InitMover(gentity_t * ent)
|
|||
qboolean lightSet, colorSet;
|
||||
char *sound;
|
||||
|
||||
// if the "model2" key is set, use a seperate model
|
||||
// if the "model2" key is set, use a separate model
|
||||
// for drawing, but clip against the brushes
|
||||
if (ent->model2) {
|
||||
ent->s.modelindex2 = G_ModelIndex(ent->model2);
|
||||
|
@ -2276,7 +2276,7 @@ void Reached_Train(gentity_t * ent)
|
|||
vec3_t move;
|
||||
float length;
|
||||
|
||||
// copy the apropriate values
|
||||
// copy the appropriate values
|
||||
next = ent->nextTrain;
|
||||
if (!next || !next->nextTrain) {
|
||||
return; // just stop
|
||||
|
|
|
@ -97,10 +97,6 @@ void G_WriteClientSessionData(gclient_t * client)
|
|||
|
||||
//Slicer how about savedTeam ?!
|
||||
|
||||
if (!g_RQ3_matchmode.integer && g_gametype.integer >= GT_TEAM) {
|
||||
//Reset teams on map changes / map_restarts, except on matchmode
|
||||
client->sess.savedTeam = TEAM_SPECTATOR;
|
||||
}
|
||||
s = va("%i %i %i %i %i %i %i %i %i %i %i",
|
||||
client->sess.sessionTeam,
|
||||
client->sess.spectatorTime,
|
||||
|
@ -164,7 +160,9 @@ void G_ReadSessionData(gclient_t * client)
|
|||
|
||||
if (g_gametype.integer == GT_CTF) {
|
||||
client->sess.sessionTeam = TEAM_SPECTATOR;
|
||||
client->sess.savedTeam = TEAM_SPECTATOR;
|
||||
if (!(g_entities[(int)(client-level.clients)].r.svFlags & SVF_BOT)) {
|
||||
client->sess.savedTeam = TEAM_SPECTATOR;
|
||||
}
|
||||
client->sess.captain = TEAM_FREE;
|
||||
client->sess.sub = TEAM_FREE;
|
||||
}
|
||||
|
@ -201,25 +199,29 @@ void G_InitSessionData(gclient_t * client, char *userinfo)
|
|||
// JBravo: adding PERS_SAVEDTEAM
|
||||
client->ps.persistant[PERS_SAVEDTEAM] = TEAM_SPECTATOR;
|
||||
|
||||
// check for team preference, mainly for bots
|
||||
value = Info_ValueForKey( userinfo, "teampref" );
|
||||
|
||||
// check for human's team preference set by start server menu
|
||||
if ( !value[0] && g_localTeamPref.string[0] && client->pers.localClient ) {
|
||||
value = g_localTeamPref.string;
|
||||
|
||||
// clear team so it's only used once
|
||||
trap_Cvar_Set( "g_localTeamPref", "" );
|
||||
}
|
||||
|
||||
// initial team determination
|
||||
if (g_gametype.integer >= GT_TEAM) {
|
||||
if ( g_teamAutoJoin.integer && !(g_entities[ client - level.clients ].r.svFlags & SVF_BOT) ) {
|
||||
if (g_gametype.integer == GT_TEAMPLAY) {
|
||||
sess->savedTeam = PickTeam(-1);
|
||||
client->ps.persistant[PERS_SAVEDTEAM] = sess->savedTeam;
|
||||
} else if (g_gametype.integer == GT_CTF || g_gametype.integer == GT_TEAM) {
|
||||
sess->savedTeam = PickTeam(-1);
|
||||
client->ps.persistant[PERS_SAVEDTEAM] = sess->savedTeam;
|
||||
sess->sessionTeam = sess->savedTeam;
|
||||
} else
|
||||
sess->sessionTeam = PickTeam(-1);
|
||||
BroadcastTeamChange(client, -1);
|
||||
} else {
|
||||
// always spawn as spectator in team games
|
||||
sess->sessionTeam = TEAM_SPECTATOR;
|
||||
// always spawn as spectator in team games
|
||||
sess->sessionTeam = TEAM_SPECTATOR;
|
||||
sess->spectatorState = SPECTATOR_FREE;
|
||||
client->specMode = SPECTATOR_FREE;
|
||||
sess->spectatorTime = level.time;
|
||||
|
||||
if (value[0] || g_teamAutoJoin.integer) {
|
||||
SetTeam(&g_entities[client - level.clients], value[0] ? value : "auto");
|
||||
}
|
||||
} else {
|
||||
value = Info_ValueForKey(userinfo, "team");
|
||||
if (value[0] == 's') {
|
||||
// a willing spectator, not a waiting-in-line
|
||||
sess->sessionTeam = TEAM_SPECTATOR;
|
||||
|
@ -245,11 +247,11 @@ void G_InitSessionData(gclient_t * client, char *userinfo)
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sess->spectatorState = SPECTATOR_FREE;
|
||||
client->specMode = SPECTATOR_FREE;
|
||||
sess->spectatorTime = level.time;
|
||||
sess->spectatorState = SPECTATOR_FREE;
|
||||
client->specMode = SPECTATOR_FREE;
|
||||
sess->spectatorTime = level.time;
|
||||
}
|
||||
|
||||
G_WriteClientSessionData(client);
|
||||
}
|
||||
|
@ -290,6 +292,11 @@ void G_WriteSessionData(void)
|
|||
|
||||
for (i = 0; i < level.maxclients; i++) {
|
||||
if (level.clients[i].pers.connected == CON_CONNECTED) {
|
||||
if (!g_RQ3_matchmode.integer && g_gametype.integer >= GT_TEAM && !(g_entities[i].r.svFlags & SVF_BOT)) {
|
||||
//Slicer: reset teams on map changes / map_restarts, except on matchmode
|
||||
level.clients[i].sess.savedTeam = TEAM_SPECTATOR;
|
||||
}
|
||||
|
||||
G_WriteClientSessionData(&level.clients[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -681,7 +681,7 @@ void G_ParseField(const char *key, const char *value, gentity_t * ent)
|
|||
G_SpawnGEntityFromSpawnVars
|
||||
|
||||
Spawn an entity and fill in all of the level fields from
|
||||
level.spawnVars[], then call the class specfic spawn function
|
||||
level.spawnVars[], then call the class specific spawn function
|
||||
===================
|
||||
*/
|
||||
void G_SpawnGEntityFromSpawnVars(void)
|
||||
|
|
|
@ -328,8 +328,8 @@ void Svcmd_EntityList_f(void)
|
|||
int e;
|
||||
gentity_t *check;
|
||||
|
||||
check = g_entities + 1;
|
||||
for (e = 1; e < level.num_entities; e++, check++) {
|
||||
check = g_entities;
|
||||
for (e = 0; e < level.num_entities; e++, check++) {
|
||||
if (!check->inuse) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ void Use_Target_Delay(gentity_t * ent, gentity_t * other, gentity_t * activator)
|
|||
void SP_target_delay(gentity_t * ent)
|
||||
{
|
||||
|
||||
// check delay for backwards compatability
|
||||
// check delay for backwards compatibility
|
||||
if (!G_SpawnFloat("delay", "0", &ent->wait)) {
|
||||
G_SpawnFloat("wait", "1", &ent->wait);
|
||||
}
|
||||
|
|
|
@ -344,6 +344,7 @@ void Team_FragBonuses(gentity_t * targ, gentity_t * inflictor, gentity_t * attac
|
|||
}
|
||||
|
||||
if (g_gametype.integer == GT_1FCTF) {
|
||||
flag_pw = PW_NEUTRALFLAG;
|
||||
enemy_flag_pw = PW_NEUTRALFLAG;
|
||||
}
|
||||
// did the attacker frag the flag carrier?
|
||||
|
@ -405,26 +406,6 @@ void Team_FragBonuses(gentity_t * targ, gentity_t * inflictor, gentity_t * attac
|
|||
return;
|
||||
}
|
||||
|
||||
if (targ->client->pers.teamState.lasthurtcarrier &&
|
||||
level.time - targ->client->pers.teamState.lasthurtcarrier < CTF_CARRIER_DANGER_PROTECT_TIMEOUT) {
|
||||
// attacker is on the same team as the skull carrier and
|
||||
AddScore(attacker, targ->r.currentOrigin, CTF_CARRIER_DANGER_PROTECT_BONUS);
|
||||
|
||||
attacker->client->pers.teamState.carrierdefense++;
|
||||
targ->client->pers.teamState.lasthurtcarrier = 0;
|
||||
|
||||
//Blaze: Removed because it uses the persistant stats stuff
|
||||
//attacker->client->ps.persistant[PERS_DEFEND_COUNT]++;
|
||||
team = attacker->client->sess.sessionTeam;
|
||||
// add the sprite over the player's head
|
||||
/* attacker->client->ps.eFlags &=
|
||||
~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND |
|
||||
EF_AWARD_CAP);
|
||||
attacker->client->ps.eFlags |= EF_AWARD_DEFEND;
|
||||
attacker->client->rewardTime = level.time + REWARD_SPRITE_TIME; */
|
||||
|
||||
return;
|
||||
}
|
||||
// flag and flag carrier area defense bonuses
|
||||
// we have to find the flag and carrier entities
|
||||
// find the flag
|
||||
|
@ -484,7 +465,7 @@ void Team_FragBonuses(gentity_t * targ, gentity_t * inflictor, gentity_t * attac
|
|||
|
||||
if (carrier && carrier != attacker) {
|
||||
VectorSubtract(targ->r.currentOrigin, carrier->r.currentOrigin, v1);
|
||||
VectorSubtract(attacker->r.currentOrigin, carrier->r.currentOrigin, v1);
|
||||
VectorSubtract(attacker->r.currentOrigin, carrier->r.currentOrigin, v2);
|
||||
|
||||
if (((VectorLength(v1) < CTF_ATTACKER_PROTECT_RADIUS &&
|
||||
trap_InPVS(carrier->r.currentOrigin, targ->r.currentOrigin)) ||
|
||||
|
@ -528,6 +509,10 @@ void Team_CheckHurtCarrier(gentity_t * targ, gentity_t * attacker)
|
|||
else
|
||||
flag_pw = PW_REDFLAG;
|
||||
|
||||
if (g_gametype.integer == GT_1FCTF) {
|
||||
flag_pw = PW_NEUTRALFLAG;
|
||||
}
|
||||
|
||||
// flags
|
||||
if (targ->client->ps.powerups[flag_pw] && targ->client->sess.sessionTeam != attacker->client->sess.sessionTeam)
|
||||
attacker->client->pers.teamState.lasthurtcarrier = level.time;
|
||||
|
|
|
@ -108,7 +108,7 @@ void InitTrigger(gentity_t * self)
|
|||
self->r.svFlags = SVF_NOCLIENT;
|
||||
}
|
||||
|
||||
/*QUAKED trigger_multiple (.5 .5 .5) ? DOOR
|
||||
/*QUAKED trigger_multiple (.5 .5 .5) ? RED_ONLY BLUE_ONLY DOOR
|
||||
"wait" : Seconds between triggerings, 0.5 default, -1 = one time only.
|
||||
"random" wait variance, default is 0
|
||||
Variable sized repeatable trigger. Must be targeted at one or more entities.
|
||||
|
@ -527,7 +527,7 @@ Any entity that touches this will be hurt.
|
|||
It does dmg points of damage each server frame
|
||||
Targeting the trigger will toggle its on / off state.
|
||||
|
||||
SILENT supresses playing the sound
|
||||
SILENT suppresses playing the sound
|
||||
SLOW changes the damage rate to once per second
|
||||
NO_PROTECTION *nothing* stops the damage
|
||||
|
||||
|
|
|
@ -516,7 +516,6 @@ gentity_t *G_Spawn(void)
|
|||
gentity_t *e;
|
||||
|
||||
e = NULL; // shut up warning
|
||||
i = 0; // shut up warning
|
||||
for (force = 0; force < 2; force++) {
|
||||
// if we go through all entities and can't find one to free,
|
||||
// override the normal minimum times before use
|
||||
|
@ -534,11 +533,11 @@ gentity_t *G_Spawn(void)
|
|||
G_InitGentity(e);
|
||||
return e;
|
||||
}
|
||||
if (i != MAX_GENTITIES) {
|
||||
if (level.num_entities < ENTITYNUM_MAX_NORMAL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == ENTITYNUM_MAX_NORMAL) {
|
||||
if (level.num_entities == ENTITYNUM_MAX_NORMAL) {
|
||||
for (i = 0; i < MAX_GENTITIES; i++) {
|
||||
G_Printf("%4i: %s\n", i, g_entities[i].classname);
|
||||
}
|
||||
|
@ -565,6 +564,11 @@ qboolean G_EntitiesFree(void)
|
|||
int i;
|
||||
gentity_t *e;
|
||||
|
||||
if (level.num_entities < ENTITYNUM_MAX_NORMAL) {
|
||||
// can open a new slot if needed
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
e = &g_entities[MAX_CLIENTS];
|
||||
for (i = MAX_CLIENTS; i < level.num_entities; i++, e++) {
|
||||
if (e->inuse) {
|
||||
|
|
|
@ -695,6 +695,7 @@ qboolean ShotgunPellet(vec3_t start, vec3_t end, gentity_t * ent)
|
|||
int damage, i, passent;
|
||||
gentity_t *traceEnt;
|
||||
vec3_t tr_start, tr_end;
|
||||
qboolean hitClient = qfalse;
|
||||
|
||||
passent = ent->s.number;
|
||||
VectorCopy(start, tr_start);
|
||||
|
@ -710,6 +711,10 @@ qboolean ShotgunPellet(vec3_t start, vec3_t end, gentity_t * ent)
|
|||
}
|
||||
|
||||
if (traceEnt->takedamage) {
|
||||
if (LogAccuracyHit(traceEnt, ent)) {
|
||||
hitClient = qtrue;
|
||||
}
|
||||
|
||||
//Elder: added to discern handcannon and m3 damage
|
||||
if (ent->client && ent->client->ps.weapon == WP_HANDCANNON) {
|
||||
//G_Printf("Firing handcannon\n");
|
||||
|
@ -721,7 +726,7 @@ qboolean ShotgunPellet(vec3_t start, vec3_t end, gentity_t * ent)
|
|||
G_Damage(traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_M3);
|
||||
}
|
||||
|
||||
if (LogAccuracyHit(traceEnt, ent)) {
|
||||
if (hitClient) {
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
@ -975,6 +980,9 @@ void Weapon_LightningFire(gentity_t * ent)
|
|||
traceEnt = &g_entities[tr.entityNum];
|
||||
|
||||
if (traceEnt->takedamage) {
|
||||
if( LogAccuracyHit( traceEnt, ent ) ) {
|
||||
ent->client->accuracy_hits++;
|
||||
}
|
||||
G_Damage(traceEnt, ent, ent, forward, tr.endpos, damage, 0, MOD_LIGHTNING);
|
||||
}
|
||||
|
||||
|
@ -983,9 +991,6 @@ void Weapon_LightningFire(gentity_t * ent)
|
|||
tent->s.otherEntityNum = traceEnt->s.number;
|
||||
tent->s.eventParm = DirToByte(tr.plane.normal);
|
||||
tent->s.weapon = ent->s.weapon;
|
||||
if (LogAccuracyHit(traceEnt, ent)) {
|
||||
ent->client->accuracy_hits++;
|
||||
}
|
||||
} else if (!(tr.surfaceFlags & SURF_NOIMPACT)) {
|
||||
tent = G_TempEntity(tr.endpos, EV_MISSILE_MISS);
|
||||
tent->s.eventParm = DirToByte(tr.plane.normal);
|
||||
|
|
Loading…
Reference in a new issue