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 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "g_local.h"
26 #include "m_player.h"
27 
28 
ClientTeam(edict_t * ent)29 char *ClientTeam (edict_t *ent)
30 {
31 	char		*p;
32 	static char	value[512];
33 
34 	value[0] = 0;
35 
36 	if (!ent->client)
37 		return value;
38 
39 	strcpy(value, Info_ValueForKey (ent->client->pers.userinfo, "skin"));
40 	p = strchr(value, '/');
41 	if (!p)
42 		return value;
43 
44 	return ++p;
45 }
46 
OnSameTeam(edict_t * ent1,edict_t * ent2)47 qboolean OnSameTeam (edict_t *ent1, edict_t *ent2)
48 {
49 	char	ent1Team [512];
50 	char	ent2Team [512];
51 
52 	if(g_tactical->value)
53 	{
54 		if(ent1->ctype == ent2->ctype)
55 			return true;
56 	}
57 
58 	if (!((dmflags->integer & DF_SKINTEAMS) || ctf->value || tca->value || cp->value))
59 		return false;
60 
61 	strcpy (ent1Team, ClientTeam (ent1));
62 	strcpy (ent2Team, ClientTeam (ent2));
63 
64 	if (strcmp(ent1Team, ent2Team) == 0)
65 		return true;
66 
67 	return false;
68 }
69 
70 
SelectNextItem(edict_t * ent,int itflags)71 void SelectNextItem (edict_t *ent, int itflags)
72 {
73 	gclient_t	*cl;
74 	int			i, index;
75 	gitem_t		*it;
76 
77 	cl = ent->client;
78 
79 	if (cl->chase_target) {
80 		ChaseNext(ent);
81 		return;
82 	}
83 
84 	// scan  for the next valid one
85 	for (i=1 ; i<=MAX_ITEMS ; i++)
86 	{
87 		index = (cl->pers.selected_item + i)%MAX_ITEMS;
88 		if (!cl->pers.inventory[index])
89 			continue;
90 		it = &itemlist[index];
91 		if (!it->use)
92 			continue;
93 		if (!(it->flags & itflags))
94 			continue;
95 
96 		cl->pers.selected_item = index;
97 		return;
98 	}
99 
100 	cl->pers.selected_item = -1;
101 }
102 
SelectPrevItem(edict_t * ent,int itflags)103 void SelectPrevItem (edict_t *ent, int itflags)
104 {
105 	gclient_t	*cl;
106 	int			i, index;
107 	gitem_t		*it;
108 
109 	cl = ent->client;
110 
111 	if (cl->chase_target) {
112 		ChasePrev(ent);
113 		return;
114 	}
115 
116 	// scan  for the next valid one
117 	for (i=1 ; i<=MAX_ITEMS ; i++)
118 	{
119 		index = (cl->pers.selected_item + MAX_ITEMS - i)%MAX_ITEMS;
120 		if (!cl->pers.inventory[index])
121 			continue;
122 		it = &itemlist[index];
123 		if (!it->use)
124 			continue;
125 		if (!(it->flags & itflags))
126 			continue;
127 
128 		cl->pers.selected_item = index;
129 		return;
130 	}
131 
132 	cl->pers.selected_item = -1;
133 }
134 
ValidateSelectedItem(edict_t * ent)135 void ValidateSelectedItem (edict_t *ent)
136 {
137 	gclient_t	*cl;
138 
139 	cl = ent->client;
140 
141 	if (cl->pers.inventory[cl->pers.selected_item])
142 		return;		// valid
143 
144 	SelectNextItem (ent, -1);
145 }
146 
DrawChatBubble(edict_t * ent)147 void DrawChatBubble (edict_t *ent)
148 {
149 
150 	if(!ent->client)
151 		return;
152 	if(ent->client->resp.spectator)
153 		return;
154 
155 	gi.WriteByte (svc_temp_entity);
156 	gi.WriteByte (TE_SAYICON);
157 	gi.WritePosition (ent->s.origin);
158 	gi.multicast (ent->s.origin, MULTICAST_PVS);
159 }
160 
161 //=================================================================================
162 
163 /*
164 ==================
165 Cmd_Give_f
166 
167 Give items to a client
168 ==================
169 */
Cmd_Give_f(edict_t * ent)170 void Cmd_Give_f (edict_t *ent)
171 {
172 	char		*name;
173 	gitem_t		*it;
174 	int			index;
175 	int			i;
176 	qboolean	give_all;
177 	edict_t		*it_ent;
178 
179 	if (deathmatch->value && !sv_cheats->value)
180 	{
181 		safe_cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
182 		return;
183 	}
184 
185 	name = gi.args();
186 
187 	if (Q_strcasecmp(name, "all") == 0)
188 		give_all = true;
189 	else
190 		give_all = false;
191 
192 	if (give_all || Q_strcasecmp(gi.argv(1), "health") == 0)
193 	{
194 		if (gi.argc() == 3)
195 			ent->health = atoi(gi.argv(2));
196 		else
197 			ent->health = ent->max_health;
198 		if (!give_all)
199 			return;
200 	}
201 
202 	if (give_all || Q_strcasecmp(name, "weapons") == 0)
203 	{
204 		for (i=0 ; i<game.num_items ; i++)
205 		{
206 			it = itemlist + i;
207 			if (!it->pickup)
208 				continue;
209 			if (!(it->flags & IT_WEAPON))
210 				continue;
211 			ent->client->pers.inventory[i] += 1;
212 		}
213 		if (!give_all)
214 			return;
215 	}
216 
217 	if (give_all || Q_strcasecmp(name, "ammo") == 0)
218 	{
219 		for (i=0 ; i<game.num_items ; i++)
220 		{
221 			it = itemlist + i;
222 			if (!it->pickup)
223 				continue;
224 			if (!(it->flags & IT_AMMO))
225 				continue;
226 			Add_Ammo (ent, it, 1000, true, true);
227 		}
228 		if (!give_all)
229 			return;
230 	}
231 
232 	if (give_all || Q_strcasecmp(name, "armor") == 0)
233 	{
234 		gitem_armor_t	*info;
235 
236 		it = FindItem("Jacket Armor");
237 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
238 
239 		it = FindItem("Combat Armor");
240 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
241 
242 		it = FindItem("Body Armor");
243 		info = (gitem_armor_t *)it->info;
244 		ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count;
245 
246 		if (!give_all)
247 			return;
248 	}
249 
250 	if (give_all)
251 	{
252 		for (i=0 ; i<game.num_items ; i++)
253 		{
254 			it = itemlist + i;
255 			if (!it->pickup)
256 				continue;
257 			if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO))
258 				continue;
259 			ent->client->pers.inventory[i] = 1;
260 		}
261 		//don't give vehicles or flags
262 		it = FindItem("Bomber");
263 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
264 		it = FindItem("Strafer");
265 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
266 		it = FindItem("Hover");
267 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
268 		it = FindItem("Blue Flag");
269 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
270 		it = FindItem("Red Flag");
271 		ent->client->pers.inventory[ITEM_INDEX(it)] = 0;
272 		return;
273 	}
274 	it = FindItem (name);
275 	if (!it)
276 	{
277 		name = gi.argv(1);
278 		it = FindItem (name);
279 		if (!it)
280 		{
281 			safe_cprintf (ent, PRINT_HIGH, "unknown item\n");
282 			return;
283 		}
284 	}
285 
286 	if (!it->pickup)
287 	{
288 		safe_cprintf (ent, PRINT_HIGH, "non-pickup item\n");
289 		return;
290 	}
291 
292 	index = ITEM_INDEX(it);
293 
294 	if (it->flags & IT_AMMO)
295 	{
296 		if (gi.argc() == 3)
297 			ent->client->pers.inventory[index] = atoi(gi.argv(2));
298 		else
299 			ent->client->pers.inventory[index] += it->quantity;
300 	}
301 	else
302 	{
303 		it_ent = G_Spawn();
304 		it_ent->classname = it->classname;
305 		SpawnItem (it_ent, it);
306 		Touch_Item (it_ent, ent, NULL, NULL);
307 		if (it_ent->inuse)
308 			G_FreeEdict(it_ent);
309 	}
310 
311 }
312 
313 
314 /*
315 ==================
316 Cmd_God_f
317 
318 Sets client to godmode
319 
320 argv(0) god
321 ==================
322 */
Cmd_God_f(edict_t * ent)323 void Cmd_God_f (edict_t *ent)
324 {
325 	char	*msg;
326 
327 	if (deathmatch->value && !sv_cheats->value)
328 	{
329 		safe_cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
330 		return;
331 	}
332 
333 	ent->flags ^= FL_GODMODE;
334 	if (!(ent->flags & FL_GODMODE) )
335 		msg = "godmode OFF\n";
336 	else
337 		msg = "godmode ON\n";
338 
339 	safe_cprintf (ent, PRINT_HIGH, msg);
340 }
341 
342 
343 /*
344 ==================
345 Cmd_Notarget_f
346 
347 Sets client to notarget
348 
349 argv(0) notarget
350 ==================
351 */
Cmd_Notarget_f(edict_t * ent)352 void Cmd_Notarget_f (edict_t *ent)
353 {
354 	char	*msg;
355 
356 	if (deathmatch->value && !sv_cheats->value)
357 	{
358 		safe_cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
359 		return;
360 	}
361 
362 	ent->flags ^= FL_NOTARGET;
363 	if (!(ent->flags & FL_NOTARGET) )
364 		msg = "notarget OFF\n";
365 	else
366 		msg = "notarget ON\n";
367 
368 	safe_cprintf (ent, PRINT_HIGH, msg);
369 }
370 
371 
372 /*
373 ==================
374 Cmd_Noclip_f
375 
376 argv(0) noclip
377 ==================
378 */
Cmd_Noclip_f(edict_t * ent)379 void Cmd_Noclip_f (edict_t *ent)
380 {
381 	char	*msg;
382 
383 	if (deathmatch->value && !sv_cheats->value)
384 	{
385 		safe_cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n");
386 		return;
387 	}
388 
389 	if (ent->movetype == MOVETYPE_NOCLIP)
390 	{
391 		ent->movetype = MOVETYPE_WALK;
392 		msg = "noclip OFF\n";
393 	}
394 	else
395 	{
396 		ent->movetype = MOVETYPE_NOCLIP;
397 		msg = "noclip ON\n";
398 	}
399 
400 	safe_cprintf (ent, PRINT_HIGH, msg);
401 }
402 
403 
404 /*
405 ==================
406 Cmd_Use_f
407 
408 Use an inventory item
409 ==================
410 */
Cmd_Use_f(edict_t * ent)411 void Cmd_Use_f (edict_t *ent)
412 {
413 	int			index;
414 	gitem_t		*it;
415 	char		*s;
416 
417 	s = gi.args();
418 	it = FindItem (s);
419 	if (!it)
420 	{
421 		safe_cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
422 		return;
423 	}
424 	if (!it->use)
425 	{
426 		safe_cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
427 		return;
428 	}
429 	index = ITEM_INDEX(it);
430 	if (!ent->client->pers.inventory[index])
431 	{
432 		safe_cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
433 		if (it->flags & IT_WEAPON) {
434 		    ent->client->pers.lastfailedswitch = it;
435 		    ent->client->pers.failedswitch_framenum = level.framenum;
436 		}
437 		return;
438 	}
439 
440 	it->use (ent, it);
441 }
442 
443 
444 /*
445 ==================
446 Cmd_Drop_f
447 
448 Drop an inventory item
449 ==================
450 */
Cmd_Drop_f(edict_t * ent)451 void Cmd_Drop_f (edict_t *ent)
452 {
453 	int			index;
454 	gitem_t		*it;
455 	char		*s;
456 
457 	s = gi.args();
458 	it = FindItem (s);
459 	if (!it)
460 	{
461 		safe_cprintf (ent, PRINT_HIGH, "unknown item: %s\n", s);
462 		return;
463 	}
464 	if (!it->drop)
465 	{
466 		safe_cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
467 		return;
468 	}
469 	index = ITEM_INDEX(it);
470 	if (!ent->client->pers.inventory[index])
471 	{
472 		safe_cprintf (ent, PRINT_HIGH, "Out of item: %s\n", s);
473 		return;
474 	}
475 
476 	it->drop (ent, it);
477 }
478 
479 
480 /*
481 =================
482 Cmd_Inven_f
483 =================
484 */
Cmd_Inven_f(edict_t * ent)485 void Cmd_Inven_f (edict_t *ent)
486 {
487 	int			i;
488 	gclient_t	*cl;
489 
490 	cl = ent->client;
491 
492 	cl->showscores = false;
493 	cl->showhelp = false;
494 
495 	if (cl->showinventory)
496 	{
497 		cl->showinventory = false;
498 		return;
499 	}
500 
501 	cl->showinventory = true;
502 
503 	gi.WriteByte (svc_inventory);
504 	for (i=0 ; i<MAX_ITEMS ; i++)
505 	{
506 		gi.WriteShort (cl->pers.inventory[i]);
507 	}
508 	gi.unicast (ent, true);
509 }
510 
511 /*
512 =================
513 Cmd_InvUse_f
514 =================
515 */
Cmd_InvUse_f(edict_t * ent)516 void Cmd_InvUse_f (edict_t *ent)
517 {
518 	gitem_t		*it;
519 
520 	ValidateSelectedItem (ent);
521 
522 	if (ent->client->pers.selected_item == -1)
523 	{
524 		safe_cprintf (ent, PRINT_HIGH, "No item to use.\n");
525 		return;
526 	}
527 
528 	it = &itemlist[ent->client->pers.selected_item];
529 	if (!it->use)
530 	{
531 		safe_cprintf (ent, PRINT_HIGH, "Item is not usable.\n");
532 		return;
533 	}
534 	it->use (ent, it);
535 }
536 
537 /*
538 =================
539 Cmd_WeapPrev_f
540 =================
541 */
Cmd_WeapPrev_f(edict_t * ent)542 void Cmd_WeapPrev_f (edict_t *ent)
543 {
544 	gclient_t	*cl;
545 	int			i, index;
546 	gitem_t		*it;
547 	int			selected_weapon;
548 
549 	cl = ent->client;
550 
551 	if (!cl->pers.weapon)
552 		return;
553 
554 	selected_weapon = ITEM_INDEX(cl->pers.weapon);
555 
556 	// scan  for the next valid one
557 	for (i=1 ; i<=MAX_ITEMS ; i++)
558 	{
559 		index = (selected_weapon + i)%MAX_ITEMS;
560 		if (!cl->pers.inventory[index])
561 			continue;
562 		it = &itemlist[index];
563 		if (!it->use)
564 			continue;
565 		if (! (it->flags & IT_WEAPON) )
566 			continue;
567 		it->use (ent, it);
568 		if (cl->pers.weapon == it)
569 			return;	// successful
570 	}
571 }
572 
573 /*
574 =================
575 Cmd_WeapNext_f
576 =================
577 */
Cmd_WeapNext_f(edict_t * ent)578 void Cmd_WeapNext_f (edict_t *ent)
579 {
580 	gclient_t	*cl;
581 	int			i, index;
582 	gitem_t		*it;
583 	int			selected_weapon;
584 
585 	cl = ent->client;
586 
587 	if (!cl->pers.weapon)
588 		return;
589 
590 	selected_weapon = ITEM_INDEX(cl->pers.weapon);
591 
592 	// scan  for the next valid one
593 	for (i=1 ; i<=MAX_ITEMS ; i++)
594 	{
595 		index = (selected_weapon + MAX_ITEMS - i)%MAX_ITEMS;
596 		if (!cl->pers.inventory[index])
597 			continue;
598 		it = &itemlist[index];
599 		if (!it->use)
600 			continue;
601 		if (! (it->flags & IT_WEAPON) )
602 			continue;
603 		it->use (ent, it);
604 		if (cl->pers.weapon == it)
605 			return;	// successful
606 	}
607 }
608 
609 /*
610 =================
611 Cmd_WeapLast_f
612 =================
613 */
Cmd_WeapLast_f(edict_t * ent)614 void Cmd_WeapLast_f (edict_t *ent)
615 {
616 	gclient_t	*cl;
617 	int			index;
618 	gitem_t		*it;
619 
620 	cl = ent->client;
621 
622 	if (!cl->pers.weapon || !cl->pers.lastweapon)
623 		return;
624 
625 	index = ITEM_INDEX(cl->pers.lastweapon);
626 	if (!cl->pers.inventory[index])
627 		return;
628 	it = &itemlist[index];
629 	if (!it->use)
630 		return;
631 	if (! (it->flags & IT_WEAPON) )
632 		return;
633 	it->use (ent, it);
634 }
635 
636 /*
637 =================
638 Cmd_InvDrop_f
639 =================
640 */
Cmd_InvDrop_f(edict_t * ent)641 void Cmd_InvDrop_f (edict_t *ent)
642 {
643 	gitem_t		*it;
644 
645 	ValidateSelectedItem (ent);
646 
647 	if (ent->client->pers.selected_item == -1)
648 	{
649 		safe_cprintf (ent, PRINT_HIGH, "No item to drop.\n");
650 		return;
651 	}
652 
653 	it = &itemlist[ent->client->pers.selected_item];
654 	if (!it->drop)
655 	{
656 		safe_cprintf (ent, PRINT_HIGH, "Item is not dropable.\n");
657 		return;
658 	}
659 	it->drop (ent, it);
660 }
661 
662 /*
663 =================
664 Cmd_Kill_f
665 =================
666 */
Cmd_Kill_f(edict_t * ent)667 void Cmd_Kill_f (edict_t *ent)
668 {
669 	if((level.time - ent->client->respawn_time) < 5)
670 		return;
671 	ent->flags &= ~FL_GODMODE;
672 	ent->health = 0;
673 	meansOfDeath = MOD_SUICIDE;
674 	player_die (ent, ent, ent, 100000, vec3_origin);
675 }
676 
677 /*
678 =================
679 Cmd_PutAway_f
680 =================
681 */
Cmd_PutAway_f(edict_t * ent)682 void Cmd_PutAway_f (edict_t *ent)
683 {
684 	ent->client->showscores = false;
685 	ent->client->showhelp = false;
686 	ent->client->showinventory = false;
687 }
688 
689 
PlayerSort(void const * a,void const * b)690 int PlayerSort (void const *a, void const *b)
691 {
692 	int		anum, bnum;
693 
694 	anum = *(int *)a;
695 	bnum = *(int *)b;
696 
697 	if ( game.clients[anum].ps.stats[STAT_SPECTATOR] == 0 )
698 		anum = game.clients[anum].ps.stats[STAT_FRAGS];
699 	else
700 		anum = 0;
701 	if ( game.clients[bnum].ps.stats[STAT_SPECTATOR] == 0 )
702 		bnum = game.clients[bnum].ps.stats[STAT_FRAGS];
703 	else
704 		bnum = 0;
705 
706 	if (anum < bnum)
707 		return -1;
708 	if (anum > bnum)
709 		return 1;
710 	return 0;
711 }
712 
713 /*
714 =================
715 Cmd_Players_f
716 =================
717 */
Cmd_Players_f(edict_t * ent)718 void Cmd_Players_f (edict_t *ent)
719 {
720 	int		i;
721 	int		count;
722 	char	small[64];
723 	char	large[1280];
724 	int		index[256];
725 
726 	count = 0;
727 	for (i = 0 ; i < g_maxclients->value ; i++)
728 		if (game.clients[i].pers.connected)
729 		{
730 			index[count] = i;
731 			count++;
732 		}
733 
734 	// sort by frags
735 	qsort (index, count, sizeof(index[0]), PlayerSort);
736 
737 	// print information
738 	large[0] = 0;
739 
740 	for (i = 0 ; i < count ; i++)
741 	{
742 
743 		Com_sprintf (small, sizeof(small), "%3i %s\n",
744 			game.clients[index[i]].ps.stats[STAT_FRAGS],
745 			game.clients[index[i]].pers.netname);
746 
747 		if (strlen (small) + strlen(large) > sizeof(large) - 100 )
748 		{	// can't print all of them in one packet
749 			strcat (large, "...\n");
750 			break;
751 		}
752 		strcat (large, small);
753 	}
754 
755 	safe_cprintf (ent, PRINT_HIGH, "%s\n%i players\n", large, count);
756 }
757 
758 /*
759 =================
760 Cmd_Wave_f
761 =================
762 */
Cmd_Wave_f(edict_t * ent)763 void Cmd_Wave_f (edict_t *ent)
764 {
765 	int		i;
766 
767 	i = atoi (gi.argv(1));
768 
769 	// can't wave when ducked
770 	if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
771 		return;
772 
773 	if (ent->client->anim_priority > ANIM_WAVE)
774 		return;
775 
776 	ent->client->anim_priority = ANIM_WAVE;
777 
778 	switch (i)
779 	{
780 	case 0:
781 		safe_cprintf (ent, PRINT_HIGH, "flipoff\n");
782 		ent->s.frame = FRAME_flip01-1;
783 		ent->client->anim_end = FRAME_flip12;
784 		break;
785 	case 1:
786 		safe_cprintf (ent, PRINT_HIGH, "salute\n");
787 		ent->s.frame = FRAME_salute01-1;
788 		ent->client->anim_end = FRAME_salute11;
789 		break;
790 	case 2:
791 		safe_cprintf (ent, PRINT_HIGH, "taunt\n");
792 		ent->s.frame = FRAME_taunt01-1;
793 		ent->client->anim_end = FRAME_taunt17;
794 		break;
795 	case 3:
796 		safe_cprintf (ent, PRINT_HIGH, "wave\n");
797 		ent->s.frame = FRAME_wave01-1;
798 		ent->client->anim_end = FRAME_wave11;
799 		break;
800 	case 4:
801 	default:
802 		safe_cprintf (ent, PRINT_HIGH, "point\n");
803 		ent->s.frame = FRAME_point01-1;
804 		ent->client->anim_end = FRAME_point12;
805 		break;
806 	}
807 }
808 
809 /*
810 ==================
811 Cmd_Say_f
812 ==================
813 */
Cmd_Say_f(edict_t * ent,qboolean team,qboolean arg0)814 void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0)
815 {
816 	int		i, j;
817 	edict_t	*other;
818 	char	*p;
819 	char	text[2048];
820 	gclient_t *cl;
821 
822 	if (gi.argc () < 2 && !arg0)
823 		return;
824 
825 	if (strlen(gi.args()) < 3) //no text, don't send
826 		return;
827 
828 	gi.WriteByte (svc_temp_entity);
829 	gi.WriteByte (TE_SAYICON);
830 	gi.WritePosition (ent->s.origin);
831 	gi.multicast (ent->s.origin, MULTICAST_PVS);
832 
833 	if (!((dmflags->integer & DF_SKINTEAMS) || ctf->value || tca->value || cp->value))
834 		team = false;
835 
836 	if (team)
837 		Com_sprintf (text, sizeof(text), "[TEAM] %s: ", ent->client->pers.netname);
838 	else
839 		Com_sprintf (text, sizeof(text), "%s: ", ent->client->pers.netname);
840 
841 	if (arg0)
842 	{
843 		strcat (text, gi.argv(0));
844 		strcat (text, " ");
845 		strcat (text, gi.args());
846 	}
847 	else
848 	{
849 		p = gi.args();
850 
851 		if (*p == '"')
852 		{
853 			p++;
854 			p[strlen(p)-1] = 0;
855 		}
856 		strcat(text, p);
857 	}
858 
859 	// don't let text be too long for malicious reasons
860 	if (strlen(text) > 150)
861 		text[150] = 0;
862 
863 	strcat(text, "\n");
864 
865 	if (flood_msgs->value) {
866 		cl = ent->client;
867 
868         if (level.time < cl->flood_locktill) {
869 			safe_cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
870 				(int)(cl->flood_locktill - level.time));
871             return;
872         }
873         i = cl->flood_whenhead - flood_msgs->value + 1;
874         if (i < 0)
875             i = (sizeof(cl->flood_when)/sizeof(cl->flood_when[0])) + i;
876 		if (cl->flood_when[i] &&
877 			level.time - cl->flood_when[i] < flood_persecond->value) {
878 			cl->flood_locktill = level.time + flood_waitdelay->value;
879 			safe_cprintf(ent, PRINT_CHAT, "Flood protection:  You can't talk for %d seconds.\n",
880 				(int)flood_waitdelay->value);
881             return;
882         }
883 		cl->flood_whenhead = (cl->flood_whenhead + 1) %
884 			(sizeof(cl->flood_when)/sizeof(cl->flood_when[0]));
885 		cl->flood_when[cl->flood_whenhead] = level.time;
886 	}
887 
888 	if (g_dedicated->value)
889 		safe_cprintf(NULL, PRINT_CHAT, "%s", text);
890 
891 	for (j = 1; j <= game.maxclients; j++)
892 	{
893 		other = &g_edicts[j];
894 		if (!other->inuse)
895 			continue;
896 		if (!other->client)
897 			continue;
898 		if(other->is_bot) //JD - security fix
899 			continue;
900 		if (team)
901 		{
902 			if (!OnSameTeam(ent, other))
903 				continue;
904 		}
905 		//safe_cprintf(other, PRINT_CHAT, "%s", text);
906 		//JD - security fix
907 		gi.cprintf(other, PRINT_CHAT, "%s", text);
908 	}
909 
910 }
911 
Cmd_PlayerList_f(edict_t * ent)912 void Cmd_PlayerList_f(edict_t *ent)
913 {
914 	int i;
915 	char st[80];
916 	char text[1400];
917 	edict_t *e2;
918 
919 	// connect time, ping, score, name
920 	*text = 0;
921 	for (i = 0, e2 = g_edicts + 1; i < g_maxclients->value; i++, e2++) {
922 		if (!e2->inuse)
923 			continue;
924 
925 		Com_sprintf(st, sizeof(st), "%02d:%02d %4d %3d %s%s\n",
926 			(level.framenum - e2->client->resp.enterframe) / 600,
927 			((level.framenum - e2->client->resp.enterframe) % 600)/10,
928 			e2->client->ping,
929 			e2->client->resp.score,
930 			e2->client->pers.netname,
931 			e2->client->resp.spectator ? " (spectator)" : "");
932 		if (strlen(text) + strlen(st) > sizeof(text) - 50) {
933 			sprintf(text+strlen(text), "And more...\n");
934 			safe_cprintf(ent, PRINT_HIGH, "%s", text);
935 			return;
936 		}
937 		strcat(text, st);
938 	}
939 	safe_cprintf(ent, PRINT_HIGH, "%s", text);
940 }
941 
942 /*
943 =================
944 Cmd_CallVote_f
945 =================
946 */
Cmd_CallVote_f(edict_t * ent)947 void Cmd_CallVote_f (edict_t *ent)
948 {
949 
950 	if(level.time <= warmuptime->value) {
951 		safe_bprintf(PRINT_HIGH, "Cannot call a vote during warmup!\n");
952 		return;
953 	}
954 
955 	if(playervote.called) {
956 		safe_bprintf(PRINT_HIGH, "Vote already in progress, please wait.\n");
957 		return;
958 	}
959 
960 	//start a vote
961 	playervote.called = true;
962 	playervote.yay = playervote.nay = 0;
963 	playervote.starttime = level.time;
964 	if(strlen(gi.args()) < 128) {
965 		strcpy(playervote.command, gi.args());
966 		safe_bprintf(PRINT_HIGH, "%s called a vote: %s\n", ent->client->pers.netname, playervote.command);
967 	}
968 }
969 
970 /*
971 =================
972 Cmd_Vote_f
973 =================
974 */
Cmd_Vote_f(edict_t * ent)975 void Cmd_Vote_f (edict_t *ent)
976 {
977 
978 	int	i, j, mostvotes, winner;
979 	int	n_candidates;
980 	int	candidates[4];
981 	char	buffer[512];
982 	char	buffer2[60];
983 	edict_t *cl_ent;
984 
985 	i = atoi (gi.argv(1));
986 
987 	if(g_callvote->value && playervote.called) {
988 
989 		switch(i) { //to do - move "voted" to persistant data
990 			case 1:
991 				if(!ent->client->resp.voted) {
992 					ent->client->resp.voted = true;
993 					playervote.yay++;
994 					safe_bprintf(PRINT_HIGH, "%s voted ^2YES\n", ent->client->pers.netname);
995 				}
996 				break;
997 			case 2:
998 				if(!ent->client->resp.voted) {
999 					ent->client->resp.voted = true;
1000 					playervote.nay++;
1001 					safe_bprintf(PRINT_HIGH, "%s voted ^1NO\n", ent->client->pers.netname);
1002 				}
1003 				break;
1004 		}
1005 	}
1006 
1007 	if (!level.intermissiontime || ! (g_mapvote && g_mapvote->value && !g_mapvote->modified) )
1008 		return;
1009 
1010 	ent->client->mapvote = i;
1011 	safe_bprintf(PRINT_HIGH, "%s voted for map %i\n", ent->client->pers.netname, i);
1012 
1013 	//update scoreboard
1014 	mostvotes = 0;
1015 	winner = 1; //next map in line
1016 	for(i = 0; i < 4; i++)
1017 		votedmap[i].tally = 0;
1018 	for (i=0 ; i<g_maxclients->value ; i++)
1019 	{
1020 		cl_ent = g_edicts + 1 + i;
1021 		if (!cl_ent->inuse || cl_ent->is_bot)
1022 			continue;
1023 		for(j = 0; j < 4; j++) {
1024 			if(cl_ent->client->mapvote-1 == j)
1025 				votedmap[j].tally++;
1026 			if(votedmap[j].tally > mostvotes){
1027 				mostvotes = votedmap[j].tally;
1028 			}
1029 		}
1030 	}
1031 
1032 	if ( g_voterand && g_voterand->value )
1033 	{
1034 		// random tie resolution
1035 		n_candidates = 0;
1036 		for (j = 0; j < 4; j ++) {
1037 			if ( votedmap[j].tally < mostvotes )
1038 				continue;
1039 			candidates[n_candidates ++] = j;
1040 		}
1041 
1042 		if ( n_candidates == 1 )
1043 		{
1044 			winner = candidates[0];
1045 			sprintf( buffer, "Map %s leads with %i vote%s!", votedmap[winner].mapname, votedmap[winner].tally, (mostvotes > 1) ? "s" : ""  );
1046 		}
1047 		else
1048 		{
1049 			strcpy( buffer, "It's a tie!\nMaps ");
1050 			for ( i = 0 ; i < n_candidates ; i ++ ) {
1051 				j = candidates[i];
1052 				if ( i > 0 )
1053 				{
1054 					if ( i == n_candidates - 1 )
1055 						strcat( buffer, " and " );
1056 					else
1057 						strcat( buffer, ", " );
1058 				}
1059 				strcat( buffer, votedmap[j].mapname );
1060 			}
1061 			sprintf( buffer2, "\nlead with %i vote%s!" , mostvotes , (mostvotes > 1) ? "s" : "" );
1062 			strcat( buffer, buffer2 );
1063 		}
1064 	}
1065 	else
1066 	{
1067 		// "old" voting system, leading map is the first one with enough votes
1068 		for (j = 0; j < 4; j ++) {
1069 			i = (j + 1) % 4;
1070 			if ( votedmap[i].tally < mostvotes )
1071 				continue;
1072 			winner = i;
1073 			break;
1074 		}
1075 		sprintf( buffer, "Map %s leads with %i vote%s!", votedmap[winner].mapname, votedmap[winner].tally, (mostvotes > 1) ? "s" : "" );
1076 	}
1077 
1078 	for (i=0 ; i<g_maxclients->value ; i++)
1079 	{
1080 		cl_ent = g_edicts + 1 + i;
1081 		if (!cl_ent->inuse || cl_ent->is_bot)
1082 			continue;
1083 		safe_centerprintf(cl_ent, "%s", buffer );
1084 	}
1085 }
1086 
Cmd_VoiceTaunt_f(edict_t * ent)1087 void Cmd_VoiceTaunt_f (edict_t *ent)
1088 {
1089 	int			index, i;
1090 	qboolean	done;
1091 	char		name[32];
1092 	char		string[256]; //a small string to send
1093 	char		playermodel[MAX_OSPATH], tauntsound[MAX_OSPATH];
1094 	char		*info;
1095 
1096 	index = atoi (gi.argv(1));
1097 
1098 	if(index > 5 || index < 1 || ent->is_bot) {
1099 		index = (int)(1 + random() * 5);
1100 		if(index > 5)
1101 			index = 5;
1102 	}
1103 
1104 	//get info about this client
1105 	if(ent->inuse && ent->client) {
1106 
1107 		if((level.time - ent->client->lasttaunttime) > 2) { //prevent flooding
1108 
1109 			ent->client->lasttaunttime = level.time;
1110 
1111 			strcpy(name, ent->client->pers.netname);
1112 			info = Info_ValueForKey (ent->client->pers.userinfo, "skin");
1113 
1114 			if ( *info == '\0' )
1115 			{ /* could not find skin. probable programming error. */
1116 				gi.dprintf("Cmd_VoiceTaunt_f: skin not found in userinfo\n");
1117 				return;
1118 			}
1119 
1120 			info[96] = 0; //truncate to prevent bad people from harming the server
1121 
1122 			i = 0;
1123 			done = false;
1124 			while(!done)
1125 			{
1126 				if((info[i] == '/') || (info[i] == '\\'))
1127 					done = true;
1128 				playermodel[i] = info[i];
1129 				if(i > 62)
1130 					done = true;
1131 				i++;
1132 			}
1133 			playermodel[i-1] = 0;
1134 
1135 			sprintf(tauntsound, "taunts/%s/taunt%i.wav", playermodel, index);
1136 
1137 			Com_sprintf(string, sizeof(string),
1138 				"%s %s %s ", info, tauntsound, name);
1139 
1140 			//send to all clients as a general config string
1141 			gi.configstring (CS_GENERAL, string);
1142 		}
1143 	}
1144 }
1145 
1146 /*
1147 =================
1148 ClientCommand
1149 =================
1150 */
ClientCommand(edict_t * ent)1151 void ClientCommand (edict_t *ent)
1152 {
1153 	char	*cmd;
1154 
1155 	if (!ent->client)
1156 		return;		// not fully in game yet
1157 
1158 // ACEBOT_ADD
1159 	if(ACECM_Commands(ent))
1160 		return;
1161 // ACEBOT_END
1162 
1163 	cmd = gi.argv(0);
1164 
1165 	if (Q_strcasecmp (cmd, "players") == 0)
1166 	{
1167 		Cmd_Players_f (ent);
1168 		return;
1169 	}
1170 	if (Q_strcasecmp (cmd, "say") == 0)
1171 	{
1172 		Cmd_Say_f (ent, false, false);
1173 		return;
1174 	}
1175 	if (Q_strcasecmp (cmd, "say_team") == 0)
1176 	{
1177 		Cmd_Say_f (ent, true, false);
1178 		return;
1179 	}
1180 	if (Q_strcasecmp (cmd, "score") == 0)
1181 	{
1182 		Cmd_Score_f (ent);
1183 		return;
1184 	}
1185 	if (Q_strcasecmp (cmd, "callvote") == 0)
1186 	{
1187 		Cmd_CallVote_f(ent);
1188 		return;
1189 	}
1190 	if (Q_strcasecmp (cmd, "vote") == 0)
1191 	{
1192 		Cmd_Vote_f(ent);
1193 		return;
1194 	}
1195 	if	(Q_strcasecmp (cmd, "vtaunt") == 0)
1196 	{
1197 		Cmd_VoiceTaunt_f(ent);
1198 		return;
1199 	}
1200 
1201 	if (level.intermissiontime)
1202 		return;
1203 
1204 	if (Q_strcasecmp (cmd, "use") == 0)
1205 		Cmd_Use_f (ent);
1206 	else if (Q_strcasecmp (cmd, "drop") == 0)
1207 		Cmd_Drop_f (ent);
1208 	else if (Q_strcasecmp (cmd, "give") == 0)
1209 		Cmd_Give_f (ent);
1210 	else if (Q_strcasecmp (cmd, "god") == 0)
1211 		Cmd_God_f (ent);
1212 	else if (Q_strcasecmp (cmd, "notarget") == 0)
1213 		Cmd_Notarget_f (ent);
1214 	else if (Q_strcasecmp (cmd, "noclip") == 0)
1215 		Cmd_Noclip_f (ent);
1216 	else if (Q_strcasecmp (cmd, "inven") == 0)
1217 		Cmd_Inven_f (ent);
1218 	else if (Q_strcasecmp (cmd, "invnext") == 0)
1219 		SelectNextItem (ent, -1);
1220 	else if (Q_strcasecmp (cmd, "invprev") == 0)
1221 		SelectPrevItem (ent, -1);
1222 	else if (Q_strcasecmp (cmd, "invnextw") == 0)
1223 		SelectNextItem (ent, IT_WEAPON);
1224 	else if (Q_strcasecmp (cmd, "invprevw") == 0)
1225 		SelectPrevItem (ent, IT_WEAPON);
1226 	else if (Q_strcasecmp (cmd, "invnextp") == 0)
1227 		SelectNextItem (ent, IT_POWERUP);
1228 	else if (Q_strcasecmp (cmd, "invprevp") == 0)
1229 		SelectPrevItem (ent, IT_POWERUP);
1230 	else if (Q_strcasecmp (cmd, "invuse") == 0)
1231 		Cmd_InvUse_f (ent);
1232 	else if (Q_strcasecmp (cmd, "invdrop") == 0)
1233 		Cmd_InvDrop_f (ent);
1234 	else if (Q_strcasecmp (cmd, "weapprev") == 0)
1235 		Cmd_WeapPrev_f (ent);
1236 	else if (Q_strcasecmp (cmd, "weapnext") == 0)
1237 		Cmd_WeapNext_f (ent);
1238 	else if (Q_strcasecmp (cmd, "weaplast") == 0)
1239 		Cmd_WeapLast_f (ent);
1240 	else if (Q_strcasecmp (cmd, "kill") == 0)
1241 		Cmd_Kill_f (ent);
1242 	else if (Q_strcasecmp (cmd, "putaway") == 0)
1243 		Cmd_PutAway_f (ent);
1244 	else if (Q_strcasecmp (cmd, "wave") == 0)
1245 		Cmd_Wave_f (ent);
1246 	else if (Q_strcasecmp(cmd, "playerlist") == 0)
1247 		Cmd_PlayerList_f(ent);
1248 	else if (Q_strcasecmp (cmd, "chatbubble") == 0)
1249 		DrawChatBubble(ent);
1250 	else	// anything that doesn't match a command will be a chat
1251 		Cmd_Say_f (ent, false, true);
1252 
1253 }
1254