yquake2remaster/src/game/g_cmds.c
Daniel Gibson 5e33152f6a One entity shooting another should work even if friendly fire is off
In rogue's RHANGAR1 the turret didn't blow up the ceiling when friendly fire
was off, because in ClientTeam() both entities were set to "" (no team),
but OnSameTeam() just did a strcmp() instead of checking this special
case (no team).
We check this now and thus it works. Hooray.
I also refactored ClientTeam() to take the buffer instead of using a
static one and to be static (it's only called by OnSameTeam() anyway).

The savegame table entry for this function was invalid, but it doesn't
need to be saved anyway, so I just deleted it from the table.
2014-11-30 17:58:18 +01:00

1375 lines
20 KiB
C

/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Game command processing.
*
* =======================================================================
*/
#include "header/local.h"
#include "monster/misc/player.h"
static char *
ClientTeam(edict_t *ent, char* value)
{
char *p;
value[0] = 0;
if (!ent)
{
return value;
}
if (!ent->client)
{
return value;
}
strcpy(value, Info_ValueForKey(ent->client->pers.userinfo, "skin"));
p = strchr(value, '/');
if (!p)
{
return value;
}
if ((int)(dmflags->value) & DF_MODELTEAMS)
{
*p = 0;
return value;
}
return ++p;
}
qboolean
OnSameTeam(edict_t *ent1, edict_t *ent2)
{
char ent1Team[512];
char ent2Team[512];
if (!ent1 || !ent2)
{
return false;
}
if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
{
return false;
}
ClientTeam(ent1, ent1Team);
ClientTeam(ent2, ent2Team);
if (ent1Team[0] != '\0' && strcmp(ent1Team, ent2Team) == 0)
{
return true;
}
return false;
}
void
SelectNextItem(edict_t *ent, int itflags)
{
gclient_t *cl;
int i, index;
gitem_t *it;
if (!ent)
{
return;
}
cl = ent->client;
if (cl->chase_target)
{
ChaseNext(ent);
return;
}
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
{
index = (cl->pers.selected_item + i) % MAX_ITEMS;
if (!cl->pers.inventory[index])
{
continue;
}
it = &itemlist[index];
if (!it->use)
{
continue;
}
if (!(it->flags & itflags))
{
continue;
}
cl->pers.selected_item = index;
return;
}
cl->pers.selected_item = -1;
}
void
SelectPrevItem(edict_t *ent, int itflags)
{
gclient_t *cl;
int i, index;
gitem_t *it;
if (!ent)
{
return;
}
cl = ent->client;
if (cl->chase_target)
{
ChasePrev(ent);
return;
}
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
{
index = (cl->pers.selected_item + MAX_ITEMS - i) % MAX_ITEMS;
if (!cl->pers.inventory[index])
{
continue;
}
it = &itemlist[index];
if (!it->use)
{
continue;
}
if (!(it->flags & itflags))
{
continue;
}
cl->pers.selected_item = index;
return;
}
cl->pers.selected_item = -1;
}
void
ValidateSelectedItem(edict_t *ent)
{
gclient_t *cl;
if (!ent)
{
return;
}
cl = ent->client;
if (cl->pers.inventory[cl->pers.selected_item])
{
return; /* valid */
}
SelectNextItem(ent, -1);
}
/* ================================================================================= */
/*
* Give items to a client
*/
void
Cmd_Give_f(edict_t *ent)
{
char *name;
gitem_t *it;
int index;
int i;
qboolean give_all;
edict_t *it_ent;
if (!ent)
{
return;
}
if ((deathmatch->value || coop->value) && !sv_cheats->value)
{
gi.cprintf( ent, PRINT_HIGH,
"You must run the server with '+set cheats 1' to enable this command.\n");
return;
}
name = gi.args();
if (Q_stricmp(name, "all") == 0)
{
give_all = true;
}
else
{
give_all = false;
}
if (give_all || (Q_stricmp(gi.argv(1), "health") == 0))
{
if (gi.argc() == 3)
{
ent->health = (int)strtol(gi.argv(2), (char **)NULL, 10);
}
else
{
ent->health = ent->max_health;
}
if (!give_all)
{
return;
}
}
if (give_all || (Q_stricmp(name, "weapons") == 0))
{
for (i = 0; i < game.num_items; i++)
{
it = itemlist + i;
if (!it->pickup)
{
continue;
}
if (!(it->flags & IT_WEAPON))
{
continue;
}
ent->client->pers.inventory[i] += 1;
}
if (!give_all)
{
return;
}
}
if (give_all || (Q_stricmp(name, "ammo") == 0))
{
for (i = 0; i < game.num_items; i++)
{
it = itemlist + i;
if (!it->pickup)
{
continue;
}
if (!(it->flags & IT_AMMO))
{
continue;
}
Add_Ammo(ent, it, 1000);
}
if (!give_all)
{
return;
}
}
if (give_all || (Q_stricmp(name, "armor") == 0))
{
gitem_armor_t *info;
it = FindItem("Jacket Armor");
ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
it = FindItem("Combat Armor");
ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
it = FindItem("Body Armor");
info = (gitem_armor_t *)it->info;
ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count;
if (!give_all)
{
return;
}
}
if (give_all || (Q_stricmp(name, "Power Shield") == 0))
{
it = FindItem("Power Shield");
it_ent = G_Spawn();
it_ent->classname = it->classname;
SpawnItem(it_ent, it);
Touch_Item(it_ent, ent, NULL, NULL);
if (it_ent->inuse)
{
G_FreeEdict(it_ent);
}
if (!give_all)
{
return;
}
}
if (give_all)
{
for (i = 0; i < game.num_items; i++)
{
it = itemlist + i;
if (!it->pickup)
{
continue;
}
if (it->flags & (IT_ARMOR | IT_WEAPON | IT_AMMO))
{
continue;
}
ent->client->pers.inventory[i] = 1;
}
return;
}
it = FindItem(name);
if (!it)
{
name = gi.argv(1);
it = FindItem(name);
if (!it)
{
gi.cprintf(ent, PRINT_HIGH, "unknown item\n");
return;
}
}
if (!it->pickup)
{
gi.cprintf(ent, PRINT_HIGH, "non-pickup item\n");
return;
}
index = ITEM_INDEX(it);
if (it->flags & IT_AMMO)
{
if (gi.argc() == 3)
{
ent->client->pers.inventory[index] = (int)strtol(gi.argv(2), (char **)NULL, 10);
}
else
{
ent->client->pers.inventory[index] += it->quantity;
}
}
else
{
it_ent = G_Spawn();
it_ent->classname = it->classname;
SpawnItem(it_ent, it);
Touch_Item(it_ent, ent, NULL, NULL);
if (it_ent->inuse)
{
G_FreeEdict(it_ent);
}
}
}
/*
* Sets client to godmode
*/
void
Cmd_God_f(edict_t *ent)
{
char *msg;
if (!ent)
{
return;
}
if ((deathmatch->value || coop->value) && !sv_cheats->value)
{
gi.cprintf( ent, PRINT_HIGH,
"You must run the server with '+set cheats 1' to enable this command.\n");
return;
}
ent->flags ^= FL_GODMODE;
if (!(ent->flags & FL_GODMODE))
{
msg = "godmode OFF\n";
}
else
{
msg = "godmode ON\n";
}
gi.cprintf(ent, PRINT_HIGH, msg);
}
/*
* Sets client to notarget
*/
void
Cmd_Notarget_f(edict_t *ent)
{
char *msg;
if (!ent)
{
return;
}
if ((deathmatch->value || coop->value) && !sv_cheats->value)
{
gi.cprintf( ent, PRINT_HIGH,
"You must run the server with '+set cheats 1' to enable this command.\n");
return;
}
ent->flags ^= FL_NOTARGET;
if (!(ent->flags & FL_NOTARGET))
{
msg = "notarget OFF\n";
}
else
{
msg = "notarget ON\n";
}
gi.cprintf(ent, PRINT_HIGH, msg);
}
/*
* argv(0) noclip
*/
void
Cmd_Noclip_f(edict_t *ent)
{
char *msg;
if (!ent)
{
return;
}
if ((deathmatch->value || coop->value) && !sv_cheats->value)
{
gi.cprintf( ent, PRINT_HIGH,
"You must run the server with '+set cheats 1' to enable this command.\n");
return;
}
if (ent->movetype == MOVETYPE_NOCLIP)
{
ent->movetype = MOVETYPE_WALK;
msg = "noclip OFF\n";
}
else
{
ent->movetype = MOVETYPE_NOCLIP;
msg = "noclip ON\n";
}
gi.cprintf(ent, PRINT_HIGH, msg);
}
/*
* Use an inventory item
*/
void
Cmd_Use_f(edict_t *ent)
{
int index;
gitem_t *it;
char *s;
if (!ent)
{
return;
}
s = gi.args();
it = FindItem(s);
if (!it)
{
gi.cprintf(ent, PRINT_HIGH, "unknown item: %s\n", s);
return;
}
if (!it->use)
{
gi.cprintf(ent, PRINT_HIGH, "Item is not usable.\n");
return;
}
index = ITEM_INDEX(it);
if (!ent->client->pers.inventory[index])
{
gi.cprintf(ent, PRINT_HIGH, "Out of item: %s\n", s);
return;
}
it->use(ent, it);
}
/*
* Drop an inventory item
*/
void
Cmd_Drop_f(edict_t *ent)
{
int index;
gitem_t *it;
char *s;
if (!ent)
{
return;
}
s = gi.args();
it = FindItem(s);
if (!it)
{
gi.cprintf(ent, PRINT_HIGH, "unknown item: %s\n", s);
return;
}
if (!it->drop)
{
gi.cprintf(ent, PRINT_HIGH, "Item is not dropable.\n");
return;
}
index = ITEM_INDEX(it);
if (!ent->client->pers.inventory[index])
{
gi.cprintf(ent, PRINT_HIGH, "Out of item: %s\n", s);
return;
}
it->drop(ent, it);
}
void
Cmd_Score_f(edict_t *ent)
{
if (!ent)
{
return;
}
ent->client->showinventory = false;
ent->client->showhelp = false;
if (!deathmatch->value && !coop->value)
{
return;
}
if (ent->client->showscores)
{
ent->client->showscores = false;
return;
}
ent->client->showscores = true;
DeathmatchScoreboardMessage(ent, ent->enemy);
gi.unicast(ent, true);
}
void
Cmd_Help_f(edict_t *ent)
{
if (!ent)
{
return;
}
/* this is for backwards compatibility */
if (deathmatch->value)
{
Cmd_Score_f(ent);
return;
}
ent->client->showinventory = false;
ent->client->showscores = false;
if (ent->client->showhelp)
{
ent->client->showhelp = false;
return;
}
ent->client->showhelp = true;
ent->client->pers.helpchanged = 0;
HelpComputerMessage(ent);
gi.unicast(ent, true);
}
void
Cmd_Inven_f(edict_t *ent)
{
gclient_t *cl;
if (!ent)
{
return;
}
cl = ent->client;
cl->showscores = false;
cl->showhelp = false;
if (cl->showinventory)
{
cl->showinventory = false;
return;
}
cl->showinventory = true;
InventoryMessage(ent);
gi.unicast(ent, true);
}
void
Cmd_InvUse_f(edict_t *ent)
{
gitem_t *it;
if (!ent)
{
return;
}
ValidateSelectedItem(ent);
if (ent->client->pers.selected_item == -1)
{
gi.cprintf(ent, PRINT_HIGH, "No item to use.\n");
return;
}
it = &itemlist[ent->client->pers.selected_item];
if (!it->use)
{
gi.cprintf(ent, PRINT_HIGH, "Item is not usable.\n");
return;
}
it->use(ent, it);
}
void
Cmd_WeapPrev_f(edict_t *ent)
{
gclient_t *cl;
int i, index;
gitem_t *it;
int selected_weapon;
if (!ent)
{
return;
}
cl = ent->client;
if (!cl->pers.weapon)
{
return;
}
selected_weapon = ITEM_INDEX(cl->pers.weapon);
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
{
index = (selected_weapon + i) % MAX_ITEMS;
if (!cl->pers.inventory[index])
{
continue;
}
it = &itemlist[index];
if (!it->use)
{
continue;
}
if (!(it->flags & IT_WEAPON))
{
continue;
}
it->use(ent, it);
if (cl->pers.weapon == it)
{
return; /* successful */
}
}
}
void
Cmd_WeapNext_f(edict_t *ent)
{
gclient_t *cl;
int i, index;
gitem_t *it;
int selected_weapon;
if (!ent)
{
return;
}
cl = ent->client;
if (!cl->pers.weapon)
{
return;
}
selected_weapon = ITEM_INDEX(cl->pers.weapon);
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
{
index = (selected_weapon + MAX_ITEMS - i) % MAX_ITEMS;
if (!cl->pers.inventory[index])
{
continue;
}
it = &itemlist[index];
if (!it->use)
{
continue;
}
if (!(it->flags & IT_WEAPON))
{
continue;
}
it->use(ent, it);
if (cl->pers.weapon == it)
{
return; /* successful */
}
}
}
void
Cmd_WeapLast_f(edict_t *ent)
{
gclient_t *cl;
int index;
gitem_t *it;
if (!ent)
{
return;
}
cl = ent->client;
if (!cl->pers.weapon || !cl->pers.lastweapon)
{
return;
}
index = ITEM_INDEX(cl->pers.lastweapon);
if (!cl->pers.inventory[index])
{
return;
}
it = &itemlist[index];
if (!it->use)
{
return;
}
if (!(it->flags & IT_WEAPON))
{
return;
}
it->use(ent, it);
}
void
Cmd_InvDrop_f(edict_t *ent)
{
gitem_t *it;
if (!ent)
{
return;
}
ValidateSelectedItem(ent);
if (ent->client->pers.selected_item == -1)
{
gi.cprintf(ent, PRINT_HIGH, "No item to drop.\n");
return;
}
it = &itemlist[ent->client->pers.selected_item];
if (!it->drop)
{
gi.cprintf(ent, PRINT_HIGH, "Item is not dropable.\n");
return;
}
it->drop(ent, it);
}
void
Cmd_Kill_f(edict_t *ent)
{
if (!ent)
{
return;
}
if (((level.time - ent->client->respawn_time) < 5) ||
(ent->client->resp.spectator))
{
return;
}
ent->flags &= ~FL_GODMODE;
ent->health = 0;
meansOfDeath = MOD_SUICIDE;
player_die(ent, ent, ent, 100000, vec3_origin);
}
void
Cmd_PutAway_f(edict_t *ent)
{
if (!ent)
{
return;
}
ent->client->showscores = false;
ent->client->showhelp = false;
ent->client->showinventory = false;
}
int
PlayerSort(void const *a, void const *b)
{
int anum, bnum;
if (!a || !b)
{
return 0;
}
anum = *(int *)a;
bnum = *(int *)b;
anum = game.clients[anum].ps.stats[STAT_FRAGS];
bnum = game.clients[bnum].ps.stats[STAT_FRAGS];
if (anum < bnum)
{
return -1;
}
if (anum > bnum)
{
return 1;
}
return 0;
}
void
Cmd_Players_f(edict_t *ent)
{
int i;
int count;
char small[64];
char large[1280];
int index[256];
if (!ent)
{
return;
}
count = 0;
for (i = 0; i < maxclients->value; i++)
{
if (game.clients[i].pers.connected)
{
index[count] = i;
count++;
}
}
/* sort by frags */
qsort(index, count, sizeof(index[0]), PlayerSort);
/* print information */
large[0] = 0;
for (i = 0; i < count; i++)
{
Com_sprintf(small, sizeof(small), "%3i %s\n",
game.clients[index[i]].ps.stats[STAT_FRAGS],
game.clients[index[i]].pers.netname);
if (strlen(small) + strlen(large) > sizeof(large) - 100)
{
/* can't print all of them in one packet */
strcat(large, "...\n");
break;
}
strcat(large, small);
}
gi.cprintf(ent, PRINT_HIGH, "%s\n%i players\n", large, count);
}
void
Cmd_Wave_f(edict_t *ent)
{
int i;
if (!ent)
{
return;
}
i = (int)strtol(gi.argv(1), (char **)NULL, 10);
/* can't wave when ducked */
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
{
return;
}
if (ent->client->anim_priority > ANIM_WAVE)
{
return;
}
ent->client->anim_priority = ANIM_WAVE;
switch (i)
{
case 0:
gi.cprintf(ent, PRINT_HIGH, "flipoff\n");
ent->s.frame = FRAME_flip01 - 1;
ent->client->anim_end = FRAME_flip12;
break;
case 1:
gi.cprintf(ent, PRINT_HIGH, "salute\n");
ent->s.frame = FRAME_salute01 - 1;
ent->client->anim_end = FRAME_salute11;
break;
case 2:
gi.cprintf(ent, PRINT_HIGH, "taunt\n");
ent->s.frame = FRAME_taunt01 - 1;
ent->client->anim_end = FRAME_taunt17;
break;
case 3:
gi.cprintf(ent, PRINT_HIGH, "wave\n");
ent->s.frame = FRAME_wave01 - 1;
ent->client->anim_end = FRAME_wave11;
break;
case 4:
default:
gi.cprintf(ent, PRINT_HIGH, "point\n");
ent->s.frame = FRAME_point01 - 1;
ent->client->anim_end = FRAME_point12;
break;
}
}
void
Cmd_Say_f(edict_t *ent, qboolean team, qboolean arg0)
{
int i, j;
edict_t *other;
char *p;
char text[2048];
gclient_t *cl;
if (!ent)
{
return;
}
if ((gi.argc() < 2) && !arg0)
{
return;
}
if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
{
team = false;
}
if (team)
{
Com_sprintf(text, sizeof(text), "(%s): ", ent->client->pers.netname);
}
else
{
Com_sprintf(text, sizeof(text), "%s: ", ent->client->pers.netname);
}
if (arg0)
{
strcat(text, gi.argv(0));
strcat(text, " ");
strcat(text, gi.args());
}
else
{
p = gi.args();
if (*p == '"')
{
p++;
p[strlen(p) - 1] = 0;
}
strcat(text, p);
}
/* don't let text be too long for malicious reasons */
if (strlen(text) > 150)
{
text[150] = 0;
}
strcat(text, "\n");
if (flood_msgs->value)
{
cl = ent->client;
if (level.time < cl->flood_locktill)
{
gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
(int)(cl->flood_locktill - level.time));
return;
}
i = cl->flood_whenhead - flood_msgs->value + 1;
if (i < 0)
{
i = (sizeof(cl->flood_when) / sizeof(cl->flood_when[0])) + i;
}
if (cl->flood_when[i] &&
(level.time - cl->flood_when[i] < flood_persecond->value))
{
cl->flood_locktill = level.time + flood_waitdelay->value;
gi.cprintf(ent, PRINT_CHAT,
"Flood protection: You can't talk for %d seconds.\n",
(int)flood_waitdelay->value);
return;
}
cl->flood_whenhead = (cl->flood_whenhead + 1) %
(sizeof(cl->flood_when) / sizeof(cl->flood_when[0]));
cl->flood_when[cl->flood_whenhead] = level.time;
}
if (dedicated->value)
{
gi.cprintf(NULL, PRINT_CHAT, "%s", text);
}
for (j = 1; j <= game.maxclients; j++)
{
other = &g_edicts[j];
if (!other->inuse)
{
continue;
}
if (!other->client)
{
continue;
}
if (team)
{
if (!OnSameTeam(ent, other))
{
continue;
}
}
gi.cprintf(other, PRINT_CHAT, "%s", text);
}
}
void
Cmd_PlayerList_f(edict_t *ent)
{
int i;
char st[80];
char text[1400];
edict_t *e2;
if (!ent)
{
return;
}
/* connect time, ping, score, name */
*text = 0;
for (i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++)
{
if (!e2->inuse)
{
continue;
}
Com_sprintf(st, sizeof(st), "%02d:%02d %4d %3d %s%s\n",
(level.framenum - e2->client->resp.enterframe) / 600,
((level.framenum - e2->client->resp.enterframe) % 600) / 10,
e2->client->ping,
e2->client->resp.score,
e2->client->pers.netname,
e2->client->resp.spectator ? " (spectator)" : "");
if (strlen(text) + strlen(st) > sizeof(text) - 50)
{
strcpy(text + strlen(text), "And more...\n");
gi.cprintf(ent, PRINT_HIGH, "%s", text);
return;
}
strcat(text, st);
}
gi.cprintf(ent, PRINT_HIGH, "%s", text);
}
void
ClientCommand(edict_t *ent)
{
char *cmd;
if (!ent)
{
return;
}
if (!ent->client)
{
return; /* not fully in game yet */
}
cmd = gi.argv(0);
if (Q_stricmp(cmd, "players") == 0)
{
Cmd_Players_f(ent);
return;
}
if (Q_stricmp(cmd, "say") == 0)
{
Cmd_Say_f(ent, false, false);
return;
}
if (Q_stricmp(cmd, "say_team") == 0)
{
Cmd_Say_f(ent, true, false);
return;
}
if (Q_stricmp(cmd, "score") == 0)
{
Cmd_Score_f(ent);
return;
}
if (Q_stricmp(cmd, "help") == 0)
{
Cmd_Help_f(ent);
return;
}
if (level.intermissiontime)
{
return;
}
if (Q_stricmp(cmd, "use") == 0)
{
Cmd_Use_f(ent);
}
else if (Q_stricmp(cmd, "drop") == 0)
{
Cmd_Drop_f(ent);
}
else if (Q_stricmp(cmd, "give") == 0)
{
Cmd_Give_f(ent);
}
else if (Q_stricmp(cmd, "god") == 0)
{
Cmd_God_f(ent);
}
else if (Q_stricmp(cmd, "notarget") == 0)
{
Cmd_Notarget_f(ent);
}
else if (Q_stricmp(cmd, "noclip") == 0)
{
Cmd_Noclip_f(ent);
}
else if (Q_stricmp(cmd, "inven") == 0)
{
Cmd_Inven_f(ent);
}
else if (Q_stricmp(cmd, "invnext") == 0)
{
SelectNextItem(ent, -1);
}
else if (Q_stricmp(cmd, "invprev") == 0)
{
SelectPrevItem(ent, -1);
}
else if (Q_stricmp(cmd, "invnextw") == 0)
{
SelectNextItem(ent, IT_WEAPON);
}
else if (Q_stricmp(cmd, "invprevw") == 0)
{
SelectPrevItem(ent, IT_WEAPON);
}
else if (Q_stricmp(cmd, "invnextp") == 0)
{
SelectNextItem(ent, IT_POWERUP);
}
else if (Q_stricmp(cmd, "invprevp") == 0)
{
SelectPrevItem(ent, IT_POWERUP);
}
else if (Q_stricmp(cmd, "invuse") == 0)
{
Cmd_InvUse_f(ent);
}
else if (Q_stricmp(cmd, "invdrop") == 0)
{
Cmd_InvDrop_f(ent);
}
else if (Q_stricmp(cmd, "weapprev") == 0)
{
Cmd_WeapPrev_f(ent);
}
else if (Q_stricmp(cmd, "weapnext") == 0)
{
Cmd_WeapNext_f(ent);
}
else if (Q_stricmp(cmd, "weaplast") == 0)
{
Cmd_WeapLast_f(ent);
}
else if (Q_stricmp(cmd, "kill") == 0)
{
Cmd_Kill_f(ent);
}
else if (Q_stricmp(cmd, "putaway") == 0)
{
Cmd_PutAway_f(ent);
}
else if (Q_stricmp(cmd, "wave") == 0)
{
Cmd_Wave_f(ent);
}
else if (Q_stricmp(cmd, "playerlist") == 0)
{
Cmd_PlayerList_f(ent);
}
else /* anything that doesn't match a command will be a chat */
{
Cmd_Say_f(ent, false, true);
}
}