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