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