1 /* Commands for the SDL interface to Xconq.
2    Copyright (C) 2000, 2001 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 "sdlpreconq.h"
10 #include "conq.h"
11 #include "kpublic.h"
12 #include "sdlconq.h"
13 #include "print.h"
14 #include "aiunit.h"
15 #include "aiunit2.h"
16 
17 void really_do_design(Side *side);
18 
19 static void aux_add_terrain(Screen *screen, int cancel);
20 static void aux_add_terrain_2(Screen *screen, int cancel);
21 static void do_add_terrain_2(Screen *screen, int t);
22 static void aux_attack(Screen *screen, int cancel);
23 static void aux_build(Screen *screen, int cancel);
24 static void aux_build_2(Screen *screen, int cancel);
25 static void aux_change_type(Screen *screen, int cancel);
26 static void aux_distance(Screen *screen, int cancel);
27 static void aux_fire_at(Screen *screen, int cancel);
28 static void common_fire_at(Unit *unit, int x, int y);
29 static void aux_fire_into(Screen *screen, int cancel);
30 static void common_fire_into(Unit *unit, int x, int y);
31 static void aux_give_unit(Screen *screen, int cancel);
32 static void aux_move_dir(Screen *screen, Unit *unit);
33 static void aux_message(Screen *screen, int cancel);
34 static void aux_move_to(Screen *screen, int cancel);
35 static void aux_name(Screen *screen, int cancel);
36 static void aux_others(Screen *screen, int cancel);
37 static void aux_remove_terrain(Screen *screen, int cancel);
38 static void aux_remove_terrain_2(Screen *screen, int cancel);
39 static void do_remove_terrain_2(Screen *screen, int t);
40 static void aux_quit_resign(Screen *screen, int cancel);
41 static void aux_quit_resign_to(Screen *screen, int cancel);
42 static void aux_quit_exit(Screen *screen, int cancel);
43 static void aux_quit_save(Screen *screen, int cancel);
44 static void aux_quit_leave(Screen *screen, int cancel);
45 static void aux_resign(Screen *screen, int cancel);
46 static void aux_resign_to(Screen *screen, int cancel);
47 static void aux_set_formation(Screen *screen, int cancel);
48 
49 static void aux_design(Screen *screen, int cancel);
50 
51 /* Use these functions to check commands' preconditions. */
52 
53 static int
during_game_only(void)54 during_game_only(void)
55 {
56     if (endofgame) {
57 	cmd_error(dside, "Cannot do after game is over!");
58 	return FALSE;
59     }
60     return TRUE;
61 }
62 
63 static int
require_unit(Screen * screen)64 require_unit(Screen *screen)
65 {
66     if (screen == NULL) {
67 	beep();
68 	return FALSE;
69     }
70     if (!in_play(screen->curunit) || screen->curunit_id != screen->curunit->id) {
71 	screen->curunit = NULL;
72 	screen->curunit_id = 0;
73 	cmd_error(dside, "No current unit to command!");
74 	return FALSE;
75     }
76     return TRUE;
77 }
78 
79 static int
require_own_unit_during_game(Screen * screen)80 require_own_unit_during_game(Screen *screen)
81 {
82     if (!during_game_only())
83       return FALSE;
84     if (!require_unit(screen))
85       return FALSE;
86     if (!side_controls_unit(dside, screen->curunit)) {
87 	cmd_error(dside, "The unit is not yours to command!");
88 	return FALSE;
89     }
90     return TRUE;
91 }
92 
93 /* This function tests that a unit that was originally specified as
94    part of a command is still usable.  The unit may have died or
95    changed sides since the command was first given. */
96 
97 static int
unit_still_ok(Unit * unit)98 unit_still_ok(Unit *unit)
99 {
100     if (!in_play(unit)) {
101 	/* Note that this is not an error, because the player didn't
102 	   do anything wrong. */
103 	notify(dside, "Unit is gone!");
104 	return FALSE;
105     }
106     if (!side_controls_unit(dside, unit)) {
107 	notify(dside, "%s is no longer yours to command!",
108 	       unit_handle(dside, unit));
109 	return FALSE;
110     }
111     return TRUE;
112 }
113 
114 static UnitVector *selvec;
115 
116 UnitVector *
get_selected_units(Side * side)117 get_selected_units(Side *side)
118 {
119     Screen *screen = ui->curscreen;
120 
121     if (selvec == NULL)
122       selvec = make_unit_vector(2);
123     clear_unit_vector(selvec);
124     if (screen && in_play(screen->curunit) && screen->curunit_id == screen->curunit->id)
125       selvec = add_unit_to_vector(selvec, screen->curunit, 0);
126     return selvec;
127 }
128 
129 int designed_on = FALSE;
130 
131 /* Definitions of all the command functions. */
132 
133 void
do_add_terrain(Side * side)134 do_add_terrain(Side *side)
135 {
136     Screen *screen = ui->curscreen;
137     int u, t, numtypes, tfirst = NONTTYPE;
138     Unit *unit = screen->curunit;
139 
140     if (!require_own_unit_during_game(screen))
141       return;
142     u = unit->type;
143     numtypes = 0;
144     for_all_terrain_types(t) {
145 	if (ut_acp_to_add_terrain(u, t) > 0) {
146 	    tmp_t_array[t] = TRUE;
147 	    ++numtypes;
148 	    tfirst = t;
149 	} else {
150 	    tmp_t_array[t] = FALSE;
151 	}
152     }
153     if (numtypes == 0) {
154 	cmd_error(dside, "%s cannot add or alter terrain!",
155 		  unit_handle(dside, unit));
156     } else if (numtypes == 1) {
157 	screen->argunitid = unit->id;
158 	do_add_terrain_2(screen, tfirst);
159     } else {
160 	screen->argunitid = unit->id;
161 	ask_terrain_type(screen, "Type to add:", tmp_t_array, aux_add_terrain);
162     }
163 }
164 
165 static void
aux_add_terrain(Screen * screen,int cancel)166 aux_add_terrain(Screen *screen, int cancel)
167 {
168     int t;
169 
170     if (cancel)
171       return;
172     if (screen->inpch == '?') {
173 	notify(dside, "Type a key to select terrain type.");
174     }
175     if (grok_terrain_type(screen, &t)) {
176 	if (t != NONTTYPE) {
177 	    do_add_terrain_2(screen, t);
178 	}
179     } else {
180         if (screen->inpch != '?')
181 	  beep();
182 	/* Stay in this mode until we get it right. */
183 	screen->modalhandler = aux_add_terrain;
184     }
185 }
186 
187 /* This is like do_add_terrain, but with a terrain type given. */
188 
189 static void
do_add_terrain_2(Screen * screen,int t)190 do_add_terrain_2(Screen *screen, int t)
191 {
192     char abuf[100];
193 
194     screen->tmpt = t;
195     sprintf(abuf, "Add %s where?", t_type_name(t));
196     ask_position(screen, abuf, aux_add_terrain_2);
197 }
198 
199 static void
aux_add_terrain_2(Screen * screen,int cancel)200 aux_add_terrain_2(Screen *screen, int cancel)
201 {
202     int x, y, dir;
203     Unit *unit;
204 
205     if (cancel)
206       return;
207     if (screen->inpch == '?') {
208 	notify(dside, "Pick a location to add %s.", t_type_name(screen->tmpt));
209 	screen->modalhandler = aux_add_terrain_2;
210 	return;
211     }
212     if (grok_position(screen, &x, &y, NULL)) {
213 	if (in_area(x, y)) {
214 	    unit = find_unit(screen->argunitid);
215 	    if (!unit_still_ok(unit))
216 	      return;
217 	    switch (t_subtype(screen->tmpt)) {
218 	      case cellsubtype:
219 		net_prep_alter_cell_action(unit, unit, x, y, screen->tmpt);
220 		break;
221 	      case bordersubtype:
222 	      case connectionsubtype:
223 		if (x == unit->x && y == unit->y) {
224 		    beep();
225 		    notify(dside, "Pick an adjacent location.");
226 		    screen->modalhandler = aux_add_terrain_2;
227 		}
228 		dir = closest_dir(x - unit->x, y - unit->y);
229 		net_prep_add_terrain_action(unit, unit, unit->x, unit->y,
230 					    dir, screen->tmpt);
231 		break;
232 	      case coatingsubtype:
233 		net_prep_add_terrain_action(unit, unit, unit->x, unit->y,
234 					    1, screen->tmpt);
235 		break;
236 	    }
237 	}
238     } else {
239 	beep();
240 	screen->modalhandler = aux_add_terrain_2;
241     }
242 }
243 
244 void
do_attack(Side * side)245 do_attack(Side *side)
246 {
247     Screen *screen = ui->curscreen;
248     Unit *unit = screen->curunit;
249 
250     if (!require_own_unit_during_game(screen))
251       return;
252     screen->argunitid = unit->id;
253     ask_position(screen, "Attack where?", aux_attack);
254 }
255 
256 static void
aux_attack(Screen * screen,int cancel)257 aux_attack(Screen *screen, int cancel)
258 {
259     int x, y;
260     Unit *unit, *unit2;
261 
262     if (cancel)
263       return;
264     if (screen->inpch == '?') {
265 	notify(dside, "Click on a location");
266     }
267     if (grok_position(screen, &x, &y, &unit2)) {
268 	unit = find_unit(screen->argunitid);
269 	if (!unit_still_ok(unit))
270 	  return;
271 	if (unit2 != NULL) {
272 	    net_prep_attack_action(unit, unit, unit2, 100);
273 	} else {
274 	    cmd_error(dside, "Nothing to attack!");
275 	}
276     } else {
277         if (screen->inpch != '?')
278 	  beep();
279 	screen->modalhandler = aux_attack;
280     }
281 }
282 
283 void
do_build(Side * side)284 do_build(Side *side)
285 {
286     Screen *screen = ui->curscreen;
287     int u, u2, numtypes, ufirst = NONUTYPE;
288     Unit *unit = screen->curunit;
289 
290     if (!require_own_unit_during_game(screen))
291       return;
292     u = unit->type;
293     if (!can_build(unit)) {
294 	cmd_error(dside, "%s can't build anything!", unit_handle(dside, unit));
295 	return;
296     }
297     numtypes = 0;
298     for_all_unit_types(u2) {
299 	if (unit_can_build_type(unit, u2)) {
300 	    tmp_u_array[u2] = TRUE;
301 	    ++numtypes;
302 	    ufirst = u2;
303 	} else {
304 	    tmp_u_array[u2] = FALSE;
305 	}
306     }
307     if (unit->transport != NULL
308 	&& !uu_occ_can_build(unit->transport->type, u)
309 	&& !(numtypes == 1
310 	     && !completed(unit->transport)
311 	     && uu_acp_to_build(u, unit->transport->type) > 0)) {
312 	cmd_error(dside, "%s can't build anything while inside another unit!",
313 		  unit_handle(dside, unit));
314 	return;
315     }
316     switch (numtypes) {
317       case 0:
318 	cmd_error(dside, "Nothing to build right now!");
319 	break;
320       case 1:
321 	/* Only one type to build - do it. */
322 	maybe_ask_construct_location(screen, unit, ufirst);
323 	break;
324       default:
325 	/* Player has to choose a type to build. */
326 	screen->argunitid = unit->id;
327 	ask_unit_type(screen, "Type to build:", tmp_u_array, aux_build);
328 	break;
329     }
330 }
331 
332 void
maybe_ask_construct_location(Screen * screen,Unit * unit,int u2)333 maybe_ask_construct_location(Screen *screen, Unit *unit, int u2)
334 {
335     int u = NONUTYPE;
336     char *msg = NULL;
337     Unit *transport = NULL;
338 
339     assert_error(screen, "Attempted to access a NULL screen");
340     assert_error(unit, "Attempted to manipulate a NULL unit");
341     assert_error(is_unit_type(u2),
342 		 "Attempted to construct an illegal unit type");
343     u = unit->type;
344     /* If the unit is mobile or can perform a ranged create. */
345     if (u_mobile(u) || (0 < uu_create_range(u, u2))) {
346 	screen->argunitid = unit->id;
347 	screen->inptype = u2;
348 	msg = (char *)xmalloc(80 + strlen(u_type_name(u2)));
349 	sprintf(msg, "Build %s where?", u_type_name(u2));
350 	ask_position(screen, msg, aux_build_2);
351 	free(msg);
352     /* Else attempt to create at unit's location. */
353     }
354     else {
355 	if (valid(can_create_in(unit, unit, u2, unit))
356 	    && impl_build(
357 		dside, unit, u2, unit, unit->x, unit->y, screen->prefixarg)) {
358 	    reset_screen_input(screen);
359 	}
360 	else if (valid(can_create_at(unit, unit, u2, unit->x, unit->y))
361 		 && impl_build(
362 			dside, unit, u2, NULL, unit->x, unit->y,
363 			screen->prefixarg)) {
364 	    reset_screen_input(screen);
365 	}
366     }
367 }
368 
369 static void
aux_build(Screen * screen,int cancel)370 aux_build(Screen *screen, int cancel)
371 {
372     int u2;
373     Unit *unit;
374 
375     if (cancel) {
376 	cancel_unit_type(screen);
377 	return;
378     }
379     if (screen->inpch == '?') {
380 	notify(dside, "Type a key or click on a unit type to select build (or hit <esc> to cancel).");
381     }
382     if (grok_unit_type(screen, &u2)) {
383 	/* Escape silently if the player cancelled. */
384 	if (u2 == NONUTYPE)
385 	  return;
386 	unit = find_unit(screen->argunitid);
387 	if (!unit_still_ok(unit))
388 	  return;
389 	if (mobile(unit->type)
390 	    || uu_create_range(unit->type, u2) > 0) {
391 	    /* For mobile and/or at-a-distance builders, also ask
392 	       where to build. */
393 	    char *msg;
394 	    screen->inptype = u2;
395 	    /* Provide feedback about which unit type the user picked.  */
396 	    msg = (char *)xmalloc(80 + strlen (u_type_name (u2)));
397 	    sprintf (msg, "Build %s where?", u_type_name (u2));
398 	    ask_position(screen, msg, aux_build_2);
399 	    free (msg);
400 	    return;
401 	}
402 	else {
403 	    if (valid(can_create_in(unit, unit, u2, unit))
404 		&& impl_build(
405 		    dside, unit, u2, unit, unit->x, unit->y,
406 		    screen->prefixarg)) {
407 		reset_screen_input(screen);
408 	    }
409 	    else if (valid(can_create_at(unit, unit, u2, unit->x, unit->y))
410 		     && impl_build(
411 			    dside, unit, u2, NULL, unit->x, unit->y,
412 			    screen->prefixarg)) {
413 		reset_screen_input(screen);
414 	    }
415 	}
416     } else {
417 	if (screen->inpch != '?') {
418 	    beep();
419 	    screen->modalhandler = aux_build;
420 	}
421     }
422 }
423 
424 static void
aux_build_2(Screen * screen,int cancel)425 aux_build_2(Screen *screen, int cancel)
426 {
427     int x, y;
428     Unit *unit = NULL, *transport = NULL;
429 
430     if (cancel) {
431 	return;
432     }
433     if (screen->inpch == '?') {
434 	notify(dside, "Pick a location where you would like to build (or hit <esc> to cancel).");
435 	screen->modalhandler = aux_build_2;
436 	return;
437     }
438     if (grok_position(screen, &x, &y, &transport)) {
439 	unit = find_unit(screen->argunitid);
440 	if (!unit_still_ok(unit))
441 	  return;
442 	if (impl_build(
443 		dside, unit, screen->inptype, transport, x, y,
444 		screen->prefixarg)) {
445 	    reset_screen_input(screen);
446 	} else {
447 	    beep();
448 	    screen->modalhandler = aux_build_2;
449 	}
450     } else {
451 	notify(dside, "Invalid position. Please pick a new location.");
452 	beep();
453 	screen->modalhandler = aux_build_2;
454     }
455 }
456 
457 void
do_change_type(Side * side)458 do_change_type(Side *side)
459 {
460     Screen *screen = ui->curscreen;
461     int u = NONUTYPE, u2 = NONUTYPE, numtypes = 0, ufirst = NONUTYPE;
462     Unit *unit = NULL;
463 
464     if (screen && screen->curunit)
465       unit = screen->curunit;
466     else
467       return;
468     if (!require_own_unit_during_game(screen))
469       return;
470     if (unit)
471       u = unit->type;
472     else
473       return;
474     if (unit->side != dside) {
475         cmd_error(dside, "%s is not your unit!", unit_handle(dside, unit));
476         return;
477     }
478     for_all_unit_types(u2) {
479         if (uu_acp_to_change_type(unit->type, u2)) {
480             tmp_u_array[u2] = TRUE;
481             ++numtypes;
482             ufirst = u2;
483         }
484         else {
485             tmp_u_array[u2] = FALSE;
486         }
487     }
488     switch (numtypes) {
489       case 0:
490         cmd_error(dside, "Cannot change to any type right now!");
491         break;
492       case 1:
493         /* Only one possible type to change to. Change to it. */
494         if (!impl_change_type(dside, unit, ufirst)) {
495             screen->inptype = NONUTYPE;
496             return;
497         }
498         break;
499       default:
500         screen->argunitid = unit->id;
501         ask_unit_type(screen, "Type to change into:", tmp_u_array,
502                       aux_change_type);
503         break;
504     }
505 }
506 
507 static void
aux_change_type(Screen * screen,int cancel)508 aux_change_type(Screen *screen, int cancel)
509 {
510     int u2 = NONUTYPE;
511     Unit *unit = NULL;
512 
513     if (cancel) {
514         cancel_unit_type(screen);
515         return;
516     }
517     if (screen->inpch == '?') {
518         notify(dside, "Type a key or click in the unit list to select new type (or hit <esc> to cancel).");
519     }
520     if (grok_unit_type(screen, &u2)) {
521         /* Escape silently if the player cancelled. */
522         if (u2 == NONUTYPE)
523           return;
524         unit = find_unit(screen->argunitid);
525         if (!unit_still_ok(unit))
526           return;
527         if (!impl_change_type(dside, unit, u2)) {
528             screen->inptype = NONUTYPE;
529             return;
530         }
531     }
532     else {
533         if (screen->inpch != '?')
534           beep();
535         screen->modalhandler = aux_change_type;
536     }
537 }
538 
539 void
do_collect(Side * side)540 do_collect(Side *side)
541 {
542     Screen *screen = ui->curscreen;
543     Unit *unit = screen->curunit;
544     int mtocollect;
545     char *arg, *rest;
546 
547     if (!require_own_unit_during_game(screen))
548       return;
549     mtocollect = NONMTYPE;
550     if (nummtypes == 0) {
551 	cmd_error(dside, "No materials to collect");
552 	return;
553     }
554     if (!empty_string(cmdargstr)) {
555 	rest = get_next_arg(cmdargstr, tmpbuf, &arg);
556 	mtocollect = mtype_from_name(arg);
557     } else {
558 	cmd_error(dside, "No material name given");
559 	return;
560     }
561     if (!is_material_type(mtocollect)) {
562 	cmd_error(dside, "`%s' is not a recognized material name", arg);
563 	return;
564     }
565     if (unit->plan)
566       net_set_collect_task(unit, mtocollect, unit->x, unit->y);
567 }
568 
569 void
do_copying(Side * side)570 do_copying(Side *side)
571 {
572     popup_help(dside, copying_help_node);
573 }
574 
575 void
do_dir(Side * side)576 do_dir(Side *side)
577 {
578     Screen *screen = ui->curscreen;
579 
580     if (!require_own_unit_during_game(screen))
581       return;
582     aux_move_dir(screen, screen->curunit);
583 }
584 
585 void
do_dir_multiple(Side * side)586 do_dir_multiple(Side *side)
587 {
588     Screen *screen = ui->curscreen;
589 
590     if (!require_own_unit_during_game(screen))
591       return;
592     screen->prefixarg = 9999;
593     aux_move_dir(screen, screen->curunit);
594 }
595 
596 /* Handle both single and multiple moves in the direction given by
597    tmpkey. */
598 
599 static void
aux_move_dir(Screen * screen,Unit * unit)600 aux_move_dir(Screen *screen, Unit *unit)
601 {
602     int ndirs, dir, n = screen->prefixarg, x, y;
603     HistEventType reason;
604     char failbuf[BUFSIZE];
605 
606     if (!unit->act || !unit->plan) { /* use a more sophisticated test? */
607 	/* ??? can't act ??? */
608 	return;
609     }
610     ndirs = char_to_dir(tmpkey, &dir, NULL, NULL);
611     if (ndirs < 1) {
612 	/* (would never occur in real life though...) */
613 	cmd_error(dside, "what direction is that?!?");
614 	return;
615     }
616     if (n > 1) {
617 	DGprintf("Ordering %s to move %d %s\n",
618 		 unit_desig(unit), n, dirnames[dir]);
619 	net_set_move_dir_task(unit, dir, n);
620     } else {
621 	/* Moving directly into an adjacent cell, do now instead of
622 	   making a task. */
623 	if (!point_in_dir(unit->x, unit->y, dir, &x, &y)) {
624 	    /* (but what if leaving the world is allowed?) */
625 	    beep();
626 	    return;
627 	}
628 	if (!advance_into_cell(dside, unit, x, y, unit_at(x, y), &reason)) {
629 	    advance_failure_desc(failbuf, unit, reason);
630 	    notify(dside, "%s", failbuf);
631 	    beep();
632 	}
633     }
634 }
635 
636 void
do_distance(Side * side)637 do_distance(Side *side)
638 {
639     Screen *screen = ui->curscreen;
640 
641     if (!require_unit(screen))
642       return;
643     screen->argunitid = screen->curunit->id;
644     ask_position(screen, "Distance to where?", aux_distance);
645 }
646 
647 static void
aux_distance(Screen * screen,int cancel)648 aux_distance(Screen *screen, int cancel)
649 {
650     int x, y, dist;
651     Unit *unit;
652 
653     if (cancel)
654       return;
655     if (screen->inpch == '?') {
656 	notify(dside, "Pick a location to which you want the distance.");
657 	screen->modalhandler = aux_distance;
658 	return;
659     }
660     if (grok_position(screen, &x, &y, NULL)) {
661 	unit = find_unit(screen->argunitid);
662 	/* We don't care about the unit's ownership. */
663 	if (in_area(x, y) && unit != NULL) {
664 	    dist = distance(unit->x, unit->y, x, y);
665 	    notify(dside, "Distance from the current unit is %d cells.", dist);
666 	} else {
667 	    cmd_error(dside, "Measurement failed.");
668 	}
669     } else {
670         beep();
671 	screen->modalhandler = aux_distance;
672     }
673 }
674 
675 void
do_escape(Side * side)676 do_escape(Side *side)
677 {
678 }
679 
680 void
do_fire(Side * side)681 do_fire(Side *side)
682 {
683     Screen *screen = ui->curscreen;
684     int sx, sy, x, y;
685     Unit *unit = screen->curunit;
686 
687     if (!require_own_unit_during_game(screen))
688       return;
689 
690     if (screen->inpch == '\0') {
691 	screen->argunitid = unit->id;
692 	ask_position(screen, "Fire at what unit?", aux_fire_at);
693     } else {
694 	sx = screen->inpsx;  sy = screen->inpsy;
695 	if (nearest_cell(screen->map->main_vp, sx, sy, &x, &y, NULL, NULL)) {
696 	    common_fire_at(unit, x, y);
697 	} else {
698 	    cmd_error(dside, "Cannot fire outside the world!");
699 	}
700     }
701 }
702 
703 static void
aux_fire_at(Screen * screen,int cancel)704 aux_fire_at(Screen *screen, int cancel)
705 {
706     int x, y;
707     Unit *unit;
708 
709     if (cancel)
710       return;
711     if (grok_position(screen, &x, &y, NULL)) {
712 	unit = find_unit(screen->argunitid);
713 	if (!unit_still_ok(unit))
714 	  return;
715 	common_fire_at(unit, x, y);
716     } else {
717 	screen->modalhandler = aux_fire_at;
718     }
719 }
720 
721 static void
common_fire_at(Unit * unit,int x,int y)722 common_fire_at(Unit *unit, int x, int y)
723 {
724     int rslt;
725     Unit *other;
726 
727     /* (should only be able to target unit if covered...) */
728     other = unit_at(x, y);
729     if (other == NULL) {
730 	cmd_error(dside, "Nothing there to fire at!");
731     } else if (other == unit) {
732 	cmd_error(dside, "You can't fire at yourself!");
733     } else if (other->side == unit->side) {
734 	cmd_error(dside, "You can't fire at one of your own units!");
735     } else {
736 	rslt = check_fire_at_action(unit, unit, other, -1);
737 	if (valid(rslt)) {
738 	    net_prep_fire_at_action(unit, unit, other, -1);
739 	} else {
740 	    /* (should say which unit was target) */
741 	    cmd_error(dside, "%s fire at unit not valid: %s",
742 		      unit_handle(dside, unit),
743 		      action_result_desc(rslt));
744 	}
745     }
746 }
747 
748 void
do_fire_into(Side * side)749 do_fire_into(Side *side)
750 {
751     Screen *screen = ui->curscreen;
752     int x = screen->inpx, y = screen->inpy;
753     Unit *unit = screen->curunit;
754 
755     if (!require_own_unit_during_game(screen))
756       return;
757 
758     if (screen->inpch == '\0') {
759 	screen->argunitid = unit->id;
760 	ask_position(screen, "Fire into which location?", aux_fire_into);
761     } else {
762 	common_fire_into(unit, x, y);
763     }
764 }
765 
766 static void
aux_fire_into(Screen * screen,int cancel)767 aux_fire_into(Screen *screen, int cancel)
768 {
769     int x, y;
770     Unit *unit;
771 
772     if (cancel)
773       return;
774     if (grok_position(screen, &x, &y, NULL)) {
775 	unit = find_unit(screen->argunitid);
776 	if (!unit_still_ok(unit))
777 	  return;
778 	common_fire_into(unit, x, y);
779     } else {
780 	screen->modalhandler = aux_fire_into;
781     }
782 }
783 
784 static void
common_fire_into(Unit * unit,int x,int y)785 common_fire_into(Unit *unit, int x, int y)
786 {
787     int rslt;
788 
789     if (!inside_area(x, y)) {
790 	cmd_error(dside, "Cannot fire outside the world!");
791 	return;
792     }
793     rslt = check_fire_into_action(unit, unit, x, y, 0, -1);
794     if (valid(rslt)) {
795 	net_prep_fire_into_action(unit, unit, x, y, 0, -1);
796     } else {
797 	cmd_error(dside, "%s fire into %d,%d not valid: %s",
798 		  unit_handle(dside, unit), x, y, action_result_desc(rslt));
799     }
800 }
801 
802 void
do_flash(Side * side)803 do_flash(Side *side)
804 {
805     cmd_error(dside, "Not implemented.");
806 }
807 
808 /* Toggle the "follow-action" flag. */
809 
810 void
do_follow_action(Side * side)811 do_follow_action(Side *side)
812 {
813     Screen *screen = ui->curscreen;
814 
815     if (screen == NULL)
816       return;
817     if (!during_game_only())
818       return;
819     screen->follow_action = !screen->follow_action;
820     if (screen->follow_action) {
821 	notify(dside, "Following the action on screen.");
822     } else {
823 	notify(dside, "Not following the action on screen.");
824     }
825 }
826 
827 /* Give a unit to another side or make it independent. */
828 
829 /* (but giving to indep should be tested, otherwise might kill unit) */
830 
831 static void really_do_give_unit(Unit *unit, Side *side2);
832 
833 void
do_give_unit(Side * side)834 do_give_unit(Side *side)
835 {
836     Screen *screen = ui->curscreen;
837     Side *side2;
838 
839     if (!require_own_unit_during_game(screen))
840       return;
841     if (between(0, screen->prefixarg, numsides)) {
842 	/* Interpret a prefix as the recipient side. */
843 	side2 = side_n(screen->prefixarg);
844 	really_do_give_unit(screen->curunit, side2);
845     } else {
846 	ask_side(screen, "To whom do you wish to give the unit?", NULL,
847 		 aux_give_unit);
848     }
849 }
850 
851 static void
aux_give_unit(Screen * screen,int cancel)852 aux_give_unit(Screen *screen, int cancel)
853 {
854     Side *side2;
855 
856     if (cancel)
857       return;
858     if (grok_side(screen, &side2)) {
859 	really_do_give_unit(screen->curunit, side2);
860     } else {
861 	/* Iterate until grok_side is happy. */
862 	screen->modalhandler = aux_give_unit;
863     }
864 }
865 
866 static void
really_do_give_unit(Unit * unit,Side * side2)867 really_do_give_unit(Unit *unit, Side *side2)
868 {
869     if (unit->side == side2)
870       return;
871 #ifdef DESIGNERS
872     if (is_designer(dside)) {
873 	net_designer_change_side(unit, side2);
874 	return;
875     }
876 #endif /* DESIGNERS */
877     if (0 /* unit is a type that cannot act */) {
878 	/* (should add case for nonacting units) */
879     } else {
880 	/* (should check validity!) */
881 	if (side2 != NULL && side2 != indepside) {
882 	    notify(dside, "You give %s to %s.",
883 		   unit_handle(dside, unit), short_side_title(side2));
884 	    net_prep_change_side_action(unit, unit, side2);
885 	} else {
886 	    notify(dside, "You give %s its independence.",
887 		   unit_handle(dside, unit));
888 	    net_prep_change_side_action(unit, unit, indepside);
889 	}
890     }
891 }
892 
893 void
do_help(Side * side)894 do_help(Side *side)
895 {
896     popup_help(dside, NULL);
897 }
898 
899 /* In general, the subcommands of "screen" are for the GUI to use. */
900 
901 void
do_map(Side * side)902 do_map(Side *side)
903 {
904     Screen *screen = ui->curscreen;
905     VP *vp;
906 
907     if (empty_string(cmdargstr))
908       return;
909     if (screen == NULL)
910       return;
911     vp = screen->map->main_vp;
912     if (strncmp(cmdargstr, "contour-interval=", 17) == 0) {
913 	if (strcmp("?", cmdargstr+17) == 0) {
914 	    notify(dside, "Contour interval is %d.", vp->contour_interval);
915 	} else {
916 	    int n = strtol(cmdargstr+17, NULL, 10);
917 	    set_contour_interval(vp, n);
918 	    redraw_screen(screen);
919 	}
920     } else if (strcmp(cmdargstr, "iso") == 0) {
921     } else if (strcmp(cmdargstr, "meridians") == 0) {
922 	vp->draw_meridians = !vp->draw_meridians;
923 	if (screen->prefixarg > 0)
924 	  set_meridian_interval(vp, screen->prefixarg);
925 	redraw_screen(screen);
926     } else if (strcmp(cmdargstr, "rotl") == 0) {
927 	notify(dside, "Now looking %s.", dirnames[vp->isodir]);
928     } else if (strcmp(cmdargstr, "rotr") == 0) {
929 	notify(dside, "Now looking %s.", dirnames[vp->isodir]);
930     } else if (strcmp(cmdargstr, "show-all") == 0) {
931 	if (!side->may_set_show_all) {
932 	    cmd_error(dside, "You are not permitted to see everything!");
933 	    return;
934 	}
935 	set_show_all(screen, !screen->show_all);
936 	redraw_screen(screen);
937     } else if (strcmp(cmdargstr, "unit-colorize") == 0) {
938 	screen->colorize_units = !screen->colorize_units;
939 	redraw_screen(screen);
940     } else if (*cmdargstr == '!') {
941     } else {
942 	cmd_error(dside, "Screen command \"%s\" not recognized!", cmdargstr);
943     }
944 }
945 
946 /* Send a short (1 line) message to another player.  Some messages are
947    recognized specially, causing various actions. */
948 
949 void
do_message(Side * side)950 do_message(Side *side)
951 {
952     Screen *screen = ui->curscreen;
953     char prompt[BUFSIZE];
954     Side *side2;
955 
956     if (screen == NULL)
957       return;
958     side2 = side_n(screen->prefixarg);
959     if (dside == side2) {
960 	sprintf(prompt, "Message to yourself: ");
961     } else if (side2) {
962 	sprintf(prompt, "Message to %s: ", short_side_title(side2));
963     } else {
964 	sprintf(prompt, "Broadcast to all: ");
965     }
966     screen->argside = side2;
967     ask_string(screen, prompt, NULL, aux_message);
968 }
969 
970 static void
aux_message(Screen * screen,int cancel)971 aux_message(Screen *screen, int cancel)
972 {
973     char *msg;
974     SideMask sidemask;
975 
976     if (cancel)
977       return;
978     if (grok_string(screen, &msg)) {
979 	if (empty_string(msg)) {
980 	    notify(dside, "You keep your mouth shut.");
981 	    sidemask = NOSIDES;
982 	} else if (screen->argside == NULL) {
983 	    notify(dside, "You broadcast to everybody.", msg);
984 	    sidemask = ALLSIDES;
985 	} else {
986 	    notify(dside, "You send the message.");
987 	    sidemask = add_side_to_set(screen->argside, NOSIDES);
988 	}
989 	if (!empty_string(msg) && sidemask != NOSIDES)
990 	  net_send_message(dside, sidemask, msg);
991     } else {
992 	screen->modalhandler = aux_message;
993     }
994 }
995 
996 /* Set unit to move to a given location.  */
997 
998 /* The command proper. */
999 
1000 void
do_move_to(Side * side)1001 do_move_to(Side *side)
1002 {
1003     Screen *screen = ui->curscreen;
1004     Unit *unit = screen->curunit;
1005 
1006     if (!is_designer(side)) {
1007 	if (!mobile(unit->type)) {
1008 	    cmd_error(side, "%s cannot move at all!", unit_handle(side, unit));
1009 	    return;
1010 	}
1011     }
1012     if (!require_own_unit_during_game(screen))
1013       return;
1014     screen->argunitid = unit->id;
1015     ask_position(screen, "Move to where?", aux_move_to);
1016 }
1017 
1018 static void
aux_move_to(Screen * screen,int cancel)1019 aux_move_to(Screen *screen, int cancel)
1020 {
1021     int x, y;
1022     Unit *unit;
1023 
1024     if (cancel)
1025       return;
1026     if (grok_position(screen, &x, &y, NULL)) {
1027 	unit = find_unit(screen->argunitid);
1028 	if (!unit_still_ok(unit)) {
1029 	    return;
1030 	}
1031 	if (impl_move_to(dside, unit, x, y, 0)) {
1032 	    return;
1033 	} else {
1034 	    beep();
1035 	    screen->modalhandler = aux_move_to;
1036 	}
1037     } else {
1038 	beep();
1039 	notify(dside, "Invalid position. Please pick a new destination.");
1040 	screen->modalhandler = aux_move_to;
1041     }
1042 }
1043 
1044 /* Name/rename the current unit. */
1045 
1046 void
do_name(Side * side)1047 do_name(Side *side)
1048 {
1049     Screen *screen = ui->curscreen;
1050     char tmpbuf[BUFSIZE];
1051     Unit *unit = screen->curunit;
1052 
1053     if (!require_own_unit_during_game(screen))
1054       return;
1055     screen->argunitid = unit->id;
1056     sprintf(tmpbuf, "New name for %s:", unit_handle(dside, unit));
1057     ask_string(screen, tmpbuf, unit->name, aux_name);
1058 }
1059 
1060 static void
aux_name(Screen * screen,int cancel)1061 aux_name(Screen *screen, int cancel)
1062 {
1063     char *name;
1064     Unit *unit;
1065 
1066     if (cancel)
1067       return;
1068     if (grok_string(screen, &name)) {
1069 	unit = find_unit(screen->argunitid);
1070 	if (!unit_still_ok(unit))
1071 	  return;
1072 	net_set_unit_name(dside, unit, name);
1073     } else {
1074 	screen->modalhandler = aux_name;
1075     }
1076 }
1077 
1078 /* Create a new screen, of standard size and zoom. */
1079 /* (should clone last screen in list perhaps?) */
1080 
1081 void
do_new_map(Side * side)1082 do_new_map(Side *side)
1083 {
1084     cmd_error(dside, "Cannot have more than one SDL screen");
1085 }
1086 
1087 /* This is a command to examine all occupants and suboccupants, in an
1088    inorder fashion. */
1089 
1090 /* Should have an option to open up a list window that shows everything
1091    all at once. */
1092 
1093 void
do_occupant(Side * side)1094 do_occupant(Side *side)
1095 {
1096     Screen *screen = ui->curscreen;
1097     Unit *nextocc;
1098 
1099     if (!require_unit(screen))
1100       return;
1101     nextocc = find_next_occupant(screen->curunit);
1102     if (nextocc != screen->curunit)
1103       set_current_unit(screen, nextocc);
1104     else
1105       beep();
1106 }
1107 
1108 void
do_orders_popup(Side * side)1109 do_orders_popup(Side *side)
1110 {
1111     cmd_error(dside, "Not implemented.");
1112 }
1113 
1114 void
do_other(Side * side)1115 do_other(Side *side)
1116 {
1117     Screen *screen = ui->curscreen;
1118 
1119     if (screen == NULL)
1120       return;
1121     ask_string(screen, "Command:", "", aux_others);
1122 }
1123 
1124 static void
aux_others(Screen * screen,int cancel)1125 aux_others(Screen *screen, int cancel)
1126 {
1127     char *cmd;
1128 
1129     if (cancel)
1130       return;
1131     if (grok_string(screen, &cmd)) {
1132 	if (empty_string(cmd)) {
1133 	    notify(dside, "No command.");
1134 	} else if (strcmp(cmd, "?") == 0) {
1135 #if 0
1136 	    do_help(dside);
1137 	    /* (should do with special jump routine) */
1138 	    ui->curhelpnode = long_commands_help_node;
1139 	    update_help(dside);
1140 #endif
1141 	} else {
1142 	    execute_long_command(dside, cmd);
1143 	}
1144     } else {
1145 	screen->modalhandler = aux_others;
1146     }
1147 }
1148 
1149 void
do_print_view(Side * side)1150 do_print_view(Side *side)
1151 {
1152     double conv;
1153     PrintParameters *ps_pp;
1154 
1155     ps_pp = (PrintParameters *) xmalloc(sizeof(PrintParameters));
1156 
1157     init_ps_print(ps_pp);
1158 
1159     /* convert to cm or in */
1160     if (ps_pp->cm) {
1161 	conv = 72 / 2.54;
1162     } else {
1163 	conv = 72;
1164     }
1165     ps_pp->cell_size /= conv;
1166     ps_pp->cell_grid_width /= conv;
1167     ps_pp->border_width /= conv;
1168     ps_pp->connection_width /= conv;
1169     ps_pp->page_width /= conv;
1170     ps_pp->page_height /= conv;
1171     ps_pp->top_margin /= conv;
1172     ps_pp->bottom_margin /= conv;
1173     ps_pp->left_margin /= conv;
1174     ps_pp->right_margin /= conv;
1175 
1176     dump_ps_view(dside, ps_pp, "view.ps");
1177 }
1178 
1179 void
do_produce(Side * side)1180 do_produce(Side *side)
1181 {
1182     int m, n;
1183     Screen *screen = ui->curscreen;
1184     Unit *unit = screen->curunit;
1185 
1186     if (!require_unit(screen))
1187 	return;
1188 
1189     if (!can_produce(unit)) {
1190 	cmd_error(dside, "cannot do active production");
1191     }
1192     n = 9999;
1193     if (screen->prefixarg > 0)
1194 	n = screen->prefixarg;
1195     /* Find the first produceable type and set up to produce it. */
1196     for_all_material_types(m) {
1197 	if (um_acp_to_produce(unit->type, m) > 0) {
1198 	    net_push_produce_task(unit, m, n);
1199 	    return;
1200 	}
1201     }
1202 }
1203 
1204 void
do_quit(Side * side)1205 do_quit(Side *side)
1206 {
1207     Screen *screen = ui->curscreen;
1208 
1209     if (screen == NULL || endofgame || beforestart) {
1210 	/* If the game is over or never started, nothing to test or confirm. */
1211 	exit_xconq();
1212     } else if (dside->ingame) {
1213 	if (gamestatesafe
1214 	    || all_others_willing_to_quit(dside)
1215 	    || is_designer(dside)) {
1216 	    /* For the above cases, there is no obstacle to quitting,
1217 	       but confirm anyway, in case there was a slip of the
1218 	       keyboard. */
1219 	    ask_bool(screen, "Do you really want to quit?", FALSE,
1220 		     aux_quit_exit);
1221 	} else if (keeping_score()) {
1222 	    ask_bool(screen, "Do you want to save the game before quitting?",
1223 		     FALSE, aux_quit_save);
1224 	} else {
1225 	    /* Everybody is just participating. */
1226 	    ask_bool(screen, "Do you want to leave this game?", FALSE,
1227 		     aux_quit_leave);
1228 	}
1229     } else {
1230 	/* We're already out of the game, not really anything to confirm. */
1231 	/* (is this common to all interfaces?) */
1232 	if (all_others_willing_to_quit(dside) || num_active_displays() == 1)
1233 	  exit_xconq();
1234     }
1235 }
1236 
1237 /* (Have an extra confirm for designers not to lose unsaved work?) */
1238 
1239 static void
aux_quit_exit(Screen * screen,int cancel)1240 aux_quit_exit(Screen *screen, int cancel)
1241 {
1242     if (cancel)
1243       return;
1244     if (grok_bool(screen)) {
1245 	exit_xconq();
1246     } else {
1247 	/* Nothing to do if we said not to exit. */
1248     }
1249 }
1250 
1251 static void
aux_quit_save(Screen * screen,int cancel)1252 aux_quit_save(Screen *screen, int cancel)
1253 {
1254     if (cancel)
1255       return;
1256     if (grok_bool(screen)) {
1257 	do_save(dside);
1258 	/* Don't exit unless we know we saved successfully. */
1259 	if (gamestatesafe)
1260 	  exit_xconq();
1261     } else {
1262 	ask_bool(screen, "You cannot quit without resigning; give up now?",
1263 		 FALSE, aux_quit_resign);
1264     }
1265 }
1266 
1267 static void
aux_quit_resign(Screen * screen,int cancel)1268 aux_quit_resign(Screen *screen, int cancel)
1269 {
1270     if (cancel)
1271       return;
1272     if (grok_bool(screen)) {
1273 	if (numsides > 2) {
1274 	    /* (should suggest resigning to a trusted side) */
1275 	    ask_side(screen, "To whom do you wish to surrender?", NULL,
1276 		     aux_quit_resign_to);
1277 	} else {
1278 	    net_resign_game(dside, NULL);
1279 	    exit_xconq();
1280 	}
1281     }
1282 }
1283 
1284 static void
aux_quit_resign_to(Screen * screen,int cancel)1285 aux_quit_resign_to(Screen *screen, int cancel)
1286 {
1287     Side *side2;
1288 
1289     if (cancel)
1290       return;
1291     if (grok_side(screen, &side2)) {
1292 	net_resign_game(dside, side2);
1293 	exit_xconq();
1294     } else {
1295 	/* Iterate until grok_side is happy. */
1296 	screen->modalhandler = aux_quit_resign_to;
1297     }
1298 }
1299 
1300 /* Do the act of leaving the game. */
1301 
1302 static void
aux_quit_leave(Screen * screen,int cancel)1303 aux_quit_leave(Screen *screen, int cancel)
1304 {
1305     if (cancel)
1306       return;
1307     if (grok_bool(screen)) {
1308 	/* (should probably structure differently, but how?) */
1309 	remove_side_from_game(dside);
1310 	exit_xconq();
1311     } else {
1312 	/* Nothing to do if we said not to exit. */
1313     }
1314 }
1315 
1316 /* Center the screen on the current location. */
1317 
1318 void
do_recenter(Side * side)1319 do_recenter(Side *side)
1320 {
1321     Screen *screen = ui->curscreen;
1322 
1323     if (!require_unit(screen))
1324       return;
1325     recenter(screen->map, screen->curunit->x, screen->curunit->y);
1326 }
1327 
1328 /* Redraw everything using the same code as when windows need a redraw. */
1329 
1330 void
do_refresh(Side * side)1331 do_refresh(Side *side)
1332 {
1333     Screen *screen;
1334 
1335     reset_coverage();
1336     reset_all_views();
1337     ui->legends = NULL;
1338     compute_all_feature_centroids();
1339     place_legends(dside);
1340 #if 0
1341     update_contour_intervals();
1342 #endif
1343     for_all_screens(screen)
1344       redraw_screen(screen);
1345 }
1346 
1347 void
do_remove_terrain(Side * side)1348 do_remove_terrain(Side *side)
1349 {
1350     Screen *screen = ui->curscreen;
1351     int u, t, numtypes, tfirst = NONTTYPE;
1352     Unit *unit = screen->curunit;
1353 
1354     if (!require_own_unit_during_game(screen))
1355       return;
1356     u = unit->type;
1357     numtypes = 0;
1358     for_all_terrain_types(t) {
1359 	if (ut_acp_to_remove_terrain(u, t) > 0) {
1360 	    tmp_t_array[t] = TRUE;
1361 	    ++numtypes;
1362 	    tfirst = t;
1363 	} else {
1364 	    tmp_t_array[t] = FALSE;
1365 	}
1366     }
1367     if (numtypes == 0) {
1368 	cmd_error(dside, "%s cannot remove terrain!", unit_handle(side, unit));
1369     } else if (numtypes == 1) {
1370 	screen->argunitid = unit->id;
1371 	do_remove_terrain_2(screen, tfirst);
1372     } else {
1373 	screen->argunitid = unit->id;
1374 	ask_terrain_type(screen, "Type to remove:",
1375 			 tmp_t_array, aux_remove_terrain);
1376     }
1377 }
1378 
1379 static void
aux_remove_terrain(Screen * screen,int cancel)1380 aux_remove_terrain(Screen *screen, int cancel)
1381 {
1382     int t;
1383 
1384     if (cancel)
1385       return;
1386     if (screen->inpch == '?') {
1387 	notify(dside, "Type a key to select terrain type to remove.");
1388     }
1389     if (grok_terrain_type(screen, &t)) {
1390 	if (t != NONTTYPE) {
1391 	    do_remove_terrain_2(screen, t);
1392 	}
1393     } else {
1394         if (screen->inpch != '?')
1395 	  beep();
1396 	/* Stay in this mode until we get it right. */
1397 	screen->modalhandler = aux_remove_terrain;
1398     }
1399 }
1400 
1401 /* This is like do_remove_terrain, but with a terrain type given. */
1402 
1403 static void
do_remove_terrain_2(Screen * screen,int t)1404 do_remove_terrain_2(Screen *screen, int t)
1405 {
1406     screen->tmpt = t;
1407     ask_position(screen, "Remove where?", aux_remove_terrain_2);
1408 }
1409 
1410 static void
aux_remove_terrain_2(Screen * screen,int cancel)1411 aux_remove_terrain_2(Screen *screen, int cancel)
1412 {
1413     int x, y, dir;
1414     Unit *unit;
1415 
1416     if (cancel)
1417       return;
1418     if (screen->inpch == '?') {
1419 	notify(dside, "Pick a location to remove %s.", t_type_name(screen->tmpt));
1420 	screen->modalhandler = aux_remove_terrain_2;
1421 	return;
1422     }
1423     if (grok_position(screen, &x, &y, NULL)) {
1424 	if (in_area(x, y)) {
1425 	    unit = find_unit(screen->argunitid);
1426 	    if (!unit_still_ok(unit))
1427 	      return;
1428 	    switch (t_subtype(screen->tmpt)) {
1429 	      case cellsubtype:
1430 		cmd_error(dside, "can't remove cell terrain!");
1431 		break;
1432 	      case bordersubtype:
1433 	      case connectionsubtype:
1434 		dir = closest_dir(x - unit->x, y - unit->y);
1435 		net_prep_remove_terrain_action(unit, unit, unit->x, unit->y, dir, screen->tmpt);
1436 		break;
1437 	      case coatingsubtype:
1438 		net_prep_remove_terrain_action(unit, unit, unit->x, unit->y, 1, screen->tmpt);
1439 		break;
1440 	    }
1441 	}
1442     } else {
1443 	beep();
1444 	screen->modalhandler = aux_remove_terrain_2;
1445     }
1446 }
1447 
1448 void
do_repair(Side * side)1449 do_repair(Side *side)
1450 {
1451     Screen *screen = ui->curscreen;
1452     Unit *unit, *other;
1453 
1454     if (!require_own_unit_during_game(screen))
1455       return;
1456     unit = screen->curunit;
1457     if (valid(check_repair_action(unit, unit, unit))) {
1458 	net_prep_repair_action(unit, unit, unit);
1459 	return;
1460     }
1461     other = unit->transport;
1462     if (other != NULL
1463 	&& valid(check_repair_action(other, other, unit))) {
1464 	net_prep_repair_action(other, other, unit);
1465 	return;
1466     }
1467     cmd_error(dside, "No repair possible right now");
1468 }
1469 
1470 void
do_resign(Side * side)1471 do_resign(Side *side)
1472 {
1473     Screen *screen = ui->curscreen;
1474 
1475     if (screen == NULL || endofgame) {
1476 	notify(dside, "Game is already over.");
1477 	beep();
1478     } else if (!side->ingame) {
1479 	notify(dside, "You are already out of the game.");
1480 	beep();
1481     } else {
1482 	ask_bool(screen, "Are you sure you want to resign now?",
1483 		 FALSE, aux_resign);
1484     }
1485 }
1486 
1487 static void
aux_resign(Screen * screen,int cancel)1488 aux_resign(Screen *screen, int cancel)
1489 {
1490     if (cancel)
1491       return;
1492     if (grok_bool(screen)) {
1493 	if (numsides > 2) {
1494 	    /* (should suggest resigning to a trusted side) */
1495 	    ask_side(screen, "To whom do you wish to surrender?",
1496 		     NULL, aux_resign_to);
1497 	} else {
1498 	    net_resign_game(dside, NULL);
1499 	}
1500     }
1501 }
1502 
1503 static void
aux_resign_to(Screen * screen,int cancel)1504 aux_resign_to(Screen *screen, int cancel)
1505 {
1506     Side *side2;
1507 
1508     if (cancel)
1509       return;
1510     if (grok_side(screen, &side2)) {
1511 	net_resign_game(dside, side2);
1512     } else {
1513 	/* Iterate until grok_side is happy. */
1514 	screen->modalhandler = aux_resign_to;
1515     }
1516 }
1517 
1518 /* Stuff game state into a file. */
1519 
1520 void
do_save(Side * side)1521 do_save(Side *side)
1522 {
1523     if (!during_game_only())
1524       return;
1525     /* (TODO: Actually do the save.) */
1526     gamestatesafe = TRUE;
1527 }
1528 
1529 void
do_set_formation(Side * side)1530 do_set_formation(Side *side)
1531 {
1532     Screen *screen = ui->curscreen;
1533 
1534     if (!require_own_unit_during_game(screen))
1535       return;
1536     screen->argunitid = screen->curunit->id;
1537     ask_position(screen, "Form up on who?", aux_set_formation);
1538 }
1539 
1540 static void
aux_set_formation(Screen * screen,int cancel)1541 aux_set_formation(Screen *screen, int cancel)
1542 {
1543     int x, y;
1544     char ubuf[BUFSIZE];
1545     Unit *unit, *leader;
1546 
1547     if (cancel)
1548       return;
1549     if (screen->inpch == '?') {
1550 	notify(dside, "Click on a unit that you want to follow.");
1551 	screen->modalhandler = aux_set_formation;
1552 	return;
1553     }
1554     if (grok_position(screen, &x, &y, NULL)) {
1555 	unit = find_unit(screen->argunitid);
1556 	if (!unit_still_ok(unit))
1557 	  return;
1558 	if (in_area(x, y)) {
1559 	    strcpy(ubuf, unit_handle(dside, unit));
1560 	    leader = unit_at(x, y);
1561 	    if (in_play(leader)
1562 		&& leader != unit
1563 		&& trusted_side(unit->side, leader->side)) {
1564 		net_set_formation(unit, leader,
1565 				  unit->x - leader->x, unit->y - leader->y,
1566 				  1, 1);
1567 		notify(dside, "%s to keep formation with %s.",
1568 		       ubuf, unit_handle(dside, leader));
1569 	    } else if (unit->plan != NULL
1570 		       && unit->plan->formation != NULL) {
1571 		/* Assume this is to cancel the formation. */
1572 		net_set_formation(unit, NULL, 0, 0, 0, 0);
1573 		notify(dside, "%s no longer keeping formation.", ubuf);
1574 	    } else {
1575 		cmd_error(dside, "Nobody here to form on!");
1576 	    }
1577 	}
1578     } else {
1579 	beep();
1580 	screen->modalhandler = aux_set_formation;
1581     }
1582 }
1583 
1584 void
do_set_view_angle(Side * side)1585 do_set_view_angle(Side *side)
1586 {
1587   sscreen->map->main_vp->isometric = !sscreen->map->main_vp->isometric;
1588   redraw_screen(sscreen);
1589 }
1590 
1591 void
do_side_closeup(Side * side)1592 do_side_closeup(Side *side)
1593 {
1594     cmd_error(dside, "Not implemented.");
1595 }
1596 
1597 void
do_standing_orders(Side * side)1598 do_standing_orders(Side *side)
1599 {
1600     int rslt;
1601 
1602     if (!during_game_only())
1603       return;
1604     if (cmdargstr) {
1605 	rslt = parse_standing_order(dside, cmdargstr);
1606 	if (rslt < 0)
1607 	  cmd_error(dside, "Parse error");
1608     } else
1609       cmd_error(dside, "No arguments given.");
1610 }
1611 
1612 void
do_survey(Side * side)1613 do_survey(Side *side)
1614 {
1615     Screen *screen = ui->curscreen;
1616 
1617     if (screen == NULL)
1618       return;
1619     if (endofgame && screen->mode == survey_mode)
1620       return;
1621     if (screen->mode == survey_mode && !endofgame) {
1622 	screen->mode = move_mode;
1623 	if (is_designer(dside))
1624 	  screen->mode = survey_mode; /* should be last design mode */
1625     } else if (screen->mode == move_mode) {
1626 	screen->mode = survey_mode;
1627     } else if (is_designer(dside)) {
1628 	screen->mode = survey_mode;
1629     } else {
1630 	beep();
1631 	return;
1632     }
1633     if (!is_designer(dside)) {
1634 	screen->autoselect = !screen->autoselect;
1635 	screen->move_on_click = !screen->move_on_click;
1636     }
1637     set_tool_cursor(screen);
1638     if (!screen->autoselect && screen->curunit != NULL)
1639       update_cell(screen, screen->curunit->x, screen->curunit->y);
1640     if (screen->mode == move_mode)
1641       ;
1642     else if (screen->mode == survey_mode)
1643       ;
1644     update_cursor(screen);
1645 }
1646 
1647 void
do_unit_closeup(Side * side)1648 do_unit_closeup(Side *side)
1649 {
1650     cmd_error(dside, "Not implemented.");
1651 }
1652 
1653 void
do_up(Side * side)1654 do_up(Side *side)
1655 {
1656     cmd_error(dside, "Not implemented.");
1657 }
1658 
1659 /* Command to display the program version. */
1660 
1661 void
do_version(Side * side)1662 do_version(Side *side)
1663 {
1664     notify(dside, "Xconq version %s", version_string());
1665     notify(dside, "(c) %s", copyright_string());
1666 }
1667 
1668 void
do_warranty(Side * side)1669 do_warranty(Side *side)
1670 {
1671     popup_help(dside, warranty_help_node);
1672 }
1673 
1674 /* Create a new world screen (a regular screen zoomed to display the whole
1675    world at once). */
1676 
1677 void
do_world_map(Side * side)1678 do_world_map(Side *side)
1679 {
1680     cmd_error(dside, "Not implemented.");
1681 }
1682 
1683 void
do_zoom_in(Side * side)1684 do_zoom_in(Side *side)
1685 {
1686     Map *map = sscreen->map;
1687 
1688     set_view_power(map->main_vp, min(6, map->main_vp->power + 1));
1689     recenter(map, map->main_vp->vcx, map->main_vp->vcy);
1690     redraw_screen(sscreen);
1691 }
1692 
1693 void
do_zoom_out(Side * side)1694 do_zoom_out(Side *side)
1695 {
1696     Map *map = sscreen->map;
1697 
1698     set_view_power(map->main_vp, max(0, map->main_vp->power - 1));
1699     recenter(map, map->main_vp->vcx, map->main_vp->vcy);
1700     redraw_screen(sscreen);
1701 }
1702 
1703 #ifdef DESIGNERS
1704 
1705 void
do_design(Side * side)1706 do_design(Side *side)
1707 {
1708     Screen *screen = ui->curscreen;
1709     Screen *screen2;
1710 
1711     if (screen == NULL)
1712       return;
1713     if (!is_designer(dside)) {
1714 	if (!designed_on) {
1715 	    ask_bool(screen, "Do you really want to start designing?",
1716 		     FALSE, aux_design);
1717 	} else {
1718 	    really_do_design(dside);
1719 	}
1720     } else {
1721 	net_become_nondesigner(dside);
1722 	for_all_screens(screen2) {
1723 	    set_show_all(screen2, side->show_all);
1724 	    /* Force back to survey mode; would be perhaps spiffier to
1725 	       switch back to pre-design mode, but given the effects
1726 	       of design mode, not much reason to bother. */
1727 	    screen->mode = survey_mode;
1728 	    set_tool_cursor(screen);
1729 	}
1730 	/* Just redo every display. */
1731 	do_refresh(dside);
1732     }
1733 }
1734 
1735 static void
aux_design(Screen * screen,int cancel)1736 aux_design(Screen *screen, int cancel)
1737 {
1738     if (cancel)
1739       return;
1740     if (grok_bool(screen)) {
1741 	really_do_design(dside);
1742     } else {
1743 	/* nothing to do if we said not to design */
1744     }
1745 }
1746 
1747 void
really_do_design(Side * side)1748 really_do_design(Side *side)
1749 {
1750     Screen *screen;
1751 
1752     net_become_designer(dside);
1753     for_all_screens(screen) {
1754 	set_show_all(screen, side->show_all);
1755 	redraw_screen(screen);
1756 	screen->autoselect = FALSE;
1757 	screen->mode = survey_mode;
1758     }
1759 }
1760 
1761 #endif /* DESIGNERS */
1762 
1763 #ifdef DEBUGGING
1764 
1765 void
do_profile(Side * side)1766 do_profile(Side *side)
1767 {
1768     cmd_error(dside, "Not implemented.");
1769 }
1770 
1771 void
do_trace(Side * side)1772 do_trace(Side *side)
1773 {
1774     extern int activity_trace;
1775 
1776     if (activity_trace)
1777       dump_activity_trace();
1778     activity_trace = !activity_trace;
1779 }
1780 
1781 #endif /* DEBUGGING */
1782 
1783 /* Generic command error feedback. */
1784 
1785 void
cmd_error(Side * side,char * fmt,...)1786 cmd_error(Side *side, char *fmt, ...)
1787 {
1788     va_list ap;
1789 
1790     if (!empty_string(fmt)) {
1791 	va_start(ap, fmt);
1792 	vnotify(dside, fmt, ap);
1793 	va_end(ap);
1794     }
1795     /* Only beep once, even if a command generates multiple error messages. */
1796     if (ui->beepcount++ < 1)
1797       beep();
1798 }
1799