Update to ioquake3 2018-12-21 part 4 (CGame/Game code)

This commit is contained in:
Zack Middleton 2019-01-07 02:21:48 -06:00
parent a4be4e4a37
commit ac4155327b
42 changed files with 661 additions and 501 deletions

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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 ) {

View file

@ -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;

View file

@ -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 );

View file

@ -791,7 +791,7 @@ Draw the oversize scoreboard for tournements
=================
*/
void CG_DrawOldTourneyScoreboard(void)
void CG_DrawTourneyScoreboard(void)
{
const char *s;
vec4_t color;

View file

@ -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;
}

View file

@ -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

View file

@ -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();

View file

@ -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;

View file

@ -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;
//

View file

@ -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))

View file

@ -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;
}
//

View file

@ -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);

View file

@ -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_?)

View file

@ -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);

View file

@ -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")))

View file

@ -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

View file

@ -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!

View file

@ -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

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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");
}

View file

@ -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) {

View file

@ -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
}

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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]);
}
}

View file

@ -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)

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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

View file

@ -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) {

View file

@ -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);