1
0
Fork 0
forked from fte/fteqw
fteqw/engine/client/teamplay.c

459 lines
9.5 KiB
C
Raw Normal View History

/*
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"
#ifndef 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
#ifdef ZQUAKETEAMPLAY
/*
===============
CL_Say
Handles both say and say_team
===============
*/
void CL_Say (qboolean team)
{
extern cvar_t cl_fakename;
char text[1024], sendtext[1024], *s;
if (Cmd_Argc() < 2)
{
if (team)
Con_Printf ("%s <text>: send a team message\n", Cmd_Argv(0));
return;
}
if (cls.state == ca_disconnected)
{
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
return;
}
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
SZ_Print (&cls.netchan.message, team ? "say_team " : "say ");
s = TP_ParseMacroString (Cmd_Args());
Q_strncpyz (text, TP_ParseFunChars (s, true), sizeof(text));
sendtext[0] = 0;
if (team && !cl.spectator && cl_fakename.string[0] &&
!strchr(s, '\x0d') /* explicit $\ in message overrides cl_fakename */)
{
char buf[1024];
Cmd_ExpandString (cl_fakename.string, buf);
strcpy (buf, TP_ParseMacroString (buf));
Q_snprintfz (sendtext, sizeof(sendtext), "\x0d%s: ", TP_ParseFunChars(buf, true));
}
strlcat (sendtext, text, sizeof(sendtext));
if (sendtext[0] < 32)
SZ_Print (&cls.netchan.message, "\""); // add quotes so that old servers parse the message correctly
SZ_Print (&cls.netchan.message, sendtext);
if (sendtext[0] < 32)
SZ_Print (&cls.netchan.message, "\""); // add quotes so that old servers parse the message correctly
}
void CL_Say_f (void)
{
CL_Say (false);
}
void CL_SayTeam_f (void)
{
CL_Say (true);
}
#else
void CL_Say_f (void)
{
char string[256];
char *msg;
int c;
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;
}
}
MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
Q_strncpyz(string, Cmd_Argv(0), sizeof(string));
for (msg = string; *msg; msg++)
if (*msg >= 'A' && *msg <= 'Z')
*msg = *msg - 'A' + 'a';
SZ_Print (&cls.netchan.message, string);
cls.netchan.message.cursize--;
msg = Cmd_Args();
if (Cmd_Argc() > 1)
{
SZ_Print (&cls.netchan.message," ");
cls.netchan.message.cursize--;
MSG_WriteChar(&cls.netchan.message, '\"');
while(*msg)
{
c = *msg;
if (c == '%')
{
char *message = NULL;
msg++;
if (message == NULL)
switch(*msg)
{
case 'n':
SZ_Print(&cls.netchan.message, name.string);
cls.netchan.message.cursize--;
msg++;
continue;
case 'h':
SZ_Print(&cls.netchan.message, va("%i", cl.stats[0][STAT_HEALTH]));
cls.netchan.message.cursize--; //remove the null term
msg++;
continue;
case 'a':
SZ_Print(&cls.netchan.message, va("%i", cl.stats[0][STAT_ARMOR]));
cls.netchan.message.cursize--;
msg++;
continue;
case 'A':
SZ_Print(&cls.netchan.message, TP_ArmourType());
cls.netchan.message.cursize--;
msg++;
continue;
case 'l':
SZ_Print(&cls.netchan.message, CL_LocationName(r_refdef.vieworg));
cls.netchan.message.cursize--;
msg++;
continue;
case 'S':
SZ_Print(&cls.netchan.message, TP_ClassForTFSkin());
cls.netchan.message.cursize--;
msg++;
continue;
case '\0': //whoops.
MSG_WriteChar(&cls.netchan.message, '%');
MSG_WriteChar(&cls.netchan.message, '\"');
MSG_WriteChar(&cls.netchan.message, *msg);
return;
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;
}
}
MSG_WriteChar(&cls.netchan.message, c);
msg++;
}
MSG_WriteChar(&cls.netchan.message, '\"');
}
MSG_WriteChar(&cls.netchan.message, '\0');
}
#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;
}
void TP_Init(void)
{
}
void TP_CheckPickupSound(char *s, vec3_t org)
{
}
#endif