~collinp/paradise-netrek/3.1p0

« back to all changes in this revision

Viewing changes to src/ntserv/message.c

  • Committer: Collin Pruitt
  • Date: 2009-05-22 04:40:09 UTC
  • Revision ID: collinp111@gmail.com-20090522044009-gw30zywb9oaae4nr
Initial upload - just the source release of 3.1p0

Show diffs side-by-side

added added

removed removed

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