
Posted by Riviera (62.20.148.*) on July 05, 1999
at 06:46:51:
Author: Peter 'Riviera' Engstrom
Who needs it: If say_team
%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a%a
crashes your server
This code fixes two bugs in
the CTF say_team code tha can crash your server. One bug is that there were no
length checks during the parsing and the other that the maximum message length
was about 1024 characters. Fear no more. There's also some optimizations and
the parsing has it's own function (to be used for radio messages or similar).
vec_t
VectorLengthSqr(vec3_t v)
{
int i;
float length;
length = 0.0f;
for (i=0; i<3; i++)
length += v[i]*v[i];
return length;
}
static void
CTFSay_Team_Location(edict_t * who, char *buf)
{
edict_t *what = NULL;
edict_t *hot = NULL;
float hotdist =
222222222.2, newdist;
vec3_t v;
int hotindex = 999;
int i;
gitem_t *item;
int nearteam = -1;
edict_t *flag1,
*flag2;
qboolean hotsee =
false;
qboolean cansee;
int ibuf = 0;
while ((what =
loc_findradius(what, who->s.origin, 1024)) != NULL) {
//
find what in loc_classnames
for
(i = 0; loc_names[i].classname; i++)
if
(!strcmp(what->classname, loc_names[i].classname))
break;
if
(!loc_names[i].classname)
continue;
//
something we can see get priority over something we can't
cansee
= loc_CanSee(what, who);
if
(cansee && !hotsee) {
hotsee
= true;
hotindex
= loc_names[i].priority;
hot
= what;
VectorSubtract(what->s.origin,
who->s.origin, v);
hotdist
= VectorLengthSqr(v);
continue;
}
//
if we can't see this, but we have something we can see, skip it
if
(hotsee && !cansee)
continue;
if
(hotsee && hotindex < loc_names[i].priority)
continue;
VectorSubtract(what->s.origin,
who->s.origin, v);
newdist
= VectorLengthSqr(v);
if
(newdist < hotdist ||
(cansee
&& loc_names[i].priority < hotindex)) {
hot
= what;
hotdist
= newdist;
hotindex
= i;
hotsee
= loc_CanSee(hot, who);
}
}
if (!hot) {
memcpy(buf,
"nowhere", 8);
return;
}
// we now have the
closest item
// see if there's
more than one in the map, if so
// we need to
determine what team is closest
what = NULL;
while ((what =
G_Find(what, FOFS(classname), hot->classname)) != NULL) {
if
(what == hot)
continue;
//
if we are here, there is more than one, find out if hot
//
is closer to red flag or blue flag
if
((flag1 = G_Find(NULL, FOFS(classname), "item_flag_team1")) != NULL
&&
(flag2
= G_Find(NULL, FOFS(classname), "item_flag_team2")) != NULL) {
VectorSubtract(hot->s.origin,
flag1->s.origin, v);
hotdist
= VectorLengthSqr(v);
VectorSubtract(hot->s.origin,
flag2->s.origin, v);
newdist
= VectorLengthSqr(v);
if
(hotdist < newdist)
nearteam
= CTF_TEAM1;
else
if (hotdist > newdist)
nearteam
= CTF_TEAM2;
}
break;
}
if ((item =
FindItemByClassname(hot->classname)) == NULL) {
memcpy(buf,
"nowhere", 8);
return;
}
// in water?
if (who->waterlevel)
{
memcpy(buf,
"in the water ", 13);
ibuf
= 13;
}
else
*buf
= 0;
// near or above
VectorSubtract(who->s.origin, hot->s.origin, v);
if (fabs(v[2]) >
fabs(v[0]) && fabs(v[2]) > fabs(v[1])) {
if
(v[2] > 0) {
memcpy(buf
+ ibuf, "above ", 6);
ibuf
+= 6;
}
else
{
memcpy(buf
+ ibuf, "below ", 6);
ibuf
+= 6;
}
}
else {
memcpy(buf
+ ibuf, "near ", 5);
ibuf
+= 5;
}
if (nearteam ==
CTF_TEAM1) {
memcpy(buf
+ ibuf, "the red ", 8);
ibuf
+= 8;
}
else if (nearteam ==
CTF_TEAM2) {
memcpy(buf
+ ibuf, "the blue ", 9);
ibuf
+= 9;
}
else {
memcpy(buf
+ ibuf, "the ", 4);
ibuf
+= 4;
}
strcpy(buf + ibuf,
item->pickup_name);
}
static void
CTFSay_Team_Armor(edict_t *who, char *buf)
{
gitem_t *item;
int index,
cells;
int power_armor_type;
*buf
= 0;
power_armor_type
= PowerArmorType(who);
if
(power_armor_type)
{
cells
= who->client->pers.inventory[ITEM_INDEX(FindItem("cells"))];
if
(cells)
sprintf(buf+strlen(buf),
"%s with %i cells ",
(power_armor_type
== POWER_ARMOR_SCREEN) ?
"Power
Screen" : "Power Shield", cells);
}
index
= ArmorIndex(who);
if
(index)
{
item
= GetItemByIndex(index);
if
(item) {
if
(*buf)
strcat(buf,
"and ");
sprintf(buf+strlen(buf),
"%i units of %s",
who->client->pers.inventory[index],
item->pickup_name);
}
}
if (!*buf)
memcpy(buf,
"no armor", 9);
}
static void
CTFSay_Team_Health(edict_t * who, char *buf)
{
if (who->health
<= 0)
memcpy(buf,
"dead", 5);
else
sprintf(buf,
"%i health", who->health);
}
static void
CTFSay_Team_Tech(edict_t *who, char *buf)
{
gitem_t
*tech;
int
i;
//
see if the player has a tech powerup
i
= 0;
while
(tnames[i]) {
if
((tech = FindItemByClassname(tnames[i])) != NULL &&
who->client->pers.inventory[ITEM_INDEX(tech)])
{
sprintf(buf,
"the %s", tech->pickup_name);
return;
}
i++;
}
memcpy(buf, "no
powerup", 11);
}
static void
CTFSay_Team_Weapon(edict_t *who, char *buf)
{
if
(who->client->pers.weapon)
strcpy(buf,
who->client->pers.weapon->pickup_name);
else
memcpy(buf,
"none", 5);
}
static void
CTFSay_Team_Sight(edict_t *who, char *buf)
{
int
i;
edict_t
*targ;
int
n = 0;
char
s[1024];
char
s2[1024];
*s
= *s2 = 0;
for
(i = 1; i <= game.maxclients; i++) {
targ
= g_edicts + i;
if
(!targ->inuse ||
targ->svflags
& SVF_NOCLIENT ||
targ
== who ||
!loc_CanSee(targ,
who))
continue;
if
(*s2) {
if
(strlen(s) + strlen(s2) + 3 < sizeof(s)) {
if
(n)
strcat(s,
", ");
strcat(s,
s2);
*s2
= 0;
}
n++;
}
strcpy(s2,
targ->client->pers.netname);
}
if
(*s2) {
if
(strlen(s) + strlen(s2) + 6 < sizeof(s)) {
if
(n)
strcat(s,
" and ");
strcat(s,
s2);
}
strcpy(buf,
s);
}
else
memcpy(buf,
"no one", 7);
}
void
CTFParseTeamMessage(edict_t * who, char *msg, char *outmsg, int size)
{
char buf[1024];
char *p;
int
len;
outmsg[0] = 0;
if (*msg ==
'\"') {
msg[strlen(msg)
- 1] = 0;
msg++;
}
for (p = outmsg; *msg
&& (p - outmsg) < size - 1; msg++) {
if
(*msg == '%') {
switch
(*++msg) {
case
'l':
case
'L':
CTFSay_Team_Location(who,
buf);
len
= strlen(buf);
if
(p-outmsg+len < size) {
memcpy(p,
buf, len);
p +=
len;
}
break;
case
'a':
case
'A':
CTFSay_Team_Armor(who,
buf);
len
= strlen(buf);
if
(p-outmsg+len < size) {
memcpy(p,
buf, len);
p
+= len;
}
break;
case
'h':
case
'H':
CTFSay_Team_Health(who,
buf);
len
= strlen(buf);
if
(p-outmsg+len < size) {
memcpy(p,
buf, len);
p
+= len;
}
break;
case
't':
case
'T':
CTFSay_Team_Tech(who,
buf);
len
= strlen(buf);
if
(p-outmsg+len < size) {
memcpy(p,
buf, len);
p
+= len;
}
break;
case
'w':
case
'W':
CTFSay_Team_Weapon(who,
buf);
len
= strlen(buf);
if
(p-outmsg+len < size) {
memcpy(p,
buf, len);
p
+= len;
}
break;
case
'n':
case
'N':
CTFSay_Team_Sight(who,
buf);
len
= strlen(buf);
if
(p-outmsg+len < size) {
memcpy(p,
buf, len);
p
+= len;
}
break;
case
'%':
*p++
= '%';
break;
case
'\0':
--msg;
break;
default:
break;
}
}
else
*p++
= *msg;
}
*p = 0;
}
void
CTFSay_Team(edict_t * who, char *msg)
{
char outmsg[160];
int i;
edict_t *cl_ent;
//FIXME:
Insert flood protection here
CTFParseTeamMessage(who, msg, outmsg, sizeof (outmsg));
for
(i = 1; i <= game.maxclients; i++) {
cl_ent
= g_edicts + i;
if
(!cl_ent->inuse)
continue;
if
(cl_ent->client->resp.ctf_team == who->client->resp.ctf_team)
gi.cprintf(cl_ent,
PRINT_CHAT, "(%s): %s\n",
who->client->pers.netname,
outmsg);
}
}
Good luck!!!