Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

g_cmds.c (18481B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 #include "g_local.h"
     21 #include "m_player.h"
     22 
     23 
     24 char *ClientTeam (edict_t *ent)
     25 {
     26 	char		*p;
     27 	static char	value[512];
     28 
     29 	value[0] = 0;
     30 
     31 	if (!ent->client)
     32 		return value;
     33 
     34 	strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
     35 	p = strchr(value, '/');
     36 	if (!p)
     37 		return value;
     38 
     39 	if ((int)(dmflags->value) & DF_MODELTEAMS)
     40 	{
     41 		*p = 0;
     42 		return value;
     43 	}
     44 
     45 	// if ((int)(dmflags->value) & DF_SKINTEAMS)
     46 	return ++p;
     47 }
     48 
     49 qboolean OnSameTeam (edict_t *ent1, edict_t *ent2)
     50 {
     51 	char	ent1Team [512];
     52 	char	ent2Team [512];
     53 
     54 	if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
     55 		return false;
     56 
     57 	strcpy (ent1Team, ClientTeam (ent1));
     58 	strcpy (ent2Team, ClientTeam (ent2));
     59 
     60 	if (strcmp(ent1Team, ent2Team) == 0)
     61 		return true;
     62 	return false;
     63 }
     64 
     65 
     66 void SelectNextItem (edict_t *ent, int itflags)
     67 {
     68 	gclient_t	*cl;
     69 	int			i, index;
     70 	gitem_t		*it;
     71 
     72 	cl = ent->client;
     73 
     74 	if (cl->chase_target) {
     75 		ChaseNext(ent);
     76 		return;
     77 	}
     78 
     79 	// scan  for the next valid one
     80 	for (i=1 ; i<=MAX_ITEMS ; i++)
     81 	{
     82 		index = (cl->pers.selected_item + i)%MAX_ITEMS;
     83 		if (!cl->pers.inventory[index])
     84 			continue;
     85 		it = &itemlist[index];
     86 		if (!it->use)
     87 			continue;
     88 		if (!(it->flags & itflags))
     89 			continue;
     90 
     91 		cl->pers.selected_item = index;
     92 		return;
     93 	}
     94 
     95 	cl->pers.selected_item = -1;
     96 }
     97 
     98 void SelectPrevItem (edict_t *ent, int itflags)
     99 {
    100 	gclient_t	*cl;
    101 	int			i, index;
    102 	gitem_t		*it;
    103 
    104 	cl = ent->client;
    105 
    106 	if (cl->chase_target) {
    107 		ChasePrev(ent);
    108 		return;
    109 	}
    110 
    111 	// scan  for the next valid one
    112 	for (i=1 ; i<=MAX_ITEMS ; i++)
    113 	{
    114 		index = (cl->pers.selected_item + MAX_ITEMS - i)%MAX_ITEMS;
    115 		if (!cl->pers.inventory[index])
    116 			continue;
    117 		it = &itemlist[index];
    118 		if (!it->use)
    119 			continue;
    120 		if (!(it->flags & itflags))
    121 			continue;
    122 
    123 		cl->pers.selected_item = index;
    124 		return;
    125 	}
    126 
    127 	cl->pers.selected_item = -1;
    128 }
    129 
    130 void ValidateSelectedItem (edict_t *ent)
    131 {
    132 	gclient_t	*cl;
    133 
    134 	cl = ent->client;
    135 
    136 	if (cl->pers.inventory[cl->pers.selected_item])
    137 		return;		// valid
    138 
    139 	SelectNextItem (ent, -1);
    140 }
    141 
    142 
    143 //=================================================================================
    144 
    145 /*
    146 ==================
    147 Cmd_Give_f
    148 
    149 Give items to a client
    150 ==================
    151 */
    152 void Cmd_Give_f (edict_t *ent)
    153 {
    154 	char		*name;
    155 	gitem_t		*it;
    156 	int			index;
    157 	int			i;
    158 	qboolean	give_all;
    159 	edict_t		*it_ent;
    160 
    161 	if (deathmatch->value && !sv_cheats->value)
    162 	{
    163 		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
    164 		return;
    165 	}
    166 
    167 	name = gi.args();
    168 
    169 	if (Q_stricmp(name, "all") == 0)
    170 		give_all = true;
    171 	else
    172 		give_all = false;
    173 
    174 	if (give_all || Q_stricmp(gi.argv(1), "health") == 0)
    175 	{
    176 		if (gi.argc() == 3)
    177 			ent->health = atoi(gi.argv(2));
    178 		else
    179 			ent->health = ent->max_health;
    180 		if (!give_all)
    181 			return;
    182 	}
    183 
    184 	if (give_all || Q_stricmp(name, "weapons") == 0)
    185 	{
    186 		for (i=0 ; i<game.num_items ; i++)
    187 		{
    188 			it = itemlist + i;
    189 			if (!it->pickup)
    190 				continue;
    191 			if (!(it->flags & IT_WEAPON))
    192 				continue;
    193 			ent->client->pers.inventory[i] += 1;
    194 		}
    195 		if (!give_all)
    196 			return;
    197 	}
    198 
    199 	if (give_all || Q_stricmp(name, "ammo") == 0)
    200 	{
    201 		for (i=0 ; i<game.num_items ; i++)
    202 		{
    203 			it = itemlist + i;
    204 			if (!it->pickup)
    205 				continue;
    206 			if (!(it->flags & IT_AMMO))
    207 				continue;
    208 			Add_Ammo (ent, it, 1000);
    209 		}
    210 		if (!give_all)
    211 			return;
    212 	}
    213 
    214 	if (give_all || Q_stricmp(name, "armor") == 0)
    215 	{
    216 		gitem_armor_t	*info;
    217 
    218 		it = FindItem("Jacket Armor");
    219 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
    220 
    221 		it = FindItem("Combat Armor");
    222 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
    223 
    224 		it = FindItem("Body Armor");
    225 		info = (gitem_armor_t *)it->info;
    226 		ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count;
    227 
    228 		if (!give_all)
    229 			return;
    230 	}
    231 
    232 	if (give_all || Q_stricmp(name, "Power Shield") == 0)
    233 	{
    234 		it = FindItem("Power Shield");
    235 		it_ent = G_Spawn();
    236 		it_ent->classname = it->classname;
    237 		SpawnItem (it_ent, it);
    238 		Touch_Item (it_ent, ent, NULL, NULL);
    239 		if (it_ent->inuse)
    240 			G_FreeEdict(it_ent);
    241 
    242 		if (!give_all)
    243 			return;
    244 	}
    245 
    246 	if (give_all)
    247 	{
    248 		for (i=0 ; i<game.num_items ; i++)
    249 		{
    250 			it = itemlist + i;
    251 			if (!it->pickup)
    252 				continue;
    253 			if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO))
    254 				continue;
    255 			ent->client->pers.inventory[i] = 1;
    256 		}
    257 		return;
    258 	}
    259 
    260 	it = FindItem (name);
    261 	if (!it)
    262 	{
    263 		name = gi.argv(1);
    264 		it = FindItem (name);
    265 		if (!it)
    266 		{
    267 			gi.cprintf (ent, PRINT_HIGH, "unknown item\n");
    268 			return;
    269 		}
    270 	}
    271 
    272 	if (!it->pickup)
    273 	{
    274 		gi.cprintf (ent, PRINT_HIGH, "non-pickup item\n");
    275 		return;
    276 	}
    277 
    278 	index = ITEM_INDEX(it);
    279 
    280 	if (it->flags & IT_AMMO)
    281 	{
    282 		if (gi.argc() == 3)
    283 			ent->client->pers.inventory[index] = atoi(gi.argv(2));
    284 		else
    285 			ent->client->pers.inventory[index] += it->quantity;
    286 	}
    287 	else
    288 	{
    289 		it_ent = G_Spawn();
    290 		it_ent->classname = it->classname;
    291 		SpawnItem (it_ent, it);
    292 		Touch_Item (it_ent, ent, NULL, NULL);
    293 		if (it_ent->inuse)
    294 			G_FreeEdict(it_ent);
    295 	}
    296 }
    297 
    298 
    299 /*
    300 ==================
    301 Cmd_God_f
    302 
    303 Sets client to godmode
    304 
    305 argv(0) god
    306 ==================
    307 */
    308 void Cmd_God_f (edict_t *ent)
    309 {
    310 	char	*msg;
    311 
    312 	if (deathmatch->value && !sv_cheats->value)
    313 	{
    314 		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
    315 		return;
    316 	}
    317 
    318 	ent->flags ^= FL_GODMODE;
    319 	if (!(ent->flags & FL_GODMODE) )
    320 		msg = "godmode OFF\n";
    321 	else
    322 		msg = "godmode ON\n";
    323 
    324 	gi.cprintf (ent, PRINT_HIGH, msg);
    325 }
    326 
    327 
    328 /*
    329 ==================
    330 Cmd_Notarget_f
    331 
    332 Sets client to notarget
    333 
    334 argv(0) notarget
    335 ==================
    336 */
    337 void Cmd_Notarget_f (edict_t *ent)
    338 {
    339 	char	*msg;
    340 
    341 	if (deathmatch->value && !sv_cheats->value)
    342 	{
    343 		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
    344 		return;
    345 	}
    346 
    347 	ent->flags ^= FL_NOTARGET;
    348 	if (!(ent->flags & FL_NOTARGET) )
    349 		msg = "notarget OFF\n";
    350 	else
    351 		msg = "notarget ON\n";
    352 
    353 	gi.cprintf (ent, PRINT_HIGH, msg);
    354 }
    355 
    356 
    357 /*
    358 ==================
    359 Cmd_Noclip_f
    360 
    361 argv(0) noclip
    362 ==================
    363 */
    364 void Cmd_Noclip_f (edict_t *ent)
    365 {
    366 	char	*msg;
    367 
    368 	if (deathmatch->value && !sv_cheats->value)
    369 	{
    370 		gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
    371 		return;
    372 	}
    373 
    374 	if (ent->movetype == MOVETYPE_NOCLIP)
    375 	{
    376 		ent->movetype = MOVETYPE_WALK;
    377 		msg = "noclip OFF\n";
    378 	}
    379 	else
    380 	{
    381 		ent->movetype = MOVETYPE_NOCLIP;
    382 		msg = "noclip ON\n";
    383 	}
    384 
    385 	gi.cprintf (ent, PRINT_HIGH, msg);
    386 }
    387 
    388 
    389 /*
    390 ==================
    391 Cmd_Use_f
    392 
    393 Use an inventory item
    394 ==================
    395 */
    396 void Cmd_Use_f (edict_t *ent)
    397 {
    398 	int			index;
    399 	gitem_t		*it;
    400 	char		*s;
    401 
    402 	s = gi.args();
    403 	it = FindItem (s);
    404 	if (!it)
    405 	{
    406 		gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
    407 		return;
    408 	}
    409 	if (!it->use)
    410 	{
    411 		gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
    412 		return;
    413 	}
    414 	index = ITEM_INDEX(it);
    415 	if (!ent->client->pers.inventory[index])
    416 	{
    417 		gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
    418 		return;
    419 	}
    420 
    421 	it->use (ent, it);
    422 }
    423 
    424 
    425 /*
    426 ==================
    427 Cmd_Drop_f
    428 
    429 Drop an inventory item
    430 ==================
    431 */
    432 void Cmd_Drop_f (edict_t *ent)
    433 {
    434 	int			index;
    435 	gitem_t		*it;
    436 	char		*s;
    437 
    438 	s = gi.args();
    439 	it = FindItem (s);
    440 	if (!it)
    441 	{
    442 		gi.cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
    443 		return;
    444 	}
    445 	if (!it->drop)
    446 	{
    447 		gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
    448 		return;
    449 	}
    450 	index = ITEM_INDEX(it);
    451 	if (!ent->client->pers.inventory[index])
    452 	{
    453 		gi.cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
    454 		return;
    455 	}
    456 
    457 	it->drop (ent, it);
    458 }
    459 
    460 
    461 /*
    462 =================
    463 Cmd_Inven_f
    464 =================
    465 */
    466 void Cmd_Inven_f (edict_t *ent)
    467 {
    468 	int			i;
    469 	gclient_t	*cl;
    470 
    471 	cl = ent->client;
    472 
    473 	cl->showscores = false;
    474 	cl->showhelp = false;
    475 
    476 	if (cl->showinventory)
    477 	{
    478 		cl->showinventory = false;
    479 		return;
    480 	}
    481 
    482 	cl->showinventory = true;
    483 
    484 	gi.WriteByte (svc_inventory);
    485 	for (i=0 ; i<MAX_ITEMS ; i++)
    486 	{
    487 		gi.WriteShort (cl->pers.inventory[i]);
    488 	}
    489 	gi.unicast (ent, true);
    490 }
    491 
    492 /*
    493 =================
    494 Cmd_InvUse_f
    495 =================
    496 */
    497 void Cmd_InvUse_f (edict_t *ent)
    498 {
    499 	gitem_t		*it;
    500 
    501 	ValidateSelectedItem (ent);
    502 
    503 	if (ent->client->pers.selected_item == -1)
    504 	{
    505 		gi.cprintf (ent, PRINT_HIGH, "No item to use.\n");
    506 		return;
    507 	}
    508 
    509 	it = &itemlist[ent->client->pers.selected_item];
    510 	if (!it->use)
    511 	{
    512 		gi.cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
    513 		return;
    514 	}
    515 	it->use (ent, it);
    516 }
    517 
    518 /*
    519 =================
    520 Cmd_WeapPrev_f
    521 =================
    522 */
    523 void Cmd_WeapPrev_f (edict_t *ent)
    524 {
    525 	gclient_t	*cl;
    526 	int			i, index;
    527 	gitem_t		*it;
    528 	int			selected_weapon;
    529 
    530 	cl = ent->client;
    531 
    532 	if (!cl->pers.weapon)
    533 		return;
    534 
    535 	selected_weapon = ITEM_INDEX(cl->pers.weapon);
    536 
    537 	// scan  for the next valid one
    538 	for (i=1 ; i<=MAX_ITEMS ; i++)
    539 	{
    540 		index = (selected_weapon + i)%MAX_ITEMS;
    541 		if (!cl->pers.inventory[index])
    542 			continue;
    543 		it = &itemlist[index];
    544 		if (!it->use)
    545 			continue;
    546 		if (! (it->flags & IT_WEAPON) )
    547 			continue;
    548 		it->use (ent, it);
    549 		if (cl->pers.weapon == it)
    550 			return;	// successful
    551 	}
    552 }
    553 
    554 /*
    555 =================
    556 Cmd_WeapNext_f
    557 =================
    558 */
    559 void Cmd_WeapNext_f (edict_t *ent)
    560 {
    561 	gclient_t	*cl;
    562 	int			i, index;
    563 	gitem_t		*it;
    564 	int			selected_weapon;
    565 
    566 	cl = ent->client;
    567 
    568 	if (!cl->pers.weapon)
    569 		return;
    570 
    571 	selected_weapon = ITEM_INDEX(cl->pers.weapon);
    572 
    573 	// scan  for the next valid one
    574 	for (i=1 ; i<=MAX_ITEMS ; i++)
    575 	{
    576 		index = (selected_weapon + MAX_ITEMS - i)%MAX_ITEMS;
    577 		if (!cl->pers.inventory[index])
    578 			continue;
    579 		it = &itemlist[index];
    580 		if (!it->use)
    581 			continue;
    582 		if (! (it->flags & IT_WEAPON) )
    583 			continue;
    584 		it->use (ent, it);
    585 		if (cl->pers.weapon == it)
    586 			return;	// successful
    587 	}
    588 }
    589 
    590 /*
    591 =================
    592 Cmd_WeapLast_f
    593 =================
    594 */
    595 void Cmd_WeapLast_f (edict_t *ent)
    596 {
    597 	gclient_t	*cl;
    598 	int			index;
    599 	gitem_t		*it;
    600 
    601 	cl = ent->client;
    602 
    603 	if (!cl->pers.weapon || !cl->pers.lastweapon)
    604 		return;
    605 
    606 	index = ITEM_INDEX(cl->pers.lastweapon);
    607 	if (!cl->pers.inventory[index])
    608 		return;
    609 	it = &itemlist[index];
    610 	if (!it->use)
    611 		return;
    612 	if (! (it->flags & IT_WEAPON) )
    613 		return;
    614 	it->use (ent, it);
    615 }
    616 
    617 /*
    618 =================
    619 Cmd_InvDrop_f
    620 =================
    621 */
    622 void Cmd_InvDrop_f (edict_t *ent)
    623 {
    624 	gitem_t		*it;
    625 
    626 	ValidateSelectedItem (ent);
    627 
    628 	if (ent->client->pers.selected_item == -1)
    629 	{
    630 		gi.cprintf (ent, PRINT_HIGH, "No item to drop.\n");
    631 		return;
    632 	}
    633 
    634 	it = &itemlist[ent->client->pers.selected_item];
    635 	if (!it->drop)
    636 	{
    637 		gi.cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
    638 		return;
    639 	}
    640 	it->drop (ent, it);
    641 }
    642 
    643 /*
    644 =================
    645 Cmd_Kill_f
    646 =================
    647 */
    648 void Cmd_Kill_f (edict_t *ent)
    649 {
    650 	if((level.time - ent->client->respawn_time) < 5)
    651 		return;
    652 	ent->flags &= ~FL_GODMODE;
    653 	ent->health = 0;
    654 	meansOfDeath = MOD_SUICIDE;
    655 	player_die (ent, ent, ent, 100000, vec3_origin);
    656 }
    657 
    658 /*
    659 =================
    660 Cmd_PutAway_f
    661 =================
    662 */
    663 void Cmd_PutAway_f (edict_t *ent)
    664 {
    665 	ent->client->showscores = false;
    666 	ent->client->showhelp = false;
    667 	ent->client->showinventory = false;
    668 }
    669 
    670 
    671 int PlayerSort (void const *a, void const *b)
    672 {
    673 	int		anum, bnum;
    674 
    675 	anum = *(int *)a;
    676 	bnum = *(int *)b;
    677 
    678 	anum = game.clients[anum].ps.stats[STAT_FRAGS];
    679 	bnum = game.clients[bnum].ps.stats[STAT_FRAGS];
    680 
    681 	if (anum < bnum)
    682 		return -1;
    683 	if (anum > bnum)
    684 		return 1;
    685 	return 0;
    686 }
    687 
    688 /*
    689 =================
    690 Cmd_Players_f
    691 =================
    692 */
    693 void Cmd_Players_f (edict_t *ent)
    694 {
    695 	int		i;
    696 	int		count;
    697 	char	small[64];
    698 	char	large[1280];
    699 	int		index[256];
    700 
    701 	count = 0;
    702 	for (i = 0 ; i < maxclients->value ; i++)
    703 		if (game.clients[i].pers.connected)
    704 		{
    705 			index[count] = i;
    706 			count++;
    707 		}
    708 
    709 	// sort by frags
    710 	qsort (index, count, sizeof(index[0]), PlayerSort);
    711 
    712 	// print information
    713 	large[0] = 0;
    714 
    715 	for (i = 0 ; i < count ; i++)
    716 	{
    717 		Com_sprintf (small, sizeof(small), "%3i %s\n",
    718 			game.clients[index[i]].ps.stats[STAT_FRAGS],
    719 			game.clients[index[i]].pers.netname);
    720 		if (strlen (small) + strlen(large) > sizeof(large) - 100 )
    721 		{	// can't print all of them in one packet
    722 			strcat (large, "...\n");
    723 			break;
    724 		}
    725 		strcat (large, small);
    726 	}
    727 
    728 	gi.cprintf (ent, PRINT_HIGH, "%s\n%i players\n", large, count);
    729 }
    730 
    731 /*
    732 =================
    733 Cmd_Wave_f
    734 =================
    735 */
    736 void Cmd_Wave_f (edict_t *ent)
    737 {
    738 	int		i;
    739 
    740 	i = atoi (gi.argv(1));
    741 
    742 	// can't wave when ducked
    743 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
    744 		return;
    745 
    746 	if (ent->client->anim_priority > ANIM_WAVE)
    747 		return;
    748 
    749 	ent->client->anim_priority = ANIM_WAVE;
    750 
    751 	switch (i)
    752 	{
    753 	case 0:
    754 		gi.cprintf (ent, PRINT_HIGH, "flipoff\n");
    755 		ent->s.frame = FRAME_flip01-1;
    756 		ent->client->anim_end = FRAME_flip12;
    757 		break;
    758 	case 1:
    759 		gi.cprintf (ent, PRINT_HIGH, "salute\n");
    760 		ent->s.frame = FRAME_salute01-1;
    761 		ent->client->anim_end = FRAME_salute11;
    762 		break;
    763 	case 2:
    764 		gi.cprintf (ent, PRINT_HIGH, "taunt\n");
    765 		ent->s.frame = FRAME_taunt01-1;
    766 		ent->client->anim_end = FRAME_taunt17;
    767 		break;
    768 	case 3:
    769 		gi.cprintf (ent, PRINT_HIGH, "wave\n");
    770 		ent->s.frame = FRAME_wave01-1;
    771 		ent->client->anim_end = FRAME_wave11;
    772 		break;
    773 	case 4:
    774 	default:
    775 		gi.cprintf (ent, PRINT_HIGH, "point\n");
    776 		ent->s.frame = FRAME_point01-1;
    777 		ent->client->anim_end = FRAME_point12;
    778 		break;
    779 	}
    780 }
    781 
    782 /*
    783 ==================
    784 Cmd_Say_f
    785 ==================
    786 */
    787 void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0)
    788 {
    789 	int		i, j;
    790 	edict_t	*other;
    791 	char	*p;
    792 	char	text[2048];
    793 	gclient_t *cl;
    794 
    795 	if (gi.argc () < 2 && !arg0)
    796 		return;
    797 
    798 	if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
    799 		team = false;
    800 
    801 	if (team)
    802 		Com_sprintf (text, sizeof(text), "(%s): ", ent->client->pers.netname);
    803 	else
    804 		Com_sprintf (text, sizeof(text), "%s: ", ent->client->pers.netname);
    805 
    806 	if (arg0)
    807 	{
    808 		strcat (text, gi.argv(0));
    809 		strcat (text, " ");
    810 		strcat (text, gi.args());
    811 	}
    812 	else
    813 	{
    814 		p = gi.args();
    815 
    816 		if (*p == '"')
    817 		{
    818 			p++;
    819 			p[strlen(p)-1] = 0;
    820 		}
    821 		strcat(text, p);
    822 	}
    823 
    824 	// don't let text be too long for malicious reasons
    825 	if (strlen(text) > 150)
    826 		text[150] = 0;
    827 
    828 	strcat(text, "\n");
    829 
    830 	if (flood_msgs->value) {
    831 		cl = ent->client;
    832 
    833         if (level.time < cl->flood_locktill) {
    834 			gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
    835 				(int)(cl->flood_locktill - level.time));
    836             return;
    837         }
    838         i = cl->flood_whenhead - flood_msgs->value + 1;
    839         if (i < 0)
    840             i = (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])) + i;
    841 		if (cl->flood_when[i] && 
    842 			level.time - cl->flood_when[i] < flood_persecond->value) {
    843 			cl->flood_locktill = level.time + flood_waitdelay->value;
    844 			gi.cprintf(ent, PRINT_CHAT, "Flood protection:  You can't talk for %d seconds.\n",
    845 				(int)flood_waitdelay->value);
    846             return;
    847         }
    848 		cl->flood_whenhead = (cl->flood_whenhead + 1) %
    849 			(sizeof(cl->flood_when)/sizeof(cl->flood_when[0]));
    850 		cl->flood_when[cl->flood_whenhead] = level.time;
    851 	}
    852 
    853 	if (dedicated->value)
    854 		gi.cprintf(NULL, PRINT_CHAT, "%s", text);
    855 
    856 	for (j = 1; j <= game.maxclients; j++)
    857 	{
    858 		other = &g_edicts[j];
    859 		if (!other->inuse)
    860 			continue;
    861 		if (!other->client)
    862 			continue;
    863 		if (team)
    864 		{
    865 			if (!OnSameTeam(ent, other))
    866 				continue;
    867 		}
    868 		gi.cprintf(other, PRINT_CHAT, "%s", text);
    869 	}
    870 }
    871 
    872 void Cmd_PlayerList_f(edict_t *ent)
    873 {
    874 	int i;
    875 	char st[80];
    876 	char text[1400];
    877 	edict_t *e2;
    878 
    879 	// connect time, ping, score, name
    880 	*text = 0;
    881 	for (i = 0, e2 = g_edicts + 1; i < maxclients->value; i++, e2++) {
    882 		if (!e2->inuse)
    883 			continue;
    884 
    885 		sprintf(st, "%02d:%02d %4d %3d %s%s\n",
    886 			(level.framenum - e2->client->resp.enterframe) / 600,
    887 			((level.framenum - e2->client->resp.enterframe) % 600)/10,
    888 			e2->client->ping,
    889 			e2->client->resp.score,
    890 			e2->client->pers.netname,
    891 			e2->client->resp.spectator ? " (spectator)" : "");
    892 		if (strlen(text) + strlen(st) > sizeof(text) - 50) {
    893 			sprintf(text+strlen(text), "And more...\n");
    894 			gi.cprintf(ent, PRINT_HIGH, "%s", text);
    895 			return;
    896 		}
    897 		strcat(text, st);
    898 	}
    899 	gi.cprintf(ent, PRINT_HIGH, "%s", text);
    900 }
    901 
    902 
    903 /*
    904 =================
    905 ClientCommand
    906 =================
    907 */
    908 void ClientCommand (edict_t *ent)
    909 {
    910 	char	*cmd;
    911 
    912 	if (!ent->client)
    913 		return;		// not fully in game yet
    914 
    915 	cmd = gi.argv(0);
    916 
    917 	if (Q_stricmp (cmd, "players") == 0)
    918 	{
    919 		Cmd_Players_f (ent);
    920 		return;
    921 	}
    922 	if (Q_stricmp (cmd, "say") == 0)
    923 	{
    924 		Cmd_Say_f (ent, false, false);
    925 		return;
    926 	}
    927 	if (Q_stricmp (cmd, "say_team") == 0)
    928 	{
    929 		Cmd_Say_f (ent, true, false);
    930 		return;
    931 	}
    932 	if (Q_stricmp (cmd, "score") == 0)
    933 	{
    934 		Cmd_Score_f (ent);
    935 		return;
    936 	}
    937 	if (Q_stricmp (cmd, "help") == 0)
    938 	{
    939 		Cmd_Help_f (ent);
    940 		return;
    941 	}
    942 
    943 	if (level.intermissiontime)
    944 		return;
    945 
    946 	if (Q_stricmp (cmd, "use") == 0)
    947 		Cmd_Use_f (ent);
    948 	else if (Q_stricmp (cmd, "drop") == 0)
    949 		Cmd_Drop_f (ent);
    950 	else if (Q_stricmp (cmd, "give") == 0)
    951 		Cmd_Give_f (ent);
    952 	else if (Q_stricmp (cmd, "god") == 0)
    953 		Cmd_God_f (ent);
    954 	else if (Q_stricmp (cmd, "notarget") == 0)
    955 		Cmd_Notarget_f (ent);
    956 	else if (Q_stricmp (cmd, "noclip") == 0)
    957 		Cmd_Noclip_f (ent);
    958 	else if (Q_stricmp (cmd, "inven") == 0)
    959 		Cmd_Inven_f (ent);
    960 	else if (Q_stricmp (cmd, "invnext") == 0)
    961 		SelectNextItem (ent, -1);
    962 	else if (Q_stricmp (cmd, "invprev") == 0)
    963 		SelectPrevItem (ent, -1);
    964 	else if (Q_stricmp (cmd, "invnextw") == 0)
    965 		SelectNextItem (ent, IT_WEAPON);
    966 	else if (Q_stricmp (cmd, "invprevw") == 0)
    967 		SelectPrevItem (ent, IT_WEAPON);
    968 	else if (Q_stricmp (cmd, "invnextp") == 0)
    969 		SelectNextItem (ent, IT_POWERUP);
    970 	else if (Q_stricmp (cmd, "invprevp") == 0)
    971 		SelectPrevItem (ent, IT_POWERUP);
    972 	else if (Q_stricmp (cmd, "invuse") == 0)
    973 		Cmd_InvUse_f (ent);
    974 	else if (Q_stricmp (cmd, "invdrop") == 0)
    975 		Cmd_InvDrop_f (ent);
    976 	else if (Q_stricmp (cmd, "weapprev") == 0)
    977 		Cmd_WeapPrev_f (ent);
    978 	else if (Q_stricmp (cmd, "weapnext") == 0)
    979 		Cmd_WeapNext_f (ent);
    980 	else if (Q_stricmp (cmd, "weaplast") == 0)
    981 		Cmd_WeapLast_f (ent);
    982 	else if (Q_stricmp (cmd, "kill") == 0)
    983 		Cmd_Kill_f (ent);
    984 	else if (Q_stricmp (cmd, "putaway") == 0)
    985 		Cmd_PutAway_f (ent);
    986 	else if (Q_stricmp (cmd, "wave") == 0)
    987 		Cmd_Wave_f (ent);
    988 	else if (Q_stricmp(cmd, "playerlist") == 0)
    989 		Cmd_PlayerList_f(ent);
    990 	else	// anything that doesn't match a command will be a chat
    991 		Cmd_Say_f (ent, false, true);
    992 }