1 /* Commands for the curses interface to Xconq.
2    Copyright (C) 1986-1989, 1991-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 #include "conq.h"
10 #include "kpublic.h"
11 #include "cconq.h"
12 #include "aiunit.h"
13 #include "aiunit2.h"
14 
15 extern int drawlinear;
16 extern char linear_char;
17 extern char bord_char;
18 extern char conn_char;
19 
20 static void resize_map(int n);
21 
22 #if 0 /* (should preserve in help somewhere) */
23     tbcat(buf, "To move a unit, use [hjklyubn]\n");
24     tbcat(buf, "[HJKLYUBN] moves unit repeatedly in that direction\n");
25     tbcat(buf, "To look at another unit, use survey mode ('z')\n");
26     tbcat(buf, "and use [hjklyubnHJKLYUBN] to move the cursor\n");
27 #endif
28 
29 /* Use this macro in any command if it requires a current unit. */
30 
31 #define REQUIRE_UNIT()  \
32   if (!in_play(curunit)) {  \
33     curunit = NULL;  \
34     cmd_error(side, "No current unit to command!");  \
35     return;  \
36   }
37 
38 Unit *lastactor = NULL;
39 
40 Unit *
find_next_and_look()41 find_next_and_look()
42 {
43     Unit *nextunit;
44 
45     nextunit = find_next_actor(dside, curunit);
46     if (nextunit != NULL) {
47 	make_current(nextunit);
48 	show_cursor();
49     }
50     return nextunit;
51 }
52 
53 static UnitVector *selvec;
54 
55 UnitVector *
get_selected_units(Side * side)56 get_selected_units(Side *side)
57 {
58     if (selvec == NULL)
59       selvec = make_unit_vector(2);
60     clear_unit_vector(selvec);
61     if (in_play(curunit))
62       selvec = add_unit_to_vector(selvec, curunit, 0);
63     return selvec;
64 }
65 
66 void
do_add_terrain(Side * side)67 do_add_terrain(Side *side)
68 {
69     int u, t, dir;
70 
71     REQUIRE_UNIT();
72     u = curunit->type;
73     if (ask_direction("Add terrain to where?", &dir)) {
74 	for_all_terrain_types(t) {
75 	    if (ut_acp_to_add_terrain(u, t) > 0
76 		&& curunit->act
77 		&& curunit->act->acp >= ut_acp_to_add_terrain(u, t)) {
78 		if (0 <= ut_alter_range(curunit->type, t)) {
79 		    if (net_prep_add_terrain_action(curunit, curunit,
80 						curunit->x, curunit->y,
81 						dir, t))
82 		      ;
83 		    else
84 		      xbeep();
85 		}
86 	    }
87 	}
88     }
89 }
90 
91 void
do_attack(Side * side)92 do_attack(Side *side)
93 {
94     int x, y;
95     Unit *other;
96 
97     REQUIRE_UNIT();
98     if (ask_position("Attack where?", &x, &y)) {
99 	for_all_stack(x, y, other) {
100 	    if (!unit_trusts_unit(curunit, other)) {
101 		if (valid(check_attack_action(curunit, curunit, other, 100))) {
102 		    net_prep_attack_action(curunit, curunit, other, 100);
103 		    return;
104 		}
105 		/* (should try other types of actions?) */
106 	    }
107 	}
108 	cmd_error(side, "Nothing for %s to attack at %d,%d!",
109 		  unit_handle(dside, curunit), x, y);
110     }
111 }
112 
113 void
do_build(Side * side)114 do_build(Side *side)
115 {
116     int u, u2, numtypes, ufirst;
117 
118     REQUIRE_UNIT();
119     u = curunit->type;
120     if (!can_build(curunit)) {
121 	cmd_error(side, "%s cannot build anything!", unit_handle(dside, curunit));
122 	return;
123     }
124     numtypes = 0;
125     for_all_unit_types(u2) {
126 	if (unit_can_build_type(curunit, u2)) {
127 	    tmp_u_array[u2] = TRUE;
128 	    ++numtypes;
129 	    ufirst = u2;
130 	} else {
131 	    tmp_u_array[u2] = FALSE;
132 	}
133     }
134     if (curunit->transport != NULL
135 	&& !uu_occ_can_build(curunit->transport->type, u)
136 	&& !(!completed(curunit->transport)
137 	     && uu_acp_to_build(u, curunit->transport->type) > 0)) {
138 	cmd_error(side, "%s cannot build while inside another unit!",
139 		  unit_handle(side, curunit));
140 	return;
141     }
142     switch (numtypes) {
143       case 0:
144 	cmd_error(side, "%s cannot build anything right now!",
145 			unit_handle(side, curunit));
146 	break;
147       case 1:
148 	/* Only one type to build - just do it. */
149 	if (valid(can_create_in(curunit, curunit, ufirst, curunit)))
150 	    impl_build(side, curunit, ufirst, curunit, -1, -1, prefixarg);
151 	else
152 	    impl_build(
153 		side, curunit, ufirst, NULL, curunit->x, curunit->y, prefixarg);
154 	break;
155       default:
156 	/* Player has to choose a type to build. */
157 	u2 = ask_unit_type("Type to build:", tmp_u_array);
158 	if (u2 != NONUTYPE) {
159 	    if (valid(can_create_in(curunit, curunit, ufirst, curunit)))
160 		impl_build(side, curunit, u2, curunit, -1, -1, prefixarg);
161 	    else
162 		impl_build(
163 		    side, curunit, ufirst, NULL, curunit->x, curunit->y,
164 		    prefixarg);
165 	} else {
166 	    /* should clear toplines */
167 	}
168 	break;
169     }
170 }
171 
172 void
do_change_type(Side * side)173 do_change_type(Side *side)
174 {
175     int u = NONUTYPE, u2 = NONUTYPE, numtypes = 0, ufirst = NONUTYPE;
176 
177     REQUIRE_UNIT();
178     u = curunit->type;
179     if (curunit->side != side) {
180         cmd_error(side, "%s is not your unit!", unit_handle(side, curunit));
181         return;
182     }
183     for_all_unit_types(u2) {
184         if (uu_acp_to_change_type(curunit->type, u2)) {
185             tmp_u_array[u2] = TRUE;
186             ++numtypes;
187             ufirst = u2;
188         }
189         else {
190             tmp_u_array[u2] = FALSE;
191         }
192     }
193     switch (numtypes) {
194       case 0:
195         cmd_error(side, "Cannot change to any type right now!");
196         break;
197       case 1:
198         /* Only one possible type to change to. Change to it. */
199         impl_change_type(side, curunit, ufirst);
200         break;
201       default:
202         u2 = ask_unit_type("Type to change into:", tmp_u_array);
203         if (u2 != NONUTYPE) {
204             impl_change_type(side, curunit, ufirst);
205         }
206         else {
207             /* should clear toplines */
208         }
209         break;
210     }
211 }
212 
213 void
do_collect(Side * side)214 do_collect(Side *side)
215 {
216     int mtocollect;
217     char *arg, *rest;
218 
219     REQUIRE_UNIT();
220     mtocollect = NONMTYPE;
221     if (nummtypes == 0) {
222 	cmd_error(side, "No materials to collect");
223 	return;
224     }
225     if (!empty_string(cmdargstr)) {
226 	rest = get_next_arg(cmdargstr, tmpbuf, &arg);
227 	mtocollect = mtype_from_name(arg);
228     } else {
229 	cmd_error(side, "No material name given");
230 	return;
231     }
232     if (!is_material_type(mtocollect)) {
233 	cmd_error(side, "`%s' is not a recognized material name", arg);
234 	return;
235     }
236     if (curunit->plan)
237       net_set_collect_task(curunit, mtocollect, curunit->x, curunit->y);
238 }
239 
240 void
do_copying(Side * side)241 do_copying(Side *side)
242 {
243     cur_help_node = copying_help_node;
244     do_help(side);
245 }
246 
247 /* Supposedly you could only get to these by typing the full command names. */
248 
249 void
do_dir(Side * side)250 do_dir(Side *side)
251 {
252     int ndirs, dir1, dir2, modif;
253 
254     ndirs = char_to_dir(tmpkey, &dir1, &dir2, &modif);
255     if (ndirs >= 1) {
256 	do_dir_2(dir1, prefixarg);
257     } else {
258 	xbeep();
259 	return;
260     }
261 }
262 
263 void
do_dir_multiple(Side * side)264 do_dir_multiple(Side *side)
265 {
266     cmd_error(side, "use the single-character commands instead");
267 }
268 
269 /* Determine how far away another point is.  */
270 
271 void
do_distance(Side * side)272 do_distance(Side *side)
273 {
274     int x, y;
275 
276     if (ask_position("Distance to where?", &x, &y)) {
277 	notify(dside, "Distance is %d cells.", distance(curx, cury, x, y));
278     }
279 }
280 
281 void
do_escape(Side * side)282 do_escape(Side *side)
283 {
284     cmd_error(side, "No curses version of this command.");
285 }
286 
287 /* Command to fire at a specified unit or location. */
288 
289 void
do_fire(Side * side)290 do_fire(Side *side)
291 {
292     int x, y;
293     Unit *unit2;
294     UnitView *uview;
295 
296     REQUIRE_UNIT();
297     sprintf(spbuf, "Fire %s at where?", unit_handle(dside, curunit));
298     /* (should have some sort of range feedback) */
299     if (ask_position(spbuf, &x, &y)) {
300 	for_all_view_stack(dside, x, y, uview) {
301 	    unit2 = view_unit(uview);
302 	    /* (should avoid shooting at allies too) */
303 	    if (unit2 != NULL
304 		&& unit2->side != curunit->side
305 		&& uview->date == g_turn()) {
306 		net_prep_fire_at_action(curunit, curunit, unit2, -1);
307 		return;
308 	    }
309 	}
310 	notify(dside, "No target unit seen, firing blindly");
311 	net_prep_fire_into_action(curunit, curunit, x, y, 0, -1);
312     }
313 }
314 
315 void
do_fire_into(Side * side)316 do_fire_into(Side *side)
317 {
318     int x, y;
319 
320     REQUIRE_UNIT();
321     sprintf(spbuf, "Fire %s at where?", unit_handle(dside, curunit));
322     /* (should have some sort of range feedback) */
323     if (ask_position(spbuf, &x, &y)) {
324 	net_prep_fire_into_action(curunit, curunit, x, y, 0, -1);
325     }
326 }
327 
328 void
do_flash(Side * side)329 do_flash(Side *side)
330 {
331     cmd_error(side, "No curses version of this command.");
332 }
333 
334 /* Toggle the action following flag. */
335 
336 void
do_follow_action(Side * side)337 do_follow_action(Side *side)
338 {
339     follow_action = !follow_action;
340     if (follow_action) {
341 	notify(dside, "Following the action.");
342     } else {
343 	notify(dside, "Not following the action.");
344     }
345 }
346 
347 /* Give a unit to another side or "to" independence. */
348 
349 void
do_give_unit(Side * side)350 do_give_unit(Side *side)
351 {
352     REQUIRE_UNIT();
353 #ifdef DESIGNERS
354     if (dside->designer) {
355 	net_designer_change_side(curunit, side_n(prefixarg));
356 	return;
357     }
358 #endif /* DESIGNERS */
359     if (1) { /* (should test both temporary and permanent invalidity) */
360 	net_prep_change_side_action(curunit, curunit, side_n(prefixarg));
361     } else {
362 	cmd_error(side, "You can't just give away the %s!", unit_handle(dside, curunit));
363     }
364 }
365 
366 /* Bring up help info. */
367 
368 void
do_help(Side * side)369 do_help(Side *side)
370 {
371     /* Switch to help mode, saving current mode first. */
372     prevmode = mode;
373     mode = HELP;
374     show_help();
375     refresh();
376 }
377 
378 /* Set the display of various kinds of data. */
379 
380 void
do_map(Side * side)381 do_map(Side *side)
382 {
383     int value;
384     char *str, *str2, tmpbuf[BUFSIZE];
385 
386     if (cmdargstr) {
387 	str = cmdargstr;
388 	while (*str != '\0') {
389 	    /* Collect the next whitespace-separated token from the
390                arg string. */
391 	    while (*str != '\0' && *str == ' ')
392 	      ++str;
393 	    str2 = tmpbuf;
394 	    while (*str != '\0' && *str != ' ')
395 	      *str2++ = *str++;
396 	    *str2 = '\0';
397 	    str2 = tmpbuf;
398 	    value = TRUE;
399 	    /* See if it is prefixed with a "-" or "no". */
400 	    if (*str2 == '-') {
401 		value = FALSE;
402 		++str2;
403 	    } else if (*str2 == 'n' && *(str2+1) == 'o') {
404 		value = FALSE;
405 		str2 += 2;
406 	    }
407 	    if (strcmp(str2, "terrain") == 0 || strcmp(str2, "t") == 0) {
408 		drawterrain = value;
409 	    } else if (strcmp(str2, "unit") == 0 || strcmp(str2, "u") == 0) {
410 		drawunits = value;
411 	    } else if (strcmp(str2, "name") == 0 || strcmp(str2, "n") == 0) {
412 		drawnames = value;
413 	    } else if (strcmp(str2, "people") == 0 || strcmp(str2, "p") == 0) {
414 		drawpeople = value;
415 	    } else if (strcmp(str2, "cover") == 0 || strcmp(str2, "c") == 0) {
416 		draw_cover = value;
417 	    } else if (strcmp(str2, "one") == 0 || strcmp(str2, "1") == 0) {
418 		use_both_chars = !value;
419 	    } else if (strcmp(str2, "two") == 0 || strcmp(str2, "2") == 0) {
420 		use_both_chars = value;
421 	    } else if (strncmp(str2, "lin", 3) == 0) {
422 		drawlinear = value;
423 		if (value && str2[3] == '=' && str2[4] != '\0') {
424 		    linear_char = str2[4];
425 		}
426 	    } else if (strcmp(str2, ">") == 0) {
427 		if (prefixarg < 0)
428 		  prefixarg = 5;
429 		if (lw <= 5 && prefixarg > 0) {
430 		    cmd_error(side, "list side must be at least 5");
431 		    return;
432 		}
433 		if (lw - prefixarg < 5)
434 		  prefixarg = lw - 5;
435 		resize_map(prefixarg);
436 		return;
437 	    } else if (strcmp(str2, "<") == 0) {
438 		if (prefixarg < 0)
439 		  prefixarg = 5;
440 		if (mw <= 10 && prefixarg > 0) {
441 		    cmd_error(side, "map side must be at least 10");
442 		    return;
443 		}
444 		if (mw - prefixarg < 10)
445 		  prefixarg = mw - 10;
446 		resize_map(0 - prefixarg);
447 		return;
448 	    } else if (strcmp(str2, "_") == 0) {
449 		if (prefixarg < 0)
450 		  prefixarg = 5;
451 		if (prefixarg < 1)
452 		  prefixarg = 1;
453 		if (prefixarg > 10)
454 		  prefixarg = 10;
455 		infoh = prefixarg;
456 		mh = LINES - 2 - infoh - 1;
457 		closeupwin->h = infoh;
458 		mapwin->y = 2 + infoh;
459 		mapwin->h = mh + 1;
460 		/* Update the screen to reflect the changes. */
461 		set_scroll();
462 		redraw();
463 	    } else if (strcmp(str2, "v") == 0) {
464 		if (prefixarg < 0) {
465 		    cycle_list_type();
466 		} else if (prefixarg == 0) {
467 		    cycle_list_filter();
468 		} else if (prefixarg == 1) {
469 		    cycle_list_order();
470 		}
471 		show_list();
472 		refresh();
473 	    } else {
474 		cmd_error(side, "\"%s\" not recognized", tmpbuf);
475 	    }
476 	}
477     } else {
478 	notify(dside, "Nothing to do.");
479     }
480     show_map();
481     refresh();
482 }
483 
484 static void
resize_map(int n)485 resize_map(int n)
486 {
487     /* Resize the left-hand-side windows. */
488     mw += n;
489     closeupwin->w += n;
490     mapwin->w += n;
491     /* Move and resize the right-hand-side windows. */
492     lw -= n;
493     sideswin->x += n;
494     sideswin->w -= n;
495     listwin->x += n;
496     listwin->w -= n;
497     /* Update the screen to reflect the changes. */
498     set_scroll();
499     redraw();
500 }
501 
502 /* Send a short message to another side. */
503 
504 void
do_message(Side * side)505 do_message(Side *side)
506 {
507     char *msg;
508     Side *side2;
509     SideMask sidemask;
510 
511     if (prefixarg == 0) {
512 	/* (should ask who to send to) */
513     }
514     side2 = side_n(prefixarg);
515     if (ask_string("Message:", "", &msg)) {
516 	if (empty_string(msg) || (prefixarg >= 0 && side2 == NULL)) {
517 	    notify(dside, "You keep your mouth shut.");
518 	    sidemask = NOSIDES;
519 	} else if (prefixarg < 0) {
520 	    notify(dside, "You made the announcement \"%s\"", msg);
521 	    sidemask = ALLSIDES;
522 	} else if (side2 != NULL) {
523 	    notify(dside, "Your message was sent.");
524 	    sidemask = add_side_to_set(side2, NOSIDES);
525 	}
526 	if (!empty_string(msg) && sidemask != NOSIDES)
527 	  net_send_message(dside, sidemask, msg);
528     }
529 }
530 
531 /* Set unit to move to a given location.  Designers do a teleport. */
532 
533 void
do_move_to(Side * side)534 do_move_to(Side *side)
535 {
536     int x, y;
537 
538     REQUIRE_UNIT();
539     if (!is_designer(side)) {
540 	if (!mobile(curunit->type)) {
541 	    cmd_error(side, "%s cannot move at all!", unit_handle(side, curunit));
542 	    return;
543 	}
544     }
545     sprintf(spbuf, "Move %s to where?", unit_handle(dside, curunit));
546     if (ask_position(spbuf, &x, &y)) {
547 	if (impl_move_to(side, curunit, x, y, 0)) {
548 	    return;
549 	} else {
550 
551 	}
552     }
553 }
554 
555 /* Command to name or rename the current unit or a given side. */
556 
557 void
do_name(Side * side)558 do_name(Side *side)
559 {
560     char *newname;
561 
562     REQUIRE_UNIT();
563     if (ask_string("New name for unit:", curunit->name, &newname)) {
564 	if (empty_string(newname))
565 	  newname = NULL;
566 	net_set_unit_name(dside, curunit, newname);
567     }
568 }
569 
570 void
do_new_map(Side * side)571 do_new_map(Side *side)
572 {
573     cmd_error(side, "No curses version of this command.");
574 }
575 
576 void
do_occupant(Side * side)577 do_occupant(Side *side)
578 {
579     Unit *nextocc;
580 
581     if (curunit == NULL) {
582 	make_current_at(curx, cury);
583     }
584     REQUIRE_UNIT();
585     nextocc = find_next_occupant(curunit);
586     if (nextocc != curunit)
587       make_current(nextocc);
588 }
589 
590 void
do_orders_popup(Side * side)591 do_orders_popup(Side *side)
592 {
593     cmd_error(side, "No curses version of this command.");
594 }
595 
596 void
do_other(Side * side)597 do_other(Side *side)
598 {
599     char *cmd;
600 
601     if (ask_string("Command:", NULL, &cmd)) {
602 	if (empty_string(cmd)) {
603 	    cmd_error(side, "No command");
604 	} else if (strcmp(cmd, "?") == 0) {
605 	    cur_help_node = long_commands_help_node;
606 	    do_help(side);
607 	} else {
608 	    execute_long_command(side, cmd);
609 	}
610     }
611 }
612 
613 void
do_print_view(Side * side)614 do_print_view(Side *side)
615 {
616     dump_text_view(dside, use_both_chars);
617 }
618 
619 void
do_produce(Side * side)620 do_produce(Side *side)
621 {
622     int m, n;
623     Unit *unit = curunit;
624 
625     REQUIRE_UNIT();
626     if (!can_produce(unit)) {
627 	cmd_error(side, "cannot do active production");
628     }
629     n = 9999;
630     if (prefixarg > 0)
631       n = prefixarg;
632     /* Find the first produceable type and set up to produce it. */
633     for_all_material_types(m) {
634 	if (um_acp_to_produce(unit->type, m) > 0) {
635 	    net_push_produce_task(unit, m, n);
636 	    return;
637 	}
638     }
639 }
640 
641 /* Command to get out of a game, one way or another. */
642 
643 void
do_quit(Side * side)644 do_quit(Side *side)
645 {
646     if (endofgame || beforestart || !dside->ingame) {
647 	exit_cconq();
648 	return;
649     }
650     /* Confirm the saving of any state. */
651     if (!gamestatesafe) {
652 	if (ask_bool("Do you want to save the game?", TRUE)) {
653 	    if (all_others_willing_to_save(dside)) {
654 		do_save(side);
655 		exit_cconq();
656 		return;
657 	    } else {
658 		net_set_willing_to_save(dside, TRUE);
659 		notify(dside, "Other sides not willing to save.");
660 	    }
661 	}
662     }
663     if (all_others_willing_to_quit(dside)) {
664 	if (ask_bool("Do you really want to declare a draw?", FALSE)) {
665 	    net_set_willing_to_draw(dside, TRUE);
666 	} else {
667 	    notify(dside, "Not willing to draw.");
668 	}
669 	return;
670     } else {
671 	if (ask_bool("You must resign to get out; do you want to resign?", FALSE)) {
672 	    do_resign(side);
673 	} else {
674 	    notify(dside, "Not resigning.");
675 	}
676     }
677 }
678 
679 /* Move the current location as close to the center of the display as
680    possible, and redraw everything. */
681 
682 void
do_recenter(Side * side)683 do_recenter(Side *side)
684 {
685     set_view_focus(mvp, curx, cury);
686     center_on_focus(mvp);
687     set_map_viewport();
688     show_map();
689     refresh();
690 }
691 
692 /* Redraw everything using the same code as when windows need a redraw. */
693 
694 void
do_refresh(Side * side)695 do_refresh(Side *side)
696 {
697     redraw();
698 }
699 
700 void
do_remove_terrain(Side * side)701 do_remove_terrain(Side *side)
702 {
703     int t, dir;
704 
705     REQUIRE_UNIT();
706     if (ask_direction("Remove terrain from where?", &dir)) {
707       for_all_terrain_types(t) {
708 	if (ut_acp_to_remove_terrain(curunit->type, t) > 0
709 	    && curunit->act
710 	    && curunit->act->acp >= ut_acp_to_remove_terrain(curunit->type, t)) {
711 	    if (0 <= ut_alter_range(curunit->type, t)) {
712 		if (net_prep_remove_terrain_action(curunit, curunit, curunit->x, curunit->y, dir, t))
713 		  ;
714 		else
715 		  xbeep();
716 	    }
717 	}
718       }
719     }
720 }
721 
722 void
do_repair(Side * side)723 do_repair(Side *side)
724 {
725     cmd_error(side, "repair command not implemented");
726 }
727 
728 void
do_resign(Side * side)729 do_resign(Side *side)
730 {
731     Side *side2;
732 
733     if (endofgame) {
734 	cmd_error(side, "Game is already over.");
735     } else if (!dside->ingame) {
736 	cmd_error(side, "You are already out of the game.");
737     } else if (ask_bool("Do you really want to resign?", FALSE)) {
738 	side2 = NULL;
739 	if (numsides > 2) {
740 	    side2 = ask_side("Who do you want to inherit?", NULL);
741 	    if (side2 == dside) {
742 		cmd_error(side, "You can't inherit your own units! (not giving to anybody)");
743 		side2 = NULL;
744 	    }
745 	}
746 	net_resign_game(dside, side2);
747     }
748 }
749 
750 /* Stuff game state into a file.  By default, it goes into the current
751    directory.  If building a scenario, we can specify just which parts
752    of the game state are to be written. */
753 
754 void
do_save(Side * side)755 do_save(Side *side)
756 {
757     char *rawcontents;
758     Module *module;
759     Obj *contents;
760 
761 #ifdef DESIGNERS
762     if (dside->designer) {
763 	if (ask_string("Data to write?", "everything", &rawcontents)) {
764 	    /* (should be in a designer_create_module?) */
765 	    /* need to be able to get this name from somewhere */
766 	    module = create_game_module("random.scn");
767 	    /* need something better to turn contents into a Lisp object */
768 	    contents = intern_symbol(rawcontents);
769 	    /*	interpret_content_spec(module, contents);  */
770 	    notify(dside, "Module will be written to \"%s\" ...", module->filename);
771 	    /* This seems broken anyway, but we add module->filename to
772 	    make the code compile ... */
773 	    if (write_game_module(module, module->filename)) {
774 		notify(dside, "Done writing to \"%s\".", module->filename);
775 	    } else {
776 		cmd_error(side, "Can't open file \"%s\"!", module->filename);
777 	    }
778 	    return;
779 	} else {
780 	    return;
781 	}
782     }
783 #endif /* DESIGNERS */
784     if (0 /* checkpointing not allowed */) {
785 	if (ask_bool("You really want to save and exit?", FALSE)) {
786 	    notify(dside, "Game will be saved to \"%s\" ...", saved_game_filename());
787 	    if (write_entire_game_state(saved_game_filename())) {
788 		close_displays();
789 		/* this should be conditional? */
790 		exit(0);
791 	    } else {
792 		cmd_error(side, "Can't open file \"%s\"!", saved_game_filename());
793 	    }
794 	}
795     } else {
796 	notify(dside, "Saving...");
797 	if (write_entire_game_state(saved_game_filename())) {
798 	    notify(dside, "Game saved.");
799 	} else {
800 	    cmd_error(side, "Couldn't save to \"%s\"!", saved_game_filename());
801 	}
802     }
803 }
804 
805 void
do_set_formation(Side * side)806 do_set_formation(Side *side)
807 {
808     Unit *leader;
809 
810     REQUIRE_UNIT();
811     sprintf(spbuf, "Which unit to follow?");
812     if (ask_unit(spbuf, &leader)) {
813 	if (!in_play(leader)) {
814 	    cmd_error(side, "No unit to follow!");
815 	} else if (leader == curunit) {
816 	    cmd_error(side, "Unit can't follow itself!");
817 	} else if (leader->side != dside /* or "trusted side"? */) {
818 	    cmd_error(side, "Can't follow somebody else's unit!");
819 	} else {
820 	    net_set_formation(curunit, leader, curunit->x - leader->x, curunit->y - leader->y, 1, 1);
821 	}
822     }
823 }
824 
825 void
do_set_view_angle(Side * side)826 do_set_view_angle(Side *side)
827 {
828     cmd_error(side, "No curses version of this command.");
829 }
830 
831 void
do_side_closeup(Side * side)832 do_side_closeup(Side *side)
833 {
834     cmd_error(side, "No curses version of this command.");
835 }
836 
837 void
do_standing_orders(Side * side)838 do_standing_orders(Side *side)
839 {
840     int rslt;
841 
842     if (cmdargstr) {
843 	rslt = parse_standing_order(dside, cmdargstr);
844 	if (rslt < 0)
845 	  xbeep();
846     } else
847       xbeep();
848 }
849 
850 /* Command to toggle between interaction modes. */
851 
852 void
do_survey(Side * side)853 do_survey(Side *side)
854 {
855     if (mode == MOVE) {
856 	lastactor = curunit;
857 	mode = SURVEY;
858     } else {
859 	mode = MOVE;
860 	/* If we weren't looking at a unit when we switched modes,
861 	   go back to the last unit that was being moved. */
862 	if (curunit == NULL && in_play(lastactor)) {
863 	    make_current(lastactor);
864 	}
865     }
866     show_map();
867     refresh();
868 }
869 
870 void
do_unit_closeup(Side * side)871 do_unit_closeup(Side *side)
872 {
873     cmd_error(side, "No curses version of this command.");
874 }
875 
876 void
do_up(Side * side)877 do_up(Side *side)
878 {
879     cmd_error(side, "No curses version of this command.");
880 }
881 
882 /* Display the program version. */
883 
884 void
do_version(Side * side)885 do_version(Side *side)
886 {
887     notify(dside, "Curses Xconq version %s", version_string());
888     notify(dside, "(c) %s", copyright_string());
889 }
890 
891 void
do_warranty(Side * side)892 do_warranty(Side *side)
893 {
894     cur_help_node = warranty_help_node;
895     do_help(side);
896 }
897 
898 void
do_world_map(Side * side)899 do_world_map(Side *side)
900 {
901     cmd_error(side, "No curses version of this command.");
902 }
903 
904 void
do_zoom_in(Side * side)905 do_zoom_in(Side *side)
906 {
907     cmd_error(side, "No curses version of this command.");
908 }
909 
910 void
do_zoom_out(Side * side)911 do_zoom_out(Side *side)
912 {
913     cmd_error(side, "No curses version of this command.");
914 }
915 
916 #ifdef DESIGNERS
917 
918 void
do_design(Side * side)919 do_design(Side *side)
920 {
921     if (!dside->designer) {
922 	net_become_designer(dside);
923     } else {
924 	net_become_nondesigner(dside);
925     }
926 }
927 
928 #endif /* DESIGNERS */
929 
930 #ifdef DEBUGGING
931 
932 void
do_profile(Side * side)933 do_profile(Side *side)
934 {
935     cmd_error(side, "No curses version of this command.");
936 }
937 
938 void
do_trace(Side * side)939 do_trace(Side *side)
940 {
941     cmd_error(side, "No curses version of this command.");
942 }
943 
944 #endif /* DEBUGGING */
945 
946 /* Generic command error routine just does a notify. */
947 
948 void
cmd_error(Side * side,char * fmt,...)949 cmd_error(Side *side, char *fmt, ...)
950 {
951     char tmpnbuf[BUFSIZE];
952     va_list ap;
953 
954     if (!empty_string(fmt)) {
955 
956 	va_start(ap, fmt);
957 	vsnprintf(tmpnbuf, sizeof tmpnbuf, fmt, ap);
958 	va_end(ap);
959 
960 	low_notify(dside, tmpnbuf);
961     }
962     xbeep();
963 }
964