1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 /* utility */
19 #include "bitvector.h"
20 #include "fcintl.h"
21 #include "log.h"
22 #include "mem.h"
23 #include "timing.h"
24
25 /* common */
26 #include "combat.h"
27 #include "game.h"
28 #include "map.h"
29 #include "movement.h"
30 #include "unitlist.h"
31
32 /* common/aicore */
33 #include "path_finding.h"
34
35 /* client/include */
36 #include "chatline_g.h"
37 #include "citydlg_g.h"
38 #include "dialogs_g.h"
39 #include "gui_main_g.h"
40 #include "mapctrl_g.h"
41 #include "mapview_g.h"
42 #include "menu_g.h"
43
44 /* client */
45 #include "audio.h"
46 #include "client_main.h"
47 #include "climap.h"
48 #include "climisc.h"
49 #include "editor.h"
50 #include "goto.h"
51 #include "options.h"
52 #include "overview_common.h"
53 #include "tilespec.h"
54 #include "update_queue.h"
55
56 #include "control.h"
57
58
59 struct client_nuke_data {
60 int *units_id;
61 int units_num;
62 int tile_idx;
63 };
64
65 /* gui-dep code may adjust depending on tile size etc: */
66 int num_units_below = MAX_NUM_UNITS_BELOW;
67
68 /* current_focus points to the current unit(s) in focus */
69 static struct unit_list *current_focus = NULL;
70
71 /* The previously focused unit(s). Focus can generally be recalled
72 * with keypad 5 (or the equivalent). */
73 static struct unit_list *previous_focus = NULL;
74
75 /* The priority unit(s) for unit_focus_advance(). */
76 static struct unit_list *urgent_focus_queue = NULL;
77
78 /* These should be set via set_hover_state() */
79 enum cursor_hover_state hover_state = HOVER_NONE;
80 enum unit_activity connect_activity;
81 struct extra_type *connect_tgt;
82 enum unit_orders goto_last_order; /* Last order for goto */
83
84 static struct tile *hover_tile = NULL;
85 static struct unit_list *battlegroups[MAX_NUM_BATTLEGROUPS];
86
87 /* Current moving unit. */
88 static struct unit *punit_moving = NULL;
89
90 /* units involved in current combat */
91 static struct unit *punit_attacking = NULL;
92 static struct unit *punit_defending = NULL;
93
94 /* The ID of the unit that currently is in the action selection process.
95 *
96 * The action selection process begins when the client asks the server what
97 * actions a unit can take. It ends when the last follow up question is
98 * answered.
99 *
100 * No common client code using client supports more than one action
101 * selection process at once. The interface between the common client code
102 * and the clients would have to change before that could happen. (See
103 * action_selection_actor_unit() etc)
104 */
105 static int action_selection_in_progress_for = IDENTITY_NUMBER_ZERO;
106
107 /*
108 * This variable is TRUE iff a NON-AI controlled unit was focused this
109 * turn.
110 */
111 bool non_ai_unit_focus;
112
113 static void key_unit_clean(enum unit_activity act, enum extra_rmcause rmcause);
114
115 /*************************************************************************/
116
117 static struct unit *quickselect(struct tile *ptile,
118 enum quickselect_type qtype);
119
120 /**************************************************************************
121 Called only by client_game_init() in client/client_main.c
122 **************************************************************************/
control_init(void)123 void control_init(void)
124 {
125 int i;
126
127 current_focus = unit_list_new();
128 previous_focus = unit_list_new();
129 urgent_focus_queue = unit_list_new();
130
131 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
132 battlegroups[i] = unit_list_new();
133 }
134 hover_tile = NULL;
135 }
136
137 /**************************************************************************
138 Called only by client_game_free() in client/client_main.c
139 **************************************************************************/
control_free(void)140 void control_free(void)
141 {
142 int i;
143
144 unit_list_destroy(current_focus);
145 current_focus = NULL;
146 unit_list_destroy(previous_focus);
147 previous_focus = NULL;
148 unit_list_destroy(urgent_focus_queue);
149 urgent_focus_queue = NULL;
150
151 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
152 unit_list_destroy(battlegroups[i]);
153 battlegroups[i] = NULL;
154 }
155
156 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
157 free_client_goto();
158 }
159
160 /**************************************************************************
161 Returns list of units currently in focus.
162 **************************************************************************/
get_units_in_focus(void)163 struct unit_list *get_units_in_focus(void)
164 {
165 return current_focus;
166 }
167
168 /****************************************************************************
169 Return the number of units currently in focus (0 or more).
170 ****************************************************************************/
get_num_units_in_focus(void)171 int get_num_units_in_focus(void)
172 {
173 return (NULL != current_focus ? unit_list_size(current_focus) : 0);
174 }
175
176 /**************************************************************************
177 Store the focus unit(s). This is used so that we can return to the
178 previously focused unit with an appropriate keypress.
179 **************************************************************************/
store_previous_focus(void)180 static void store_previous_focus(void)
181 {
182 if (get_num_units_in_focus() > 0) {
183 unit_list_clear(previous_focus);
184 unit_list_iterate(get_units_in_focus(), punit) {
185 unit_list_append(previous_focus, punit);
186 } unit_list_iterate_end;
187 }
188 }
189
190 /****************************************************************************
191 Store a priority focus unit.
192 ****************************************************************************/
unit_focus_urgent(struct unit * punit)193 void unit_focus_urgent(struct unit *punit)
194 {
195 unit_list_append(urgent_focus_queue, punit);
196 }
197
198 /**************************************************************************
199 Do various updates required when the set of units in focus changes.
200 **************************************************************************/
focus_units_changed(void)201 static void focus_units_changed(void)
202 {
203 update_unit_info_label(get_units_in_focus());
204 menus_update();
205 /* Notify the GUI */
206 real_focus_units_changed();
207 }
208
209 /**************************************************************************
210 Called when a unit is killed; this removes it from the control lists.
211 **************************************************************************/
control_unit_killed(struct unit * punit)212 void control_unit_killed(struct unit *punit)
213 {
214 int i;
215
216 goto_unit_killed(punit);
217
218 unit_list_remove(get_units_in_focus(), punit);
219 if (get_num_units_in_focus() < 1) {
220 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
221 }
222
223 unit_list_remove(previous_focus, punit);
224 unit_list_remove(urgent_focus_queue, punit);
225
226 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
227 unit_list_remove(battlegroups[i], punit);
228 }
229
230 focus_units_changed();
231 }
232
233 /**************************************************************************
234 Change the battlegroup for this unit.
235 **************************************************************************/
unit_change_battlegroup(struct unit * punit,int battlegroup)236 void unit_change_battlegroup(struct unit *punit, int battlegroup)
237 {
238 if (battlegroup < 0 || battlegroup >= MAX_NUM_BATTLEGROUPS) {
239 battlegroup = BATTLEGROUP_NONE;
240 }
241
242 if (punit->battlegroup != battlegroup) {
243 if (battlegroup != BATTLEGROUP_NONE) {
244 unit_list_append(battlegroups[battlegroup], punit);
245 }
246 if (punit->battlegroup != BATTLEGROUP_NONE) {
247 unit_list_remove(battlegroups[punit->battlegroup], punit);
248 }
249 punit->battlegroup = battlegroup;
250 }
251 }
252
253 /**************************************************************************
254 Call this on new units to enter them in the battlegroup lists.
255 **************************************************************************/
unit_register_battlegroup(struct unit * punit)256 void unit_register_battlegroup(struct unit *punit)
257 {
258 if (punit->battlegroup < 0 || punit->battlegroup >= MAX_NUM_BATTLEGROUPS) {
259 punit->battlegroup = BATTLEGROUP_NONE;
260 } else {
261 unit_list_append(battlegroups[punit->battlegroup], punit);
262 }
263 }
264
265 /**************************************************************************
266 Enter the given hover state.
267
268 activity => The connect activity (ACTIVITY_IRRIGATE, etc.)
269 order => The last order (ORDER_BUILD_CITY, ORDER_LAST, etc.)
270 **************************************************************************/
set_hover_state(struct unit_list * punits,enum cursor_hover_state state,enum unit_activity activity,struct extra_type * tgt,enum unit_orders order)271 void set_hover_state(struct unit_list *punits, enum cursor_hover_state state,
272 enum unit_activity activity,
273 struct extra_type *tgt,
274 enum unit_orders order)
275 {
276 fc_assert_ret((punits && unit_list_size(punits) > 0)
277 || state == HOVER_NONE);
278 fc_assert_ret(state == HOVER_CONNECT || activity == ACTIVITY_LAST);
279 fc_assert_ret(state == HOVER_GOTO || order == ORDER_LAST);
280 exit_goto_state();
281 hover_state = state;
282 connect_activity = activity;
283 if (tgt) {
284 connect_tgt = tgt;
285 } else {
286 connect_tgt = NULL;
287 }
288 goto_last_order = order;
289 }
290
291 /**************************************************************************
292 Returns TRUE iff the client should ask the server about what actions a
293 unit can perform.
294 **************************************************************************/
should_ask_server_for_actions(const struct unit * punit)295 bool should_ask_server_for_actions(const struct unit *punit)
296 {
297 return (punit->action_decision_want == ACT_DEC_ACTIVE
298 /* The player is interested in getting a pop up for a mere
299 * arrival. */
300 || (punit->action_decision_want == ACT_DEC_PASSIVE
301 && gui_options.popup_actor_arrival));
302 }
303
304 /**************************************************************************
305 Returns TRUE iff it is OK to ask the server about what actions a unit
306 can perform.
307 **************************************************************************/
can_ask_server_for_actions(void)308 static bool can_ask_server_for_actions(void)
309 {
310 /* OK as long as no other unit already asked and aren't done yet. */
311 return (action_selection_in_progress_for == IDENTITY_NUMBER_ZERO
312 && action_selection_actor_unit() == IDENTITY_NUMBER_ZERO);
313 }
314
315 /**************************************************************************
316 Ask the server about what actions punit may be able to perform against
317 it's stored target tile.
318
319 The server's reply will pop up the action selection dialog unless no
320 alternatives exists.
321 **************************************************************************/
ask_server_for_actions(struct unit * punit)322 static void ask_server_for_actions(struct unit *punit)
323 {
324 fc_assert_ret(punit);
325 fc_assert_ret(punit->action_decision_tile);
326
327 /* Only one action selection dialog at a time is supported. */
328 fc_assert_msg(action_selection_in_progress_for == IDENTITY_NUMBER_ZERO,
329 "Unit %d started action selection before unit %d was done",
330 action_selection_in_progress_for, punit->id);
331 action_selection_in_progress_for = punit->id;
332
333 dsend_packet_unit_get_actions(&client.conn,
334 punit->id,
335 IDENTITY_NUMBER_ZERO,
336 IDENTITY_NUMBER_ZERO,
337 tile_index(punit->action_decision_tile),
338 TRUE);
339 }
340
341 /****************************************************************************
342 Return TRUE iff this unit is in focus.
343 ****************************************************************************/
unit_is_in_focus(const struct unit * punit)344 bool unit_is_in_focus(const struct unit *punit)
345 {
346 return unit_list_search(get_units_in_focus(), punit) != NULL;
347 }
348
349 /****************************************************************************
350 Return TRUE iff a unit on this tile is in focus.
351 ****************************************************************************/
get_focus_unit_on_tile(const struct tile * ptile)352 struct unit *get_focus_unit_on_tile(const struct tile *ptile)
353 {
354 unit_list_iterate(get_units_in_focus(), punit) {
355 if (unit_tile(punit) == ptile) {
356 return punit;
357 }
358 } unit_list_iterate_end;
359
360 return NULL;
361 }
362
363 /****************************************************************************
364 Return head of focus units list.
365 ****************************************************************************/
head_of_units_in_focus(void)366 struct unit *head_of_units_in_focus(void)
367 {
368 return unit_list_get(current_focus, 0);
369 }
370
371 /****************************************************************************
372 Finds a single focus unit that we can center on. May return NULL.
373 ****************************************************************************/
find_a_focus_unit_tile_to_center_on(void)374 static struct tile *find_a_focus_unit_tile_to_center_on(void)
375 {
376 struct unit *punit;
377
378 if (NULL != (punit = get_focus_unit_on_tile(get_center_tile_mapcanvas()))) {
379 return unit_tile(punit);
380 } else if (get_num_units_in_focus() > 0) {
381 return unit_tile(head_of_units_in_focus());
382 } else {
383 return NULL;
384 }
385 }
386
387 /**************************************************************************
388 Center on the focus unit, if off-screen and auto_center_on_unit is true.
389 **************************************************************************/
auto_center_on_focus_unit(void)390 void auto_center_on_focus_unit(void)
391 {
392 struct tile *ptile = find_a_focus_unit_tile_to_center_on();
393
394 if (ptile && gui_options.auto_center_on_unit &&
395 !tile_visible_and_not_on_border_mapcanvas(ptile)) {
396 center_tile_mapcanvas(ptile);
397 }
398 }
399
400 /**************************************************************************
401 Add unit to list of units currently in focus.
402 **************************************************************************/
current_focus_append(struct unit * punit)403 static void current_focus_append(struct unit *punit)
404 {
405 unit_list_append(current_focus, punit);
406
407 punit->client.focus_status = FOCUS_AVAIL;
408 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
409
410 if (should_ask_server_for_actions(punit)
411 && can_ask_server_for_actions()) {
412 ask_server_for_actions(punit);
413 }
414
415 if (gui_options.unit_selection_clears_orders) {
416 clear_unit_orders(punit);
417 }
418 }
419
420 /**************************************************************************
421 Remove focus from unit.
422 **************************************************************************/
current_focus_remove(struct unit * punit)423 static void current_focus_remove(struct unit *punit)
424 {
425 /* Close the action selection dialog if the actor unit lose focus. */
426 if (action_selection_actor_unit() == punit->id) {
427 action_selection_close();
428 }
429
430 unit_list_remove(current_focus, punit);
431 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
432 }
433
434 /**************************************************************************
435 Clear all orders for the given unit.
436 **************************************************************************/
clear_unit_orders(struct unit * punit)437 void clear_unit_orders(struct unit *punit)
438 {
439 if (!punit) {
440 return;
441 }
442
443 if (punit->activity != ACTIVITY_IDLE
444 || punit->ai_controlled) {
445 punit->ai_controlled = FALSE;
446 refresh_unit_city_dialogs(punit);
447 request_new_unit_activity(punit, ACTIVITY_IDLE);
448 } else if (unit_has_orders(punit)) {
449 /* Clear the focus unit's orders. */
450 request_orders_cleared(punit);
451 }
452 }
453
454 /**************************************************************************
455 Sets the focus unit directly. The unit given will be given the
456 focus; if NULL the focus will be cleared.
457
458 This function is called for several reasons. Sometimes a fast-focus
459 happens immediately as a result of a client action. Other times it
460 happens because of a server-sent packet that wakes up a unit.
461 **************************************************************************/
unit_focus_set(struct unit * punit)462 void unit_focus_set(struct unit *punit)
463 {
464 bool focus_changed = FALSE;
465
466 if (NULL != punit
467 && NULL != client.conn.playing
468 && unit_owner(punit) != client.conn.playing) {
469 /* Callers should make sure this never happens. */
470 return;
471 }
472
473 /* FIXME: this won't work quite right; for instance activating a
474 * battlegroup twice in a row will store the focus erronously. The only
475 * solution would be a set_units_focus() */
476 if (!(get_num_units_in_focus() == 1
477 && punit == head_of_units_in_focus())) {
478 store_previous_focus();
479 focus_changed = TRUE;
480 }
481
482 /* Close the action selection dialog if the actor unit lose focus. */
483 unit_list_iterate(current_focus, punit_old) {
484 if (action_selection_actor_unit() == punit_old->id) {
485 action_selection_close();
486 }
487 } unit_list_iterate_end;
488
489 /* Redraw the old focus unit (to fix blinking or remove the selection
490 * circle). */
491 unit_list_iterate(current_focus, punit_old) {
492 refresh_unit_mapcanvas(punit_old, unit_tile(punit_old), TRUE, FALSE);
493 } unit_list_iterate_end;
494 unit_list_clear(current_focus);
495
496 if (!can_client_change_view()) {
497 /* This function can be called to set the focus to NULL when
498 * disconnecting. In this case we don't want any other actions! */
499 fc_assert(punit == NULL);
500 return;
501 }
502
503 if (NULL != punit) {
504 current_focus_append(punit);
505 auto_center_on_focus_unit();
506 }
507
508 if (focus_changed) {
509 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
510 focus_units_changed();
511 }
512 }
513
514 /**************************************************************************
515 Adds this unit to the list of units in focus.
516 **************************************************************************/
unit_focus_add(struct unit * punit)517 void unit_focus_add(struct unit *punit)
518 {
519 if (NULL != punit
520 && NULL != client.conn.playing
521 && unit_owner(punit) != client.conn.playing) {
522 /* Callers should make sure this never happens. */
523 return;
524 }
525
526 if (NULL == punit || !can_client_change_view()) {
527 return;
528 }
529
530 if (unit_is_in_focus(punit)) {
531 return;
532 }
533
534 if (hover_state != HOVER_NONE) {
535 /* Can't continue with current goto if set of focus units
536 * change. Cancel it. */
537 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
538 }
539
540 current_focus_append(punit);
541 focus_units_changed();
542 }
543
544 /**************************************************************************
545 Removes this unit from the list of units in focus.
546 **************************************************************************/
unit_focus_remove(struct unit * punit)547 void unit_focus_remove(struct unit *punit)
548 {
549 if (NULL != punit
550 && NULL != client.conn.playing
551 && unit_owner(punit) != client.conn.playing) {
552 /* Callers should make sure this never happens. */
553 return;
554 }
555
556 if (NULL == punit || !can_client_change_view()) {
557 return;
558 }
559
560 if (!unit_is_in_focus(punit)) {
561 return;
562 }
563
564 if (hover_state != HOVER_NONE) {
565 /* Can't continue with current goto if set of focus units
566 * change. Cancel it. */
567 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
568 }
569
570 current_focus_remove(punit);
571 if (get_num_units_in_focus() > 0) {
572 focus_units_changed();
573 } else {
574 unit_focus_advance();
575 }
576 }
577
578 /**************************************************************************
579 The only difference is that here we draw the "cross".
580 **************************************************************************/
unit_focus_set_and_select(struct unit * punit)581 void unit_focus_set_and_select(struct unit *punit)
582 {
583 unit_focus_set(punit);
584 if (punit) {
585 put_cross_overlay_tile(unit_tile(punit));
586 }
587 }
588
589 /**************************************************************************
590 Find the nearest available unit for focus, excluding any current unit
591 in focus unless "accept_current" is TRUE. If the current focus unit
592 is the only possible unit, or if there is no possible unit, returns NULL.
593 **************************************************************************/
find_best_focus_candidate(bool accept_current)594 static struct unit *find_best_focus_candidate(bool accept_current)
595 {
596 struct tile *ptile = get_center_tile_mapcanvas();
597
598 if (!get_focus_unit_on_tile(ptile)) {
599 struct unit *pfirst = head_of_units_in_focus();
600
601 if (pfirst) {
602 ptile = unit_tile(pfirst);
603 }
604 }
605
606 iterate_outward(ptile, FC_INFINITY, ptile2) {
607 unit_list_iterate(ptile2->units, punit) {
608 if ((!unit_is_in_focus(punit) || accept_current)
609 && unit_owner(punit) == client.conn.playing
610 && punit->client.focus_status == FOCUS_AVAIL
611 && punit->activity == ACTIVITY_IDLE
612 && !unit_has_orders(punit)
613 && (punit->moves_left > 0 || unit_type_get(punit)->move_rate == 0)
614 && !punit->done_moving
615 && !punit->ai_controlled) {
616 return punit;
617 }
618 } unit_list_iterate_end;
619 } iterate_outward_end;
620
621 return NULL;
622 }
623
624 /**************************************************************************
625 This function may be called from packhand.c, via unit_focus_update(),
626 as a result of packets indicating change in activity for a unit. Also
627 called when user press the "Wait" command.
628
629 FIXME: Add feature to focus only units of a certain category.
630 **************************************************************************/
unit_focus_advance(void)631 void unit_focus_advance(void)
632 {
633 struct unit *candidate = NULL;
634 const int num_units_in_old_focus = get_num_units_in_focus();
635
636 if (NULL == client.conn.playing
637 || !is_player_phase(client.conn.playing, game.info.phase)
638 || !can_client_change_view()) {
639 unit_focus_set(NULL);
640 return;
641 }
642
643 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
644
645 unit_list_iterate(get_units_in_focus(), punit) {
646 /*
647 * Is the unit which just lost focus a non-AI unit? If yes this
648 * enables the auto end turn.
649 */
650 if (!punit->ai_controlled) {
651 non_ai_unit_focus = TRUE;
652 break;
653 }
654 } unit_list_iterate_end;
655
656 if (unit_list_size(urgent_focus_queue) > 0) {
657 /* Try top of the urgent list. */
658 struct tile *focus_tile = (get_num_units_in_focus() > 0
659 ? unit_tile(head_of_units_in_focus())
660 : NULL);
661
662 unit_list_both_iterate(urgent_focus_queue, plink, punit) {
663 if ((ACTIVITY_IDLE != punit->activity
664 || unit_has_orders(punit))
665 /* This isn't an action decision needed because of an
666 * ORDER_ACTION_MOVE located in the middle of an order. */
667 && !should_ask_server_for_actions(punit)) {
668 /* We have assigned new orders to this unit since, remove it. */
669 unit_list_erase(urgent_focus_queue, plink);
670 } else if (NULL == focus_tile
671 || focus_tile == unit_tile(punit)) {
672 /* Use the first one found */
673 candidate = punit;
674 break;
675 } else if (NULL == candidate) {
676 candidate = punit;
677 }
678 } unit_list_both_iterate_end;
679
680 if (NULL != candidate) {
681 unit_list_remove(urgent_focus_queue, candidate);
682
683 /* Autocenter on Wakeup, regardless of the local option
684 * "auto_center_on_unit". */
685 if (!tile_visible_and_not_on_border_mapcanvas(unit_tile(candidate))) {
686 center_tile_mapcanvas(unit_tile(candidate));
687 }
688 }
689 }
690
691 if (NULL == candidate) {
692 candidate = find_best_focus_candidate(FALSE);
693
694 if (!candidate) {
695 /* Try for "waiting" units. */
696 unit_list_iterate(client.conn.playing->units, punit) {
697 if(punit->client.focus_status == FOCUS_WAIT) {
698 punit->client.focus_status = FOCUS_AVAIL;
699 }
700 } unit_list_iterate_end;
701 candidate = find_best_focus_candidate(FALSE);
702
703 if (!candidate) {
704 /* Accept current focus unit as last resort. */
705 candidate = find_best_focus_candidate(TRUE);
706 }
707 }
708 }
709
710 unit_focus_set(candidate);
711
712 /*
713 * Handle auto-turn-done mode: If a unit was in focus (did move),
714 * but now none are (no more to move) and there was at least one
715 * non-AI unit this turn which was focused, then fake a Turn Done
716 * keypress.
717 */
718 if (gui_options.auto_turn_done
719 && num_units_in_old_focus > 0
720 && get_num_units_in_focus() == 0
721 && non_ai_unit_focus) {
722 key_end_turn();
723 }
724 }
725
726 /**************************************************************************
727 If there is no unit currently in focus, or if the current unit in
728 focus should not be in focus, then get a new focus unit.
729 We let GOTO-ing units stay in focus, so that if they have moves left
730 at the end of the goto, then they are still in focus.
731 **************************************************************************/
unit_focus_update(void)732 void unit_focus_update(void)
733 {
734 if (NULL == client.conn.playing || !can_client_change_view()) {
735 return;
736 }
737
738 if (!can_ask_server_for_actions()) {
739 fc_assert(get_num_units_in_focus() > 0);
740
741 /* An actor unit is asking the player what to do. Don't steal his
742 * focus. */
743 return;
744 }
745
746 /* iterate zero times for no units in focus,
747 * otherwise quit for any of the conditions. */
748 unit_list_iterate(get_units_in_focus(), punit) {
749 if ((punit->activity == ACTIVITY_IDLE
750 || punit->activity == ACTIVITY_GOTO
751 || unit_has_orders(punit))
752 && punit->moves_left > 0
753 && !punit->done_moving
754 && !punit->ai_controlled) {
755 return;
756 }
757 } unit_list_iterate_end;
758
759 unit_focus_advance();
760 }
761
762 /**************************************************************************
763 Return a pointer to a visible unit, if there is one.
764 **************************************************************************/
find_visible_unit(struct tile * ptile)765 struct unit *find_visible_unit(struct tile *ptile)
766 {
767 struct unit *panyowned = NULL, *panyother = NULL, *ptptother = NULL;
768
769 /* If no units here, return nothing. */
770 if (unit_list_size(ptile->units)==0) {
771 return NULL;
772 }
773
774 /* If a unit is attacking we should show that on top */
775 if (punit_attacking && same_pos(unit_tile(punit_attacking), ptile)) {
776 unit_list_iterate(ptile->units, punit)
777 if(punit == punit_attacking) return punit;
778 unit_list_iterate_end;
779 }
780
781 /* If a unit is defending we should show that on top */
782 if (punit_defending && same_pos(unit_tile(punit_defending), ptile)) {
783 unit_list_iterate(ptile->units, punit)
784 if(punit == punit_defending) return punit;
785 unit_list_iterate_end;
786 }
787
788 /* If the unit in focus is at this tile, show that on top */
789 unit_list_iterate(get_units_in_focus(), punit) {
790 if (punit != punit_moving && unit_tile(punit) == ptile) {
791 return punit;
792 }
793 } unit_list_iterate_end;
794
795 /* If a city is here, return nothing (unit hidden by city). */
796 if (tile_city(ptile)) {
797 return NULL;
798 }
799
800 /* Iterate through the units to find the best one we prioritize this way:
801 1: owned transporter.
802 2: any owned unit
803 3: any transporter
804 4: any unit
805 (always return first in stack). */
806 unit_list_iterate(ptile->units, punit)
807 if (unit_owner(punit) == client.conn.playing) {
808 if (!unit_transported(punit)) {
809 if (get_transporter_capacity(punit) > 0) {
810 return punit;
811 } else if (!panyowned) {
812 panyowned = punit;
813 }
814 }
815 } else if (!ptptother && !unit_transported(punit)) {
816 if (get_transporter_capacity(punit) > 0) {
817 ptptother = punit;
818 } else if (!panyother) {
819 panyother = punit;
820 }
821 }
822 unit_list_iterate_end;
823
824 return (panyowned ? panyowned : (ptptother ? ptptother : panyother));
825 }
826
827 /**************************************************************************
828 Blink the active unit (if necessary). Return the time until the next
829 blink (in seconds).
830 **************************************************************************/
blink_active_unit(void)831 double blink_active_unit(void)
832 {
833 static struct timer *blink_timer = NULL;
834 const double blink_time = get_focus_unit_toggle_timeout(tileset);
835
836 if (get_num_units_in_focus() > 0) {
837 if (!blink_timer || timer_read_seconds(blink_timer) > blink_time) {
838 toggle_focus_unit_state(tileset);
839
840 /* If we lag, we don't try to catch up. Instead we just start a
841 * new blink_time on every update. */
842 blink_timer = timer_renew(blink_timer, TIMER_USER, TIMER_ACTIVE);
843 timer_start(blink_timer);
844
845 unit_list_iterate(get_units_in_focus(), punit) {
846 /* We flush to screen directly here. This is most likely faster
847 * since these drawing operations are all small but may be spread
848 * out widely. */
849 refresh_unit_mapcanvas(punit, unit_tile(punit), FALSE, TRUE);
850 } unit_list_iterate_end;
851 }
852
853 return blink_time - timer_read_seconds(blink_timer);
854 }
855
856 return blink_time;
857 }
858
859 /****************************************************************************
860 Blink the turn done button (if necessary). Return the time until the next
861 blink (in seconds).
862 ****************************************************************************/
blink_turn_done_button(void)863 double blink_turn_done_button(void)
864 {
865 static struct timer *blink_timer = NULL;
866 const double blink_time = 0.5; /* half-second blink interval */
867
868 if (NULL != client.conn.playing
869 && client.conn.playing->is_alive
870 && !client.conn.playing->phase_done
871 && is_player_phase(client.conn.playing, game.info.phase)) {
872 if (!blink_timer || timer_read_seconds(blink_timer) > blink_time) {
873 int is_waiting = 0, is_moving = 0;
874 bool blocking_mode;
875 struct option *opt;
876
877 opt = optset_option_by_name(server_optset, "turnblock");
878 if (opt != NULL) {
879 blocking_mode = option_bool_get(opt);
880 } else {
881 blocking_mode = FALSE;
882 }
883
884 players_iterate_alive(pplayer) {
885 if ((pplayer->is_connected || blocking_mode)
886 && is_player_phase(pplayer, game.info.phase)) {
887 if (pplayer->phase_done) {
888 is_waiting++;
889 } else {
890 is_moving++;
891 }
892 }
893 } players_iterate_alive_end;
894
895 if (is_moving == 1 && is_waiting > 0) {
896 update_turn_done_button(FALSE); /* stress the slow player! */
897 }
898 blink_timer = timer_renew(blink_timer, TIMER_USER, TIMER_ACTIVE);
899 timer_start(blink_timer);
900 }
901 return blink_time - timer_read_seconds(blink_timer);
902 }
903
904 return blink_time;
905 }
906
907 /**************************************************************************
908 Update unit icons (and arrow) in the information display, for specified
909 punit as the active unit and other units on the same square. In practice
910 punit is almost always (or maybe strictly always?) the focus unit.
911
912 Static vars store some info on current (ie previous) state, to avoid
913 unnecessary redraws; initialise to "flag" values to always redraw first
914 time. In principle we _might_ need more info (eg ai.control, connecting),
915 but in practice this is enough?
916
917 Used to store unit_ids for below units, to use for callbacks (now done
918 inside gui-dep set_unit_icon()), but even with ids here they would not
919 be enough information to know whether to redraw -- instead redraw every
920 time. (Could store enough info to know, but is it worth it?)
921 **************************************************************************/
update_unit_pix_label(struct unit_list * punitlist)922 void update_unit_pix_label(struct unit_list *punitlist)
923 {
924 int i;
925
926 /* Check for any change in the unit's state. This assumes that a unit's
927 * orders cannot be changed directly but must be removed and then reset. */
928 if (punitlist && unit_list_size(punitlist) > 0
929 && C_S_OVER != client_state()) {
930 /* There used to be a complicated and bug-prone check here to see if
931 * the unit had actually changed. This was misguided since the stacked
932 * units (below) are redrawn in any case. Unless we write a general
933 * system for unit updates here we might as well just redraw it every
934 * time. */
935 struct unit *punit = unit_list_get(punitlist, 0);
936
937 set_unit_icon(-1, punit);
938
939 i = 0; /* index into unit_below_canvas */
940 unit_list_iterate(unit_tile(punit)->units, aunit) {
941 if (aunit != punit) {
942 if (i < num_units_below) {
943 set_unit_icon(i, aunit);
944 }
945 i++;
946 }
947 }
948 unit_list_iterate_end;
949
950 if (i > num_units_below) {
951 set_unit_icons_more_arrow(TRUE);
952 } else {
953 set_unit_icons_more_arrow(FALSE);
954 for(; i < num_units_below; i++) {
955 set_unit_icon(i, NULL);
956 }
957 }
958 } else {
959 for(i=-1; i<num_units_below; i++) {
960 set_unit_icon(i, NULL);
961 }
962 set_unit_icons_more_arrow(FALSE);
963 }
964 }
965
966 /**************************************************************************
967 Adjusts way combatants are displayed suitable for combat.
968 **************************************************************************/
set_units_in_combat(struct unit * pattacker,struct unit * pdefender)969 void set_units_in_combat(struct unit *pattacker, struct unit *pdefender)
970 {
971 punit_attacking = pattacker;
972 punit_defending = pdefender;
973
974 if (unit_is_in_focus(punit_attacking)
975 || unit_is_in_focus(punit_defending)) {
976 /* If one of the units is the focus unit, make sure hidden-focus is
977 * disabled. We don't just do this as a check later because then
978 * with a blinking unit it would just disappear again right after the
979 * battle. */
980 focus_unit_in_combat(tileset);
981 }
982 }
983
984 /**************************************************************************
985 The action selection process is no longer in progres for the specified
986 unit. It is safe to let another unit enter it.
987 **************************************************************************/
action_selection_no_longer_in_progress(const int old_actor_id)988 void action_selection_no_longer_in_progress(const int old_actor_id)
989 {
990 /* IDENTITY_NUMBER_ZERO is accepted for cases where the unit is gone
991 * without a trace. */
992 fc_assert_msg(old_actor_id == action_selection_in_progress_for
993 || old_actor_id == IDENTITY_NUMBER_ZERO,
994 "Decision taken for %d but selection is for %d.",
995 old_actor_id, action_selection_in_progress_for);
996
997 /* Stop objecting to allowing the next unit to ask. */
998 action_selection_in_progress_for = IDENTITY_NUMBER_ZERO;
999
1000 /* Clean up any client specific assumptions. */
1001 action_selection_no_longer_in_progress_gui_specific(old_actor_id);
1002 }
1003
1004 /**************************************************************************
1005 Have the server record that a decision no longer is wanted for the
1006 specified unit.
1007 **************************************************************************/
action_decision_clear_want(const int old_actor_id)1008 void action_decision_clear_want(const int old_actor_id)
1009 {
1010 struct unit *old;
1011
1012 if ((old = game_unit_by_number(old_actor_id))) {
1013 /* Have the server record that a decision no longer is wanted. */
1014 request_do_action(ACTION_COUNT, old_actor_id, IDENTITY_NUMBER_ZERO,
1015 ACTSIG_UNQUEUE);
1016 }
1017 }
1018
1019 /**************************************************************************
1020 Move on to the next unit in focus that needs an action decision.
1021 **************************************************************************/
action_selection_next_in_focus(const int old_actor_id)1022 void action_selection_next_in_focus(const int old_actor_id)
1023 {
1024 struct unit *old;
1025
1026 old = game_unit_by_number(old_actor_id);
1027
1028 /* Go to the next unit in focus that needs a decision. */
1029 unit_list_iterate(get_units_in_focus(), funit) {
1030 if (old != funit && should_ask_server_for_actions(funit)) {
1031 ask_server_for_actions(funit);
1032 return;
1033 }
1034 } unit_list_iterate_end;
1035 }
1036
1037 /**************************************************************************
1038 Request that the player makes a decision for the specified unit.
1039 **************************************************************************/
action_decision_request(struct unit * actor_unit)1040 void action_decision_request(struct unit *actor_unit)
1041 {
1042 fc_assert_ret(actor_unit);
1043 fc_assert_ret(actor_unit->action_decision_tile);
1044
1045 if (!unit_is_in_focus(actor_unit)) {
1046 /* Getting feed back may be urgent. A unit standing next to an enemy
1047 * could be killed while waiting. */
1048 unit_focus_urgent(actor_unit);
1049 } else if (can_client_issue_orders()
1050 && can_ask_server_for_actions()) {
1051 /* No need to wait. The actor unit is in focus. No other actor unit
1052 * is currently asking about action selection. */
1053 ask_server_for_actions(actor_unit);
1054 }
1055 }
1056
1057 /**************************************************************************
1058 Do a goto with an order at the end (or ORDER_LAST).
1059 **************************************************************************/
request_unit_goto(enum unit_orders last_order)1060 void request_unit_goto(enum unit_orders last_order)
1061 {
1062 struct unit_list *punits = get_units_in_focus();
1063
1064 if (unit_list_size(punits) == 0) {
1065 return;
1066 }
1067
1068 if (hover_state != HOVER_GOTO) {
1069 set_hover_state(punits, HOVER_GOTO, ACTIVITY_LAST, NULL,
1070 last_order);
1071 enter_goto_state(punits);
1072 create_line_at_mouse_pos();
1073 update_unit_info_label(punits);
1074 control_mouse_cursor(NULL);
1075 } else {
1076 fc_assert_ret(goto_is_active());
1077 goto_add_waypoint();
1078 }
1079 }
1080
1081 /****************************************************************************
1082 Return TRUE if at least one of the units can do an attack at the tile.
1083 ****************************************************************************/
can_units_attack_at(struct unit_list * punits,const struct tile * ptile)1084 static bool can_units_attack_at(struct unit_list *punits,
1085 const struct tile *ptile)
1086 {
1087 unit_list_iterate(punits, punit) {
1088 if (is_attack_unit(punit)
1089 && can_unit_attack_tile(punit, ptile)) {
1090 return TRUE;
1091 }
1092 } unit_list_iterate_end;
1093
1094 return FALSE;
1095 }
1096
1097 /**************************************************************************
1098 Determines which mouse cursor should be used, according to hover_state,
1099 and the information gathered from the tile which is under the mouse
1100 cursor (ptile).
1101 **************************************************************************/
control_mouse_cursor(struct tile * ptile)1102 void control_mouse_cursor(struct tile *ptile)
1103 {
1104 struct unit *punit = NULL;
1105 struct city *pcity = NULL;
1106 struct unit_list *active_units = get_units_in_focus();
1107 enum cursor_type mouse_cursor_type = CURSOR_DEFAULT;
1108
1109 if (!gui_options.enable_cursor_changes) {
1110 return;
1111 }
1112
1113 if (C_S_RUNNING != client_state()) {
1114 update_mouse_cursor(CURSOR_DEFAULT);
1115 return;
1116 }
1117
1118 if (is_server_busy()) {
1119 /* Server will not accept any commands. */
1120 update_mouse_cursor(CURSOR_WAIT);
1121 return;
1122 }
1123
1124 if (!ptile) {
1125 if (hover_tile) {
1126 /* hover_tile is the tile that was previously under the mouse cursor. */
1127 ptile = hover_tile;
1128 } else {
1129 update_mouse_cursor(CURSOR_DEFAULT);
1130 return;
1131 }
1132 } else {
1133 hover_tile = ptile;
1134 }
1135
1136 punit = find_visible_unit(ptile);
1137 pcity = ptile ? tile_city(ptile) : NULL;
1138
1139 switch (hover_state) {
1140 case HOVER_NONE:
1141 if (NULL != punit
1142 && unit_owner(punit) == client_player()) {
1143 /* Set mouse cursor to select a unit. */
1144 mouse_cursor_type = CURSOR_SELECT;
1145 } else if (NULL != pcity
1146 && can_player_see_city_internals(client.conn.playing, pcity)) {
1147 /* Set mouse cursor to select a city. */
1148 mouse_cursor_type = CURSOR_SELECT;
1149 } else {
1150 /* Set default mouse cursor, because nothing selectable found. */
1151 }
1152 break;
1153 case HOVER_GOTO:
1154 /* Determine if the goto is valid, invalid or will attack. */
1155 if (is_valid_goto_destination(ptile)) {
1156 if (can_units_attack_at(active_units, ptile)) {
1157 /* Goto results in military attack. */
1158 mouse_cursor_type = CURSOR_ATTACK;
1159 } else if (is_enemy_city_tile(ptile, client.conn.playing)) {
1160 /* Goto results in attack of enemy city. */
1161 mouse_cursor_type = CURSOR_ATTACK;
1162 } else {
1163 mouse_cursor_type = CURSOR_GOTO;
1164 }
1165 } else {
1166 mouse_cursor_type = CURSOR_INVALID;
1167 }
1168 break;
1169 case HOVER_PATROL:
1170 if (is_valid_goto_destination(ptile)) {
1171 mouse_cursor_type = CURSOR_PATROL;
1172 } else {
1173 mouse_cursor_type = CURSOR_INVALID;
1174 }
1175 break;
1176 case HOVER_CONNECT:
1177 if (is_valid_goto_destination(ptile)) {
1178 mouse_cursor_type = CURSOR_GOTO;
1179 } else {
1180 mouse_cursor_type = CURSOR_INVALID;
1181 }
1182 break;
1183 case HOVER_NUKE:
1184 if (is_valid_goto_destination(ptile)) {
1185 mouse_cursor_type = CURSOR_NUKE;
1186 } else {
1187 mouse_cursor_type = CURSOR_INVALID;
1188 }
1189 break;
1190 case HOVER_PARADROP:
1191 /* FIXME: check for invalid tiles. */
1192 mouse_cursor_type = CURSOR_PARADROP;
1193 break;
1194 case HOVER_ACT_SEL_TGT:
1195 /* Select a tile to target / find targets on. */
1196 mouse_cursor_type = CURSOR_SELECT;
1197 break;
1198 };
1199
1200 update_mouse_cursor(mouse_cursor_type);
1201 }
1202
1203 /**************************************************************************
1204 Return TRUE if there are any units doing the activity on the tile.
1205 **************************************************************************/
is_activity_on_tile(struct tile * ptile,enum unit_activity activity)1206 static bool is_activity_on_tile(struct tile *ptile,
1207 enum unit_activity activity)
1208 {
1209 unit_list_iterate(ptile->units, punit) {
1210 if (punit->activity == activity) {
1211 return TRUE;
1212 }
1213 } unit_list_iterate_end;
1214
1215 return FALSE;
1216 }
1217
1218 /**************************************************************************
1219 Fill orders to build recursive roads. This modifies ptile, so virtual
1220 copy of the real tile should be passed.
1221 **************************************************************************/
check_recursive_road_connect(struct tile * ptile,const struct extra_type * pextra,const struct unit * punit,const struct player * pplayer,int rec)1222 int check_recursive_road_connect(struct tile *ptile, const struct extra_type *pextra,
1223 const struct unit *punit, const struct player *pplayer, int rec)
1224 {
1225 int activity_mc = 0;
1226 struct terrain *pterrain = tile_terrain(ptile);
1227
1228 if (rec > MAX_EXTRA_TYPES) {
1229 return -1;
1230 }
1231
1232 if (!is_extra_caused_by(pextra, EC_ROAD)) {
1233 return -1;
1234 }
1235
1236 extra_deps_iterate(&(pextra->reqs), pdep) {
1237 if (!tile_has_extra(ptile, pdep)) {
1238 int single_mc;
1239
1240 single_mc = check_recursive_road_connect(ptile, pdep, punit, pplayer, rec + 1);
1241
1242 if (single_mc < 0) {
1243 return -1;
1244 }
1245
1246 activity_mc += single_mc;
1247 }
1248 } extra_deps_iterate_end;
1249
1250 /* Can build road after that? */
1251 if (punit != NULL) {
1252 if (!can_build_road(extra_road_get(pextra), punit, ptile)) {
1253 return -1;
1254 }
1255 } else if (pplayer != NULL) {
1256 if (!player_can_build_road(extra_road_get(pextra), pplayer, ptile)) {
1257 return -1;
1258 }
1259 }
1260
1261 tile_add_extra(ptile, pextra);
1262
1263 activity_mc += terrain_extra_build_time(pterrain, ACTIVITY_GEN_ROAD, pextra);
1264
1265 return activity_mc;
1266 }
1267
1268 /**************************************************************************
1269 Return whether the unit can connect with given activity (or with
1270 any activity if activity arg is set to ACTIVITY_IDLE)
1271
1272 This function is client-specific.
1273 **************************************************************************/
can_unit_do_connect(struct unit * punit,enum unit_activity activity,struct extra_type * tgt)1274 bool can_unit_do_connect(struct unit *punit,
1275 enum unit_activity activity,
1276 struct extra_type *tgt)
1277 {
1278 struct tile *ptile = unit_tile(punit);
1279 struct terrain *pterrain = tile_terrain(ptile);
1280 struct road_type *proad = NULL;
1281
1282 /* HACK: This code duplicates that in
1283 * can_unit_do_activity_targeted_at(). The general logic here is that
1284 * the connect is allowed if both:
1285 * (1) the unit can do that activity type, in general
1286 * (2) either
1287 * (a) the activity has already been completed at this tile
1288 * (b) it can be done by the unit at this tile. */
1289 switch (activity) {
1290 case ACTIVITY_GEN_ROAD:
1291 {
1292 struct tile *vtile;
1293 int build_time;
1294
1295 fc_assert(is_extra_caused_by(tgt, EC_ROAD));
1296
1297 proad = extra_road_get(tgt);
1298
1299 if (tile_has_road(ptile, proad)) {
1300 /* This tile has road, can unit build road to other tiles too? */
1301 return are_reqs_active(NULL, NULL, NULL, NULL, NULL,
1302 punit, unit_type_get(punit), NULL, NULL,
1303 &tgt->reqs, RPT_POSSIBLE);
1304 }
1305
1306 /* To start connect, unit must be able to build road to this
1307 * particular tile. */
1308 vtile = tile_virtual_new(ptile);
1309 build_time = check_recursive_road_connect(vtile, tgt, punit, NULL, 0);
1310 tile_virtual_destroy(vtile);
1311
1312 return build_time >= 0;
1313 }
1314
1315 case ACTIVITY_IRRIGATE:
1316 /* Special case for irrigation: only irrigate to make S_IRRIGATION,
1317 * never to transform tiles. */
1318 if (!unit_has_type_flag(punit, UTYF_SETTLERS)) {
1319 return FALSE;
1320 }
1321 if (tile_has_extra(ptile, tgt)) {
1322 return are_reqs_active(NULL, NULL, NULL, NULL, NULL,
1323 punit, unit_type_get(punit), NULL, NULL,
1324 &tgt->reqs, RPT_POSSIBLE);
1325 }
1326
1327 return pterrain == pterrain->irrigation_result
1328 && can_be_irrigated(ptile, punit)
1329 && can_build_extra(tgt, punit, ptile)
1330 && !is_activity_on_tile(ptile,
1331 ACTIVITY_MINE);
1332 default:
1333 break;
1334 }
1335
1336 return FALSE;
1337 }
1338
1339 /**************************************************************************
1340 Prompt player for entering destination point for unit connect
1341 (e.g. connecting with roads)
1342 **************************************************************************/
request_unit_connect(enum unit_activity activity,struct extra_type * tgt)1343 void request_unit_connect(enum unit_activity activity,
1344 struct extra_type *tgt)
1345 {
1346 struct unit_list *punits = get_units_in_focus();
1347
1348 if (!can_units_do_connect(punits, activity, tgt)) {
1349 return;
1350 }
1351
1352 if (hover_state != HOVER_CONNECT || connect_activity != activity
1353 || (connect_tgt != tgt
1354 && (activity == ACTIVITY_GEN_ROAD
1355 || activity == ACTIVITY_IRRIGATE))) {
1356 set_hover_state(punits, HOVER_CONNECT, activity, tgt, ORDER_LAST);
1357 enter_goto_state(punits);
1358 create_line_at_mouse_pos();
1359 update_unit_info_label(punits);
1360 control_mouse_cursor(NULL);
1361 } else {
1362 fc_assert_ret(goto_is_active());
1363 goto_add_waypoint();
1364 }
1365 }
1366
1367 /**************************************************************************
1368 Returns one of the unit of the transporter which can have focus next.
1369 **************************************************************************/
request_unit_unload_all(struct unit * punit)1370 struct unit *request_unit_unload_all(struct unit *punit)
1371 {
1372 struct tile *ptile = unit_tile(punit);
1373 struct unit *plast = NULL;
1374
1375 if (get_transporter_capacity(punit) == 0) {
1376 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1377 _("Only transporter units can be unloaded."));
1378 return NULL;
1379 }
1380
1381 unit_list_iterate(ptile->units, pcargo) {
1382 if (unit_transport_get(pcargo) == punit) {
1383 request_unit_unload(pcargo);
1384
1385 if (pcargo->activity == ACTIVITY_SENTRY) {
1386 request_new_unit_activity(pcargo, ACTIVITY_IDLE);
1387 }
1388
1389 if (unit_owner(pcargo) == unit_owner(punit)) {
1390 plast = pcargo;
1391 }
1392 }
1393 } unit_list_iterate_end;
1394
1395 return plast;
1396 }
1397
1398 /**************************************************************************
1399 Send unit airlift request to server.
1400 **************************************************************************/
request_unit_airlift(struct unit * punit,struct city * pcity)1401 void request_unit_airlift(struct unit *punit, struct city *pcity)
1402 {
1403 dsend_packet_unit_airlift(&client.conn, punit->id, pcity->id);
1404 }
1405
1406 /**************************************************************************
1407 Return-and-recover for a particular unit. This sets the unit to GOTO
1408 the nearest city.
1409 **************************************************************************/
request_unit_return(struct unit * punit)1410 void request_unit_return(struct unit *punit)
1411 {
1412 struct pf_path *path;
1413
1414 if ((path = path_to_nearest_allied_city(punit))) {
1415 int turns = pf_path_last_position(path)->turn;
1416 int max_hp = unit_type_get(punit)->hp;
1417
1418 if (punit->hp + turns *
1419 (get_unit_bonus(punit, EFT_UNIT_RECOVER)
1420 - (max_hp * unit_class_get(punit)->hp_loss_pct / 100))
1421 < max_hp) {
1422 struct unit_order order;
1423
1424 order.order = ORDER_ACTIVITY;
1425 order.dir = DIR8_ORIGIN;
1426 order.activity = ACTIVITY_SENTRY;
1427 order.target = EXTRA_NONE;
1428 send_goto_path(punit, path, &order);
1429 } else {
1430 send_goto_path(punit, path, NULL);
1431 }
1432 pf_path_destroy(path);
1433 }
1434 }
1435
1436 /**************************************************************************
1437 Wakes all owned sentried units on tile.
1438 **************************************************************************/
wakeup_sentried_units(struct tile * ptile)1439 void wakeup_sentried_units(struct tile *ptile)
1440 {
1441 if (!can_client_issue_orders()) {
1442 return;
1443 }
1444 unit_list_iterate(ptile->units, punit) {
1445 if (punit->activity == ACTIVITY_SENTRY
1446 && unit_owner(punit) == client.conn.playing) {
1447 request_new_unit_activity(punit, ACTIVITY_IDLE);
1448 }
1449 }
1450 unit_list_iterate_end;
1451 }
1452
1453 /**************************************************************************
1454 (RP:) un-sentry all my own sentried units on punit's tile
1455 **************************************************************************/
request_unit_wakeup(struct unit * punit)1456 void request_unit_wakeup(struct unit *punit)
1457 {
1458 wakeup_sentried_units(unit_tile(punit));
1459 }
1460
1461 /****************************************************************************
1462 Defines specific hash tables needed for request_unit_select().
1463 ****************************************************************************/
1464 #define SPECHASH_TAG unit_type
1465 #define SPECHASH_IKEY_TYPE struct unit_type *
1466 #define SPECHASH_IDATA_TYPE void *
1467 #include "spechash.h"
1468
1469 #define SPECHASH_TAG continent
1470 #define SPECHASH_INT_KEY_TYPE
1471 #define SPECHASH_IDATA_TYPE void *
1472 #include "spechash.h"
1473
1474 /****************************************************************************
1475 Select all units based on the given list of units and the selection modes.
1476 ****************************************************************************/
request_unit_select(struct unit_list * punits,enum unit_select_type_mode seltype,enum unit_select_location_mode selloc)1477 void request_unit_select(struct unit_list *punits,
1478 enum unit_select_type_mode seltype,
1479 enum unit_select_location_mode selloc)
1480 {
1481 const struct player *pplayer;
1482 const struct tile *ptile;
1483 struct unit *punit_first;
1484 struct tile_hash *tile_table;
1485 struct unit_type_hash *type_table;
1486 struct continent_hash *cont_table;
1487
1488 if (!can_client_change_view() || !punits
1489 || unit_list_size(punits) < 1) {
1490 return;
1491 }
1492
1493 punit_first = unit_list_get(punits, 0);
1494
1495 if (seltype == SELTYPE_SINGLE) {
1496 unit_focus_set(punit_first);
1497 return;
1498 }
1499
1500 pplayer = unit_owner(punit_first);
1501 tile_table = tile_hash_new();
1502 type_table = unit_type_hash_new();
1503 cont_table = continent_hash_new();
1504
1505 unit_list_iterate(punits, punit) {
1506 if (seltype == SELTYPE_SAME) {
1507 unit_type_hash_insert(type_table, unit_type_get(punit), NULL);
1508 }
1509
1510 ptile = unit_tile(punit);
1511 if (selloc == SELLOC_TILE) {
1512 tile_hash_insert(tile_table, ptile, NULL);
1513 } else if (selloc == SELLOC_CONT) {
1514 continent_hash_insert(cont_table, tile_continent(ptile), NULL);
1515 }
1516 } unit_list_iterate_end;
1517
1518 if (selloc == SELLOC_TILE) {
1519 tile_hash_iterate(tile_table, hash_tile) {
1520 unit_list_iterate(hash_tile->units, punit) {
1521 if (unit_owner(punit) != pplayer) {
1522 continue;
1523 }
1524 if (seltype == SELTYPE_SAME
1525 && !unit_type_hash_lookup(type_table, unit_type_get(punit), NULL)) {
1526 continue;
1527 }
1528 unit_focus_add(punit);
1529 } unit_list_iterate_end;
1530 } tile_hash_iterate_end;
1531 } else {
1532 unit_list_iterate(pplayer->units, punit) {
1533 ptile = unit_tile(punit);
1534 if ((seltype == SELTYPE_SAME
1535 && !unit_type_hash_lookup(type_table, unit_type_get(punit), NULL))
1536 || (selloc == SELLOC_CONT
1537 && !continent_hash_lookup(cont_table, tile_continent(ptile),
1538 NULL))) {
1539 continue;
1540 }
1541
1542 unit_focus_add(punit);
1543 } unit_list_iterate_end;
1544 }
1545
1546 tile_hash_destroy(tile_table);
1547 unit_type_hash_destroy(type_table);
1548 continent_hash_destroy(cont_table);
1549 }
1550
1551 /**************************************************************************
1552 Request an actor unit to do a specific action.
1553 - action : The action to be requested.
1554 - actor_id : The unit ID of the actor unit.
1555 - target_id : The ID of the target unit, city or tile.
1556 - value : For ACTION_SPY_TARGETED_STEAL_TECH or
1557 ACTION_SPY_TARGETED_SABOTAGE_CITY, the technology or
1558 building to aim for.
1559 **************************************************************************/
request_do_action(enum gen_action action,int actor_id,int target_id,int value)1560 void request_do_action(enum gen_action action, int actor_id,
1561 int target_id, int value)
1562 {
1563 dsend_packet_unit_do_action(&client.conn,
1564 actor_id, target_id, value, action);
1565 }
1566
1567 /**************************************************************************
1568 Request data for follow up questions about an action the unit can
1569 perform.
1570 - action : The action the follow up question is about.
1571 - actor_id : The unit ID of the acting unit.
1572 - target_id : The ID of the target unit or city.
1573 **************************************************************************/
request_action_details(enum gen_action action,int actor_id,int target_id)1574 void request_action_details(enum gen_action action, int actor_id,
1575 int target_id)
1576 {
1577 dsend_packet_unit_action_query(&client.conn,
1578 actor_id, target_id, action);
1579 }
1580
1581 /**************************************************************************
1582 Player pressed 'b' or otherwise instructed unit to build or add to city.
1583 If the unit can build a city, we popup the appropriate dialog.
1584 Otherwise, we just send a packet to the server.
1585 If this action is not appropriate, the server will respond
1586 with an appropriate message. (This is to avoid duplicating
1587 all the server checks and messages here.)
1588 **************************************************************************/
request_unit_build_city(struct unit * punit)1589 void request_unit_build_city(struct unit *punit)
1590 {
1591 if (unit_can_build_city(punit)) {
1592 dsend_packet_city_name_suggestion_req(&client.conn, punit->id);
1593 /* the reply will trigger a dialog to name the new city */
1594 } else {
1595 char name[] = "";
1596 dsend_packet_unit_build_city(&client.conn, punit->id, name);
1597 }
1598 }
1599
1600 /**************************************************************************
1601 Order a unit to move to a neighboring tile without performing an action.
1602
1603 Does nothing it the destination tile isn't next to the tile where the
1604 unit currently is located.
1605 **************************************************************************/
request_unit_non_action_move(struct unit * punit,struct tile * dest_tile)1606 void request_unit_non_action_move(struct unit *punit,
1607 struct tile *dest_tile)
1608 {
1609 struct packet_unit_orders p;
1610 int dir;
1611
1612 dir = get_direction_for_step(unit_tile(punit), dest_tile);
1613
1614 if (dir == -1) {
1615 /* The unit isn't located next to the destination tile. */
1616 return;
1617 }
1618
1619 memset(&p, 0, sizeof(p));
1620
1621 p.repeat = FALSE;
1622 p.vigilant = FALSE;
1623
1624 p.unit_id = punit->id;
1625 p.src_tile = tile_index(unit_tile(punit));
1626 p.dest_tile = tile_index(dest_tile);
1627
1628 p.length = 1;
1629 p.orders[0] = ORDER_MOVE;
1630 p.dir[0] = dir;
1631 p.activity[0] = ACTIVITY_LAST;
1632 p.target[0] = EXTRA_NONE;
1633
1634 send_packet_unit_orders(&client.conn, &p);
1635 }
1636
1637 /**************************************************************************
1638 This function is called whenever the player pressed an arrow key.
1639
1640 We do NOT take into account that punit might be a caravan or a diplomat
1641 trying to move into a city, or a diplomat going into a tile with a unit;
1642 the server will catch those cases and send the client a package to pop up
1643 a dialog. (the server code has to be there anyway as goto's are entirely
1644 in the server)
1645 **************************************************************************/
request_move_unit_direction(struct unit * punit,int dir)1646 void request_move_unit_direction(struct unit *punit, int dir)
1647 {
1648 struct packet_unit_orders p;
1649 struct tile *dest_tile;
1650
1651 /* Catches attempts to move off map */
1652 dest_tile = mapstep(unit_tile(punit), dir);
1653 if (!dest_tile) {
1654 return;
1655 }
1656
1657 if (!can_unit_exist_at_tile(punit, dest_tile)) {
1658 if (request_transport(punit, dest_tile)) {
1659 return;
1660 }
1661 }
1662
1663 /* The goto system isn't used to send the order because that would
1664 * prevent direction movement from overriding it.
1665 * Example of a situation when overriding the goto system is useful:
1666 * The goto system creates a longer path to make a move legal. The player
1667 * wishes to order the illegal move so the server will explain why the
1668 * short move is illegal. */
1669
1670 memset(&p, 0, sizeof(p));
1671
1672 p.repeat = FALSE;
1673 p.vigilant = FALSE;
1674
1675 p.unit_id = punit->id;
1676 p.src_tile = tile_index(unit_tile(punit));
1677 p.dest_tile = tile_index(dest_tile);
1678
1679 p.length = 1;
1680 p.orders[0] = ORDER_ACTION_MOVE;
1681 p.dir[0] = dir;
1682 p.activity[0] = ACTIVITY_LAST;
1683 p.target[0] = EXTRA_NONE;
1684
1685 send_packet_unit_orders(&client.conn, &p);
1686 }
1687
1688 /**************************************************************************
1689 Send request for unit activity changing to server. If activity has
1690 target, use request_new_unit_activity_targeted() instead.
1691 **************************************************************************/
request_new_unit_activity(struct unit * punit,enum unit_activity act)1692 void request_new_unit_activity(struct unit *punit, enum unit_activity act)
1693 {
1694 request_new_unit_activity_targeted(punit, act, NULL);
1695 }
1696
1697 /**************************************************************************
1698 Send request for unit activity changing to server. This is for
1699 activities that are targeted to certain special or base type.
1700 **************************************************************************/
request_new_unit_activity_targeted(struct unit * punit,enum unit_activity act,struct extra_type * tgt)1701 void request_new_unit_activity_targeted(struct unit *punit,
1702 enum unit_activity act,
1703 struct extra_type *tgt)
1704 {
1705 if (!can_client_issue_orders()) {
1706 return;
1707 }
1708
1709 if (tgt == NULL) {
1710 dsend_packet_unit_change_activity(&client.conn, punit->id, act, EXTRA_NONE);
1711 } else {
1712 dsend_packet_unit_change_activity(&client.conn, punit->id, act, extra_index(tgt));
1713 }
1714 }
1715
1716 /**************************************************************************
1717 Send request to disband unit to server.
1718 **************************************************************************/
request_unit_disband(struct unit * punit)1719 void request_unit_disband(struct unit *punit)
1720 {
1721 dsend_packet_unit_disband(&client.conn, punit->id);
1722 }
1723
1724 /**************************************************************************
1725 Send request to change unit homecity to server.
1726 **************************************************************************/
request_unit_change_homecity(struct unit * punit)1727 void request_unit_change_homecity(struct unit *punit)
1728 {
1729 struct city *pcity=tile_city(unit_tile(punit));
1730
1731 if (pcity) {
1732 dsend_packet_unit_change_homecity(&client.conn, punit->id, pcity->id);
1733 }
1734 }
1735
1736 /**************************************************************************
1737 Send request to upgrade unit to server.
1738 **************************************************************************/
request_unit_upgrade(struct unit * punit)1739 void request_unit_upgrade(struct unit *punit)
1740 {
1741 struct city *pcity=tile_city(unit_tile(punit));
1742
1743 if (pcity) {
1744 dsend_packet_unit_upgrade(&client.conn, punit->id);
1745 }
1746 }
1747
1748 /**************************************************************************
1749 Sends unit convert packet.
1750 **************************************************************************/
request_unit_convert(struct unit * punit)1751 void request_unit_convert(struct unit *punit)
1752 {
1753 request_new_unit_activity(punit, ACTIVITY_CONVERT);
1754 }
1755
1756 /****************************************************************************
1757 Call to request (from the server) that the settler unit is put into
1758 autosettler mode.
1759 ****************************************************************************/
request_unit_autosettlers(const struct unit * punit)1760 void request_unit_autosettlers(const struct unit *punit)
1761 {
1762 if (punit && can_unit_do_autosettlers(punit)) {
1763 dsend_packet_unit_autosettlers(&client.conn, punit->id);
1764 } else if (punit) {
1765 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1766 _("Only settler units can be put into auto mode."));
1767 }
1768 }
1769
1770 /****************************************************************************
1771 Send a request to the server that the cargo be loaded into the transporter.
1772
1773 If ptransporter is NULL a suitable transporter will be chosen.
1774 ****************************************************************************/
request_unit_load(struct unit * pcargo,struct unit * ptrans,struct tile * ptile)1775 void request_unit_load(struct unit *pcargo, struct unit *ptrans,
1776 struct tile *ptile)
1777 {
1778 if (!ptrans) {
1779 ptrans = transporter_for_unit(pcargo);
1780 }
1781
1782 if (ptrans
1783 && can_client_issue_orders()
1784 && could_unit_load(pcargo, ptrans)) {
1785 dsend_packet_unit_load(&client.conn, pcargo->id, ptrans->id,
1786 ptile->index);
1787
1788 /* Sentry the unit. Don't request_unit_sentry since this can give a
1789 * recursive loop. */
1790 /* FIXME: Should not sentry if above loading fails (transport moved away,
1791 * or filled already in server side) */
1792 dsend_packet_unit_change_activity(&client.conn, pcargo->id,
1793 ACTIVITY_SENTRY, EXTRA_NONE);
1794 }
1795 }
1796
1797 /****************************************************************************
1798 Send a request to the server that the cargo be unloaded from its current
1799 transporter.
1800 ****************************************************************************/
request_unit_unload(struct unit * pcargo)1801 void request_unit_unload(struct unit *pcargo)
1802 {
1803 struct unit *ptrans = unit_transport_get(pcargo);
1804
1805 if (can_client_issue_orders()
1806 && ptrans
1807 && can_unit_unload(pcargo, ptrans)
1808 && can_unit_survive_at_tile(pcargo, unit_tile(pcargo))) {
1809 dsend_packet_unit_unload(&client.conn, pcargo->id, ptrans->id);
1810
1811 if (unit_owner(pcargo) == client.conn.playing
1812 && pcargo->activity == ACTIVITY_SENTRY) {
1813 /* Activate the unit. */
1814 dsend_packet_unit_change_activity(&client.conn, pcargo->id,
1815 ACTIVITY_IDLE, EXTRA_NONE);
1816 }
1817 }
1818 }
1819
1820 /**************************************************************************
1821 Send request to do caravan action - establishing traderoute or
1822 helping in wonder building - to server.
1823 **************************************************************************/
request_unit_caravan_action(struct unit * punit,enum gen_action action)1824 void request_unit_caravan_action(struct unit *punit,
1825 enum gen_action action)
1826 {
1827 struct city *target_city;
1828
1829 if (!((target_city = tile_city(unit_tile(punit))))) {
1830 return;
1831 }
1832
1833 if (action == ACTION_TRADE_ROUTE) {
1834 request_do_action(ACTION_TRADE_ROUTE, punit->id,
1835 target_city->id, 0);
1836 } else if (action == ACTION_HELP_WONDER) {
1837 request_do_action(ACTION_HELP_WONDER, punit->id,
1838 target_city->id, 0);
1839 } else {
1840 log_error("request_unit_caravan_action() Bad action (%d)", action);
1841 }
1842 }
1843
1844 /**************************************************************************
1845 Explode nuclear at a tile without enemy units
1846 **************************************************************************/
request_unit_nuke(struct unit_list * punits)1847 void request_unit_nuke(struct unit_list *punits)
1848 {
1849 if (unit_list_size(punits) == 0) {
1850 return;
1851 }
1852
1853 unit_list_iterate(punits, punit) {
1854 if (!unit_has_type_flag(punit, UTYF_NUCLEAR)) {
1855 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1856 _("Only nuclear units can do this."));
1857 return;
1858 }
1859 } unit_list_iterate_end;
1860
1861 if (hover_state != HOVER_NUKE) {
1862 set_hover_state(punits, HOVER_NUKE, ACTIVITY_LAST, NULL, ORDER_LAST);
1863 enter_goto_state(punits);
1864 create_line_at_mouse_pos();
1865 update_unit_info_label(punits);
1866 control_mouse_cursor(NULL);
1867 } else {
1868 fc_assert_ret(goto_is_active());
1869 goto_add_waypoint();
1870 }
1871 }
1872
1873 /**************************************************************************
1874 Have the player select what tile to paradrop to. Once selected a
1875 paradrop request will be sent to server.
1876 **************************************************************************/
request_unit_paradrop(struct unit_list * punits)1877 void request_unit_paradrop(struct unit_list *punits)
1878 {
1879 bool can = FALSE;
1880 struct tile *offender = NULL;
1881
1882 if (unit_list_size(punits) == 0) {
1883 return;
1884 }
1885 unit_list_iterate(punits, punit) {
1886 if (can_unit_paradrop(punit)) {
1887 can = TRUE;
1888 break;
1889 }
1890 if (!offender) { /* Take first offender tile/unit */
1891 offender = unit_tile(punit);
1892 }
1893 } unit_list_iterate_end;
1894 if (can) {
1895 set_hover_state(punits, HOVER_PARADROP, ACTIVITY_LAST, NULL,
1896 ORDER_LAST);
1897 update_unit_info_label(punits);
1898 } else {
1899 create_event(offender, E_BAD_COMMAND, ftc_client,
1900 _("Only paratrooper units can do this."));
1901 }
1902 }
1903
1904 /**************************************************************************
1905 Either start new patrol route planning, or add waypoint to current one.
1906 **************************************************************************/
request_unit_patrol(void)1907 void request_unit_patrol(void)
1908 {
1909 struct unit_list *punits = get_units_in_focus();
1910
1911 if (unit_list_size(punits) == 0) {
1912 return;
1913 }
1914
1915 if (hover_state != HOVER_PATROL) {
1916 set_hover_state(punits, HOVER_PATROL, ACTIVITY_LAST, NULL,
1917 ORDER_LAST);
1918 update_unit_info_label(punits);
1919 enter_goto_state(punits);
1920 create_line_at_mouse_pos();
1921 } else {
1922 fc_assert_ret(goto_is_active());
1923 goto_add_waypoint();
1924 }
1925 }
1926
1927 /****************************************************************
1928 Try to sentry unit.
1929 *****************************************************************/
request_unit_sentry(struct unit * punit)1930 void request_unit_sentry(struct unit *punit)
1931 {
1932 if(punit->activity!=ACTIVITY_SENTRY &&
1933 can_unit_do_activity(punit, ACTIVITY_SENTRY))
1934 request_new_unit_activity(punit, ACTIVITY_SENTRY);
1935 }
1936
1937 /****************************************************************
1938 Try to fortify unit.
1939 *****************************************************************/
request_unit_fortify(struct unit * punit)1940 void request_unit_fortify(struct unit *punit)
1941 {
1942 if(punit->activity!=ACTIVITY_FORTIFYING &&
1943 can_unit_do_activity(punit, ACTIVITY_FORTIFYING))
1944 request_new_unit_activity(punit, ACTIVITY_FORTIFYING);
1945 }
1946
1947 /**************************************************************************
1948 Send pillage request to server.
1949 **************************************************************************/
request_unit_pillage(struct unit * punit)1950 void request_unit_pillage(struct unit *punit)
1951 {
1952 if (!game.info.pillage_select) {
1953 /* Leave choice up to the server */
1954 request_new_unit_activity_targeted(punit, ACTIVITY_PILLAGE, NULL);
1955 } else {
1956 struct tile *ptile = unit_tile(punit);
1957 bv_extras pspossible;
1958 int count = 0;
1959
1960 BV_CLR_ALL(pspossible);
1961 extra_type_iterate(potential) {
1962 if (can_unit_do_activity_targeted_at(punit, ACTIVITY_PILLAGE,
1963 potential, ptile)) {
1964 BV_SET(pspossible, extra_index(potential));
1965 count++;
1966 }
1967 } extra_type_iterate_end;
1968
1969 if (count > 1) {
1970 popup_pillage_dialog(punit, pspossible);
1971 } else {
1972 /* Should be only one choice... */
1973 struct extra_type *target = get_preferred_pillage(pspossible);
1974
1975 if (target != NULL) {
1976 request_new_unit_activity_targeted(punit, ACTIVITY_PILLAGE, target);
1977 }
1978 }
1979 }
1980 }
1981
1982 /**************************************************************************
1983 Toggle display of city outlines on the map
1984 **************************************************************************/
request_toggle_city_outlines(void)1985 void request_toggle_city_outlines(void)
1986 {
1987 if (!can_client_change_view()) {
1988 return;
1989 }
1990
1991 gui_options.draw_city_outlines = !gui_options.draw_city_outlines;
1992 update_map_canvas_visible();
1993 }
1994
1995 /**************************************************************************
1996 Toggle display of worker output of cities on the map
1997 **************************************************************************/
request_toggle_city_output(void)1998 void request_toggle_city_output(void)
1999 {
2000 if (!can_client_change_view()) {
2001 return;
2002 }
2003
2004 gui_options.draw_city_output = !gui_options.draw_city_output;
2005 update_map_canvas_visible();
2006 }
2007
2008 /**************************************************************************
2009 Toggle display of grid lines on the map
2010 **************************************************************************/
request_toggle_map_grid(void)2011 void request_toggle_map_grid(void)
2012 {
2013 if (!can_client_change_view()) {
2014 return;
2015 }
2016
2017 gui_options.draw_map_grid ^= 1;
2018 update_map_canvas_visible();
2019 }
2020
2021 /**************************************************************************
2022 Toggle display of national borders on the map
2023 **************************************************************************/
request_toggle_map_borders(void)2024 void request_toggle_map_borders(void)
2025 {
2026 if (!can_client_change_view()) {
2027 return;
2028 }
2029
2030 gui_options.draw_borders ^= 1;
2031 update_map_canvas_visible();
2032 }
2033
2034 /**************************************************************************
2035 Toggle display of native tiles on the map
2036 **************************************************************************/
request_toggle_map_native(void)2037 void request_toggle_map_native(void)
2038 {
2039 if (!can_client_change_view()) {
2040 return;
2041 }
2042
2043 gui_options.draw_native ^= 1;
2044 update_map_canvas_visible();
2045 }
2046
2047 /**************************************************************************
2048 Toggle display of city full bar.
2049 **************************************************************************/
request_toggle_city_full_bar(void)2050 void request_toggle_city_full_bar(void)
2051 {
2052 if (!can_client_change_view()) {
2053 return;
2054 }
2055
2056 gui_options.draw_full_citybar ^= 1;
2057 update_map_canvas_visible();
2058 }
2059
2060 /**************************************************************************
2061 Toggle display of city names
2062 **************************************************************************/
request_toggle_city_names(void)2063 void request_toggle_city_names(void)
2064 {
2065 if (!can_client_change_view()) {
2066 return;
2067 }
2068
2069 gui_options.draw_city_names ^= 1;
2070 update_map_canvas_visible();
2071 }
2072
2073 /**************************************************************************
2074 Toggle display of city growth (turns-to-grow)
2075 **************************************************************************/
request_toggle_city_growth(void)2076 void request_toggle_city_growth(void)
2077 {
2078 if (!can_client_change_view()) {
2079 return;
2080 }
2081
2082 gui_options.draw_city_growth ^= 1;
2083 update_map_canvas_visible();
2084 }
2085
2086 /**************************************************************************
2087 Toggle display of city productions
2088 **************************************************************************/
request_toggle_city_productions(void)2089 void request_toggle_city_productions(void)
2090 {
2091 if (!can_client_change_view()) {
2092 return;
2093 }
2094
2095 gui_options.draw_city_productions ^= 1;
2096 update_map_canvas_visible();
2097 }
2098
2099 /**************************************************************************
2100 Toggle display of city buycost
2101 **************************************************************************/
request_toggle_city_buycost(void)2102 void request_toggle_city_buycost(void)
2103 {
2104 if (!can_client_change_view()) {
2105 return;
2106 }
2107
2108 gui_options.draw_city_buycost ^= 1;
2109 update_map_canvas_visible();
2110 }
2111
2112 /**************************************************************************
2113 Toggle display of city trade routes
2114 **************************************************************************/
request_toggle_city_trade_routes(void)2115 void request_toggle_city_trade_routes(void)
2116 {
2117 if (!can_client_change_view()) {
2118 return;
2119 }
2120
2121 gui_options.draw_city_trade_routes ^= 1;
2122 update_map_canvas_visible();
2123 }
2124
2125 /**************************************************************************
2126 Toggle display of terrain
2127 **************************************************************************/
request_toggle_terrain(void)2128 void request_toggle_terrain(void)
2129 {
2130 if (!can_client_change_view()) {
2131 return;
2132 }
2133
2134 gui_options.draw_terrain ^= 1;
2135 update_map_canvas_visible();
2136 }
2137
2138 /**************************************************************************
2139 Toggle display of coastline
2140 **************************************************************************/
request_toggle_coastline(void)2141 void request_toggle_coastline(void)
2142 {
2143 if (!can_client_change_view()) {
2144 return;
2145 }
2146
2147 gui_options.draw_coastline ^= 1;
2148 update_map_canvas_visible();
2149 }
2150
2151 /**************************************************************************
2152 Toggle display of roads and rails
2153 **************************************************************************/
request_toggle_roads_rails(void)2154 void request_toggle_roads_rails(void)
2155 {
2156 if (!can_client_change_view()) {
2157 return;
2158 }
2159
2160 gui_options.draw_roads_rails ^= 1;
2161 update_map_canvas_visible();
2162 }
2163
2164 /**************************************************************************
2165 Toggle display of irrigation
2166 **************************************************************************/
request_toggle_irrigation(void)2167 void request_toggle_irrigation(void)
2168 {
2169 if (!can_client_change_view()) {
2170 return;
2171 }
2172
2173 gui_options.draw_irrigation ^= 1;
2174 update_map_canvas_visible();
2175 }
2176
2177 /**************************************************************************
2178 Toggle display of mines
2179 **************************************************************************/
request_toggle_mines(void)2180 void request_toggle_mines(void)
2181 {
2182 if (!can_client_change_view()) {
2183 return;
2184 }
2185
2186 gui_options.draw_mines ^= 1;
2187 update_map_canvas_visible();
2188 }
2189
2190 /**************************************************************************
2191 Toggle display of bases
2192 **************************************************************************/
request_toggle_bases(void)2193 void request_toggle_bases(void)
2194 {
2195 if (!can_client_change_view()) {
2196 return;
2197 }
2198
2199 gui_options.draw_fortress_airbase ^= 1;
2200 update_map_canvas_visible();
2201 }
2202
2203 /**************************************************************************
2204 Toggle display of resources
2205 **************************************************************************/
request_toggle_resources(void)2206 void request_toggle_resources(void)
2207 {
2208 if (!can_client_change_view()) {
2209 return;
2210 }
2211
2212 gui_options.draw_specials ^= 1;
2213 update_map_canvas_visible();
2214 }
2215
2216 /**************************************************************************
2217 Toggle display of huts
2218 **************************************************************************/
request_toggle_huts(void)2219 void request_toggle_huts(void)
2220 {
2221 if (!can_client_change_view()) {
2222 return;
2223 }
2224
2225 gui_options.draw_huts ^= 1;
2226 update_map_canvas_visible();
2227 }
2228
2229 /**************************************************************************
2230 Toggle display of pollution
2231 **************************************************************************/
request_toggle_pollution(void)2232 void request_toggle_pollution(void)
2233 {
2234 if (!can_client_change_view()) {
2235 return;
2236 }
2237
2238 gui_options.draw_pollution ^= 1;
2239 update_map_canvas_visible();
2240 }
2241
2242 /**************************************************************************
2243 Toggle display of cities
2244 **************************************************************************/
request_toggle_cities(void)2245 void request_toggle_cities(void)
2246 {
2247 if (!can_client_change_view()) {
2248 return;
2249 }
2250
2251 gui_options.draw_cities ^= 1;
2252 update_map_canvas_visible();
2253 }
2254
2255 /**************************************************************************
2256 Toggle display of units
2257 **************************************************************************/
request_toggle_units(void)2258 void request_toggle_units(void)
2259 {
2260 if (!can_client_change_view()) {
2261 return;
2262 }
2263
2264 gui_options.draw_units ^= 1;
2265 update_map_canvas_visible();
2266 }
2267
2268 /**************************************************************************
2269 Toggle display of unit solid background.
2270 **************************************************************************/
request_toggle_unit_solid_bg(void)2271 void request_toggle_unit_solid_bg(void)
2272 {
2273 if (!can_client_change_view()) {
2274 return;
2275 }
2276
2277 gui_options.solid_color_behind_units ^= 1;
2278 update_map_canvas_visible();
2279 }
2280
2281 /**************************************************************************
2282 Toggle display of unit shields.
2283 **************************************************************************/
request_toggle_unit_shields(void)2284 void request_toggle_unit_shields(void)
2285 {
2286 if (!can_client_change_view()) {
2287 return;
2288 }
2289
2290 gui_options.draw_unit_shields ^= 1;
2291 update_map_canvas_visible();
2292 }
2293
2294 /**************************************************************************
2295 Toggle display of focus unit
2296 **************************************************************************/
request_toggle_focus_unit(void)2297 void request_toggle_focus_unit(void)
2298 {
2299 if (!can_client_change_view()) {
2300 return;
2301 }
2302
2303 gui_options.draw_focus_unit ^= 1;
2304 update_map_canvas_visible();
2305 }
2306
2307 /**************************************************************************
2308 Toggle display of fog of war
2309 **************************************************************************/
request_toggle_fog_of_war(void)2310 void request_toggle_fog_of_war(void)
2311 {
2312 if (!can_client_change_view()) {
2313 return;
2314 }
2315
2316 gui_options.draw_fog_of_war ^= 1;
2317 update_map_canvas_visible();
2318 refresh_overview_canvas();
2319 }
2320
2321 /**************************************************************************
2322 Center to focus unit.
2323 **************************************************************************/
request_center_focus_unit(void)2324 void request_center_focus_unit(void)
2325 {
2326 struct tile *ptile = find_a_focus_unit_tile_to_center_on();
2327
2328 if (ptile) {
2329 center_tile_mapcanvas(ptile);
2330 }
2331 }
2332
2333 /**************************************************************************
2334 Set units in list to waiting focus. If they are current focus units,
2335 advance focus.
2336 **************************************************************************/
request_units_wait(struct unit_list * punits)2337 void request_units_wait(struct unit_list *punits)
2338 {
2339 unit_list_iterate(punits, punit) {
2340 punit->client.focus_status = FOCUS_WAIT;
2341 } unit_list_iterate_end;
2342 if (punits == get_units_in_focus()) {
2343 unit_focus_advance();
2344 }
2345 }
2346
2347 /**************************************************************************
2348 Set focus units to FOCUS_DONE state.
2349 **************************************************************************/
request_unit_move_done(void)2350 void request_unit_move_done(void)
2351 {
2352 if (get_num_units_in_focus() > 0) {
2353 enum unit_focus_status new_status = FOCUS_DONE;
2354 unit_list_iterate(get_units_in_focus(), punit) {
2355 /* If any of the focused units are busy, keep all of them
2356 * in focus; another tap of the key will dismiss them */
2357 if (punit->activity != ACTIVITY_IDLE) {
2358 new_status = FOCUS_WAIT;
2359 }
2360 } unit_list_iterate_end;
2361 unit_list_iterate(get_units_in_focus(), punit) {
2362 clear_unit_orders(punit);
2363 punit->client.focus_status = new_status;
2364 } unit_list_iterate_end;
2365 if (new_status == FOCUS_DONE) {
2366 unit_focus_advance();
2367 }
2368 }
2369 }
2370
2371 /**************************************************************************
2372 Called to have the client move a unit from one location to another,
2373 updating the graphics if necessary. The caller must redraw the target
2374 location after the move.
2375 **************************************************************************/
do_move_unit(struct unit * punit,struct unit * target_unit)2376 void do_move_unit(struct unit *punit, struct unit *target_unit)
2377 {
2378 struct tile *src_tile = unit_tile(punit);
2379 struct tile *dst_tile = unit_tile(target_unit);
2380 bool was_teleported, do_animation;
2381 bool in_focus = unit_is_in_focus(punit);
2382
2383 was_teleported = !is_tiles_adjacent(src_tile, dst_tile);
2384 do_animation = (!was_teleported && gui_options.smooth_move_unit_msec > 0);
2385
2386 if (!was_teleported
2387 && punit->activity != ACTIVITY_SENTRY
2388 && !unit_transported(punit)) {
2389 audio_play_sound(unit_type_get(punit)->sound_move,
2390 unit_type_get(punit)->sound_move_alt);
2391 }
2392
2393 if (unit_owner(punit) == client.conn.playing
2394 && gui_options.auto_center_on_unit
2395 && !unit_has_orders(punit)
2396 && punit->activity != ACTIVITY_GOTO
2397 && punit->activity != ACTIVITY_SENTRY
2398 && ((gui_options.auto_center_on_automated == TRUE
2399 && punit->ai_controlled == TRUE)
2400 || (punit->ai_controlled == FALSE))
2401 && !tile_visible_and_not_on_border_mapcanvas(dst_tile)) {
2402 center_tile_mapcanvas(dst_tile);
2403 }
2404
2405 if (hover_state != HOVER_NONE && in_focus) {
2406 /* Cancel current goto/patrol/connect/nuke command. */
2407 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2408 update_unit_info_label(get_units_in_focus());
2409 }
2410
2411 unit_list_remove(src_tile->units, punit);
2412
2413 if (!unit_transported(punit)) {
2414 /* Mark the unit as moving unit, then find_visible_unit() won't return
2415 * it. It is especially useful to don't draw many times the unit when
2416 * refreshing the canvas. */
2417 punit_moving = punit;
2418
2419 /* We have to refresh the tile before moving. This will draw
2420 * the tile without the unit (because it was unlinked above). */
2421 refresh_unit_mapcanvas(punit, src_tile, TRUE, FALSE);
2422
2423 if (gui_options.auto_center_on_automated == FALSE
2424 && punit->ai_controlled == TRUE) {
2425 /* Dont animate automatic units */
2426 } else if (do_animation) {
2427 int dx, dy;
2428
2429 /* For the duration of the animation the unit exists at neither
2430 * tile. */
2431 map_distance_vector(&dx, &dy, src_tile, dst_tile);
2432 move_unit_map_canvas(punit, src_tile, dx, dy);
2433 }
2434 }
2435
2436 unit_tile_set(punit, dst_tile);
2437 unit_list_prepend(dst_tile->units, punit);
2438
2439 if (!unit_transported(punit)) {
2440 /* For find_visible_unit(), see above. */
2441 punit_moving = NULL;
2442
2443 refresh_unit_mapcanvas(punit, dst_tile, TRUE, FALSE);
2444 }
2445
2446 /* With the "full" city bar we have to update the city bar when units move
2447 * into or out of a city. For foreign cities this is handled separately,
2448 * via the occupied field of the short-city packet. */
2449 if (NULL != tile_city(src_tile)
2450 && can_player_see_units_in_city(client.conn.playing, tile_city(src_tile))) {
2451 update_city_description(tile_city(src_tile));
2452 }
2453 if (NULL != tile_city(dst_tile)
2454 && can_player_see_units_in_city(client.conn.playing, tile_city(dst_tile))) {
2455 update_city_description(tile_city(dst_tile));
2456 }
2457
2458 if (in_focus) {
2459 menus_update();
2460 }
2461 }
2462
2463 /**************************************************************************
2464 An action selection dialog for the selected units against the specified
2465 tile is wanted.
2466 **************************************************************************/
do_unit_act_sel_vs(struct tile * ptile)2467 static void do_unit_act_sel_vs(struct tile *ptile)
2468 {
2469 unit_list_iterate(get_units_in_focus(), punit) {
2470 if (utype_may_act_at_all(unit_type_get(punit))) {
2471 /* Have the server record that an action decision is wanted for
2472 * this unit against this tile. */
2473 request_do_action(ACTION_COUNT, punit->id, tile_index(ptile),
2474 ACTSIG_QUEUE);
2475 }
2476 } unit_list_iterate_end;
2477 }
2478
2479 /**************************************************************************
2480 Handles everything when the user clicked a tile
2481 **************************************************************************/
do_map_click(struct tile * ptile,enum quickselect_type qtype)2482 void do_map_click(struct tile *ptile, enum quickselect_type qtype)
2483 {
2484 struct city *pcity = tile_city(ptile);
2485 struct unit_list *punits = get_units_in_focus();
2486 bool maybe_goto = FALSE;
2487
2488 if (hover_state != HOVER_NONE) {
2489 switch (hover_state) {
2490 case HOVER_NONE:
2491 break;
2492 case HOVER_GOTO:
2493 do_unit_goto(ptile);
2494 break;
2495 case HOVER_NUKE:
2496 do_unit_nuke(ptile);
2497 break;
2498 case HOVER_PARADROP:
2499 unit_list_iterate(punits, punit) {
2500 do_unit_paradrop_to(punit, ptile);
2501 } unit_list_iterate_end;
2502 break;
2503 case HOVER_CONNECT:
2504 do_unit_connect(ptile, connect_activity, connect_tgt);
2505 break;
2506 case HOVER_PATROL:
2507 do_unit_patrol_to(ptile);
2508 break;
2509 case HOVER_ACT_SEL_TGT:
2510 do_unit_act_sel_vs(ptile);
2511 break;
2512 }
2513
2514 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2515 update_unit_info_label(get_units_in_focus());
2516 }
2517
2518 /* Bypass stack or city popup if quickselect is specified. */
2519 else if (qtype != SELECT_POPUP && qtype != SELECT_APPEND) {
2520 struct unit *qunit = quickselect(ptile, qtype);
2521 if (qunit) {
2522 unit_focus_set_and_select(qunit);
2523 maybe_goto = gui_options.keyboardless_goto;
2524 }
2525 }
2526 /* Otherwise use popups. */
2527 else if (NULL != pcity
2528 && can_player_see_city_internals(client.conn.playing, pcity)) {
2529 popup_city_dialog(pcity);
2530 }
2531 else if (unit_list_size(ptile->units) == 0
2532 && NULL == pcity
2533 && get_num_units_in_focus() > 0) {
2534 maybe_goto = gui_options.keyboardless_goto;
2535 }
2536 else if (unit_list_size(ptile->units) == 1
2537 && !get_transporter_occupancy(unit_list_get(ptile->units, 0))) {
2538 struct unit *punit = unit_list_get(ptile->units, 0);
2539
2540 if (unit_owner(punit) == client.conn.playing) {
2541 if(can_unit_do_activity(punit, ACTIVITY_IDLE)) {
2542 maybe_goto = gui_options.keyboardless_goto;
2543 if (qtype == SELECT_APPEND) {
2544 unit_focus_add(punit);
2545 } else {
2546 unit_focus_set_and_select(punit);
2547 }
2548 }
2549 } else if (pcity) {
2550 /* Don't hide the unit in the city. */
2551 unit_select_dialog_popup(ptile);
2552 }
2553 }
2554 else if(unit_list_size(ptile->units) > 0) {
2555 /* The stack list is always popped up, even if it includes enemy units.
2556 * If the server doesn't want the player to know about them it shouldn't
2557 * tell him! The previous behavior would only pop up the stack if you
2558 * owned a unit on the tile. This gave cheating clients an advantage,
2559 * and also showed you allied units if (and only if) you had a unit on
2560 * the tile (inconsistent). */
2561 unit_select_dialog_popup(ptile);
2562 }
2563
2564 /* See mapctrl_common.c */
2565 keyboardless_goto_start_tile = maybe_goto ? ptile : NULL;
2566 keyboardless_goto_button_down = maybe_goto;
2567 keyboardless_goto_active = FALSE;
2568 }
2569
2570 /**************************************************************************
2571 Quickselecting a unit is normally done with <control> left, right click,
2572 for the current tile. Bypassing the stack popup is quite convenient,
2573 and can be tactically important in furious multiplayer games.
2574 **************************************************************************/
quickselect(struct tile * ptile,enum quickselect_type qtype)2575 static struct unit *quickselect(struct tile *ptile,
2576 enum quickselect_type qtype)
2577 {
2578 int listsize = unit_list_size(ptile->units);
2579 struct unit *panytransporter = NULL,
2580 *panymovesea = NULL, *panysea = NULL,
2581 *panymoveland = NULL, *panyland = NULL,
2582 *panymoveunit = NULL, *panyunit = NULL;
2583
2584 fc_assert_ret_val(qtype > SELECT_POPUP, NULL);
2585
2586 if (qtype == SELECT_FOCUS) {
2587 return head_of_units_in_focus();
2588 }
2589
2590 if (listsize == 0) {
2591 return NULL;
2592 } else if (listsize == 1) {
2593 struct unit *punit = unit_list_get(ptile->units, 0);
2594 return (unit_owner(punit) == client.conn.playing) ? punit : NULL;
2595 }
2596
2597 /* Quickselect priorities. Units with moves left
2598 * before exhausted. Focus unit is excluded.
2599 *
2600 * SEA: Transporter
2601 * Sea unit
2602 * Any unit
2603 *
2604 * LAND: Military land unit
2605 * Non-combatant
2606 * Sea unit
2607 * Any unit
2608 */
2609
2610 unit_list_iterate(ptile->units, punit) {
2611 if (unit_owner(punit) != client.conn.playing || unit_is_in_focus(punit)) {
2612 continue;
2613 }
2614 if (qtype == SELECT_SEA) {
2615 /* Transporter. */
2616 if (get_transporter_capacity(punit)) {
2617 if (punit->moves_left > 0) {
2618 return punit;
2619 } else if (!panytransporter) {
2620 panytransporter = punit;
2621 }
2622 }
2623 /* Any sea, pref. moves left. */
2624 else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
2625 if (punit->moves_left > 0) {
2626 if (!panymovesea) {
2627 panymovesea = punit;
2628 }
2629 } else if (!panysea) {
2630 panysea = punit;
2631 }
2632 }
2633 } else if (qtype == SELECT_LAND) {
2634 if (utype_move_type(unit_type_get(punit)) == UMT_LAND) {
2635 if (punit->moves_left > 0) {
2636 if (is_military_unit(punit)) {
2637 return punit;
2638 } else if (!panymoveland) {
2639 panymoveland = punit;
2640 }
2641 } else if (!panyland) {
2642 panyland = punit;
2643 }
2644 }
2645 else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
2646 if (punit->moves_left > 0) {
2647 panymovesea = punit;
2648 } else {
2649 panysea = punit;
2650 }
2651 }
2652 }
2653 if (punit->moves_left > 0 && !panymoveunit) {
2654 panymoveunit = punit;
2655 }
2656 if (!panyunit) {
2657 panyunit = punit;
2658 }
2659 } unit_list_iterate_end;
2660
2661 if (qtype == SELECT_SEA) {
2662 if (panytransporter) {
2663 return panytransporter;
2664 } else if (panymovesea) {
2665 return panymovesea;
2666 } else if (panysea) {
2667 return panysea;
2668 } else if (panymoveunit) {
2669 return panymoveunit;
2670 } else if (panyunit) {
2671 return panyunit;
2672 }
2673 }
2674 else if (qtype == SELECT_LAND) {
2675 if (panymoveland) {
2676 return panymoveland;
2677 } else if (panyland) {
2678 return panyland;
2679 } else if (panymovesea) {
2680 return panymovesea;
2681 } else if (panysea) {
2682 return panysea;
2683 } else if (panymoveunit) {
2684 return panymoveunit;
2685 } else if (panyunit) {
2686 return panyunit;
2687 }
2688 }
2689 return NULL;
2690 }
2691
2692 /**************************************************************************
2693 Finish the goto mode and let the units stored in goto_map_list move
2694 to a given location.
2695 **************************************************************************/
do_unit_goto(struct tile * ptile)2696 void do_unit_goto(struct tile *ptile)
2697 {
2698 if (hover_state != HOVER_GOTO) {
2699 return;
2700 }
2701
2702 if (is_valid_goto_draw_line(ptile)) {
2703 send_goto_route();
2704 } else {
2705 create_event(ptile, E_BAD_COMMAND, ftc_client,
2706 _("Didn't find a route to the destination!"));
2707 }
2708 }
2709
2710 /****************************************************************************
2711 Destroy the client nuke data.
2712 ****************************************************************************/
client_nuke_data_destroy(void * p)2713 static void client_nuke_data_destroy(void *p)
2714 {
2715 struct client_nuke_data *data = p;
2716
2717 free(data->units_id);
2718 free(data);
2719 }
2720
2721 /****************************************************************************
2722 Explode nuclear at a tile without enemy units.
2723 ****************************************************************************/
do_real_unit_nuke(void * p)2724 static void do_real_unit_nuke(void *p)
2725 {
2726 struct client_nuke_data *data = p;
2727 struct tile *ptile = index_to_tile(data->tile_idx);
2728 struct unit *punit;
2729 int i;
2730
2731 fc_assert_ret(can_client_issue_orders());
2732 fc_assert_ret(ptile != NULL);
2733
2734 for (i = 0; i < data->units_num; i++) {
2735 /* Ensure we have reached destination. */
2736 punit = player_unit_by_number(client_player(), data->units_id[i]);
2737 if (punit != NULL && unit_tile(punit) == ptile) {
2738 dsend_packet_unit_nuke(&client.conn, punit->id);
2739 }
2740 }
2741 }
2742
2743 /****************************************************************************
2744 Send units to 'ptile' and nuke there!
2745 ****************************************************************************/
do_unit_nuke(struct tile * ptile)2746 void do_unit_nuke(struct tile *ptile)
2747 {
2748 if (hover_state != HOVER_NUKE) {
2749 return;
2750 }
2751
2752 if (is_valid_goto_draw_line(ptile)) {
2753 struct client_nuke_data *data = fc_malloc(sizeof(*data));
2754 int last_request_id_used = client.conn.client.last_request_id_used;
2755 int i = 0;
2756
2757 data->units_id = fc_malloc(sizeof(*data->units_id)
2758 * get_num_units_in_focus());
2759 unit_list_iterate(get_units_in_focus(), punit) {
2760 data->units_id[i++] = punit->id;
2761 } unit_list_iterate_end;
2762 data->units_num = i;
2763 data->tile_idx = tile_index(ptile);
2764
2765 send_goto_route();
2766
2767 if (last_request_id_used != client.conn.client.last_request_id_used) {
2768 /* We sent some packets, let's wait the server to process them to know
2769 * where our units hold. */
2770 update_queue_connect_processing_finished_full
2771 (client.conn.client.last_request_id_used,
2772 do_real_unit_nuke, data, client_nuke_data_destroy);
2773 } else {
2774 /* We didn't sent the packets, that mean that the route was nil, or
2775 * an internal error occurred. Process nuke units now. */
2776 do_real_unit_nuke(data);
2777 client_nuke_data_destroy(data);
2778 }
2779 } else {
2780 create_event(ptile, E_BAD_COMMAND, ftc_client,
2781 _("Didn't find a route to the destination!"));
2782 }
2783 }
2784
2785 /**************************************************************************
2786 Paradrop to a location.
2787 **************************************************************************/
do_unit_paradrop_to(struct unit * punit,struct tile * ptile)2788 void do_unit_paradrop_to(struct unit *punit, struct tile *ptile)
2789 {
2790 dsend_packet_unit_paradrop_to(&client.conn, punit->id, tile_index(ptile));
2791 }
2792
2793 /**************************************************************************
2794 Patrol to a location.
2795 **************************************************************************/
do_unit_patrol_to(struct tile * ptile)2796 void do_unit_patrol_to(struct tile *ptile)
2797 {
2798 if (is_valid_goto_draw_line(ptile)
2799 && !is_non_allied_unit_tile(ptile, client.conn.playing)) {
2800 send_patrol_route();
2801 } else {
2802 create_event(ptile, E_BAD_COMMAND, ftc_client,
2803 _("Didn't find a route to the destination!"));
2804 }
2805
2806 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2807 }
2808
2809 /**************************************************************************
2810 "Connect" to the given location.
2811 **************************************************************************/
do_unit_connect(struct tile * ptile,enum unit_activity activity,struct extra_type * tgt)2812 void do_unit_connect(struct tile *ptile,
2813 enum unit_activity activity,
2814 struct extra_type *tgt)
2815 {
2816 if (is_valid_goto_draw_line(ptile)) {
2817 send_connect_route(activity, tgt);
2818 } else {
2819 create_event(ptile, E_BAD_COMMAND, ftc_client,
2820 _("Didn't find a route to the destination!"));
2821 }
2822
2823 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2824 }
2825
2826 /**************************************************************************
2827 The 'Escape' key.
2828 **************************************************************************/
key_cancel_action(void)2829 void key_cancel_action(void)
2830 {
2831 cancel_tile_hiliting();
2832
2833 switch (hover_state) {
2834 case HOVER_GOTO:
2835 case HOVER_PATROL:
2836 case HOVER_CONNECT:
2837 case HOVER_NUKE:
2838 if (goto_pop_waypoint()) {
2839 break;
2840 }
2841 fc__fallthrough; /* else fall through: */
2842 case HOVER_PARADROP:
2843 case HOVER_ACT_SEL_TGT:
2844 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2845 update_unit_info_label(get_units_in_focus());
2846
2847 keyboardless_goto_button_down = FALSE;
2848 keyboardless_goto_active = FALSE;
2849 keyboardless_goto_start_tile = NULL;
2850 break;
2851 case HOVER_NONE:
2852 break;
2853 };
2854 }
2855
2856 /**************************************************************************
2857 Center the mapview on the player's capital, or print a failure message.
2858 **************************************************************************/
key_center_capital(void)2859 void key_center_capital(void)
2860 {
2861 struct city *capital = player_capital(client_player());
2862
2863 if (capital) {
2864 /* Center on the tile, and pop up the crosshair overlay. */
2865 center_tile_mapcanvas(capital->tile);
2866 put_cross_overlay_tile(capital->tile);
2867 } else {
2868 create_event(NULL, E_BAD_COMMAND, ftc_client,
2869 _("Oh my! You seem to have no capital!"));
2870 }
2871 }
2872
2873 /**************************************************************************
2874 Handle user 'end turn' input.
2875 **************************************************************************/
key_end_turn(void)2876 void key_end_turn(void)
2877 {
2878 send_turn_done();
2879 }
2880
2881 /**************************************************************************
2882 Recall the previous focus unit(s). See store_previous_focus().
2883 **************************************************************************/
key_recall_previous_focus_unit(void)2884 void key_recall_previous_focus_unit(void)
2885 {
2886 int i = 0;
2887
2888 /* Could use unit_list_copy here instead. Just having safe genlists
2889 * wouldn't be sufficient since we don't want to skip units already
2890 * removed from focus... */
2891 unit_list_iterate_safe(previous_focus, punit) {
2892 if (i == 0) {
2893 unit_focus_set(punit);
2894 } else {
2895 unit_focus_add(punit);
2896 }
2897 i++;
2898 } unit_list_iterate_safe_end;
2899 }
2900
2901 /**************************************************************************
2902 Move the focus unit in the given direction. Here directions are
2903 defined according to the GUI, so that north is "up" in the interface.
2904 **************************************************************************/
key_unit_move(enum direction8 gui_dir)2905 void key_unit_move(enum direction8 gui_dir)
2906 {
2907 unit_list_iterate(get_units_in_focus(), punit) {
2908 enum direction8 map_dir = gui_to_map_dir(gui_dir);
2909
2910 request_move_unit_direction(punit, map_dir);
2911 } unit_list_iterate_end;
2912 }
2913
2914 /**************************************************************************
2915 Handle use 'build city' input.
2916 **************************************************************************/
key_unit_build_city(void)2917 void key_unit_build_city(void)
2918 {
2919 unit_list_iterate(get_units_in_focus(), punit) {
2920 request_unit_build_city(punit);
2921 } unit_list_iterate_end;
2922 }
2923
2924 /**************************************************************************
2925 Handle user 'help build wonder' input
2926 **************************************************************************/
key_unit_build_wonder(void)2927 void key_unit_build_wonder(void)
2928 {
2929 unit_list_iterate(get_units_in_focus(), punit) {
2930 if (unit_can_do_action(punit, ACTION_HELP_WONDER)) {
2931 request_unit_caravan_action(punit, ACTION_HELP_WONDER);
2932 }
2933 } unit_list_iterate_end;
2934 }
2935
2936 /**************************************************************************
2937 handle user pressing key for 'Connect' command
2938 **************************************************************************/
key_unit_connect(enum unit_activity activity,struct extra_type * tgt)2939 void key_unit_connect(enum unit_activity activity,
2940 struct extra_type *tgt)
2941 {
2942 request_unit_connect(activity, tgt);
2943 }
2944
2945 /**************************************************************************
2946 Handle user 'Do...' input
2947 **************************************************************************/
key_unit_action_select(void)2948 void key_unit_action_select(void)
2949 {
2950 struct tile *ptile;
2951
2952 unit_list_iterate(get_units_in_focus(), punit) {
2953 if (utype_may_act_at_all(unit_type_get(punit))
2954 && (ptile = unit_tile(punit))) {
2955 /* Have the server record that an action decision is wanted for this
2956 * unit. */
2957 request_do_action(ACTION_COUNT, punit->id, tile_index(ptile),
2958 ACTSIG_QUEUE);
2959 }
2960 } unit_list_iterate_end;
2961 }
2962
2963 /**************************************************************************
2964 Have the user select what action the unit(s) in focus should perform to
2965 the targets at the tile the user will specify by clicking on it.
2966
2967 Will stop asking for a target tile and have each actor unit act against
2968 its own tile if called twice.
2969 **************************************************************************/
key_unit_action_select_tgt(void)2970 void key_unit_action_select_tgt(void)
2971 {
2972 struct unit_list *punits = get_units_in_focus();
2973
2974 if (hover_state == HOVER_ACT_SEL_TGT) {
2975 /* The 2nd key press means that the actor should target its own
2976 * tile. */
2977 key_unit_action_select();
2978
2979 /* Target tile selected. Clean up hover state. */
2980 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2981 update_unit_info_label(punits);
2982
2983 return;
2984 }
2985
2986 set_hover_state(punits, HOVER_ACT_SEL_TGT, ACTIVITY_LAST, NULL,
2987 ORDER_LAST);
2988 }
2989
2990 /**************************************************************************
2991 Handle user 'unit done' input
2992 **************************************************************************/
key_unit_done(void)2993 void key_unit_done(void)
2994 {
2995 request_unit_move_done();
2996 }
2997
2998 /**************************************************************************
2999 Handle user 'unit goto' input
3000 **************************************************************************/
key_unit_goto(void)3001 void key_unit_goto(void)
3002 {
3003 request_unit_goto(ORDER_LAST);
3004 }
3005
3006 /**************************************************************************
3007 Explode nuclear at a tile without enemy units
3008 **************************************************************************/
key_unit_nuke(void)3009 void key_unit_nuke(void)
3010 {
3011 request_unit_nuke(get_units_in_focus());
3012 }
3013
3014 /**************************************************************************
3015 Handle user 'paradrop' input
3016 **************************************************************************/
key_unit_paradrop(void)3017 void key_unit_paradrop(void)
3018 {
3019 request_unit_paradrop(get_units_in_focus());
3020 }
3021
3022 /**************************************************************************
3023 Handle user 'patrol' input
3024 **************************************************************************/
key_unit_patrol(void)3025 void key_unit_patrol(void)
3026 {
3027 request_unit_patrol();
3028 }
3029
3030 /**************************************************************************
3031 Handle user 'establish traderoute' input
3032 **************************************************************************/
key_unit_trade_route(void)3033 void key_unit_trade_route(void)
3034 {
3035 unit_list_iterate(get_units_in_focus(), punit) {
3036 /* TODO: Is falling back on ACTION_MARKETPLACE if not able to establish
3037 * a trade route trade a good idea or an unplecant surprice? */
3038 if (unit_can_do_action(punit, ACTION_TRADE_ROUTE)) {
3039 request_unit_caravan_action(punit, ACTION_TRADE_ROUTE);
3040 }
3041 } unit_list_iterate_end;
3042 }
3043
3044 /**************************************************************************
3045 Handle user 'unload all' input
3046 **************************************************************************/
key_unit_unload_all(void)3047 void key_unit_unload_all(void)
3048 {
3049 struct unit *pnext_focus = NULL, *plast;
3050
3051 unit_list_iterate(get_units_in_focus(), punit) {
3052 if ((plast = request_unit_unload_all(punit))) {
3053 pnext_focus = plast;
3054 }
3055 } unit_list_iterate_end;
3056
3057 if (pnext_focus) {
3058 unit_list_iterate(get_units_in_focus(), punit) {
3059 /* Unfocus the ships, and advance the focus to the last unloaded unit.
3060 * If there is no unit unloaded (which shouldn't happen, but could if
3061 * the caller doesn't check if the transporter is loaded), the we
3062 * don't do anything. */
3063 punit->client.focus_status = FOCUS_WAIT;
3064 } unit_list_iterate_end;
3065 unit_focus_set(pnext_focus);
3066 }
3067 }
3068
3069 /**************************************************************************
3070 Handle user 'wait' input
3071 **************************************************************************/
key_unit_wait(void)3072 void key_unit_wait(void)
3073 {
3074 request_units_wait(get_units_in_focus());
3075 }
3076
3077 /**************************************************************************
3078 Handle user 'wakeup others' input
3079 ***************************************************************************/
key_unit_wakeup_others(void)3080 void key_unit_wakeup_others(void)
3081 {
3082 unit_list_iterate(get_units_in_focus(), punit) {
3083 request_unit_wakeup(punit);
3084 } unit_list_iterate_end;
3085 }
3086
3087 /**************************************************************************
3088 Handle user 'build base of class airbase' input
3089 **************************************************************************/
key_unit_airbase(void)3090 void key_unit_airbase(void)
3091 {
3092 unit_list_iterate(get_units_in_focus(), punit) {
3093 struct base_type *pbase =
3094 get_base_by_gui_type(BASE_GUI_AIRBASE, punit, unit_tile(punit));
3095
3096 if (pbase) {
3097 struct extra_type *pextra = base_extra_get(pbase);
3098
3099 request_new_unit_activity_targeted(punit, ACTIVITY_BASE, pextra);
3100 }
3101 } unit_list_iterate_end;
3102 }
3103
3104 /**************************************************************************
3105 Handle user 'autoexplore' input
3106 **************************************************************************/
key_unit_auto_explore(void)3107 void key_unit_auto_explore(void)
3108 {
3109 unit_list_iterate(get_units_in_focus(), punit) {
3110 if (can_unit_do_activity(punit, ACTIVITY_EXPLORE)) {
3111 request_new_unit_activity(punit, ACTIVITY_EXPLORE);
3112 }
3113 } unit_list_iterate_end;
3114 }
3115
3116 /**************************************************************************
3117 Call to request (from the server) that the focus unit is put into
3118 autosettler mode.
3119 **************************************************************************/
key_unit_auto_settle(void)3120 void key_unit_auto_settle(void)
3121 {
3122 unit_list_iterate(get_units_in_focus(), punit) {
3123 if (can_unit_do_autosettlers(punit)) {
3124 request_unit_autosettlers(punit);
3125 }
3126 } unit_list_iterate_end;
3127 }
3128
3129 /**************************************************************************
3130 Unit convert key pressed or respective menu entry selected.
3131 **************************************************************************/
key_unit_convert(void)3132 void key_unit_convert(void)
3133 {
3134 unit_list_iterate(get_units_in_focus(), punit) {
3135 request_unit_convert(punit);
3136 } unit_list_iterate_end;
3137 }
3138
3139 /**************************************************************************
3140 Handle user 'clean fallout' input
3141 **************************************************************************/
key_unit_fallout(void)3142 void key_unit_fallout(void)
3143 {
3144 key_unit_clean(ACTIVITY_FALLOUT, ERM_CLEANFALLOUT);
3145 }
3146
3147 /**************************************************************************
3148 Handle user 'fortify' input
3149 **************************************************************************/
key_unit_fortify(void)3150 void key_unit_fortify(void)
3151 {
3152 unit_list_iterate(get_units_in_focus(), punit) {
3153 if (can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
3154 request_new_unit_activity(punit, ACTIVITY_FORTIFYING);
3155 }
3156 } unit_list_iterate_end;
3157 }
3158
3159 /**************************************************************************
3160 Handle user 'build base of class fortress' input
3161 **************************************************************************/
key_unit_fortress(void)3162 void key_unit_fortress(void)
3163 {
3164 unit_list_iterate(get_units_in_focus(), punit) {
3165 struct base_type *pbase =
3166 get_base_by_gui_type(BASE_GUI_FORTRESS, punit, unit_tile(punit));
3167
3168 if (pbase) {
3169 struct extra_type *pextra = base_extra_get(pbase);
3170
3171 request_new_unit_activity_targeted(punit, ACTIVITY_BASE, pextra);
3172 }
3173 } unit_list_iterate_end;
3174 }
3175
3176 /**************************************************************************
3177 Handle user 'change homecity' input
3178 **************************************************************************/
key_unit_homecity(void)3179 void key_unit_homecity(void)
3180 {
3181 unit_list_iterate(get_units_in_focus(), punit) {
3182 request_unit_change_homecity(punit);
3183 } unit_list_iterate_end;
3184 }
3185
3186 /**************************************************************************
3187 Handle user extra building input of given type
3188 **************************************************************************/
key_unit_extra(enum unit_activity act,enum extra_cause cause)3189 static void key_unit_extra(enum unit_activity act, enum extra_cause cause)
3190 {
3191 unit_list_iterate(get_units_in_focus(), punit) {
3192 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
3193 cause,
3194 unit_owner(punit),
3195 punit);
3196
3197 if (can_unit_do_activity_targeted(punit, act, tgt)) {
3198 request_new_unit_activity_targeted(punit, act, tgt);
3199 }
3200 } unit_list_iterate_end;
3201 }
3202
3203 /**************************************************************************
3204 Handle user extra cleaning input of given type
3205 **************************************************************************/
key_unit_clean(enum unit_activity act,enum extra_rmcause rmcause)3206 static void key_unit_clean(enum unit_activity act, enum extra_rmcause rmcause)
3207 {
3208 unit_list_iterate(get_units_in_focus(), punit) {
3209 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
3210 rmcause,
3211 unit_owner(punit),
3212 punit);
3213
3214 if (tgt != NULL
3215 && can_unit_do_activity_targeted(punit, act, tgt)) {
3216 request_new_unit_activity_targeted(punit, act, tgt);
3217 }
3218 } unit_list_iterate_end;
3219 }
3220
3221 /**************************************************************************
3222 Handle user 'irrigate' input
3223 **************************************************************************/
key_unit_irrigate(void)3224 void key_unit_irrigate(void)
3225 {
3226 key_unit_extra(ACTIVITY_IRRIGATE, EC_IRRIGATION);
3227 }
3228
3229 /**************************************************************************
3230 Handle user 'build mine' input
3231 **************************************************************************/
key_unit_mine(void)3232 void key_unit_mine(void)
3233 {
3234 key_unit_extra(ACTIVITY_MINE, EC_MINE);
3235 }
3236
3237 /**************************************************************************
3238 Handle user 'pillage' input
3239 **************************************************************************/
key_unit_pillage(void)3240 void key_unit_pillage(void)
3241 {
3242 unit_list_iterate(get_units_in_focus(), punit) {
3243 if (can_unit_do_activity(punit, ACTIVITY_PILLAGE)) {
3244 request_unit_pillage(punit);
3245 }
3246 } unit_list_iterate_end;
3247 }
3248
3249 /**************************************************************************
3250 Handle user 'clean pollution' input
3251 **************************************************************************/
key_unit_pollution(void)3252 void key_unit_pollution(void)
3253 {
3254 key_unit_clean(ACTIVITY_POLLUTION, ERM_CLEANPOLLUTION);
3255 }
3256
3257 /**************************************************************************
3258 Handle user 'build road or railroad' input
3259 **************************************************************************/
key_unit_road(void)3260 void key_unit_road(void)
3261 {
3262 unit_list_iterate(get_units_in_focus(), punit) {
3263 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
3264 EC_ROAD,
3265 unit_owner(punit),
3266 punit);
3267
3268 if (tgt != NULL
3269 && can_unit_do_activity_targeted(punit, ACTIVITY_GEN_ROAD, tgt)) {
3270 request_new_unit_activity_targeted(punit, ACTIVITY_GEN_ROAD, tgt);
3271 }
3272 } unit_list_iterate_end;
3273 }
3274
3275 /**************************************************************************
3276 Handle user 'sentry' input
3277 **************************************************************************/
key_unit_sentry(void)3278 void key_unit_sentry(void)
3279 {
3280 unit_list_iterate(get_units_in_focus(), punit) {
3281 if (can_unit_do_activity(punit, ACTIVITY_SENTRY)) {
3282 request_new_unit_activity(punit, ACTIVITY_SENTRY);
3283 }
3284 } unit_list_iterate_end;
3285 }
3286
3287 /**************************************************************************
3288 Handle user 'transform unit' input
3289 **************************************************************************/
key_unit_transform(void)3290 void key_unit_transform(void)
3291 {
3292 unit_list_iterate(get_units_in_focus(), punit) {
3293 if (can_unit_do_activity(punit, ACTIVITY_TRANSFORM)) {
3294 request_new_unit_activity(punit, ACTIVITY_TRANSFORM);
3295 }
3296 } unit_list_iterate_end;
3297 }
3298
3299 /****************************************************************************
3300 Assign all focus units to this battlegroup.
3301 ****************************************************************************/
key_unit_assign_battlegroup(int battlegroup,bool append)3302 void key_unit_assign_battlegroup(int battlegroup, bool append)
3303 {
3304 if (NULL != client.conn.playing && can_client_issue_orders()
3305 && battlegroups >= 0 && battlegroup < MAX_NUM_BATTLEGROUPS) {
3306 if (!append) {
3307 unit_list_iterate_safe(battlegroups[battlegroup], punit) {
3308 if (!unit_is_in_focus(punit)) {
3309 punit->battlegroup = BATTLEGROUP_NONE;
3310 dsend_packet_unit_battlegroup(&client.conn,
3311 punit->id, BATTLEGROUP_NONE);
3312 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
3313 unit_list_remove(battlegroups[battlegroup], punit);
3314 }
3315 } unit_list_iterate_safe_end;
3316 }
3317 unit_list_iterate(get_units_in_focus(), punit) {
3318 if (punit->battlegroup != battlegroup) {
3319 if (punit->battlegroup >= 0
3320 && punit->battlegroup < MAX_NUM_BATTLEGROUPS) {
3321 unit_list_remove(battlegroups[punit->battlegroup], punit);
3322 }
3323 punit->battlegroup = battlegroup;
3324 dsend_packet_unit_battlegroup(&client.conn,
3325 punit->id, battlegroup);
3326 unit_list_append(battlegroups[battlegroup], punit);
3327 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
3328 }
3329 } unit_list_iterate_end;
3330 unit_list_iterate(battlegroups[battlegroup], punit) {
3331 unit_focus_add(punit);
3332 } unit_list_iterate_end;
3333 }
3334 }
3335
3336 /****************************************************************************
3337 Bring this battlegroup into focus.
3338 ****************************************************************************/
key_unit_select_battlegroup(int battlegroup,bool append)3339 void key_unit_select_battlegroup(int battlegroup, bool append)
3340 {
3341 if (NULL != client.conn.playing && can_client_change_view()
3342 && battlegroups >= 0 && battlegroup < MAX_NUM_BATTLEGROUPS) {
3343 int i = 0;
3344
3345 if (unit_list_size(battlegroups[battlegroup]) == 0 && !append) {
3346 unit_focus_set(NULL);
3347 return;
3348 }
3349
3350 /* FIXME: this is very inefficient and can be improved. */
3351 unit_list_iterate(battlegroups[battlegroup], punit) {
3352 if (i == 0 && !append) {
3353 unit_focus_set(punit);
3354 } else {
3355 unit_focus_add(punit);
3356 }
3357 i++;
3358 } unit_list_iterate_end;
3359 }
3360 }
3361
3362 /**************************************************************************
3363 Toggle drawing of city outlines.
3364 **************************************************************************/
key_city_outlines_toggle(void)3365 void key_city_outlines_toggle(void)
3366 {
3367 request_toggle_city_outlines();
3368 }
3369
3370 /**************************************************************************
3371 Toggle drawing of city output produced by workers of the city.
3372 **************************************************************************/
key_city_output_toggle(void)3373 void key_city_output_toggle(void)
3374 {
3375 request_toggle_city_output();
3376 }
3377
3378 /**************************************************************************
3379 Handle user 'toggle map grid' input
3380 **************************************************************************/
key_map_grid_toggle(void)3381 void key_map_grid_toggle(void)
3382 {
3383 request_toggle_map_grid();
3384 }
3385
3386 /**************************************************************************
3387 Toggle map borders on the mapview on/off based on a keypress.
3388 **************************************************************************/
key_map_borders_toggle(void)3389 void key_map_borders_toggle(void)
3390 {
3391 request_toggle_map_borders();
3392 }
3393
3394 /**************************************************************************
3395 Toggle native tiles on the mapview on/off based on a keypress.
3396 **************************************************************************/
key_map_native_toggle(void)3397 void key_map_native_toggle(void)
3398 {
3399 request_toggle_map_native();
3400 }
3401
3402 /**************************************************************************
3403 Toggle the "Draw the city bar" option.
3404 **************************************************************************/
key_city_full_bar_toggle(void)3405 void key_city_full_bar_toggle(void)
3406 {
3407 request_toggle_city_full_bar();
3408 }
3409
3410 /**************************************************************************
3411 Handle user 'toggle city names display' input
3412 **************************************************************************/
key_city_names_toggle(void)3413 void key_city_names_toggle(void)
3414 {
3415 request_toggle_city_names();
3416 }
3417
3418 /**************************************************************************
3419 Toggles the "show city growth turns" option by passing off the
3420 request to another function...
3421 **************************************************************************/
key_city_growth_toggle(void)3422 void key_city_growth_toggle(void)
3423 {
3424 request_toggle_city_growth();
3425 }
3426
3427 /**************************************************************************
3428 Toggles the showing of the buy cost of the current production in the
3429 city descriptions.
3430 **************************************************************************/
key_city_buycost_toggle(void)3431 void key_city_buycost_toggle(void)
3432 {
3433 request_toggle_city_buycost();
3434 }
3435
3436 /**************************************************************************
3437 Handle user 'toggle city production display' input
3438 **************************************************************************/
key_city_productions_toggle(void)3439 void key_city_productions_toggle(void)
3440 {
3441 request_toggle_city_productions();
3442 }
3443
3444 /**************************************************************************
3445 Handle client request to toggle drawing of trade route information
3446 by the city name for cities visible on the main map view.
3447 **************************************************************************/
key_city_trade_routes_toggle(void)3448 void key_city_trade_routes_toggle(void)
3449 {
3450 request_toggle_city_trade_routes();
3451 }
3452
3453 /**************************************************************************
3454 Handle user 'toggle terrain display' input
3455 **************************************************************************/
key_terrain_toggle(void)3456 void key_terrain_toggle(void)
3457 {
3458 request_toggle_terrain();
3459 }
3460
3461 /**************************************************************************
3462 Handle user 'toggle coastline display' input
3463 **************************************************************************/
key_coastline_toggle(void)3464 void key_coastline_toggle(void)
3465 {
3466 request_toggle_coastline();
3467 }
3468
3469 /**************************************************************************
3470 Handle user 'toggle road/railroad display' input
3471 **************************************************************************/
key_roads_rails_toggle(void)3472 void key_roads_rails_toggle(void)
3473 {
3474 request_toggle_roads_rails();
3475 }
3476
3477 /**************************************************************************
3478 Handle user 'toggle irrigation display' input
3479 **************************************************************************/
key_irrigation_toggle(void)3480 void key_irrigation_toggle(void)
3481 {
3482 request_toggle_irrigation();
3483 }
3484
3485 /**************************************************************************
3486 Handle user 'toggle mine display' input
3487 **************************************************************************/
key_mines_toggle(void)3488 void key_mines_toggle(void)
3489 {
3490 request_toggle_mines();
3491 }
3492
3493 /**************************************************************************
3494 Handle user 'toggle bases display' input
3495 **************************************************************************/
key_bases_toggle(void)3496 void key_bases_toggle(void)
3497 {
3498 request_toggle_bases();
3499 }
3500
3501 /**************************************************************************
3502 Handle user 'toggle resources display' input
3503 **************************************************************************/
key_resources_toggle(void)3504 void key_resources_toggle(void)
3505 {
3506 request_toggle_resources();
3507 }
3508
3509 /**************************************************************************
3510 Handle user 'toggle huts display' input
3511 **************************************************************************/
key_huts_toggle(void)3512 void key_huts_toggle(void)
3513 {
3514 request_toggle_huts();
3515 }
3516
3517 /**************************************************************************
3518 Handle user 'toggle pollution display' input
3519 **************************************************************************/
key_pollution_toggle(void)3520 void key_pollution_toggle(void)
3521 {
3522 request_toggle_pollution();
3523 }
3524
3525 /**************************************************************************
3526 Handle user 'toggle cities display' input
3527 **************************************************************************/
key_cities_toggle(void)3528 void key_cities_toggle(void)
3529 {
3530 request_toggle_cities();
3531 }
3532
3533 /**************************************************************************
3534 Handle user 'toggle units display' input
3535 **************************************************************************/
key_units_toggle(void)3536 void key_units_toggle(void)
3537 {
3538 request_toggle_units();
3539 }
3540
3541 /**************************************************************************
3542 Toggle the "Solid unit background color" option.
3543 **************************************************************************/
key_unit_solid_bg_toggle(void)3544 void key_unit_solid_bg_toggle(void)
3545 {
3546 request_toggle_unit_solid_bg();
3547 }
3548
3549 /**************************************************************************
3550 Toggle the "Draw shield graphics for units" option.
3551 **************************************************************************/
key_unit_shields_toggle(void)3552 void key_unit_shields_toggle(void)
3553 {
3554 request_toggle_unit_shields();
3555 }
3556
3557 /**************************************************************************
3558 Handle user 'toggle key units display' input
3559 **************************************************************************/
key_focus_unit_toggle(void)3560 void key_focus_unit_toggle(void)
3561 {
3562 request_toggle_focus_unit();
3563 }
3564
3565 /**************************************************************************
3566 Handle user 'toggle fog of war display' input
3567 **************************************************************************/
key_fog_of_war_toggle(void)3568 void key_fog_of_war_toggle(void)
3569 {
3570 request_toggle_fog_of_war();
3571 }
3572
3573 /**************************************************************************
3574 Toggle editor mode in the server.
3575 **************************************************************************/
key_editor_toggle(void)3576 void key_editor_toggle(void)
3577 {
3578 dsend_packet_edit_mode(&client.conn, !game.info.is_edit_mode);
3579 }
3580
3581 /**************************************************************************
3582 Recalculate borders.
3583 **************************************************************************/
key_editor_recalculate_borders(void)3584 void key_editor_recalculate_borders(void)
3585 {
3586 send_packet_edit_recalculate_borders(&client.conn);
3587 }
3588
3589 /**************************************************************************
3590 Send a request to the server to toggle fog-of-war for the current
3591 player (only applies in edit mode).
3592 **************************************************************************/
key_editor_toggle_fogofwar(void)3593 void key_editor_toggle_fogofwar(void)
3594 {
3595 if (client_has_player()) {
3596 dsend_packet_edit_toggle_fogofwar(&client.conn, client_player_number());
3597 }
3598 }
3599
3600 /**************************************************************************
3601 All units ready to build city to the tile should now proceed.
3602 **************************************************************************/
finish_city(struct tile * ptile,const char * name)3603 void finish_city(struct tile *ptile, const char *name)
3604 {
3605 unit_list_iterate(ptile->units, punit) {
3606 if (punit->client.asking_city_name) {
3607 /* Unit will disappear only in case city building still success.
3608 * Cancel city building status just in case something has changed
3609 * to prevent city building in the meanwhile and unit will remain
3610 * alive. */
3611 punit->client.asking_city_name = FALSE;
3612 dsend_packet_unit_build_city(&client.conn, punit->id, name);
3613 }
3614 } unit_list_iterate_end;
3615 }
3616
3617 /**************************************************************************
3618 Do not build city after all. Cancel city building mark from all units
3619 prepared for it.
3620 **************************************************************************/
cancel_city(struct tile * ptile)3621 void cancel_city(struct tile *ptile)
3622 {
3623 unit_list_iterate(ptile->units, punit) {
3624 punit->client.asking_city_name = FALSE;
3625 } unit_list_iterate_end;
3626 }
3627