4
|
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 }
|