Mercurial > ~darius > hgwebdir.cgi > paradise_server
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 } |