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 
ClientTeam(edict_t * ent)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->floatVal) & DF_MODELTEAMS)
40 	{
41 		*p = 0;
42 		return value;
43 	}
44 
45 	// if ((int)(dmflags->floatVal) & DF_SKINTEAMS)
46 	return ++p;
47 }
48 
OnSameTeam(edict_t * ent1,edict_t * ent2)49 qBool OnSameTeam (edict_t *ent1, edict_t *ent2)
50 {
51 	char	ent1Team [512];
52 	char	ent2Team [512];
53 
54 	if (!((int)(dmflags->floatVal) & (DF_MODELTEAMS | DF_SKINTEAMS)))
55 		return qFalse;
56 
57 	strcpy (ent1Team, ClientTeam (ent1));
58 	strcpy (ent2Team, ClientTeam (ent2));
59 
60 	if (strcmp(ent1Team, ent2Team) == 0)
61 		return qTrue;
62 	return qFalse;
63 }
64 
65 
SelectNextItem(edict_t * ent,int itflags)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_CS_ITEMS ; i++)
81 	{
82 		index = (cl->pers.selected_item + i)%MAX_CS_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 
SelectPrevItem(edict_t * ent,int itflags)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_CS_ITEMS ; i++)
113 	{
114 		index = (cl->pers.selected_item + MAX_CS_ITEMS - i)%MAX_CS_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 
ValidateSelectedItem(edict_t * ent)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 */
Cmd_Give_f(edict_t * ent)152 void Cmd_Give_f (edict_t *ent)
153 {
154 	char		*name;
155 	gitem_t		*it;
156 	int			index;
157 	int			i;
158 	qBool	give_all;
159 	edict_t		*it_ent;
160 
161 	if (deathmatch->floatVal && !sv_cheats->floatVal)
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 = qTrue;
171 	else
172 		give_all = qFalse;
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 */
Cmd_God_f(edict_t * ent)308 void Cmd_God_f (edict_t *ent)
309 {
310 	char	*msg;
311 
312 	if (deathmatch->floatVal && !sv_cheats->floatVal)
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 */
Cmd_Notarget_f(edict_t * ent)337 void Cmd_Notarget_f (edict_t *ent)
338 {
339 	char	*msg;
340 
341 	if (deathmatch->floatVal && !sv_cheats->floatVal)
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 */
Cmd_Noclip_f(edict_t * ent)364 void Cmd_Noclip_f (edict_t *ent)
365 {
366 	char	*msg;
367 
368 	if (deathmatch->floatVal && !sv_cheats->floatVal)
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 */
Cmd_Use_f(edict_t * ent)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 */
Cmd_Drop_f(edict_t * ent)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 */
Cmd_Inven_f(edict_t * ent)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 = qFalse;
474 	cl->showhelp = qFalse;
475 
476 	if (cl->showinventory)
477 	{
478 		cl->showinventory = qFalse;
479 		return;
480 	}
481 
482 	cl->showinventory = qTrue;
483 
484 	gi.WriteByte (SVC_INVENTORY);
485 	for (i=0 ; i<MAX_CS_ITEMS ; i++)
486 	{
487 		gi.WriteShort (cl->pers.inventory[i]);
488 	}
489 	gi.unicast (ent, qTrue);
490 }
491 
492 /*
493 =================
494 Cmd_InvUse_f
495 =================
496 */
Cmd_InvUse_f(edict_t * ent)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 */
Cmd_WeapPrev_f(edict_t * ent)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_CS_ITEMS ; i++)
539 	{
540 		index = (selected_weapon + i)%MAX_CS_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 */
Cmd_WeapNext_f(edict_t * ent)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_CS_ITEMS ; i++)
575 	{
576 		index = (selected_weapon + MAX_CS_ITEMS - i)%MAX_CS_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 */
Cmd_WeapLast_f(edict_t * ent)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 */
Cmd_InvDrop_f(edict_t * ent)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 */
Cmd_Kill_f(edict_t * ent)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, vec3Origin);
656 }
657 
658 /*
659 =================
660 Cmd_PutAway_f
661 =================
662 */
Cmd_PutAway_f(edict_t * ent)663 void Cmd_PutAway_f (edict_t *ent)
664 {
665 	ent->client->showscores = qFalse;
666 	ent->client->showhelp = qFalse;
667 	ent->client->showinventory = qFalse;
668 }
669 
670 
PlayerSort(void const * a,void const * b)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 */
Cmd_Players_f(edict_t * ent)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->floatVal ; 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 		Q_snprintfz (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 */
Cmd_Wave_f(edict_t * ent)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.pmFlags & 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 */
Cmd_Say_f(edict_t * ent,qBool team,qBool arg0)787 void Cmd_Say_f (edict_t *ent, qBool team, qBool 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->floatVal) & (DF_MODELTEAMS | DF_SKINTEAMS)))
799 		team = qFalse;
800 
801 	if (team)
802 		Q_snprintfz (text, sizeof(text), "(%s): ", ent->client->pers.netname);
803 	else
804 		Q_snprintfz (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->floatVal) {
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->floatVal + 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->floatVal) {
843 			cl->flood_locktill = level.time + flood_waitdelay->floatVal;
844 			gi.cprintf(ent, PRINT_CHAT, "Flood protection:  You can't talk for %d seconds.\n",
845 				(int)flood_waitdelay->floatVal);
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->floatVal)
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 
Cmd_PlayerList_f(edict_t * ent)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->floatVal; i++, e2++) {
882 		if (!e2->inUse)
883 			continue;
884 
885 		Q_snprintfz(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 */
ClientCommand(edict_t * ent)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, qFalse, qFalse);
925 		return;
926 	}
927 	if (Q_stricmp (cmd, "say_team") == 0)
928 	{
929 		Cmd_Say_f (ent, qTrue, qFalse);
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, qFalse, qTrue);
992 }
993