9ae7e2621d
Lots of changes. CSQC should be functional, but is still tied to debug builds. It WILL have some bugs still, hopefully I'll be able to clean them up better if people test it a bit. Precompiled headers are working properly now. Compile times are now much quicker in msvc. This takes most of the files this commit. Restructured how client commands work. They're buffered outside the network message, some multithreaded code is in. It needs a bit of testing before it's active. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@885 fc73d0e0-1445-4013-8a0c-d673dee63da5
384 lines
7.6 KiB
C
384 lines
7.6 KiB
C
/*
|
|
|
|
Teamplay.c
|
|
Contains various console stuff for improving the performance of a team...
|
|
Cheats I hear you say?...
|
|
|
|
Personally, I'd rather call it a hack job.
|
|
Most of it is dependant upon specific mod types - TF.
|
|
|
|
|
|
As far as split screen goes, this is all relative to player 0. We don't provide more than one say command.
|
|
*/
|
|
|
|
#include "quakedef.h"
|
|
|
|
#if 0 //ndef ZQUAKETEAMPLAY
|
|
|
|
cvar_t tp_name_armortype_ga = {"tp_name_armortype_ga", "g"};
|
|
cvar_t tp_name_armortype_ya = {"tp_name_armortype_ya", "y"};
|
|
cvar_t tp_name_armortype_ra = {"tp_name_armortype_ra", "r"};
|
|
cvar_t tp_name_none = {"tp_name_none", ""};
|
|
|
|
|
|
#define translatetext(i) #i
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//Macros.
|
|
|
|
char *TP_ClassForTFSkin(void)
|
|
{
|
|
char *skin;
|
|
skin = Info_ValueForKey(cls.userinfo, "skin");
|
|
if (!*skin)
|
|
return "Classless";
|
|
if (skin[0] != 't' && skin[1] != 'f' && skin[2] != '_')
|
|
return skin;
|
|
if (!strcmp(skin, "tf_sold"))
|
|
return translatetext(TLTP_CLASS_SOLIDER);
|
|
if (!strcmp(skin, "tf_demo"))
|
|
return translatetext(TLTP_CLASS_DEMOGUY);
|
|
if (!strcmp(skin, "tf_eng"))
|
|
return translatetext(TLTP_CLASS_ENGINEER);
|
|
if (!strcmp(skin, "tf_snipe"))
|
|
return translatetext(TLTP_CLASS_SNIPER);
|
|
if (!strcmp(skin, "tf_hwguy"))
|
|
return translatetext(TLTP_CLASS_HWGUY);
|
|
if (!strcmp(skin, "tf_medic"))
|
|
return translatetext(TLTP_CLASS_MEDIC);
|
|
if (!strcmp(skin, "tf_pyro"))
|
|
return translatetext(TLTP_CLASS_PYRO);
|
|
if (!strcmp(skin, "tf_scout"))
|
|
return translatetext(TLTP_CLASS_SCOUT);
|
|
if (!strcmp(skin, "tf_spy"))
|
|
return translatetext(TLTP_CLASS_SPY);
|
|
|
|
return skin;
|
|
}
|
|
|
|
void *TP_ArmourType(void)
|
|
{
|
|
if (cl.stats[0][STAT_ITEMS] & IT_ARMOR1)
|
|
return tp_name_armortype_ga.string;
|
|
else if (cl.stats[0][STAT_ITEMS] & IT_ARMOR2)
|
|
return tp_name_armortype_ya.string;
|
|
else if (cl.stats[0][STAT_ITEMS] & IT_ARMOR3)
|
|
return tp_name_armortype_ra.string;
|
|
else
|
|
return tp_name_none.string;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//Locs
|
|
|
|
typedef struct location_s {
|
|
vec3_t pos;
|
|
struct location_s *next;
|
|
char name[0];
|
|
} location_t;
|
|
location_t *location;
|
|
|
|
char LocationLevel[64];
|
|
|
|
void CL_LoadLocs(void)
|
|
{
|
|
location_t *newloc;
|
|
vec3_t pos;
|
|
|
|
char *file;
|
|
char *end;
|
|
char name[MAX_QPATH];
|
|
// if (!strcmp(LocationLevel, cl.model_name[1]))
|
|
// return;
|
|
|
|
while(location)
|
|
{
|
|
newloc = location->next;
|
|
Z_Free(location);
|
|
location = newloc;
|
|
}
|
|
|
|
strcpy(LocationLevel, cl.model_name[1]);
|
|
|
|
COM_StripExtension(COM_SkipPath(LocationLevel), name);
|
|
file = COM_LoadTempFile(va("locs/%s.loc", name));
|
|
|
|
if (!file)
|
|
return;
|
|
for(;;)
|
|
{
|
|
file = COM_Parse(file);
|
|
pos[0] = atof(com_token)/8;
|
|
file = COM_Parse(file);
|
|
pos[1] = atof(com_token)/8;
|
|
file = COM_Parse(file);
|
|
pos[2] = atof(com_token)/8;
|
|
|
|
while(*file && *file <= '\0')
|
|
file++;
|
|
|
|
if (!file)
|
|
return;
|
|
end = strchr(file, '\n');
|
|
if (!end)
|
|
{
|
|
end = file + strlen(file);
|
|
}
|
|
newloc = Z_Malloc(sizeof(location_t) + end-file+1);
|
|
newloc->next = location;
|
|
location = newloc;
|
|
|
|
Q_strncpyz(newloc->name, file, end-file);
|
|
VectorCopy(pos, newloc->pos);
|
|
|
|
|
|
if (!*end)
|
|
return;
|
|
file = end+1;
|
|
}
|
|
}
|
|
|
|
char *CL_LocationName(float *pos)
|
|
{
|
|
location_t *loc;
|
|
vec3_t dir;
|
|
char *best;
|
|
float dist, bestdist;
|
|
|
|
CL_LoadLocs();
|
|
|
|
if (!location)
|
|
return "somewhere";
|
|
|
|
//get the initial one
|
|
best = location->name;
|
|
VectorSubtract(location->pos, pos, dir);
|
|
bestdist = VectorNormalize(dir);
|
|
|
|
//check for a closer one.
|
|
for (loc = location->next; loc; loc=loc->next)
|
|
{
|
|
VectorSubtract(loc->pos, pos, dir);
|
|
dist = VectorNormalize(dir);
|
|
if (dist < bestdist)
|
|
{
|
|
best = loc->name;
|
|
bestdist = dist;
|
|
}
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//Commands
|
|
#define INVIS_CHAR1 12
|
|
#define INVIS_CHAR2 138
|
|
#define INVIS_CHAR3 160
|
|
|
|
/*
|
|
===============
|
|
CL_Say
|
|
|
|
Handles both say and say_team
|
|
===============
|
|
*/
|
|
|
|
void CL_Say_f (void)
|
|
{
|
|
char output[8192];
|
|
char string[256];
|
|
char *msg;
|
|
int c;
|
|
output[0] = '\0';
|
|
if (cls.state == ca_disconnected || cls.demoplayback)
|
|
{
|
|
#ifndef CLIENT_ONLY
|
|
if (sv.state)
|
|
SV_ConSay_f();
|
|
else
|
|
#endif
|
|
Con_TPrintf (TL_CANTXNOTCONNECTED, Cmd_Argv(0));
|
|
return;
|
|
}
|
|
|
|
if (!strcmp("sayone", Cmd_Argv(0)))
|
|
{
|
|
if (strcmp(Info_ValueForKey(cl.serverinfo, "*distrib"), DISTRIBUTION) || atoi(Info_ValueForKey(cl.serverinfo, "*ver")) < PRE_SAYONE)
|
|
{
|
|
Con_TPrintf (TLC_REQUIRESSERVERMOD, Cmd_Argv(0));
|
|
return;
|
|
}
|
|
}
|
|
|
|
Q_strncpyz(output, Cmd_Argv(0), sizeof(string));
|
|
for (msg = output; *msg; msg++)
|
|
if (*msg >= 'A' && *msg <= 'Z')
|
|
*msg = *msg - 'A' + 'a';
|
|
|
|
msg = Cmd_Args();
|
|
|
|
if (Cmd_Argc() > 1)
|
|
{
|
|
Q_strncatz(output, " \"", sizeof(output));
|
|
|
|
while(*msg)
|
|
{
|
|
c = *msg;
|
|
|
|
if (c == '%')
|
|
{
|
|
char *message = NULL;
|
|
msg++;
|
|
|
|
if (message == NULL)
|
|
switch(*msg)
|
|
{
|
|
case 'n':
|
|
Q_strncatz(output, name.string, sizeof(output));
|
|
msg++;
|
|
continue;
|
|
case 'h':
|
|
Q_strncatz(output, va("%i", cl.stats[0][STAT_HEALTH]), sizeof(output));
|
|
msg++;
|
|
continue;
|
|
case 'a':
|
|
Q_strncatz(output, va("%i", cl.stats[0][STAT_ARMOR]), sizeof(output));
|
|
msg++;
|
|
continue;
|
|
case 'A':
|
|
Q_strncatz(output, TP_ArmourType(), sizeof(output));
|
|
msg++;
|
|
continue;
|
|
case 'l':
|
|
Q_strncatz(output, CL_LocationName(cl.simorg[0]), sizeof(output));
|
|
msg++;
|
|
continue;
|
|
case 'S':
|
|
Q_strncatz(output, TP_ClassForTFSkin(), sizeof(output));
|
|
msg++;
|
|
continue;
|
|
case '%':
|
|
c = '%';
|
|
break;
|
|
default:
|
|
c = '%';
|
|
msg--;
|
|
break;
|
|
}
|
|
}
|
|
else if (c == '$')
|
|
{
|
|
msg++;
|
|
switch(*msg)
|
|
{
|
|
case '\\': c = 0x0D; break;
|
|
case ':': c = 0x0A; break;
|
|
case '[': c = 0x10; break;
|
|
case ']': c = 0x11; break;
|
|
case 'G': c = 0x86; break;
|
|
case 'R': c = 0x87; break;
|
|
case 'Y': c = 0x88; break;
|
|
case 'B': c = 0x89; break;
|
|
case '(': c = 0x80; break;
|
|
case '=': c = 0x81; break;
|
|
case ')': c = 0x82; break;
|
|
case 'a': c = 0x83; break;
|
|
case '<': c = 0x1d; break;
|
|
case '-': c = 0x1e; break;
|
|
case '>': c = 0x1f; break;
|
|
case ',': c = 0x1c; break;
|
|
case '.': c = 0x9c; break;
|
|
case 'b': c = 0x8b; break;
|
|
case 'c':
|
|
case 'd': c = 0x8d; break;
|
|
case '$': c = '$'; break;
|
|
case '^': c = '^'; break;
|
|
case 'x':
|
|
c = INVIS_CHAR1;
|
|
break;
|
|
case 'y':
|
|
c = INVIS_CHAR2;
|
|
break;
|
|
case 'z':
|
|
c = INVIS_CHAR3;
|
|
break;
|
|
default:
|
|
msg--;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
Q_strncatz(output, va("%c", c), sizeof(output));
|
|
|
|
msg++;
|
|
}
|
|
Q_strncatz(output, "\"", sizeof(output));
|
|
}
|
|
|
|
CL_SendClientCommand("%s", output);
|
|
}
|
|
|
|
void TP_Init(void)
|
|
{
|
|
}
|
|
|
|
void TP_CheckPickupSound(char *s, vec3_t org)
|
|
{
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
qboolean TP_SoundTrigger(char *message) //if there is a trigger there, play it. Return true if we found one, stripping off the file (it's neater that way).
|
|
{
|
|
char *strip;
|
|
char *lineend = NULL;
|
|
char soundname[128];
|
|
int filter = 0;
|
|
|
|
for (strip = message+strlen(message)-1; *strip && strip >= message; strip--)
|
|
{
|
|
if (*strip == '#')
|
|
filter++;
|
|
if (*strip == ':')
|
|
break; //if someone says just one word, we can take any tidles in thier name to be a voice command
|
|
if (*strip == '\n')
|
|
lineend = strip;
|
|
else if (*strip <= ' ')
|
|
{
|
|
if (filter == 0 || filter == 1) //allow one space in front of a filter.
|
|
{
|
|
filter++;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
else if (*strip == '~')
|
|
{
|
|
//looks like a trigger, whoopie!
|
|
if (lineend-strip > sizeof(soundname)-1)
|
|
{
|
|
Con_Printf("Sound trigger's file-name was too long\n");
|
|
return false;
|
|
}
|
|
Q_strncpyz(soundname, strip+1, lineend-strip);
|
|
memmove(strip, lineend, strlen(lineend)+1);
|
|
|
|
Cbuf_AddText(va("play %s\n", soundname), RESTRICT_LOCAL);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|