File: game\g_cmds.c

    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                 Com_sprintf(st, sizeof(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 }
  993