1 /* Generic commands.
2 Copyright (C) 1998-2000 Stanley T. Shebs.
3
4 Xconq is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version. See the file COPYING. */
8
9 /* The commands in this file are the same for all interfaces. They
10 typically consist of direct operations on units, or complicated
11 command-line-type commands. */
12
13 #include "conq.h"
14 #include "kpublic.h"
15 #include "imf.h"
16 #include "ui.h"
17
18 int autofinish_start;
19 int autofinish_count;
20
21 static void notify_relationships(Side *side);
22 static int parse_advance_spec(char *str);
23 static int do_one_auto(Side *side, Unit *unit);
24 static int do_one_clear_plan(Side *side, Unit *unit);
25 static int do_one_delay(Side *side, Unit *unit);
26 static int do_one_detach(Side *side, Unit *unit);
27 static int do_one_detonate(Side *side, Unit *unit);
28 static int do_one_disband(Side *side, Unit *unit);
29 static int do_one_disembark(Side *side, Unit *unit);
30 static int do_one_embark(Side *side, Unit *unit);
31 static int do_one_give(Side *side, Unit *unit);
32 static int do_one_idle(Side *side, Unit *unit);
33 static int do_one_reserve(Side *side, Unit *unit);
34 static int do_one_return(Side *side, Unit *unit);
35 static int do_one_sleep(Side *side, Unit *unit);
36 static int do_one_take(Side *side, Unit *unit);
37 static int do_one_wake(Side *side, Unit *unit);
38 static int do_one_wake_all(Side *side, Unit *unit);
39
40 /* The command table is an array of all the commands. */
41
42 typedef struct cmdtab {
43 char fchar; /* character to match against */
44 char *name; /* Full name of command */
45 void (*fn)(Side *side); /* Pointer to command's function */
46 char *help; /* short documentation string */
47 } CmdTab;
48
49 #define C(c) ((c)-0x40)
50
51 #undef DEF_CMD
52 #define DEF_CMD(LETTER,NAME,FN,HELP) { LETTER, NAME, FN, HELP },
53
54 /* Define the table of commands. */
55
56 CmdTab commands[] = {
57
58 #include "cmd.def"
59
60 { 0, NULL, /* NULL, */ NULL, NULL }
61 };
62
63 /* This is the actual key typed, for use if several keyboard commands
64 share a single function. */
65
66 char tmpkey;
67
68 /* If the command was typed as a command-line sort of thing, then this
69 global will point to whatever came after the name of the
70 command. */
71
72 char *cmdargstr;
73
74 /* Help nodes that list all the commands, both single-char and long. */
75
76 HelpNode *key_commands_help_node;
77
78 HelpNode *long_commands_help_node;
79
80 HelpNode *map_help_node;
81
82 /* Search in command table and execute function if found, complaining if
83 the command is not recognized. */
84
85 void
execute_command(Side * side,int ch)86 execute_command(Side *side, int ch)
87 {
88 CmdTab *cmd;
89 void (*fn)(Side *side);
90
91 /* The long-name commands all have a char of 0, so we must ensure
92 nonzero characters coming in here. */
93 if (ch == '\0')
94 run_error("Character '\\0' in execute_command");
95 cmdargstr = NULL;
96 for (cmd = commands; cmd->name != NULL; ++cmd) {
97 if (ch == cmd->fchar) {
98 fn = cmd->fn;
99 if (fn == NULL) {
100 run_warning("no command function for %s (0x%x)?",
101 cmd->name, ch);
102 return;
103 }
104 tmpkey = ch;
105 (*fn)(side);
106 /* Whatever might have happened, we *did* find the command. */
107 return;
108 }
109 }
110 cmd_error(side, "unrecognized command key '%c'", ch);
111 }
112
113 /* Given a string, find and interpret a long-name command in it. */
114
115 void
execute_long_command(Side * side,char * cmdstr)116 execute_long_command(Side *side, char *cmdstr)
117 {
118 int prefix;
119 char *cmdname;
120 CmdTab *cmd;
121 void (*fn)(Side *side);
122
123 /* (should do something with prefix, which is presently ignored) */
124 parse_long_name_command(cmdstr, &prefix, &cmdname, &cmdargstr,
125 copy_string(cmdstr));
126 if (empty_string(cmdname)) {
127 /* Treat this is a deliberate cancellation, not an error. */
128 notify(side, "No command.");
129 return;
130 }
131 for (cmd = commands; cmd->name != NULL; ++cmd) {
132 if (strcmp(cmdname, cmd->name) == 0) {
133 fn = cmd->fn;
134 if (fn == NULL) {
135 run_warning("no command function for %s?", cmd->name);
136 return;
137 }
138 tmpkey = cmd->fchar;
139 (*fn)(side);
140 /* Whatever might have happened, we *did* find the command. */
141 return;
142 }
143 }
144 cmd_error(side, "unrecognized command name \"%s\"", cmdname);
145 }
146
147 /* Collect a command name and an argument string from the given
148 string, discarding excess whitespace. */
149
150 void
parse_long_name_command(char * cmdstr,int * prefixp,char ** namep,char ** argp,char * buf)151 parse_long_name_command(char *cmdstr, int *prefixp, char **namep, char **argp,
152 char *buf)
153 {
154 int j, prefixarg = -1;
155 char *cmdname, *cmdarg;
156
157 if (empty_string(cmdstr)) {
158 *namep = *argp = NULL;
159 return;
160 }
161 strcpy(buf, cmdstr);
162 /* Look for the first nonwhite char, make it start of command name. */
163 cmdname = buf;
164 while ((*cmdname == ' ' || *cmdname == '\t') && *cmdname != '\0')
165 ++cmdname;
166 /* If this is a digit, then it's a prefix arg; extract it. */
167 if (isdigit(*cmdname)) {
168 prefixarg = *cmdname - '0';
169 ++cmdname;
170 while (isdigit(*cmdname)) {
171 prefixarg = prefixarg * 10 + (*cmdname - '0');
172 ++cmdname;
173 }
174 /* Skip over any space between prefix arg and cmdname. */
175 while ((*cmdname == ' ' || *cmdname == '\t') && *cmdname != '\0')
176 ++cmdname;
177 }
178 /* Scan over command name, which is delimited by whitespace or end
179 of line. */
180 for (j = 0; cmdname[j] != ' ' && cmdname[j] != '\t' && cmdname[j] != '\n' && cmdname[j] != '\0'; ++j)
181 ;
182 /* If there's more than just the command name, extract an argument. */
183 if (cmdname[j] != '\0') {
184 cmdarg = cmdname + j + 1;
185 while ((*cmdarg == ' ' || *cmdname == '\t' || *cmdname == '\n') && *cmdarg != '\0')
186 ++cmdarg;
187 if (*cmdarg == '\0')
188 cmdarg = NULL;
189 } else {
190 cmdarg = NULL;
191 }
192 /* Terminate the command name. */
193 cmdname[j] = '\0';
194 /* Remove trailing whitespace from the argument. */
195 if (!empty_string(cmdarg)) {
196 for (j = strlen(cmdarg) - 1; j >= 0 && (cmdarg[j] == ' ' || cmdarg[j] == '\t' || cmdarg[j] == '\n'); --j)
197 ;
198 cmdarg[j + 1] = '\0';
199 }
200 DGprintf("Command is \"%s\", argument is \"%s\", prefix is %d\n",
201 (cmdname != NULL ? cmdname : "<null>"),
202 (cmdarg != NULL ? cmdarg : "<null>"),
203 prefixarg);
204 *prefixp = prefixarg;
205 *namep = cmdname;
206 *argp = cmdarg;
207 }
208
209 /* Describe all the single-key commands for help. */
210
211 void
describe_key_commands(int arg,char * key,TextBuffer * buf)212 describe_key_commands(int arg, char *key, TextBuffer *buf)
213 {
214 CmdTab *cmd;
215
216 for (cmd = commands; cmd->name != NULL; ++cmd) {
217 describe_command(cmd->fchar, cmd->name, cmd->help, TRUE, buf);
218 }
219 }
220
221 /* Describe all the long-name commands for help. */
222
223 void
describe_long_commands(int arg,char * key,TextBuffer * buf)224 describe_long_commands(int arg, char *key, TextBuffer *buf)
225 {
226 CmdTab *cmd;
227
228 for (cmd = commands; cmd->name != NULL; ++cmd) {
229 describe_command (cmd->fchar, cmd->name, cmd->help, FALSE, buf);
230 }
231 }
232
233 static int
apply_to_all_selected_units(Side * side,int (* fn)(Side * side,Unit * unit))234 apply_to_all_selected_units(Side *side, int (*fn)(Side *side, Unit *unit))
235 {
236 int i, rslt, numcould = 0, numfail = 0;
237 Unit *unit;
238 UnitVector *selvec;
239
240 if (fn == NULL)
241 /* (should be a fatal error?) */
242 return 0;
243 /* Scan all the selected units. Note that we assume that the list
244 (unit vector) doesn't change while we're scanning, which means
245 that we should be checking each unit, in case a command caused
246 later units in the list to disappear (for instance a
247 detonation). */
248 selvec = get_selected_units(side);
249 for (i = 0; i < selvec->numunits; ++i) {
250 unit = unit_in_vector(selvec, i);
251 if (in_play(unit) && side_controls_unit(side, unit)) {
252 ++numcould;
253 rslt = (*fn)(side, unit);
254 if (!rslt)
255 ++numfail;
256 }
257 }
258 /* Return true if everything went OK, false if the function failed
259 on some units. */
260 return ((numcould > 0) ? (numfail == 0) : TRUE);
261 }
262
263 /* Generic command functions. These are the command functions that
264 behave identically for all interfaces. */
265
266 #define DURING_GAME_ONLY(side) \
267 if (endofgame) { \
268 cmd_error((side), "Cannot do after game is over!"); \
269 return; \
270 }
271
272 void
do_add_player(Side * side)273 do_add_player(Side *side)
274 {
275 DURING_GAME_ONLY(side);
276 net_request_additional_side(cmdargstr);
277 }
278
279 #if 0
280
281 void
282 do_agreement_draft(Side *side)
283 {
284 char *title, titlebuf[20];
285 Agreement *ag;
286
287 DURING_GAME_ONLY(side);
288 /* (should have a net_create_agreement) */
289 ag = create_agreement(0);
290 if (!empty_string(cmdargstr)) {
291 title = cmdargstr;
292 } else {
293 sprintf(titlebuf, "#%d", ag->id);
294 title = copy_string(titlebuf);
295 }
296 ag->name = title;
297 /* The creating side is by definition one of the drafters. */
298 ag->drafters = add_side_to_set(side, ag->drafters);
299 }
300
301 void
302 do_agreement_drafter(Side *side)
303 {
304 DURING_GAME_ONLY(side);
305 }
306
307 void
308 do_agreement_propose(Side *side)
309 {
310 DURING_GAME_ONLY(side);
311 }
312
313 void
314 do_agreement_proposer(Side *side)
315 {
316 DURING_GAME_ONLY(side);
317 }
318
319 void
320 do_agreement_sign(Side *side)
321 {
322 DURING_GAME_ONLY(side);
323 }
324
325 void
326 do_agreement_signer(Side *side)
327 {
328 DURING_GAME_ONLY(side);
329 }
330
331 void
332 do_agreement_term(Side *side)
333 {
334 int agid, agterm;
335 char *arg, *rest, *term;
336 Agreement *ag;
337
338 DURING_GAME_ONLY(side);
339 rest = get_next_arg(cmdargstr, tmpbuf, &arg);
340 if (empty_string(arg)) {
341 cmd_error(side, "no agreement id");
342 return;
343 }
344 agid = strtol(arg, NULL, 10);
345 agterm = 0;
346 if (isdigit(*rest)) {
347 rest = get_next_arg(rest, tmpbuf, &arg);
348 agterm = strtol(arg, NULL, 10);
349 }
350 term = copy_string(rest);
351 ag = find_agreement(agid);
352 if (ag == NULL) {
353 cmd_error(side, "no agreement #%d", agid);
354 return;
355 }
356 /* (should be kernel function) */
357 ag->terms = cons(new_string(term), ag->terms);
358 }
359
360 #endif
361
362 /* Set which AI is to run the side's play. */
363
364 void
do_ai_side(Side * side)365 do_ai_side(Side *side)
366 {
367 char *arg, *rest, *aitypename = NULL;
368
369 DURING_GAME_ONLY(side);
370 /* Look at the optional command argument, extract options and/or
371 AI type name from it. */
372 if (!empty_string(cmdargstr)) {
373 rest = get_next_arg(cmdargstr, tmpbuf, &arg);
374 if (strcmp(arg, "help") == 0
375 || strcmp(arg, "?") == 0) {
376 aitypename = next_ai_type_name(NULL);
377 while (aitypename != NULL) {
378 notify(side, " %s - %s",
379 aitypename, ai_type_help(find_ai_type(aitypename)));
380 aitypename = next_ai_type_name(aitypename);
381 }
382 return;
383 } else if (strcmp(arg, "+") == 0) {
384 /* Note that this flag is used by local AIs only, so don't
385 need to synchronize kernels here. */
386 side->ai_may_resign = TRUE;
387 notify(side, "AI may decide to draw or resign.");
388 return;
389 } else if (strcmp(arg, "-") == 0) {
390 side->ai_may_resign = FALSE;
391 notify(side, "AI may only recommend whether to draw or resign.");
392 return;
393 }
394 aitypename = arg;
395 }
396 if (empty_string(aitypename)) {
397 /* Toggle AI between mplayer and NULL. */
398 /* (should toggle between "preferred AI" for the side) */
399 if (side->player->aitypename == NULL) {
400 aitypename = "mplayer";
401 } else {
402 aitypename = NULL;
403 }
404 } else if (strcmp(aitypename, "none") == 0) {
405 /* Special case to handle command "AI None" in Side menu. */
406 aitypename = NULL;
407 }
408 /* Feed back to user. Note that we say "want to have" because we
409 haven't gotten feedback from remote programs yet. */
410 if (!empty_string(aitypename)) {
411 notify(side, "Want to have AI %s running this side.",
412 aitypename);
413 } else {
414 notify(side, "Want to have no AI running this side.");
415 }
416 net_set_side_ai(side, aitypename);
417 }
418
419 void
do_auto(Side * side)420 do_auto(Side *side)
421 {
422 DURING_GAME_ONLY(side);
423 apply_to_all_selected_units(side, do_one_auto);
424 }
425
426 static int
do_one_auto(Side * side,Unit * unit)427 do_one_auto(Side *side, Unit *unit)
428 {
429 int newval;
430
431 if (unit->plan == NULL)
432 return FALSE;
433 if (side->prefixarg < 0)
434 newval = !unit->plan->aicontrol;
435 else if (side->prefixarg == 0)
436 newval = FALSE;
437 else
438 newval = TRUE;
439 net_set_unit_ai_control(side, unit, newval, FALSE);
440 net_force_replan(unit);
441 return TRUE;
442 }
443
444 void
do_c_rate(Side * side)445 do_c_rate(Side *side)
446 {
447 int m = NONMTYPE, m1, m2, n, tot, pct;
448 char *str, *reststr;
449 char tbuf[BUFSIZE];
450
451 DURING_GAME_ONLY(side);
452 /* For now, assume only one m. */
453 for_all_material_types(m1) {
454 for_all_material_types(m2) {
455 if (mm_conversion(m1, m2) > 0) {
456 m = m1;
457 break;
458 }
459 }
460 }
461 if (m == NONMTYPE)
462 return;
463 if (side->c_rates == NULL)
464 side->c_rates = (short *) xmalloc(nummtypes * sizeof(short));
465 if (!empty_string(cmdargstr)) {
466 str = cmdargstr;
467 for_all_material_types(m2) {
468 if (mm_conversion(m, m2) > 0) {
469 n = strtol(str, &reststr, 10);
470 str = reststr;
471 /* (should use a net_ routine) */
472 side->c_rates[m2] = n;
473 }
474 }
475 }
476 tot = 0;
477 for_all_material_types(m2) {
478 if (mm_conversion(m, m2) > 0) {
479 tot += side->c_rates[m2];
480 }
481 }
482 tbuf[0] = '\0';
483 for_all_material_types(m2) {
484 if (mm_conversion(m, m2) > 0) {
485 pct = (tot > 0 ? ((side->c_rates[m2] * 100) / tot) : 0);
486 sprintf(tbuf+strlen(tbuf), " %s %d%%", m_type_name(m2), pct);
487 }
488 }
489 notify(side, "%s conversion rates: %s", m_type_name(m), tbuf);
490 }
491
492 void
do_clear_plan(Side * side)493 do_clear_plan(Side *side)
494 {
495 DURING_GAME_ONLY(side);
496 apply_to_all_selected_units(side, do_one_clear_plan);
497 }
498
499 static int
do_one_clear_plan(Side * side,Unit * unit)500 do_one_clear_plan(Side *side, Unit *unit)
501 {
502 if (unit->plan == NULL)
503 return FALSE;
504 net_set_unit_plan_type(side, unit, PLAN_NONE);
505 return TRUE;
506 }
507
508 void
do_delay(Side * side)509 do_delay(Side *side)
510 {
511 DURING_GAME_ONLY(side);
512 apply_to_all_selected_units(side, do_one_delay);
513 }
514
515 static int
do_one_delay(Side * side,Unit * unit)516 do_one_delay(Side *side, Unit *unit)
517 {
518 if (unit->plan == NULL)
519 return FALSE;
520 net_delay_unit(unit, TRUE);
521 return TRUE;
522 #if 0 /* add this case from tkcmd.c? */
523 unit = find_next_awake_mover(side, map->curunit);
524 if (unit != map->curunit) {
525 set_current_unit(map, unit);
526 } else {
527 cmd_error(side, "No next awake mover found.");
528 }
529 #endif
530 }
531
532 void
do_detach(Side * side)533 do_detach(Side *side)
534 {
535 DURING_GAME_ONLY(side);
536 apply_to_all_selected_units(side, do_one_detach);
537 }
538
539 static int
do_one_detach(Side * side,Unit * unit)540 do_one_detach(Side *side, Unit *unit)
541 {
542 int rslt;
543
544 if (!completed(unit)) {
545 cmd_error(side, "%s is incomplete; cannot detach",
546 unit_handle(side, unit));
547 return FALSE;
548 }
549 rslt = check_transfer_part_action(unit, unit, unit->hp / 2, NULL);
550 if (valid(rslt)) {
551 net_prep_transfer_part_action(unit, unit, unit->hp / 2, NULL);
552 } else {
553 notify(side, "can't detach for some reason?");
554 }
555 return TRUE;
556 }
557
558 void
do_detonate(Side * side)559 do_detonate(Side *side)
560 {
561 DURING_GAME_ONLY(side);
562 /* (should add Mac version's choice of where to detonate?) */
563 apply_to_all_selected_units(side, do_one_detonate);
564 }
565
566 static int
do_one_detonate(Side * side,Unit * unit)567 do_one_detonate(Side *side, Unit *unit)
568 {
569 int rslt;
570
571 rslt = check_detonate_action(unit, unit, unit->x, unit->y, unit->z);
572 if (valid(rslt)) {
573 net_prep_detonate_action(unit, unit, unit->x, unit->y, unit->z);
574 return TRUE;
575 } else {
576 notify(side, "can't detonate for some reason?");
577 return FALSE;
578 }
579 }
580
581 /* Get rid of a unit. */
582
583 void
do_disband(Side * side)584 do_disband(Side *side)
585 {
586 DURING_GAME_ONLY(side);
587 apply_to_all_selected_units(side, do_one_disband);
588 }
589
590 static int
do_one_disband(Side * side,Unit * unit)591 do_one_disband(Side *side, Unit *unit)
592 {
593 /* (should have more feedback?) */
594 net_disband_unit(side, unit);
595 return TRUE;
596 }
597
598 void
do_disembark(Side * side)599 do_disembark(Side *side)
600 {
601 DURING_GAME_ONLY(side);
602 apply_to_all_selected_units(side, do_one_disembark);
603 }
604
605 static int
do_one_disembark(Side * side,Unit * unit)606 do_one_disembark(Side *side, Unit *unit)
607 {
608 Unit *transport;
609
610 transport = unit->transport;
611 if (transport == NULL) {
612 cmd_error(side, "Not in a transport");
613 return FALSE;
614 }
615 if (!in_play(transport)) {
616 cmd_error(side, "Transport is nonsensical?");
617 return FALSE;
618 }
619 /* Try moving into the transport's transport, if there is one. */
620 if (transport->transport != NULL
621 && can_occupy(unit, transport->transport)) {
622 net_prep_enter_action(unit, unit, transport->transport);
623 /* (should be able to set up task if can't do action immediately) */
624 return TRUE;
625 }
626 /* Try moving into the open in the cell. We don't test for
627 type_survives_in_cell here, so it is possible to deliberately
628 jump overboard. */
629 if (type_can_occupy_cell(unit->type, unit->x, unit->y)) {
630 net_prep_move_action(unit, unit, unit->x, unit->y, unit->z);
631 /* (should be able to set up task if can't do action immediately) */
632 return TRUE;
633 }
634 cmd_error(side, "Can't disembark here!");
635 return FALSE;
636 }
637
638 void
do_distrust(Side * side)639 do_distrust(Side *side)
640 {
641 Side *side2;
642
643 DURING_GAME_ONLY(side);
644 if (empty_string(cmdargstr)) {
645 notify_relationships(side);
646 return;
647 }
648 side2 = parse_side_spec(cmdargstr);
649 if (side2 == NULL) {
650 cmd_error(side, "No side matching \"%s\"", cmdargstr);
651 return;
652 }
653 if (side2 == side) {
654 cmd_error(side, "We're not confused about trusting ourselves!");
655 return;
656 }
657 net_set_trust(side, side2, 0);
658 }
659
660 void
notify_relationships(Side * side)661 notify_relationships(Side *side)
662 {
663 char *buf, buf1[1000], buf2[1000], buf3[1000], buf4[1000];
664 Side *side2;
665
666 /* List the status of all other sides wrt us. */
667 buf1[0] = buf2[0] = buf3[0] = buf4[0] = '\0';
668 for_all_sides(side2) {
669 if (side2 != side) {
670 /* Choose which of four possible buckets the side falls into. */
671 if (trusted_side(side, side2)) {
672 if (trusted_side(side2, side)) {
673 buf = buf1;
674 } else {
675 buf = buf2;
676 }
677 } else {
678 if (trusted_side(side2, side)) {
679 buf = buf3;
680 } else {
681 buf = buf4;
682 }
683 }
684 /* Add the side's title to the chosen bucket. */
685 if (strlen(buf) > 0)
686 strcat(buf, ", ");
687 strcat(buf, short_side_title(side2));
688 }
689 }
690 /* Describe each bucket. */
691 if (strlen(buf1) > 0)
692 notify(side, "We trust them, and vice versa: %s.", buf1);
693 if (strlen(buf2) > 0)
694 notify(side, "We trust them, but they don't trust us: %s.", buf2);
695 if (strlen(buf3) > 0)
696 notify(side, "They trust us, but we don't trust them: %s.", buf3);
697 if (strlen(buf4) > 0)
698 notify(side, "We don't trust them, and vice versa: %s.", buf4);
699 }
700
701 void
do_doctrine(Side * side)702 do_doctrine(Side *side)
703 {
704 DURING_GAME_ONLY(side);
705 if (!empty_string(cmdargstr)) {
706 if (strcmp(cmdargstr, "set") == 0) {
707 notify(side, "Set what?");
708 } else if (strncmp(cmdargstr, "set ", 4) == 0) {
709 net_set_doctrine(side, cmdargstr + 4);
710 } else if (strcmp(cmdargstr, "help") == 0
711 || strcmp(cmdargstr, "?") == 0) {
712 notify(side, "doctrine set <doct-name> <property> <value>");
713 notify(side, "\"doctrine\" alone to see current settings");
714 }
715 return;
716 }
717 notify_doctrine(side, cmdargstr);
718 }
719
720 void
do_down(Side * side)721 do_down(Side *side)
722 {
723 cmd_error(side, "not yet implemented");
724 }
725
726 void
do_draw_willingness(Side * side)727 do_draw_willingness(Side *side)
728 {
729 DURING_GAME_ONLY(side);
730 if (side->prefixarg < 0)
731 side->prefixarg = 1;
732 net_set_willing_to_draw(side, (side->prefixarg ? 1 : 0));
733 }
734
735 void
do_embark(Side * side)736 do_embark(Side *side)
737 {
738 DURING_GAME_ONLY(side);
739 apply_to_all_selected_units(side, do_one_embark);
740 }
741
742 static int
do_one_embark(Side * side,Unit * unit)743 do_one_embark(Side *side, Unit *unit)
744 {
745 Unit *transport;
746
747 transport = embarkation_unit(unit);
748 if (transport != NULL) {
749 net_prep_enter_action(unit, unit, transport);
750 return TRUE;
751 }
752 cmd_error(side, "Nothing for %s to enter!", unit_handle(side, unit));
753 return FALSE;
754 }
755
756 /* Command to end the side's activity for the turn. */
757
758 void
do_end_turn(Side * side)759 do_end_turn(Side *side)
760 {
761 DURING_GAME_ONLY(side);
762 net_finish_turn(side);
763 }
764
765 void
do_force_global_replan(Side * side)766 do_force_global_replan(Side *side)
767 {
768 Unit *unit;
769
770 DURING_GAME_ONLY(side);
771 for_all_side_units(side, unit) {
772 if (in_play(unit) && unit->plan != NULL) {
773 net_force_replan(unit);
774 }
775 }
776 }
777
778 void
do_give(Side * side)779 do_give(Side *side)
780 {
781 DURING_GAME_ONLY(side);
782 if (nummtypes == 0) {
783 cmd_error(side, "No materials in this game!");
784 return;
785 }
786 apply_to_all_selected_units(side, do_one_give);
787 }
788
789 static short *gt_amts;
790 static short *gt_rslts;
791
792 static int
do_one_give(Side * side,Unit * unit)793 do_one_give(Side *side, Unit *unit)
794 {
795 short m;
796 Unit *unit2;
797
798 if (gt_amts == NULL)
799 gt_amts = (short *) xmalloc(nummtypes * sizeof(short));
800 if (gt_rslts == NULL)
801 gt_rslts = (short *) xmalloc(nummtypes * sizeof(short));
802
803 for_all_material_types(m)
804 gt_amts[m] = side->prefixarg;
805 unit2 = give_supplies(unit, gt_amts, gt_rslts);
806 report_give(side, unit, unit2, gt_rslts);
807 return TRUE;
808 }
809
810 /* Tell the unit to sit around for a given number of turns. */
811
812 void
do_idle(Side * side)813 do_idle(Side *side)
814 {
815 DURING_GAME_ONLY(side);
816 apply_to_all_selected_units(side, do_one_idle);
817 }
818
819 static int
do_one_idle(Side * side,Unit * unit)820 do_one_idle(Side *side, Unit *unit)
821 {
822 if (side->prefixarg < 0)
823 side->prefixarg = 9999;
824 net_set_sentry_task(unit, side->prefixarg);
825 return TRUE;
826 }
827
828 /* Release a controlled side to act independently. */
829
830 void
do_release(Side * side)831 do_release(Side *side)
832 {
833 Side *side2;
834
835 DURING_GAME_ONLY(side);
836 if (empty_string(cmdargstr)) {
837 cmd_error(side, "No side given to release!");
838 return;
839 }
840 side2 = parse_side_spec(cmdargstr);
841 if (side2 == NULL) {
842 cmd_error(side, "Can't get a side from \"%s\"!", cmdargstr);
843 return;
844 }
845 if (side2 == side) {
846 cmd_error(side, "Can't release ourselves!?");
847 return;
848 }
849 if (side2->controlled_by != side) {
850 cmd_error(side, "You don't control %s!", short_side_title(side2));
851 return;
852 }
853 /* Modify the controllee's bit, not the controller's. */
854 net_set_controlled_by(side2, side, FALSE);
855 }
856
857 /* Set a side's current research topic. */
858
859 void
do_research(Side * side)860 do_research(Side *side)
861 {
862 int a;
863
864 DURING_GAME_ONLY(side);
865 if (numatypes == 0) {
866 cmd_error(side, "No research in this game.");
867 return;
868 }
869 if (!empty_string(cmdargstr)) {
870 if (!g_side_can_research()) {
871 cmd_error(side, "Side cannot do research.");
872 return;
873 }
874 if (strcmp(cmdargstr, "nothing") == 0) {
875 notify(side, "Your wise men will rest now.");
876 net_set_side_research_topic(side, NONATYPE);
877 return;
878 }
879 a = parse_advance_spec(cmdargstr);
880 if (a == -1) {
881 cmd_error(side, "Not a valid advance: \"%s\"", cmdargstr);
882 return;
883 } else if (a == -2) {
884 cmd_error(side, "Ambiguous: \"%s\"", cmdargstr);
885 return;
886 }
887 notify(side, "Your wise men will search for the secret of %s.",
888 a_type_name(a));
889 net_set_side_research_topic(side, a);
890 return;
891 } else {
892 int i = 0;
893 char abuf[BUFSIZE];
894
895 if (g_side_can_research()) {
896 a = side->research_topic;
897 if (a == NOADVANCE) {
898 notify(side, "Your wise men are waiting for a research area.");
899 } else if (a == NONATYPE) {
900 notify(side, "Your wise men are resting.");
901 } else {
902 notify(side,
903 "Your wise men are %d/%d of the way to achieving %s.",
904 side->advance[a], a_rp(a), a_type_name(a));
905 }
906 }
907 /* List the available advances. */
908 /* (should be a separate function perhaps) */
909 strcpy(abuf, "Next advances: ");
910 for_all_advance_types(a) {
911 if (side_can_research(side, a)) {
912 if (i > 0)
913 strcat(abuf, ", ");
914 strcat(abuf, a_type_name(a));
915 ++i;
916 if (i == 4) {
917 notify(side, "%s", abuf);
918 abuf[0] = '\0';
919 i = 0;
920 }
921 }
922 }
923 if (i > 0)
924 notify(side, "%s", abuf);
925 }
926 }
927
928 /* Given a string, find an advance whose name at least partially matches. */
929
930 int
parse_advance_spec(char * str)931 parse_advance_spec(char *str)
932 {
933 int a, rslt = -1;
934
935 for_all_advance_types(a) {
936 if (strstr(a_type_name(a), str)) {
937 if (rslt >= 0) {
938 return -2;
939 }
940 rslt = a;
941 }
942 }
943 return rslt;
944 }
945
946 /* Make the selected units sleep just for the remainder of the current
947 turn. */
948
949 void
do_reserve(Side * side)950 do_reserve(Side *side)
951 {
952 DURING_GAME_ONLY(side);
953 apply_to_all_selected_units(side, do_one_reserve);
954 }
955
956 static int
do_one_reserve(Side * side,Unit * unit)957 do_one_reserve(Side *side, Unit *unit)
958 {
959 net_set_unit_reserve(side, unit, TRUE, FALSE);
960 return TRUE;
961 }
962
963 /* Set up tasks to resupply the selected units. */
964
965 /* (should warn if task is likely to fail) */
966
967 void
do_return(Side * side)968 do_return(Side *side)
969 {
970 DURING_GAME_ONLY(side);
971 apply_to_all_selected_units(side, do_one_return);
972 }
973
974 static int
do_one_return(Side * side,Unit * unit)975 do_one_return(Side *side, Unit *unit)
976 {
977 /* (should doublecheck range and error out if no chance) */
978 net_set_resupply_task(unit, NONMTYPE);
979 return TRUE;
980 }
981
982 /* Auto-finish turns, for the given number of turns. */
983
984 void
do_run(Side * side)985 do_run(Side *side)
986 {
987 int turns;
988
989 DURING_GAME_ONLY(side);
990 if (!empty_string(cmdargstr))
991 turns = atoi(cmdargstr);
992 else
993 turns = side->prefixarg;
994 if (turns < 0)
995 turns = 0;
996 notify(side, "Running free for %d turn%s.",
997 turns, (turns == 1 ? "" : "s"));
998 if (turns > 0) {
999 net_set_autofinish(side, TRUE);
1000 autofinish_start = g_turn();
1001 autofinish_count = turns;
1002 }
1003 }
1004
1005 /* Set the rate at which AIs move their units. */
1006
1007 void
do_set_rate(Side * side)1008 do_set_rate(Side *side)
1009 {
1010 int slow, fast;
1011 char *reststr;
1012
1013 DURING_GAME_ONLY(side);
1014 if (!empty_string(cmdargstr)) {
1015 slow = strtol(cmdargstr, &reststr, 10);
1016 fast = strtol(reststr, &reststr, 10);
1017 set_play_rate(slow, fast);
1018 }
1019 }
1020
1021 /* Put a unit to sleep, which means it is inactive each turn until it
1022 is woken up, either by some alarm going off (such as low supply) or
1023 by explicit player action. */
1024
1025 void
do_sleep(Side * side)1026 do_sleep(Side *side)
1027 {
1028 DURING_GAME_ONLY(side);
1029 apply_to_all_selected_units(side, do_one_sleep);
1030 }
1031
1032 static int
do_one_sleep(Side * side,Unit * unit)1033 do_one_sleep(Side *side, Unit *unit)
1034 {
1035 net_set_unit_asleep(side, unit, TRUE, FALSE);
1036 return TRUE;
1037 }
1038
1039 /* Submit to (become controlled by) the specified side. */
1040
1041 void
do_submit(Side * side)1042 do_submit(Side *side)
1043 {
1044 Side *side2;
1045
1046 DURING_GAME_ONLY(side);
1047 if (side->controlled_by != NULL) {
1048 cmd_error(side, "You are already controlled by %s!",
1049 short_side_title(side->controlled_by));
1050 }
1051 if (empty_string(cmdargstr)) {
1052 cmd_error(side, "No side given to submit to!");
1053 return;
1054 }
1055 side2 = parse_side_spec(cmdargstr);
1056 if (side2 == NULL) {
1057 cmd_error(side, "Can't get a side from \"%s\"!", cmdargstr);
1058 return;
1059 }
1060 if (side2 == side) {
1061 cmd_error(side, "Can't submit to ourselves!?");
1062 return;
1063 }
1064 net_set_controlled_by(side, side2, TRUE);
1065 /* (should draw emblem inverted underneath controller's emblem) */
1066 }
1067
1068 /* Take supplies from transport. */
1069
1070 void
do_take(Side * side)1071 do_take(Side *side)
1072 {
1073 DURING_GAME_ONLY(side);
1074 if (nummtypes == 0) {
1075 cmd_error(side, "No materials in this game!");
1076 return;
1077 }
1078 apply_to_all_selected_units(side, do_one_take);
1079 }
1080
1081 static int
do_one_take(Side * side,Unit * unit)1082 do_one_take(Side *side, Unit *unit)
1083 {
1084 short m, needed;
1085
1086 if (gt_amts == NULL)
1087 gt_amts = (short *) xmalloc(nummtypes * sizeof(short));
1088 if (gt_rslts == NULL)
1089 gt_rslts = (short *) xmalloc(nummtypes * sizeof(short));
1090
1091 for_all_material_types(m)
1092 gt_amts[m] = side->prefixarg;
1093 needed = take_supplies(unit, gt_amts, gt_rslts);
1094 report_take(side, unit, needed, gt_rslts);
1095 return TRUE;
1096 }
1097
1098 void
do_trust(Side * side)1099 do_trust(Side *side)
1100 {
1101 Side *side2;
1102
1103 DURING_GAME_ONLY(side);
1104 if (empty_string(cmdargstr)) {
1105 notify_relationships(side);
1106 return;
1107 }
1108 side2 = parse_side_spec(cmdargstr);
1109 if (side2 == NULL) {
1110 cmd_error(side, "No side matching \"%s\"", cmdargstr);
1111 return;
1112 }
1113 if (side2 == side) {
1114 cmd_error(side, "We're not confused about trusting ourselves!");
1115 return;
1116 }
1117 net_set_trust(side, side2, 1);
1118 }
1119
1120 void
do_wake(Side * side)1121 do_wake(Side *side)
1122 {
1123 DURING_GAME_ONLY(side);
1124 apply_to_all_selected_units(side, do_one_wake);
1125 }
1126
1127 static int
do_one_wake(Side * side,Unit * unit)1128 do_one_wake(Side *side, Unit *unit)
1129 {
1130 net_wake_unit(side, unit, FALSE);
1131 /* If an argument was given, apply to all "top-level" units within
1132 the radius specified by the argument. */
1133 if (side->prefixarg >= 0)
1134 net_wake_area(side, unit->x, unit->y, side->prefixarg, FALSE);
1135 return 1;
1136 }
1137
1138 void
do_wake_all(Side * side)1139 do_wake_all(Side *side)
1140 {
1141 DURING_GAME_ONLY(side);
1142 apply_to_all_selected_units(side, do_one_wake_all);
1143 }
1144
1145 static int
do_one_wake_all(Side * side,Unit * unit)1146 do_one_wake_all(Side *side, Unit *unit)
1147 {
1148 net_wake_unit(side, unit, TRUE);
1149 /* If an argument was given, apply to all units and occs within
1150 the radius specified by the argument. */
1151 if (side->prefixarg >= 0)
1152 net_wake_area(side, unit->x, unit->y, side->prefixarg, TRUE);
1153 return 1;
1154 }
1155
1156 void
do_warning_log(Side * side)1157 do_warning_log(Side *side)
1158 {
1159 warnings_logged = !warnings_logged;
1160 if (warnings_logged)
1161 notify_all("Warnings now being logged in \"Xconq.Warnings\".\n");
1162 else
1163 notify_all("Warnings will not be logged.\n");
1164 }
1165
1166 #ifdef DESIGNERS
1167
1168 void
do_gdl(Side * side)1169 do_gdl(Side *side)
1170 {
1171 /* (should check designer status?) */
1172 if (!empty_string(cmdargstr))
1173 interp_form(NULL, read_form_from_string(cmdargstr, NULL, NULL, NULL));
1174 /* (should broadcast to all?) */
1175 }
1176
1177 #endif /* DESIGNERS */
1178
1179 #ifdef DEBUGGING
1180
1181 /* Debugging-related commands. */
1182
1183 /* General debugging toggles. */
1184
1185 void
do_debug(Side * side)1186 do_debug(Side *side)
1187 {
1188 #ifndef Debug
1189 toggle_debugging(&Debug);
1190 #endif
1191 notify_all("Debugging: %d", Debug);
1192 update_everything();
1193 }
1194
1195 void
do_debugg(Side * side)1196 do_debugg(Side *side)
1197 {
1198 #ifndef DebugG
1199 toggle_debugging(&DebugG);
1200 #endif
1201 notify_all("Graphics debugging: %d", DebugG);
1202 update_everything();
1203 }
1204
1205 void
do_debugm(Side * side)1206 do_debugm(Side *side)
1207 {
1208 #ifndef DebugM
1209 toggle_debugging(&DebugM);
1210 #endif
1211 notify_all("Machine play/AI debugging: %d", DebugM);
1212 update_everything();
1213 }
1214
1215 #endif /* DEBUGGING */
1216