comparison src/message.c @ 4:aa38447a4b21

First entry of Paradise Server 2.9 patch 10 Beta
author darius
date Sat, 06 Dec 1997 04:37:03 +0000
parents
children
comparison
equal deleted inserted replaced
3:cafa94d86546 4:aa38447a4b21
1 /*--------------------------------------------------------------------------
2 NETREK II -- Paradise
3
4 Permission to use, copy, modify, and distribute this software and its
5 documentation, or any derivative works thereof, for any NON-COMMERCIAL
6 purpose and without fee is hereby granted, provided that this copyright
7 notice appear in all copies. No representations are made about the
8 suitability of this software for any purpose. This software is provided
9 "as is" without express or implied warranty.
10
11 Xtrek Copyright 1986 Chris Guthrie
12 Netrek (Xtrek II) Copyright 1989 Kevin P. Smith
13 Scott Silvey
14 Paradise II (Netrek II) Copyright 1993 Larry Denys
15 Kurt Olsen
16 Brandon Gillespie
17 --------------------------------------------------------------------------*/
18
19 /* was control_mess.c, but changed to message.c for a smaller filename (BG) */
20
21 /*
22 * Ugh, this code is in the middle of a rewrite.
23 *
24 * It used to use a tokenizer with a global dictionary to split the input into
25 * words. The tokenizer accepted abbreviations as long as these were unique.
26 * However, adding a new word to the dictionary would often cause old
27 * abbreviations to be invalidated.
28 *
29 * I wrote a new parser that was called as each token needed to be extracted.
30 * This used a dictionary that was local to each submenu. This localizes
31 * changes to the menu structure so that effects of adding new commands are
32 * minimized.
33 *
34 * Some of the file is converted to use this, but not all. Eventually the
35 * entire module will use the context-sensitive tokenizer.
36 *
37 */
38
39
40 #include "config.h"
41 #include <stdio.h>
42 #include <string.h>
43 #include <signal.h>
44 #include <ctype.h>
45 #include <fcntl.h>
46
47 #include "defs.h"
48 #include "data.h"
49 #include "struct.h"
50 #include "shmem.h"
51
52 enum token_names_e
53 {
54 HELPTOK = 128,
55 CONTROLTOK,
56 VERSIONTOK,
57 QUEUETOK,
58 LEAGUETOK,
59 PARAMTOK,
60 INFOTOK,
61 OBSERVETOK,
62 CLUECHECKTOK,
63
64 NUKEGAMETOK,
65 FREESLOTTOK,
66 ROBOTTOK,
67 TOURNTOK,
68 NEWGALAXY,
69 SHIPTIMERTOK,
70
71 REFITTOK,
72 PLAYERTOK,
73 EJECTTOK,
74 DIETOK,
75 ARMIESTOK,
76 PLASMATOK,
77 MISSILETOK,
78 PLANETTOK,
79 RANKTOK,
80 MOVETOK,
81
82 PASSWDTOK,
83 RATINGSTOK,
84
85 TIMETOK,
86 CAPTAINTOK,
87 RESTARTTOK,
88 STARTTOK,
89 PASSTOK,
90 TIMEOUTTOK,
91 TEAMNAMETOK,
92 AWAYTOK,
93 HOMETOK,
94 PAUSETOK,
95 CONTINUETOK,
96 MAXPLAYERTOK,
97
98 TEAMTOK,
99
100 INDTOK, /* these need to be adjacent and in order */
101 FEDTOK, /* these need to be adjacent and in order */
102 ROMTOK, /* these need to be adjacent and in order */
103 KLITOK, /* these need to be adjacent and in order */
104 ORITOK, /* these need to be adjacent and in order */
105
106 SHIPTOK,
107
108 SCOUTTOK, /* these need to be adjacent and in order */
109 DESTROYERTOK, /* these need to be adjacent and in order */
110 CRUISERTOK, /* these need to be adjacent and in order */
111 BATTLESHIPTOK, /* these need to be adjacent and in order */
112 ASSAULTTOK, /* these need to be adjacent and in order */
113 STARBASETOK, /* these need to be adjacent and in order */
114 ATTTOK, /* these need to be adjacent and in order */
115 JUMPSHIPTOK, /* these need to be adjacent and in order */
116 FRIGATETOK, /* these need to be adjacent and in order */
117 WARBASETOK, /* these need to be adjacent and in order */
118 LIGHTCRUISERTOK,
119 CARRIERTOK,
120 UTILITYTOK,
121 PATROLTOK,
122
123 PLUSTOK,
124 MINUSTOK,
125 ROYALTOK,
126 QUIETTOK,
127 KILLSTOK,
128 HOSETOK,
129 SUPERTOK,
130 ALLOWTOK, /* control allow [teams] */
131
132 ERRORTOK = 255
133 };
134
135 #ifdef GOD_CONTROLS
136 static int god_silent = 0;
137 #endif
138
139 /* static char *con_shipnos = "0123456789abcdefghijklmnopqrstuvwxyz"; */
140
141 extern int pmessage2();
142 extern int pmessage();
143 #ifndef linux
144 extern int atoi();
145 #endif /* linux */
146 extern int detourneyqueue();
147 extern void compute_ratings();
148
149 static void respond();
150
151 #if 0
152 static enum token_names_e tokstring[128]; /* list of tokens */
153 static char *thestrings[128]; /* list of corresponding strings */
154 static char *therest[128]; /* list of pointers to the original text
155 * starting with token i */
156 static int sizetokstring;
157
158 struct token
159 {
160 char string[32];
161 int token;
162 };
163
164
165
166 struct token tstrings[] = {
167 {"0", 0}, {"1", 1}, {"2", 2}, {"3", 3},
168 {"4", 4}, {"5", 5}, {"6", 6}, {"7", 7},
169 {"8", 8}, {"9", 9}, {"a", 10}, {"b", 11},
170 {"c", 12}, {"d", 13}, {"e", 14}, {"f", 15},
171 {"g", 16}, {"h", 17}, {"i", 18}, {"j", 19},
172 {"k", 20}, {"l", 21}, {"m", 22}, {"n", 23},
173 {"o", 24}, {"p", 25}, {"q", 26}, {"r", 27},
174 {"s", 28}, {"t", 29}, {"u", 30}, {"v", 31},
175 {"w", 32}, {"x", 33}, {"y", 34}, {"z", 35},
176 {"help", HELPTOK},
177 {"control", CONTROLTOK},
178 {"con", CONTROLTOK}, /* popular abbrev */
179 {"version", VERSIONTOK},
180 {"tq", QUEUETOK}, /* popular abbrev */
181 {"queue", QUEUETOK},
182 {"league", LEAGUETOK},
183 {"params", PARAMTOK},
184 {"observe", OBSERVETOK},
185 {"info", INFOTOK},
186 {"cluecheck", CLUECHECKTOK},
187
188 {"shiptimers", SHIPTIMERTOK},
189
190 {"refit", REFITTOK},
191 {"player", PLAYERTOK},
192 {"pl", PLAYERTOK}, /* popular abbrev */
193 {"planet", PLANETTOK},
194 {"eject", EJECTTOK},
195 {"die", DIETOK},
196 {"rank", RANKTOK},
197 {"royalty", ROYALTOK},
198 {"move", MOVETOK},
199 {"armies", ARMIESTOK},
200 {"plasma", PLASMATOK},
201 {"missile", MISSILETOK},
202 {"team", TEAMTOK},
203 {"ship", SHIPTOK},
204 {"quiet", QUIETTOK},
205 {"kills", KILLSTOK},
206 {"hose", HOSETOK},
207 {"super", SUPERTOK},
208 {"allow", ALLOWTOK},
209 {"+", PLUSTOK},
210 {"-", MINUSTOK},
211
212 {"robot", ROBOTTOK},
213 {"nukegame", NUKEGAMETOK},
214 {"freeslot", FREESLOTTOK},
215 {"tourn", TOURNTOK},
216 {"galaxy", NEWGALAXY},
217
218 /* player commands */
219 {"password", PASSWDTOK},
220 {"ratings", RATINGSTOK},
221
222 /* league commands */
223 {"time", TIMETOK},
224 {"captain", CAPTAINTOK},
225 {"restart", RESTARTTOK},
226 {"start", STARTTOK},
227 {"pass", PASSTOK},
228 {"timeout", TIMEOUTTOK},
229 {"teamname", TEAMNAMETOK},
230 {"away", AWAYTOK},
231 {"home", HOMETOK},
232 {"pause", PAUSETOK},
233 {"continue", CONTINUETOK},
234 {"maxplayers", MAXPLAYERTOK},
235
236 {"independent", INDTOK},
237 {"federation", FEDTOK}, {"romulan", ROMTOK},
238 {"klingon", KLITOK}, {"orion", ORITOK},
239
240 {"sc", SCOUTTOK}, {"dd", DESTROYERTOK},
241 {"ca", CRUISERTOK}, {"bb", BATTLESHIPTOK},
242 {"as", ASSAULTTOK}, {"sb", STARBASETOK},
243 {"at", ATTTOK}, {"js", JUMPSHIPTOK},
244 {"fr", FRIGATETOK}, {"wb", WARBASETOK},
245 {"cl", LIGHTCRUISERTOK}, {"cv", CARRIERTOK},
246 {"ut", UTILITYTOK}, {"pt", PATROLTOK},
247
248 {"", ERRORTOK} /* I'm last. Keep it that way. */
249 };
250
251 static void
252 dotokenize(input)
253 char *input;
254 {
255 char *temp0, *temp1;
256 int done = 0;
257 static char internal[120];
258
259 sizetokstring = 0;
260
261 /* Convert string to lowercase. */
262
263 temp0 = strcpy(internal, input);
264 while (*temp0 != '\0')
265 {
266 if (isupper(*temp0))
267 *temp0 = tolower(*temp0);
268 temp0++;
269 }
270
271
272 temp0 = internal;
273
274 while (done == 0)
275 {
276 struct token *tptr;
277 int wordlen;
278 int potentialtok, ambiguous;
279
280 /* Eat leading spaces. */
281
282 while (*temp0 == ' ')
283 temp0++;
284
285 /* Find the next word and chop the rest of the string away. */
286
287 temp1 = temp0;
288 therest[sizetokstring] = input + (temp1 - internal);
289 while (*temp1 != '\0' && *temp1 != ' ')
290 temp1++;
291 if (*temp1 != '\0')
292 *temp1++ = '\0';
293 wordlen = strlen(temp0);
294
295 /* Go find out what they've typed. */
296
297 tptr = tstrings;
298 potentialtok = ERRORTOK;
299 ambiguous = 0;
300 while (tptr->token != ERRORTOK)
301 {
302 if (0 == strncmp(temp0, tptr->string, wordlen))
303 {
304 if (strlen(tptr->string) == wordlen)
305 {
306 ambiguous = 0;
307 potentialtok = tptr->token;
308 break; /* exact match */
309 }
310 if (potentialtok != ERRORTOK)
311 {
312 ambiguous = 1; /* this isn't the only match */
313 }
314 potentialtok = tptr->token;
315 }
316 tptr++;
317 }
318
319 thestrings[sizetokstring] = temp0;
320 tokstring[sizetokstring++] = ambiguous ? ERRORTOK : potentialtok;
321 temp0 = temp1;
322
323 /* If *temp0 == 0 then we're done. */
324
325 if (*temp0 == '\0')
326 done = 1;
327 }
328 thestrings[sizetokstring] = 0;
329 }
330 #endif
331
332 /**********************************************************************/
333
334 /* New parsing method. */
335
336 struct control_cmd
337 {
338 char *literal; /* the command they should type */
339 enum token_names_e tok; /* what the parser should return */
340 char *doc; /* documentation to print for a help command */
341 };
342
343 /*
344 * Scans the string cmd for the first whitespace delimited string. Tries to
345 * match this string in a case-insensitive manner against the list in legals.
346 * Returns the appropriate token. Alters the char* pointed to by after to be
347 * the beginning of the next whitespace-delimited string.
348 *
349 * cmd: unmodified legals: unmodified after: MODIFIED
350 *
351 */
352
353 enum token_names_e
354 next_token(cmd, legals, after)
355 char *cmd;
356 struct control_cmd *legals;
357 char **after;
358 {
359 char buf[80]; /* space for the token */
360 char *s;
361 int i;
362 int ambiguous = 0;
363 enum token_names_e potentialtok = ERRORTOK;
364
365 while (*cmd && isspace(*cmd))
366 cmd++;
367
368 if (!*cmd)
369 return ERRORTOK;
370
371 for (s = buf; *cmd && !isspace(*cmd); s++, cmd++)
372 *s = *cmd;
373 *s = 0;
374
375 while (*cmd && isspace(*cmd))
376 cmd++;
377
378 if (after)
379 *after = cmd; /* so they can find the next token */
380
381 for (i = 0; legals[i].literal; i++)
382 {
383 int wordlen = strlen(buf);
384 if (0 == strncasecmp(buf, legals[i].literal, wordlen))
385 {
386 if (strlen(legals[i].literal) == wordlen)
387 {
388 ambiguous = 0;
389 potentialtok = legals[i].tok;
390 break; /* exact match */
391 }
392 if (potentialtok != ERRORTOK)
393 {
394 ambiguous = 1; /* this isn't the only match */
395 return ERRORTOK;
396 }
397 potentialtok = legals[i].tok;
398 }
399 }
400
401 return potentialtok;
402 }
403
404 int
405 match_token(cmd, token, after)
406 char *cmd;
407 char *token;
408 char **after;
409 {
410 struct control_cmd legals[2];
411 legals[0].literal = token;
412 legals[0].tok = HELPTOK; /* pick any token but ERRORTOK */
413 legals[1].literal = 0;
414 return HELPTOK == next_token(cmd, legals, after);
415 }
416
417 /*
418 * Get a player slot number. Returns -1 on failure, slot number on success.
419 * Slot number is guaranteed to be <MAXPLAYER.
420 */
421
422 int
423 get_slotnum(cmd, after)
424 char *cmd;
425 char **after;
426 {
427 int rval;
428 while (*cmd && isspace(*cmd))
429 cmd++;
430
431 if (!*cmd)
432 return -1; /* no token */
433
434 if (cmd[1] && !isspace(cmd[1]))
435 return -1; /* token too long */
436
437 if (*cmd >= '0' && *cmd <= '9')
438 rval = *cmd - '0';
439 else if (*cmd >= 'a' && *cmd <= 'z')
440 rval = *cmd - 'a' + 10;
441 else if (*cmd >= 'A' && *cmd <= 'Z')
442 rval = *cmd - 'A' + 10;
443 else
444 return -1;
445
446 if (rval >= MAXPLAYER)
447 return -1; /* there aren't that many players */
448
449 if (after)
450 {
451 /* scan to next token */
452 cmd++;
453 while (*cmd && isspace(*cmd))
454 cmd++;
455 *after = cmd;
456 }
457
458 return rval;
459 }
460
461 void
462 bad_slotnum(msg)
463 char *msg;
464 {
465 char buf[256];
466 sprintf(buf, "`%s' requires player slot number", msg);
467 respond(buf, 1);
468 }
469
470
471 /*
472 * Get a single token. Returns 0 on failure, 1 on success. Token is returned
473 * in dst.
474 */
475
476 int
477 get_one_token(cmd, dst, dstsize, after)
478 char *cmd;
479 char *dst; /* destination */
480 int dstsize;
481 char **after;
482 {
483 while (*cmd && isspace(*cmd))
484 cmd++;
485
486 if (!*cmd)
487 return 0; /* no token */
488
489 while (dstsize > 1 && *cmd && !isspace(*cmd))
490 {
491 *(dst++) = *(cmd++);
492 dstsize--;
493 }
494 *dst = 0;
495
496 if (after)
497 {
498 /* scan to next token */
499 while (*cmd && isspace(*cmd))
500 cmd++;
501 *after = cmd;
502 }
503
504 return 1;
505 }
506
507 /*
508 * Get an integer Integer is returned in dst. Returns 0 on failure without
509 * modifying dst.
510 */
511
512 int
513 get_int(cmd, dst, after)
514 char *cmd;
515 int *dst;
516 char **after;
517 {
518 int rval, offset;
519
520 if (1 != sscanf(cmd, " %i%n", &rval, &offset))
521 return 0;
522
523 cmd += offset;
524 if (*cmd && !isspace(*cmd))
525 return 0; /* token wasn't all digits */
526
527 *dst = rval;
528
529 if (after)
530 {
531 /* scan to next token */
532 while (*cmd && isspace(*cmd))
533 cmd++;
534 *after = cmd;
535 }
536
537 return 1;
538 }
539
540 /*
541 * Get a double Double is returned in dst. Returns 0 on failure without
542 * modifying dst.
543 */
544
545 int
546 get_double(cmd, dst, after)
547 char *cmd;
548 double *dst;
549 char **after;
550 {
551 double rval;
552 int offset;
553
554 if (1 != sscanf(cmd, " %lg%n", &rval, &offset))
555 return 0;
556
557 cmd += offset;
558 if (*cmd && !isspace(*cmd))
559 return 0; /* token wasn't all digits */
560
561 *dst = rval;
562
563 if (after)
564 {
565 /* scan to next token */
566 while (*cmd && isspace(*cmd))
567 cmd++;
568 *after = cmd;
569 }
570
571 return 1;
572 }
573
574 int
575 get_teamid(cmd, team, after)
576 char *cmd;
577 int *team;
578 char **after;
579 {
580 int i, j;
581
582 while (*cmd && isspace(*cmd))
583 {
584 cmd++;
585 }
586 if (cmd[3] && !isspace(cmd[3]))
587 return 0; /* too long */
588
589 *team = NOBODY;
590
591 for (i = -1; i < NUMTEAM; i++)
592 {
593 j = idx_to_mask(i);
594 if (0 == strncasecmp(cmd, teams[j].shortname, 3))
595 {
596 *team = i;
597 cmd += 3;
598 break;
599 }
600 }
601
602 if (after)
603 {
604 /* scan to next token */
605 while (*cmd && isspace(*cmd))
606 cmd++;
607 *after = cmd;
608 }
609
610 return i < NUMTEAM;
611 }
612
613 int
614 get_shipid(cmd, shipn, after)
615 char *cmd;
616 int *shipn;
617 char **after;
618 {
619 int i;
620
621 while (*cmd && isspace(*cmd))
622 {
623 cmd++;
624 }
625 *shipn = -1;
626
627 for (i = 0; i < NUM_TYPES; i++)
628 {
629 struct ship *ship = &shipvals[i];
630 int len;
631 len = strlen(ship->s_name);
632 if (0 == strncasecmp(cmd, ship->s_name, len) &&
633 (cmd[len] == 0 || isspace(cmd[len])))
634 {
635 *shipn = i;
636 cmd += len;
637 break;
638 }
639 else if (tolower(cmd[0]) == tolower(ship->s_desig1) &&
640 tolower(cmd[1]) == tolower(ship->s_desig2) &&
641 (cmd[2] == 0 || isspace(cmd[2])))
642 {
643 *shipn = i;
644 cmd += 2;
645 break;
646 }
647 }
648
649 if (after)
650 {
651 /* scan to next token */
652 while (*cmd && isspace(*cmd))
653 cmd++;
654 *after = cmd;
655 }
656
657 return i < NUM_TYPES;
658 }
659
660 /* writes a comma-separated list of help strings into the message window */
661
662 void
663 respond_with_help_string(legals)
664 struct control_cmd *legals;
665 {
666 int i;
667 char buf[65]; /* leave space for the message prefix */
668
669 strcpy(buf, "Available commands: ");
670 for (i = 0; legals[i].literal; i++)
671 {
672 if (!(legals[i].doc && legals[i].doc[0]))
673 continue;
674 if (strlen(buf) + 3 + strlen(legals[i].doc) > sizeof(buf))
675 {
676 respond(buf, 0);
677 strcpy(buf, " ");
678 if (!buf[0])
679 { /* one of the help strings was just too long */
680 respond("ACK! programmer error: help string too long", 0);
681 return;
682 }
683 i--; /* retry */
684 continue;
685 }
686 strcat(buf, legals[i].doc);
687 if (legals[i + 1].literal)
688 strcat(buf, ", ");
689 }
690 if (buf[0])
691 respond(buf, 0);
692 }
693
694 /**********************************************************************/
695
696 static void
697 respond(msg, type)
698 char *msg;
699 int type;
700 {
701 if (type == 1)
702 warning(msg);
703 else
704 pmessage2(msg, me->p_no, MINDIV, MCONTROL, 255);
705 }
706
707 #ifdef GOD_CONTROLS
708
709 /*
710 * Here we handle the controls on players. If you add something, make sure
711 * you place it in the help. Thanks, have a nice day.
712 */
713
714 static int
715 parse_control_player(cmd)
716 char *cmd;
717 {
718 char buf[120];
719 int pnum;
720 struct player *victim;
721 int godliness = me->p_stats.st_royal - GODLIKE + 1;
722 char *arg;
723 static struct control_cmd available_cmds[] = {
724 {"help", HELPTOK, 0},
725 {"die", DIETOK, "die"},
726 {"eject", EJECTTOK, "eject"},
727 {"armies", ARMIESTOK, "armies [%d=5]"},
728 {"plasma", PLASMATOK, "plasma [%d]"},
729 {"missiles", MISSILETOK, "missiles [%d=max]"},
730 {"team", TEAMTOK, "team <teamstr>"},
731 {"ship", SHIPTOK, "ship <shiptype>"},
732 {"rank", RANKTOK, "rank (+|-|%d)"},
733 {"royal", ROYALTOK, "royal (+|-|%d)"},
734 {"kills", KILLSTOK, "kills (+|-|%d)"},
735 {"hose", HOSETOK, "hose"},
736 {"move", MOVETOK, "move %d %d"},
737 {0}
738 };
739
740 pnum = get_slotnum(cmd, &cmd);
741 if (pnum < 0)
742 {
743 bad_slotnum("control player");
744 return 0;
745 }
746 victim = &players[pnum];
747
748 if (victim->p_status == PFREE)
749 {
750 respond("Slot is not alive.", 1);
751 return 1;
752 }
753
754 /*
755 * These would probably work better as pointers to functions instead of a
756 * giant switch, but what the hell, I'm lazy. Maybe I'll change it later.
757 */
758
759 switch (next_token(cmd, available_cmds, &arg))
760 {
761 case DIETOK:
762 victim->p_ship.s_type = STARBASE;
763 victim->p_whydead = KPROVIDENCE;
764 victim->p_explode = 10;
765 victim->p_status = PEXPLODE;
766 victim->p_whodead = 0;
767 if (!god_silent)
768 {
769 sprintf(buf, "%s (%2s) was utterly obliterated by %s (%2s).",
770 victim->p_name, twoletters(victim),
771 me->p_name, twoletters(me));
772 pmessage(buf, 0, MALL, MCONTROL);
773 }
774 return 1;
775
776 case EJECTTOK:
777 victim->p_ship.s_type = STARBASE;
778 victim->p_whydead = KQUIT;
779 victim->p_explode = 10;
780 victim->p_status = PEXPLODE;
781 victim->p_whodead = 0;
782 if (!god_silent)
783 {
784 sprintf(buf,
785 "%s (%2s) has been ejected from the game by %s (%2s).",
786 victim->p_name, twoletters(victim),
787 me->p_name, twoletters(me));
788 pmessage(buf, 0, MALL, MCONTROL);
789 }
790 return 1;
791
792 case ARMIESTOK:
793 {
794 int armies = 5;
795 if (*arg && !get_int(arg, &armies, (char **) 0))
796 {
797 respond("optional arg to `control player <slotnum> armies` must be integer", 0);
798 return 0;
799 }
800 victim->p_armies += armies;
801 if (!god_silent)
802 {
803 sprintf(buf, "%s (%2s) has been given %d armies by %s (%2s).",
804 victim->p_name, twoletters(victim), armies,
805 me->p_name, twoletters(me));
806 pmessage(buf, 0, MALL, MCONTROL);
807 }
808 return 1;
809 }
810
811 case PLASMATOK:
812 {
813 int yes = 1;
814 if (*arg && !get_int(arg, &yes, (char **) 0))
815 {
816 respond("optional arg to `control player <slotnum> plasma` must be integer", 0);
817 return 0;
818 }
819
820 if (yes)
821 victim->p_ship.s_nflags |= SFNPLASMAARMED;
822 else
823 victim->p_ship.s_nflags &= ~SFNPLASMAARMED;
824
825 if (!god_silent)
826 {
827 sprintf(buf, "%s (%2s) has been %s plasma torps by %s (%2s).",
828 victim->p_name, twoletters(victim),
829 yes ? "given" : "denied",
830 me->p_name, twoletters(me));
831 pmessage(buf, 0, MALL, MCONTROL);
832 }
833 return 1;
834 }
835
836 case MISSILETOK:
837 {
838 int yes = shipvals[victim->p_ship.s_type].s_missilestored;
839
840 if (*arg && !get_int(arg, &yes, (char **) 0))
841 {
842 respond("optional arg to `control player <slotnum> missile` must be integer", 0);
843 return 0;
844 }
845
846 if (yes)
847 {
848 victim->p_ship.s_nflags |= SFNHASMISSILE;
849 victim->p_ship.s_missilestored = yes;
850 }
851 else
852 {
853 victim->p_ship.s_nflags &= ~SFNHASMISSILE;
854 }
855
856 if (!god_silent)
857 {
858 sprintf(buf, "%s (%2s) has been %s %d missiles by %s (%2s).",
859 victim->p_name, twoletters(victim),
860 yes ? "given" : "denied",
861 yes, me->p_name, twoletters(me));
862 pmessage(buf, 0, MALL, MCONTROL);
863 }
864 return 1;
865 }
866
867 case TEAMTOK:
868 {
869 int team;
870
871 if (!get_teamid(arg, &team, (char **) 0))
872 {
873 respond("available teams: FED ORI ROM KLI IND", 0);
874 return 0;
875 }
876 team = idx_to_mask(team);
877
878 victim->p_hostile |= victim->p_team;
879 victim->p_team = team;
880 victim->p_hostile &= ~team;
881 victim->p_swar &= ~team;
882 sprintf(buf, "%s (%2s) has been changed to a %s by %s (%2s).",
883 victim->p_name, twoletters(victim), teams[team].nickname,
884 me->p_name, twoletters(me));
885 if (!god_silent)
886 pmessage(buf, 0, MALL, MCONTROL);
887 return 1;
888 }
889
890 case SHIPTOK:
891 {
892 int ship;
893 if (!get_shipid(arg, &ship, (char **) 0))
894 {
895 respond("available ships: SC DD CA AS BB SB AT JS FR WB CL CV SUPER", 0);
896 return 0;
897 }
898 #if 0
899 if (tokstring[4] == SUPERTOK)
900 {
901 victim->p_ship.s_maxshield = 750;
902 victim->p_shield = 750;
903 victim->p_ship.s_maxdamage = 750;
904 victim->p_ship.s_maxegntemp = 5000;
905 sprintf(buf, "%s (%2s) has been supercharged by %s (%2s).",
906 victim->p_name, twoletters(victim),
907 me->p_name, twoletters(me));
908 if (!god_silent)
909 pmessage(buf, 0, MALL, MCONTROL);
910 return 1;
911 }
912 #endif
913 /* If others are docked, then kick them off */
914 if (allows_docking(victim->p_ship))
915 {
916 int i;
917 for (i = 0; i < victim->p_ship.s_numports; i++)
918 {
919 base_undock(victim, i);
920 }
921 }
922 get_ship_for_player(victim, ship);
923 switch_special_weapon();
924 victim->p_flags &= ~PFENG;
925 sprintf(buf, "%s (%2s) has been changed to a %c%c by %s (%2s).",
926 victim->p_name, twoletters(victim),
927 victim->p_ship.s_desig1, victim->p_ship.s_desig2,
928 me->p_name, twoletters(me));
929 if (!god_silent)
930 pmessage(buf, 0, MALL, MCONTROL);
931 return 1;
932 }
933
934 case RANKTOK:
935 {
936 int rank = victim->p_stats.st_rank;
937
938 if (match_token(arg, "+", (char **) 0))
939 rank++;
940 else if (match_token(arg, "-", (char **) 0))
941 rank--;
942 else if (!get_int(arg, &rank, (char **) 0))
943 {
944 respond("Try: control player %d rank [%d]+-", 0);
945 return 0;
946 }
947
948 if (rank < 0)
949 rank = 0;
950 if (rank >= NUMRANKS)
951 rank = NUMRANKS - 1;
952
953 victim->p_stats.st_rank = rank;
954 sprintf(buf, "%s (%2s) has been given a rank of %s by %s (%2s).",
955 victim->p_name, twoletters(victim),
956 ranks[victim->p_stats.st_rank].name,
957 me->p_name, twoletters(me));
958 if (!god_silent)
959 pmessage(buf, 0, MALL, MCONTROL);
960 return 1;
961 }
962
963 case ROYALTOK:
964 {
965 int rank = victim->p_stats.st_royal;
966
967 if (match_token(arg, "+", (char **) 0))
968 rank++;
969 else if (match_token(arg, "-", (char **) 0))
970 rank--;
971 else if (!get_int(arg, &rank, (char **) 0))
972 {
973 respond("Try: control player %d royal [%d]+-", 0);
974 return 0;
975 }
976
977 if (rank < 0)
978 rank = 0;
979 if (rank >= NUMROYALRANKS)
980 rank = NUMROYALRANKS - 1;
981
982 if (rank >= GODLIKE && godliness < 2)
983 {
984 respond("You aren't powerful enough to grant godlike royalty.",
985 1);
986 return 1;
987 }
988 victim->p_stats.st_royal = rank;
989 sprintf(buf, "%s (%2s) has been given a rank of %s by %s (%2s).",
990 victim->p_name, twoletters(victim),
991 royal[victim->p_stats.st_royal].name,
992 me->p_name, twoletters(me));
993 if (!god_silent)
994 pmessage(buf, 0, MALL, MCONTROL);
995 return 1;
996 }
997
998 case KILLSTOK:
999 {
1000 double kills = victim->p_kills;
1001
1002 if (match_token(arg, "+", (char **) 0))
1003 kills += 1;
1004 else if (match_token(arg, "-", (char **) 0))
1005 {
1006 kills -= 1;
1007 if (kills < 0)
1008 kills = 0;
1009 }
1010 else if (!get_double(arg, &kills, (char **) 0))
1011 {
1012 respond("Try: control player %d kills [%f]+-", 0);
1013 return 0;
1014 }
1015
1016 victim->p_kills = kills;
1017 sprintf(buf, "%s (%2s) has been given %f kills by %s (%2s).",
1018 victim->p_name, twoletters(victim),
1019 kills, me->p_name, twoletters(me));
1020 if (!god_silent)
1021 pmessage(buf, 0, MALL, MCONTROL);
1022 return 1;
1023 }
1024
1025 case HOSETOK:
1026 victim->p_shield = 0;
1027 victim->p_damage = victim->p_ship.s_maxdamage / 2;
1028 sprintf(buf, "%s (%2s) has been hosed by %s (%2s).",
1029 victim->p_name, twoletters(victim),
1030 me->p_name, twoletters(me));
1031 if (!god_silent)
1032 pmessage(buf, 0, MALL, MCONTROL);
1033 return 1;
1034
1035 case MOVETOK:
1036 {
1037 int x, y;
1038 char *s;
1039 if (!(get_int(arg, &x, &s) && get_int(s, &y, (char **) 0)))
1040 {
1041 respond("Try: control player %d move %d %d", 0);
1042 return 0;
1043 }
1044
1045 if (x <= 0 || y <= 0 || x >= 200000 || y >= 200000)
1046 {
1047 respond("You want to move him where?", 0);
1048 return 0;
1049 }
1050 victim->p_x = x;
1051 victim->p_y = y;
1052 sprintf(buf, "%s (%2s) has been moved to %d %d by %s (%2s).",
1053 victim->p_name, twoletters(victim),
1054 x, y,
1055 me->p_name, twoletters(me));
1056 if (!god_silent)
1057 pmessage(buf, 0, MALL, MCONTROL);
1058 return 1;
1059 }
1060
1061 case HELPTOK: /* fall through */
1062 default:
1063 #if 1
1064 respond_with_help_string(available_cmds);
1065 #else
1066 respond("player controls: die, eject, armies [%d], plasma [%d],", 0);
1067 respond("player controls: missile [%d], team [team], ship [ship],", 0);
1068 respond("player controls: rank [%d]+-, royal [%d]+-, kills [%d]+-", 0);
1069 respond("player controls: hose, move %d %d", 0);
1070 #endif
1071 return 0;
1072 }
1073 }
1074
1075 static int
1076 parse_control(str)
1077 char *str;
1078 {
1079 char buf[120];
1080 struct player *victim;
1081 int i;
1082 int godliness = me->p_stats.st_royal - GODLIKE + 1;
1083
1084 static struct control_cmd available_cmds[] = {
1085 {"help", HELPTOK, 0},
1086 {"freeslot", FREESLOTTOK, "freeslot %p"},
1087 {"player", PLAYERTOK, "player ..."},
1088 {"robot", ROBOTTOK, "robot [args]"},
1089 {"quiet", QUIETTOK, "quiet"},
1090 {"nukegame", NUKEGAMETOK, "nukegame"},
1091 {"restart", RESTARTTOK, "restart"},
1092 {"galaxy", NEWGALAXY, "galaxy"},
1093 {"shiptimer", SHIPTIMERTOK, "shiptimer (teamstr|shipstr)*"},
1094 {"allow", ALLOWTOK, "allow [teams]"},
1095 {0}
1096 };
1097 char *nexttoken;
1098
1099 if (godliness <= 0)
1100 {
1101 #if 0
1102 respond("Those commands are only available to server gods");
1103 #endif
1104 return 0; /* "fail" silently. Don't advertise divine
1105 * powers to peasants. */
1106 }
1107
1108
1109 switch (next_token(str, available_cmds, &nexttoken))
1110 {
1111 case FREESLOTTOK:
1112 {
1113 int slot = get_slotnum(nexttoken, (char **) 0);
1114 if (slot < 0)
1115 {
1116 respond("\"control freeslot\" requires slot number.", 0);
1117 return 1;
1118 }
1119 victim = &players[slot];
1120 if (victim->p_ntspid)
1121 kill(victim->p_ntspid, SIGHUP);
1122
1123 victim->p_status = PFREE;
1124 victim->p_ntspid = 0;
1125
1126 if (!god_silent)
1127 {
1128 sprintf(buf, "Player slot %s has been freed by %s (%2s).",
1129 nexttoken, me->p_name, twoletters(me));
1130 pmessage(buf, 0, MALL, MCONTROL);
1131 }
1132 }
1133 return 1;
1134
1135 case ALLOWTOK:
1136 {
1137 int newlock = 0;
1138 int team;
1139 char *s;
1140 if (0 == *nexttoken)
1141 {
1142 newlock = ALLTEAM;
1143 }
1144 else
1145 {
1146 for (s = nexttoken; get_teamid(s, &team, &s);)
1147 {
1148 newlock |= idx_to_mask(team);
1149 }
1150 if (*s)
1151 {
1152 respond("Usage: control allow [fed] [rom] [kli] [ori]", 0);
1153 return 1;
1154 }
1155 }
1156
1157 status2->nontteamlock = newlock;
1158 strcpy(buf, "Allowed teams now set to:");
1159 if (status2->nontteamlock == ALLTEAM)
1160 {
1161 strcat(buf, " <all teams>");
1162 }
1163 else
1164 {
1165 if (status2->nontteamlock & FED)
1166 strcat(buf, " fed");
1167 if (status2->nontteamlock & ROM)
1168 strcat(buf, " rom");
1169 if (status2->nontteamlock & KLI)
1170 strcat(buf, " kli");
1171 if (status2->nontteamlock & ORI)
1172 strcat(buf, " ori");
1173 }
1174 respond(buf, 0);
1175 }
1176 return 1;
1177 case PLAYERTOK:
1178 return parse_control_player(nexttoken);
1179
1180 case ROBOTTOK:
1181 {
1182 int pid;
1183 char *s;
1184
1185 pid = fork();
1186 if (pid == 0)
1187 {
1188 char *argv[40];
1189 argv[0] = build_path(ROBOT);
1190
1191 s = nexttoken;
1192 for (i = 1; 1; i++)
1193 {
1194 int size = 80;
1195 argv[i] = malloc(size);
1196 if (!get_one_token(s, argv[i], size, &s))
1197 break;
1198 realloc(argv[i], strlen(argv[i]) + 1);
1199 }
1200 free(argv[i]);
1201 argv[i] = 0;
1202
1203 execvp(argv[0], argv);
1204 fprintf(stderr, "Ack! Unable to exec %s\n", argv[0]);
1205 exit(1);
1206 }
1207 else if (pid < 0)
1208 {
1209 respond("Unable to fork robot", 0);
1210 }
1211 else
1212 {
1213 sprintf(buf, "Robot forked (pid %d) with arguments %s",
1214 pid, nexttoken);
1215 respond(buf, 1);
1216 }
1217 }
1218 return 1;
1219
1220 case QUIETTOK:
1221 if (godliness < 2)
1222 {
1223 respond("No sneaking allowed", 0);
1224 return 1;
1225 }
1226 sprintf(buf, "Switching to %s mode.", god_silent ? "loud" : "quiet");
1227 respond(buf, 0);
1228 god_silent = !god_silent;
1229 return 1;
1230 case NUKEGAMETOK:
1231 warning("Nuking game. Have a nice day.");
1232 if (!god_silent)
1233 {
1234 sprintf(buf, "The game has been nuked by %s (%2s).",
1235 me->p_name, twoletters(me));
1236 pmessage(buf, 0, MALL, MCONTROL);
1237 }
1238 kill(status->nukegame, 15);
1239 return 1;
1240 case RESTARTTOK:
1241 warning("Attempting daemon restart.");
1242 startdaemon(
1243 #ifdef LEAGUE_SUPPORT
1244 status2->league
1245 #else
1246 0
1247 #endif
1248 ,1);
1249 return 1;
1250 case NEWGALAXY:
1251 explode_everyone(KPROVIDENCE, 0);
1252 if (!god_silent)
1253 {
1254 sprintf(buf, "The galaxy has been reset by %s (%2s).",
1255 me->p_name, twoletters(me));
1256 pmessage(buf, 0, MALL, MCONTROL);
1257 }
1258 status2->newgalaxy = 1;
1259 warning("Creating new galaxy");
1260 return 1;
1261 case SHIPTIMERTOK:
1262 {
1263 int teammask = 0;
1264 int shipmask = 0;
1265 int i, j;
1266 char *s = nexttoken;
1267 while (1)
1268 {
1269 if (get_shipid(s, &j, &s))
1270 shipmask |= 1 << j;
1271 else if (get_teamid(s, &j, &s))
1272 teammask |= idx_to_mask(j);
1273 else if (*s)
1274 {
1275 respond("Usage:", 0);
1276 respond("control shiptimers (fed|rom|kli|ori)* (sc|dd|ca|bb|as|sb|at|js|fr|wb)*", 0);
1277 respond(" resets the ship timers.", 0);
1278 return 0;
1279 }
1280 else
1281 break;
1282 }
1283 for (i = 0; i < NUMTEAM; i++)
1284 {
1285 int teammask = idx_to_mask(i);
1286 if (teammask && !(teammask & (1 << i)))
1287 continue;
1288
1289 for (j = 0; j < NUM_TYPES; j++)
1290 {
1291 if (shipmask && !(shipmask & (1 << j)))
1292 continue;
1293
1294 if (teams[teammask].s_turns[j])
1295 {
1296 sprintf(buf, "%s %s reset", teams[teammask].name, shipvals[j].s_name);
1297 respond(buf, 0);
1298 teams[teammask].s_turns[j] = 0;
1299 }
1300 }
1301 }
1302 }
1303 return 1;
1304 case HELPTOK: /* fall through */
1305 default:
1306 #if 1
1307 respond_with_help_string(available_cmds);
1308 #else
1309 respond("Available controls: player, quiet, nukegame, freeslot,", 0);
1310 respond(" galaxy, restart, shiptimer", 0);
1311 #endif
1312 return 0;
1313 }
1314 }
1315 #endif
1316
1317 /*
1318 */
1319
1320 static int
1321 parse_info(cmd)
1322 char *cmd;
1323 {
1324 char buf[120];
1325 char *nexttoken;
1326
1327 static struct control_cmd available_cmds[] = {
1328 {"help", HELPTOK, 0},
1329 {"shiptimer", SHIPTIMERTOK, "shiptimer (teamstr|shipstr)*"},
1330 {0}
1331 };
1332
1333 switch (next_token(cmd, available_cmds, &nexttoken))
1334 {
1335 case SHIPTIMERTOK:
1336 {
1337 int race = 0;
1338 int i, j;
1339 int anydead = 0;
1340 #if 0
1341 if (me->p_stats.st_royal < 2)
1342 race = me->p_team;
1343 #endif
1344 for (i = 0; i < NUMTEAM; i++)
1345 {
1346 int teammask = idx_to_mask(i);
1347 if (race && !(race & (1 << i)))
1348 continue;
1349 for (j = 0; j < NUM_TYPES; j++)
1350 {
1351 if (teams[teammask].s_turns[j])
1352 {
1353 sprintf(buf, "%s %s: %d minutes", teams[teammask].name,
1354 shipvals[j].s_name, teams[teammask].s_turns[j]);
1355 anydead = 1;
1356 respond(buf, 0);
1357 }
1358 }
1359 }
1360 if (!anydead)
1361 respond("All ships are available", 0);
1362 }
1363 return 1;
1364 case HELPTOK:
1365 default:
1366 respond("Available subcommands: shiptimer", 0);
1367 return 1;
1368 }
1369 }
1370
1371 #define crypt(a, b) (a)
1372
1373 static int
1374 parse_player(cmd)
1375 char *cmd;
1376 {
1377 static int passver = 0;
1378 char buf[80];
1379 #if 0
1380 static char newpass[16];
1381 #endif
1382 char *nexttoken;
1383
1384 static struct control_cmd available_cmds[] = {
1385 {"help", HELPTOK, 0},
1386 {"password", PASSWDTOK, "password %s"},
1387 {"passwd", PASSWDTOK, 0},
1388 {"ratings", RATINGSTOK, "ratings"},
1389 {"rank", RANKTOK, "rank"},
1390 {0}
1391 };
1392
1393 if (0 == *cmd)
1394 {
1395 if (passver)
1396 respond("Password change cancelled.", 0);
1397
1398 passver = 0;
1399 return 1;
1400 }
1401
1402 switch (next_token(cmd, available_cmds, &nexttoken))
1403 {
1404 case PASSWDTOK:
1405 {
1406 static char newpass[16];
1407 if (me->p_pos < 0)
1408 { /* guest login */
1409 respond("You don't have a password!", 0);
1410 }
1411 else if (*nexttoken == 0)
1412 {
1413 respond("\"player password\" requires new password as argument.", 0);
1414 respond(" example: \"player password lh4ern\"", 0);
1415 }
1416 else if (!passver)
1417 {
1418 strcpy(newpass, crypt(nexttoken, me->p_name));
1419 respond("Repeat \"player password\" command to verify new password.", 0);
1420 respond(" or send \"player\" (no arguments) to cancel.", 0);
1421 passver = 1;
1422 }
1423 else
1424 {
1425 char *paths;
1426 int fd;
1427 if (!strcmp(newpass, crypt(nexttoken, me->p_name)))
1428 {
1429
1430 /* perhaps it'd be better to put this part in */
1431 /* a different place */
1432 paths = build_path(PLAYERFILE);
1433 fd = open(paths, O_WRONLY, 0644);
1434 if (fd >= 0)
1435 {
1436 lseek(fd, 16 + me->p_pos * sizeof(struct statentry), 0);
1437 write(fd, newpass, 16);
1438 close(fd);
1439 respond("Password changed.", 0);
1440 }
1441 else
1442 {
1443 respond("open() of playerfile failed, password not changed.", 0);
1444 }
1445 }
1446 else
1447 respond("Passwords did not match, password unchanged.", 0);
1448 passver = 0;
1449 }
1450 }
1451 return 1;
1452 case RATINGSTOK: /* print your ratings */
1453 {
1454 struct rating r;
1455 compute_ratings(me, &r);
1456
1457 sprintf(buf, "Bomb:%5.2f Plnts:%5.2f Rsrcs:%5.2f Dshs:%5.2f Offns:%5.2f", r.bombrat, r.planetrat, r.resrat, r.dooshrat, r.offrat);
1458 respond(buf, 0);
1459
1460 sprintf(buf, " JS:%5.2f SB:%5.2f WB:%5.2f Ratio:%5.2f", r.jsrat, r.sbrat, r.wbrat, r.ratio);
1461 respond(buf, 0);
1462
1463 sprintf(buf, "Overall Ratings: Battle:%5.2f Strat:%5.2f Spec. Ship:%5.2f", r.battle, r.strategy, r.special);
1464 respond(buf, 0);
1465 }
1466 return 1;
1467
1468 case RANKTOK: /* print the requirements for the next rank */
1469 {
1470 int rank;
1471 rank = me->p_stats.st_rank;
1472 strcpy(buf, "Your current rank is ");
1473 strcat(buf, ranks[rank].name);
1474 respond(buf, 0);
1475 if (rank == NUMRANKS - 1)
1476 return 1;
1477
1478 sprintf(buf, "To make the next rank (%s) you need:",
1479 ranks[rank + 1].name);
1480 respond(buf, 0);
1481
1482 sprintf(buf, " Genocides: %d DI: %.2f Battle: %.2f",
1483 ranks[rank + 1].genocides, ranks[rank + 1].di,
1484 ranks[rank + 1].battle);
1485 respond(buf, 0);
1486
1487 sprintf(buf, " Strategy: %.2f Spec. Ships: %.2f",
1488 ranks[rank + 1].strategy, ranks[rank + 1].specship);
1489 respond(buf, 0);
1490 }
1491 return 1;
1492
1493 case HELPTOK:
1494 default:
1495 respond_with_help_string(available_cmds);
1496 return 1;
1497 }
1498 }
1499
1500 /*
1501 */
1502
1503 #ifdef LEAGUE_SUPPORT
1504
1505 static void
1506 umpire_speak(msg)
1507 char *msg;
1508 {
1509 pmessage(msg, -1, MALL, UMPIRE);
1510 }
1511
1512 static void
1513 talk_about_team(team, type)
1514 struct league_team *team;
1515 char *type;
1516 {
1517 char buf[120];
1518 struct player *captain;
1519
1520 if (team->captain >= 0)
1521 captain = &players[team->captain];
1522 else
1523 captain = 0;
1524
1525 sprintf(buf, "The %s team is named `%s'.", type, team->name);
1526 respond(buf, 0);
1527
1528 if (captain)
1529 sprintf(buf, " %s (%s) is their captain.", captain->p_name,
1530 twoletters(captain));
1531 else
1532 strcpy(buf, " They have not chosen a captain yet.");
1533 respond(buf, 0);
1534
1535 if (team->index >= 0)
1536 {
1537 sprintf(buf, " They have chosen the %s",
1538 teams[idx_to_mask(team->index)].name);
1539 }
1540 else
1541 {
1542 strcpy(buf, " They have not chosen an empire yet.");
1543 }
1544 respond(buf, 0);
1545 }
1546
1547 static int
1548 team_really_ready(team)
1549 struct league_team *team;
1550 {
1551 if (team->index < 0)
1552 {
1553 respond("You haven't chosen an empire", 1);
1554 return 0;
1555 }
1556 if (team->name[0] == 0)
1557 {
1558 respond("You haven't chosen a name", 1);
1559 return 0;
1560 }
1561 return 1;
1562 }
1563
1564 void
1565 trydefect(victim, dest, destname, from, fromname, actor)
1566 struct player *victim;
1567 enum HomeAway dest;
1568 char *destname;
1569 enum HomeAway from;
1570 char *fromname;
1571 struct player *actor;
1572 {
1573 char buf[120];
1574 struct league_team *fromteam =
1575 (from == AWAY) ? &status2->away : &status2->home;
1576
1577 if (victim->p_status == PFREE)
1578 {
1579 respond("Uh, he's not in the game.", 1);
1580 return;
1581 }
1582
1583 if (victim->p_homeaway == dest)
1584 {
1585 sprintf(buf, "%s already belong to the %s team",
1586 actor == victim ? "You" : "They", destname);
1587 respond(buf, 1);
1588 return;
1589 }
1590 if (actor->p_homeaway != from)
1591 {
1592 sprintf(buf, "You don't belong to the %s team. You can't kick him off.",
1593 fromname);
1594 respond(buf, 1);
1595 return;
1596 }
1597 if (fromteam->captain == actor->p_no)
1598 {
1599 if (victim == actor)
1600 {
1601 if (status2->league > 1 || status2->home.ready || status2->away.ready)
1602 {
1603 respond("You can't defect in the middle of the game. You're the captain!", 1);
1604 return;
1605 }
1606 sprintf(buf, "%s (%s), the captain of the %s team, has defected!",
1607 victim->p_name, twoletters(victim), fromname);
1608 umpire_speak(buf);
1609 }
1610 else
1611 {
1612 sprintf(buf, "%s (%s) has kicked %s (%s) off his team.",
1613 actor->p_name, twoletters(actor),
1614 victim->p_name, twoletters(victim));
1615 umpire_speak(buf);
1616 }
1617 }
1618 else
1619 {
1620 if (victim == actor)
1621 {
1622 if (status2->league > 1 || status2->home.ready || status2->away.ready)
1623 {
1624 respond("Only the captain can kick you off now.", 1);
1625 return;
1626 }
1627 sprintf(buf, "%s (%s) has defected to the %s team!",
1628 victim->p_name, twoletters(victim),
1629 destname);
1630 umpire_speak(buf);
1631 }
1632 else
1633 {
1634 respond("Only the captain can kick other people off the team.", 1);
1635 return;
1636 }
1637 }
1638 victim->p_homeaway = dest;
1639 victim->p_status = PEXPLODE;
1640 victim->p_whydead = KPROVIDENCE;
1641 victim->p_explode = 1;
1642 }
1643
1644 static int
1645 parse_league(subcommand)
1646 char *subcommand;
1647 {
1648 struct league_team *myteam, *otherteam;
1649 char *teamtype;
1650 char buf[120];
1651 int i;
1652 int iscaptain;
1653 char *nexttoken;
1654 static char captain_only[] = "That command is reserved for team captains.";
1655 static struct control_cmd available_cmds[] = {
1656 {"help", HELPTOK, 0},
1657 {"captain", CAPTAINTOK, "captain [%d]"},
1658 {"time", TIMETOK, "time [%d %d]"},
1659 {"pass", PASSTOK, "pass"},
1660 {"start", STARTTOK, "start [%d]"},
1661 {"restart", RESTARTTOK, "restart [%d]"},
1662 #if 0
1663 {"timeout", TIMEOUTTOK, "timeout [%d]"},
1664 #endif
1665 {"teamname", TEAMNAMETOK, "teamname %s"},
1666 {"information", INFOTOK, "information"},
1667 #if 0
1668 /* damn, these should be initialized from the current race list */
1669 {"federation", FEDTOK, "fed"},
1670 {"romulan", ROMTOK, "rom"},
1671 {"klingon", KLITOK, "kli"},
1672 {"orion", ORITOK, "ori"},
1673 #endif
1674
1675 {"away", AWAYTOK, "away [%d]"},
1676 {"home", HOMETOK, "home [%d]"},
1677 {"newgalaxy", NEWGALAXY, "newgalaxy [%d]"},
1678 {"pause", PAUSETOK, "pause"},
1679 {"continue", CONTINUETOK, "continue"},
1680 {"maxplayer", MAXPLAYERTOK, "maxplayer [%d]"},
1681 {"freeslot", FREESLOTTOK, "freeslot %d"},
1682 {0}
1683 };
1684
1685 switch (me->p_homeaway)
1686 {
1687 case HOME:
1688 myteam = &status2->home;
1689 otherteam = &status2->away;
1690 teamtype = "home";
1691 break;
1692 case AWAY:
1693 myteam = &status2->away;
1694 otherteam = &status2->home;
1695 teamtype = "away";
1696 break;
1697 default:
1698 respond("WHOA! internal error. You aren't on a team!", 0);
1699 respond("I'm afraid I'm going to have to kill you", 0);
1700 me->p_status = PEXPLODE;
1701 me->p_explode = 1;
1702 return 0;
1703 }
1704
1705 iscaptain = (myteam->captain == me->p_no);
1706
1707 /********************/
1708
1709 if (get_teamid(subcommand, &i, (char **) 0))
1710 {
1711 if (!iscaptain)
1712 {
1713 respond(captain_only, 1);
1714 return 1;
1715 }
1716 if (status2->league != 1)
1717 {
1718 respond("The game has started. You can't change your mind now.", 1);
1719 return 1;
1720 }
1721 if ((myteam->ready || otherteam->ready) && myteam->index >= 0)
1722 {
1723 respond("One of the teams is ready. You can't change your mind now.", 1);
1724 return 1;
1725 }
1726 if (otherteam->index >= 0)
1727 {
1728 if (i == otherteam->index)
1729 {
1730 respond("The other team has already chosen that empire", 1);
1731 return 1;
1732 }
1733 }
1734 else
1735 {
1736 if (me->p_homeaway == HOME)
1737 {
1738 if (!status2->awaypassed)
1739 {
1740 respond("Away team gets first choice of empire.", 1);
1741 return 1;
1742 }
1743 }
1744 else /* away */ if (myteam->index >= 0 && 0 == status2->awaypassed)
1745 {
1746 respond("Give the other team a chance to choose a side, will ya?", 1);
1747 return 1;
1748 }
1749 else if (status2->awaypassed == 1)
1750 {
1751 respond("You passed the choice of empire. You have to wait for their choice.", 1);
1752 return 1;
1753 }
1754 }
1755
1756 if (i == myteam->index)
1757 {
1758 respond("That already IS your empire.", 1);
1759 return 1;
1760 }
1761 if (i < 0)
1762 {
1763 #if 0
1764 sprintf(buf, "The %s team no longer wishes the %s for their empire.",
1765 teamtype, teams[idx_to_mask(myteam->index)].name);
1766 #else
1767 respond("You can't change your mind without a reset. Ask for one", 1);
1768 return 1;
1769 #endif
1770 }
1771 else
1772 sprintf(buf, "The %s team has chosen the %s for their empire.",
1773 teamtype, teams[idx_to_mask(i)].name);
1774 umpire_speak(buf);
1775
1776 myteam->index = i;
1777
1778 return 1;
1779 }
1780 else
1781 switch (next_token(subcommand, available_cmds, &nexttoken))
1782 {
1783 default:
1784 case HELPTOK: /********************/
1785 if (iscaptain)
1786 {
1787 respond_with_help_string(available_cmds);
1788 }
1789 else
1790 {
1791 respond("Available commands: captain [ %d ], time, information, maxplayer.", 0);
1792 }
1793 return 1;
1794
1795 case CAPTAINTOK: /********************/
1796 {
1797 int j;
1798 i = !get_int(nexttoken, &j, (char **) 0) || j;
1799 }
1800 if (i)
1801 {
1802 if (myteam->captain < 0 ||
1803 players[myteam->captain].p_status != PALIVE ||
1804 players[myteam->captain].p_team != me->p_team)
1805 {
1806 if (myteam->captain >= 0)
1807 {
1808 /*
1809 * safety valve in case the person is ghostbusted or on another
1810 * team
1811 */
1812 sprintf(buf, "%s has been overthrown as captain of the %s team",
1813 players[myteam->captain].p_name, teamtype);
1814 umpire_speak(buf);
1815 }
1816 respond("OK. *POOF* you're a captain!", 1);
1817 sprintf(buf, "%s (%s) is now fearless leader of the %s team!",
1818 me->p_name, twoletters(me), teamtype);
1819 umpire_speak(buf);
1820 myteam->captain = me->p_no;
1821 }
1822 else if (iscaptain)
1823 {
1824 respond("Listen, silly. You already are captain. No point in rubbing it in", 1);
1825 }
1826 else
1827 {
1828 /* if myteam->captain were <0, we wouldn't get here */
1829 struct player *capn = &players[myteam->captain];
1830 sprintf(buf, "Sorry, %s (%s) is already captain of your team.",
1831 capn->p_name, twoletters(capn));
1832 respond(buf, 1);
1833 }
1834 }
1835 else
1836 {
1837 if (iscaptain)
1838 {
1839 respond("Wimp. We didn't want you for captain anyway.", 1);
1840 sprintf(buf, "%s (%s) has chickened out.",
1841 me->p_name, twoletters(me));
1842 umpire_speak(buf);
1843 sprintf(buf, "Who now will lead the %s team?", teamtype);
1844 umpire_speak(buf);
1845 myteam->captain = -1;
1846 }
1847 else
1848 {
1849 respond("You can't quit being a captain. You weren't one in the first place.", 1);
1850 }
1851 }
1852 return 1;
1853
1854 case TIMETOK: /********************/
1855 if (0 == *nexttoken)
1856 {
1857 switch (status2->league)
1858 {
1859 case 2:
1860 sprintf(buf, "%d seconds left in pre-tourney warm-up.",
1861 status2->leagueticksleft / SECONDS(1));
1862 break;
1863 case 3:
1864 sprintf(buf, "%d minutes left in regulation play.",
1865 status2->leagueticksleft / MINUTES(1));
1866 break;
1867 case 4:
1868 sprintf(buf, "%d minutes left in overtime.",
1869 status2->leagueticksleft / MINUTES(1));
1870 break;
1871 default:
1872 sprintf(buf, "game is configured for %d minutes (%d overtime).",
1873 configvals->regulation_minutes, configvals->overtime_minutes);
1874 break;
1875 }
1876 respond(buf, 0);
1877 return 1;
1878 }
1879 else if (!iscaptain)
1880 {
1881 respond(captain_only, 1);
1882 return 1;
1883 }
1884 else if (status2->league != 1)
1885 {
1886 respond("You can only adjust the time parameters during the configuration phase", 1);
1887 return 1;
1888 }
1889 else if (otherteam->ready)
1890 {
1891 respond("The other team is ready to start. You can't change the game params NOW.", 1);
1892 return 1;
1893 }
1894 else if (!get_int(nexttoken, &myteam->desired.regulation, &nexttoken)
1895 || !get_int(nexttoken, &myteam->desired.overtime, (char **) 0))
1896 {
1897 respond("Usage: time [ %d %d ]", 1);
1898 return 1;
1899 }
1900
1901 if (status2->home.desired.regulation == status2->away.desired.regulation
1902 && status2->home.desired.overtime == status2->away.desired.overtime)
1903 {
1904 configvals->regulation_minutes = status2->home.desired.regulation;
1905 configvals->overtime_minutes = status2->home.desired.overtime;
1906 sprintf(buf, "The captains have agreed to a %d minute game (%d overtime).", configvals->regulation_minutes, configvals->overtime_minutes);
1907 umpire_speak(buf);
1908 }
1909 else
1910 {
1911 sprintf(buf, "The %s team wishes a game of %d minutes (%d overtime)",
1912 teamtype, myteam->desired.regulation, myteam->desired.overtime);
1913 umpire_speak(buf);
1914 }
1915
1916 return 1;
1917
1918 case PASSTOK: /********************/
1919 if (status2->league != 1)
1920 {
1921 respond("The time for that is long past.", 1);
1922 return 1;
1923 }
1924 if (!iscaptain)
1925 {
1926 respond(captain_only, 1);
1927 return 1;
1928 }
1929 if (me->p_homeaway == AWAY && status2->awaypassed)
1930 {
1931 respond("You already passed the choice of empire.", 1);
1932 return 1;
1933 }
1934 else if (me->p_homeaway == HOME && status2->awaypassed == 0)
1935 {
1936 respond("You can't possibly pass the choice of empire. You don't HAVE it!", 1);
1937 return 1;
1938 }
1939 else if (status2->awaypassed > 1)
1940 {
1941 respond("You both passed already, so get on with it. (indecisive wishy-washy cretins)", 1);
1942 return 1;
1943 }
1944 status2->awaypassed++;
1945
1946 sprintf(buf, "The %s team has passed the choice of empire", teamtype);
1947 umpire_speak(buf);
1948
1949 if (status2->awaypassed > 1)
1950 {
1951 umpire_speak("Computer choosing randomly for both teams");
1952 if (status2->home.index < 0)
1953 {
1954 status2->home.index = lrand48() % ((status2->away.index < 0) ? 4 : 3);
1955 if (status2->away.index >= 0 &&
1956 status2->home.index >= status2->away.index)
1957 status2->home.index++;
1958 }
1959 if (status2->away.index < 0)
1960 {
1961 status2->away.index = lrand48() % 3;
1962 if (status2->away.index >= status2->home.index)
1963 status2->away.index++;
1964 }
1965 }
1966 return 1;
1967
1968 case STARTTOK: /********************/
1969 if (status2->league != 1)
1970 {
1971 respond("The game has already started.", 1);
1972 return 1;
1973 }
1974 if (!iscaptain)
1975 {
1976 respond(captain_only, 1);
1977 return 1;
1978 }
1979 if (get_int(nexttoken, &myteam->ready, (char **) 0) && !myteam->ready)
1980 {
1981 sprintf(buf, "The %s team is not ready.", teamtype);
1982 umpire_speak(buf);
1983 return 0;
1984 }
1985 myteam->ready = 1;
1986 if (!team_really_ready(myteam))
1987 {
1988 respond("Your team is not really ready. You need a name and an empire.", 0);
1989 myteam->ready = 0;
1990 return 0;
1991 }
1992
1993 if (otherteam->ready && !team_really_ready(otherteam))
1994 {
1995 otherteam->ready = 0;
1996 sprintf(buf, "The %s team was ready but the other wasn't.", teamtype);
1997 }
1998 else
1999 {
2000 sprintf(buf, "The %s team is ready to start now.", teamtype);
2001 }
2002 umpire_speak(buf);
2003
2004
2005 if (otherteam->ready)
2006 {
2007 /* shit! we're good to go! */
2008
2009 umpire_speak("Both sides are ready. Let the carnage begin!");
2010 umpire_speak("Everybody dies. T-mode starts in 1 minute.");
2011 status2->league = 2;
2012 status2->leagueticksleft = 60 * TICKSPERSEC;
2013
2014 /* version */
2015
2016 explode_everyone(KTOURNSTART, 0);
2017 }
2018 return 1;
2019
2020 case RESTARTTOK: /********************/
2021 if (status2->league != 1)
2022 {
2023 respond("The game has started. You can't change your mind now.", 1);
2024 return 1;
2025 }
2026
2027 if (!iscaptain)
2028 {
2029 respond(captain_only, 1);
2030 return 1;
2031 }
2032
2033 myteam->desired.restart = !get_int(nexttoken, &i, (char **) 0) || i;
2034
2035 sprintf(buf, myteam->desired.restart ?
2036 "%s (%s) would like to restart team selection." :
2037 "%s (%s) is satisfied with the teams.",
2038 me->p_name, twoletters(me));
2039 umpire_speak(buf);
2040
2041 if (status2->home.desired.restart && status2->away.desired.restart)
2042 {
2043 umpire_speak("Both captains have agreed to restart team selection.");
2044
2045 status2->awaypassed = 0;
2046 status2->home.index = status2->away.index = -1;
2047
2048 status2->home.ready = status2->away.ready = 0;
2049
2050 status2->home.desired.restart = status2->away.desired.restart = 0;
2051 }
2052
2053 return 1;
2054
2055 case TIMEOUTTOK:
2056 respond("NYI", 0);
2057 return 1;
2058
2059 case TEAMNAMETOK: /********************/
2060 if (status2->league != 1)
2061 {
2062 respond("The game has started. You can't change your mind now.", 1);
2063 return 1;
2064 }
2065 if (!iscaptain)
2066 {
2067 respond(captain_only, 1);
2068 return 1;
2069 }
2070 if (0 == *nexttoken)
2071 {
2072 respond("What do you want to call your team?\n", 1);
2073 return 1;
2074 }
2075 strncpy(myteam->name, nexttoken, sizeof(myteam->name));
2076 myteam->name[sizeof(myteam->name) - 1] = 0;
2077
2078 sprintf(buf, "Henceforth let the %s team be known as `%s'!",
2079 teamtype, myteam->name);
2080 umpire_speak(buf);
2081
2082 return 1;
2083
2084 case INFOTOK: /********************/
2085 sprintf(buf, "The game will last for %d minutes (%d overtime)",
2086 configvals->regulation_minutes,
2087 configvals->overtime_minutes);
2088 respond(buf, 0);
2089 sprintf(buf, "Teams are limited to %d players on the field at once",
2090 configvals->playersperteam);
2091 respond(buf, 0);
2092 sprintf(buf, "You are on the %s team.", teamtype);
2093 respond(buf, 0);
2094 talk_about_team(&status2->home, "home");
2095 talk_about_team(&status2->away, "away");
2096
2097 if (status2->awaypassed > 1)
2098 umpire_speak("Both teams passed empire choice. Computer assigned.");
2099 else if (status2->awaypassed)
2100 umpire_speak("Away has passed empire choice to the Home team");
2101 else
2102 umpire_speak("Away chooses empire first");
2103
2104 return 1;
2105
2106
2107 case AWAYTOK: /********************/
2108 {
2109 struct player *victim;
2110 if (!*nexttoken)
2111 victim = me;
2112 else
2113 {
2114 int idx = get_slotnum(nexttoken, (char **) 0);
2115 if (idx < 0)
2116 {
2117 respond("`league away' requires a valid slot number", 0);
2118 return 1;
2119 }
2120 else
2121 {
2122 victim = &players[idx];
2123 }
2124 }
2125 trydefect(victim, AWAY, "away", HOME, "home", me);
2126 }
2127 return 1;
2128
2129 case HOMETOK: /********************/
2130 {
2131 struct player *victim;
2132 if (!*nexttoken)
2133 victim = me;
2134 else
2135 {
2136 int idx = get_slotnum(nexttoken, (char **) 0);
2137 if (idx < 0)
2138 {
2139 respond("`league away' requires a valid slot number", 0);
2140 return 1;
2141 }
2142 else
2143 {
2144 victim = &players[idx];
2145 }
2146 }
2147 trydefect(victim, HOME, "home", AWAY, "away", me);
2148 }
2149
2150 return 1;
2151 case NEWGALAXY: /********************/
2152
2153 if (status2->league != 1)
2154 {
2155 respond("The game has started. You can't change your mind now.", 1);
2156 return 1;
2157 }
2158
2159 if (myteam->ready || otherteam->ready)
2160 {
2161 respond("You can't reset the galaxy now. We're almost ready!", 1);
2162 return 1;
2163 }
2164 if (!iscaptain)
2165 {
2166 respond(captain_only, 1);
2167 return 1;
2168 }
2169
2170 {
2171 int j;
2172 myteam->desired.galaxyreset =
2173 !get_int(nexttoken, &j, (char **) 0) || j;
2174 }
2175
2176 if (myteam->desired.galaxyreset)
2177 {
2178 sprintf(buf, "%s (%s) is dissatisfied with the galaxy",
2179 me->p_name, twoletters(me));
2180 }
2181 else
2182 {
2183 sprintf(buf, "%s (%s) thinks the galaxy is just fine, thank you.",
2184 me->p_name, twoletters(me));
2185 }
2186 umpire_speak(buf);
2187
2188 if (status2->home.desired.galaxyreset &&
2189 status2->away.desired.galaxyreset)
2190 {
2191 umpire_speak("Both captains have agreed that the galaxy sucks.");
2192 status2->newgalaxy = 1;
2193 warning("Creating new galaxy");
2194
2195 status2->home.desired.galaxyreset = status2->away.desired.galaxyreset = 0;
2196
2197 status2->awaypassed = 0;
2198 status2->home.index = status2->away.index = -1;
2199 status2->home.ready = status2->away.ready = 0;
2200 status2->home.desired.restart = status2->away.desired.restart = 0;
2201 }
2202
2203 return 1;
2204
2205 case PAUSETOK: /********************/
2206 if (!iscaptain)
2207 {
2208 respond(captain_only, 1);
2209 return 1;
2210 }
2211
2212 myteam->desirepause = 1;
2213
2214 if (status2->home.desirepause && status2->away.desirepause)
2215 {
2216 /* well, it's unanimous! */
2217 status2->paused = SECONDS(10);
2218 umpire_speak("The game has been paused");
2219 }
2220 else
2221 {
2222 sprintf(buf, "The %s team wishes to PAUSE the game.", teamtype);
2223 umpire_speak(buf);
2224 }
2225
2226 status2->pausemsgfuse = 0;
2227
2228 return 1;
2229
2230 case CONTINUETOK: /********************/
2231 if (!iscaptain)
2232 {
2233 respond(captain_only, 1);
2234 return 0;
2235 }
2236
2237 myteam->desirepause = 0;
2238
2239 sprintf(buf, "The %s team wishes to CONTINUE.", teamtype);
2240 umpire_speak(buf);
2241
2242 status2->pausemsgfuse = 0;
2243
2244 return 1;
2245
2246 case MAXPLAYERTOK:
2247 {
2248 int mp;
2249 if (!get_int(nexttoken, &mp, (char **) 0))
2250 {
2251 sprintf(buf, "The game is currently configured for a maximum of %d players on each", configvals->playersperteam);
2252 respond(buf, 0);
2253 respond("team.", 0);
2254 if (configvals->playersperteam != myteam->desired.maxplayers)
2255 {
2256 sprintf(buf, "You, however, want it to be %d.",
2257 myteam->desired.maxplayers);
2258 respond(buf, 0);
2259 }
2260 }
2261 else
2262 {
2263 if (!iscaptain)
2264 {
2265 respond(captain_only, 1);
2266 return 1;
2267 }
2268
2269 if (mp < 1)
2270 {
2271 respond("That's a stupid value for players-per-team.", 1);
2272 return 1;
2273 }
2274
2275 myteam->desired.maxplayers = mp;
2276 if (status2->away.desired.maxplayers
2277 == status2->home.desired.maxplayers)
2278 {
2279 configvals->playersperteam = mp;
2280 sprintf(buf, "Captains have agreed to limit players per team to %d", mp);
2281 umpire_speak(buf);
2282 }
2283 else
2284 {
2285 sprintf(buf, "The %s team would like to limit the number of ",
2286 teamtype);
2287 umpire_speak(buf);
2288 sprintf(buf, "players per team to %d", mp);
2289 umpire_speak(buf);
2290 }
2291 }
2292 }
2293 return 1;
2294 case FREESLOTTOK:
2295 {
2296 int slotnum;
2297 struct player *victim;
2298 slotnum = get_slotnum(nexttoken, (char **) 0);
2299 if (slotnum < 0)
2300 {
2301 respond("freeslot requires slot number", 1);
2302 return 0;
2303 }
2304
2305 victim = &players[slotnum];
2306 if (victim->p_ntspid)
2307 kill(victim->p_ntspid, SIGHUP);
2308
2309 victim->p_status = PFREE;
2310 victim->p_ntspid = 0;
2311
2312 sprintf(buf, "Player slot %s has been freed by %s (%2s).",
2313 nexttoken, me->p_name, twoletters(me));
2314 umpire_speak(buf);
2315 }
2316 return 1;
2317 }
2318 }
2319 #endif
2320 /*
2321 */
2322
2323
2324
2325 /*
2326 * Parse command messages.
2327 */
2328
2329 int
2330 parse_command_mess(str, who)
2331 char *str;
2332 unsigned char who;
2333 {
2334 char buf[120];
2335 char *nexttoken;
2336 int godlike = me->p_stats.st_royal - GODLIKE + 1;
2337
2338 static struct control_cmd available_cmds[] = {
2339 {"help", HELPTOK, 0},
2340 {"control", CONTROLTOK, "control ..."},
2341 {"league", LEAGUETOK, "league ..."},
2342 {"version", VERSIONTOK, "version"},
2343 {"player", PLAYERTOK, "player ..."},
2344 {"queue", QUEUETOK, "queue"}, {"tq", QUEUETOK, 0},
2345 {"information", INFOTOK, "information ..."},
2346 {"observe", OBSERVETOK, "observe"},
2347 {"parameters", PARAMTOK, "parameters"}, {"params", PARAMTOK, 0},
2348 {"cluecheck", CLUECHECKTOK, "cluecheck [%s]"},
2349 {0}
2350 };
2351
2352 if (godlike < 0)
2353 godlike = 0;
2354
2355
2356
2357 #if 0
2358 /* so we won't damage the original string */
2359 strcpy(buf, str);
2360
2361 dotokenize(buf);
2362
2363 if (sizetokstring == 0) /* nothing? ok, then let them send it :) */
2364 return 0;
2365 #endif
2366
2367 switch (next_token(str, available_cmds, &nexttoken))
2368 {
2369 case HELPTOK:
2370 sprintf(buf, "Available commands: %s%s%s",
2371 godlike ? "control ..., " : "",
2372 #ifdef LEAGUE_SUPPORT
2373 status2->league ? "league ..., " :
2374 #endif
2375 "",
2376 "version, player ..., queue,");
2377 respond(buf, 0);
2378 respond(" information ..., observe [%d], parameters, cluecheck [%s], help", 0);
2379 return 1;
2380 case CONTROLTOK:
2381 #ifdef GOD_CONTROLS
2382 #ifdef LEAGUE_SUPPORT
2383 if (status2->league)
2384 {
2385 respond("God controls are disabled during league play.", 1);
2386 }
2387 else
2388 #endif
2389 return parse_control(nexttoken);
2390 #else
2391 respond("This ntserv is not compiled with god controls.", 1);
2392 return 1;
2393 #endif
2394
2395 case VERSIONTOK:
2396 sprintf(buf, "NetrekII (Paradise), %s", PARAVERS);
2397 respond(buf, 0);
2398 return 1;
2399
2400 case PLAYERTOK:
2401 return parse_player(nexttoken);
2402
2403 case QUEUETOK:
2404 if (me->p_status == PTQUEUE)
2405 {
2406 detourneyqueue();
2407 }
2408 else if (status->tourn)
2409 respond("Dude, what are you waiting for!? It's T-mode. GO FIGHT!", 1);
2410 else if (!(me->p_flags & PFGREEN))
2411 respond("Can not enter the tourney queue while at alert", 1);
2412 #ifndef AEDILE
2413 else if (me->p_damage != 0 || me->p_shield < me->p_ship.s_maxshield)
2414 respond("Can not enter the tourney queue while damaged", 1);
2415 #endif
2416 else if (me->p_armies > 0)
2417 respond("Can not take armies into the tourney queue", 1);
2418 else
2419 {
2420 /*
2421 * well, stick them on the queue. They will be awoken when T mode
2422 * arrives
2423 */
2424
2425 evaporate(me);
2426
2427 /* need code to blab about this */
2428 me->p_status = PTQUEUE;
2429 sprintf(buf, "%s has entered the tournament queue to wait for T-mode", me->p_name);
2430 pmessage(buf, -1, MALL, "GOD->ALL");
2431 }
2432 return 1;
2433
2434 case LEAGUETOK:
2435 #ifdef LEAGUE_SUPPORT
2436 if (status2->league)
2437 {
2438 return parse_league(nexttoken);
2439 }
2440 else
2441 {
2442 respond("League commands are disabled during non-league play.", 1);
2443 return 1;
2444 }
2445 #else
2446 respond("Server is not compiled with league support.", 1);
2447 respond("Edit config.h, recompile, install, and nuke the game.", 1);
2448 return 1;
2449 #endif
2450
2451 case INFOTOK:
2452 return parse_info(nexttoken);
2453
2454 case OBSERVETOK:
2455 {
2456 int i;
2457 i = !get_int(nexttoken, &i, (char **) 0) || i;
2458
2459 if (i)
2460 {
2461 if (me->p_observer && me->p_status == POBSERVE)
2462 {
2463 respond("You are already an observer.", 1);
2464 }
2465 else
2466 {
2467 if (!(me->p_flags & PFGREEN))
2468 respond("Can not become an observer while at alert", 1);
2469 else if (me->p_damage != 0 || me->p_shield < me->p_ship.s_maxshield)
2470 respond("Can not become an observer while damaged", 1);
2471 else if (me->p_armies > 0)
2472 respond("Can not become an observer while carrying armies", 1);
2473 else
2474 {
2475 evaporate(me);
2476 me->p_status = POBSERVE;
2477 }
2478 me->p_observer = 1;
2479 }
2480 }
2481 else
2482 {
2483 if (me->p_observer && me->p_status == POBSERVE)
2484 {
2485 me->p_observer = 0;
2486 #if 1
2487 #ifdef LEAGUE_SUPPORT
2488 if (!(status2->league && status->tourn))
2489 #endif
2490 evaporate(me);
2491 #else
2492 respond("You may now self-destruct and reenter the game as a player", 0);
2493 respond("(assuming there's room for you).", 0);
2494 #endif
2495 }
2496 }
2497 }
2498 return 1;
2499
2500 case PARAMTOK:
2501 warning("Transmitting new game parameters");
2502 updateGameparams();
2503 return 1;
2504 case CLUECHECKTOK:
2505 #if defined(CLUECHECK1) || defined(CLUECHECK2)
2506 return accept_cluecheck(nexttoken);
2507 #else
2508 return 0;
2509 #endif
2510 default:
2511 return 0;
2512 }
2513 }