Replaced deprecated gtk_menu_popup() calls with modern constructs in gtk3.22-client
[freeciv.git] / client / control.c
blobf0dd6273feb34877bc966ab8f8154d445bd34ed1
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* utility */
19 #include "bitvector.h"
20 #include "fcintl.h"
21 #include "log.h"
22 #include "mem.h"
23 #include "timing.h"
25 /* common */
26 #include "combat.h"
27 #include "game.h"
28 #include "map.h"
29 #include "movement.h"
30 #include "unitlist.h"
32 /* common/aicore */
33 #include "path_finding.h"
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"
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"
56 #include "control.h"
59 struct client_nuke_data {
60 int *units_id;
61 int units_num;
62 int tile_idx;
65 /* gui-dep code may adjust depending on tile size etc: */
66 int num_units_below = MAX_NUM_UNITS_BELOW;
68 /* current_focus points to the current unit(s) in focus */
69 static struct unit_list *current_focus = NULL;
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;
75 /* The priority unit(s) for unit_focus_advance(). */
76 static struct unit_list *urgent_focus_queue = NULL;
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 */
84 static struct tile *hover_tile = NULL;
85 static struct unit_list *battlegroups[MAX_NUM_BATTLEGROUPS];
87 /* Current moving unit. */
88 static struct unit *punit_moving = NULL;
90 /* units involved in current combat */
91 static struct unit *punit_attacking = NULL;
92 static struct unit *punit_defending = NULL;
94 /* The ID of the unit that currently is in the action selection process.
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.
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)
105 static int action_selection_in_progress_for = IDENTITY_NUMBER_ZERO;
108 * This variable is TRUE iff a NON-AI controlled unit was focused this
109 * turn.
111 bool non_ai_unit_focus;
113 static void key_unit_clean(enum unit_activity act, enum extra_rmcause rmcause);
115 /*************************************************************************/
117 static struct unit *quickselect(struct tile *ptile,
118 enum quickselect_type qtype);
120 /**************************************************************************
121 Called only by client_game_init() in client/client_main.c
122 **************************************************************************/
123 void control_init(void)
125 int i;
127 current_focus = unit_list_new();
128 previous_focus = unit_list_new();
129 urgent_focus_queue = unit_list_new();
131 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
132 battlegroups[i] = unit_list_new();
134 hover_tile = NULL;
137 /**************************************************************************
138 Called only by client_game_free() in client/client_main.c
139 **************************************************************************/
140 void control_free(void)
142 int i;
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;
151 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
152 unit_list_destroy(battlegroups[i]);
153 battlegroups[i] = NULL;
156 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
157 free_client_goto();
160 /**************************************************************************
161 Returns list of units currently in focus.
162 **************************************************************************/
163 struct unit_list *get_units_in_focus(void)
165 return current_focus;
168 /****************************************************************************
169 Return the number of units currently in focus (0 or more).
170 ****************************************************************************/
171 int get_num_units_in_focus(void)
173 return (NULL != current_focus ? unit_list_size(current_focus) : 0);
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 **************************************************************************/
180 static void store_previous_focus(void)
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;
190 /****************************************************************************
191 Store a priority focus unit.
192 ****************************************************************************/
193 void unit_focus_urgent(struct unit *punit)
195 unit_list_append(urgent_focus_queue, punit);
198 /**************************************************************************
199 Do various updates required when the set of units in focus changes.
200 **************************************************************************/
201 static void focus_units_changed(void)
203 update_unit_info_label(get_units_in_focus());
204 menus_update();
205 /* Notify the GUI */
206 real_focus_units_changed();
209 /**************************************************************************
210 Called when a unit is killed; this removes it from the control lists.
211 **************************************************************************/
212 void control_unit_killed(struct unit *punit)
214 int i;
216 goto_unit_killed(punit);
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);
223 unit_list_remove(previous_focus, punit);
224 unit_list_remove(urgent_focus_queue, punit);
226 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
227 unit_list_remove(battlegroups[i], punit);
230 focus_units_changed();
233 /**************************************************************************
234 Change the battlegroup for this unit.
235 **************************************************************************/
236 void unit_change_battlegroup(struct unit *punit, int battlegroup)
238 if (battlegroup < 0 || battlegroup >= MAX_NUM_BATTLEGROUPS) {
239 battlegroup = BATTLEGROUP_NONE;
242 if (punit->battlegroup != battlegroup) {
243 if (battlegroup != BATTLEGROUP_NONE) {
244 unit_list_append(battlegroups[battlegroup], punit);
246 if (punit->battlegroup != BATTLEGROUP_NONE) {
247 unit_list_remove(battlegroups[punit->battlegroup], punit);
249 punit->battlegroup = battlegroup;
253 /**************************************************************************
254 Call this on new units to enter them in the battlegroup lists.
255 **************************************************************************/
256 void unit_register_battlegroup(struct unit *punit)
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);
265 /**************************************************************************
266 Enter the given hover state.
268 activity => The connect activity (ACTIVITY_IRRIGATE, etc.)
269 order => The last order (ORDER_BUILD_CITY, ORDER_LAST, etc.)
270 **************************************************************************/
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)
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;
288 goto_last_order = order;
291 /**************************************************************************
292 Returns TRUE iff the client should ask the server about what actions a
293 unit can perform.
294 **************************************************************************/
295 bool should_ask_server_for_actions(const struct unit *punit)
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));
304 /**************************************************************************
305 Returns TRUE iff it is OK to ask the server about what actions a unit
306 can perform.
307 **************************************************************************/
308 static bool can_ask_server_for_actions(void)
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);
315 /**************************************************************************
316 Ask the server about what actions punit may be able to perform against
317 it's stored target tile.
319 The server's reply will pop up the action selection dialog unless no
320 alternatives exists.
321 **************************************************************************/
322 static void ask_server_for_actions(struct unit *punit)
324 fc_assert_ret(punit);
325 fc_assert_ret(punit->action_decision_tile);
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;
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);
341 /****************************************************************************
342 Return TRUE iff this unit is in focus.
343 ****************************************************************************/
344 bool unit_is_in_focus(const struct unit *punit)
346 return unit_list_search(get_units_in_focus(), punit) != NULL;
349 /****************************************************************************
350 Return TRUE iff a unit on this tile is in focus.
351 ****************************************************************************/
352 struct unit *get_focus_unit_on_tile(const struct tile *ptile)
354 unit_list_iterate(get_units_in_focus(), punit) {
355 if (unit_tile(punit) == ptile) {
356 return punit;
358 } unit_list_iterate_end;
360 return NULL;
363 /****************************************************************************
364 Return head of focus units list.
365 ****************************************************************************/
366 struct unit *head_of_units_in_focus(void)
368 return unit_list_get(current_focus, 0);
371 /****************************************************************************
372 Finds a single focus unit that we can center on. May return NULL.
373 ****************************************************************************/
374 static struct tile *find_a_focus_unit_tile_to_center_on(void)
376 struct unit *punit;
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;
387 /**************************************************************************
388 Center on the focus unit, if off-screen and auto_center_on_unit is true.
389 **************************************************************************/
390 void auto_center_on_focus_unit(void)
392 struct tile *ptile = find_a_focus_unit_tile_to_center_on();
394 if (ptile && gui_options.auto_center_on_unit &&
395 !tile_visible_and_not_on_border_mapcanvas(ptile)) {
396 center_tile_mapcanvas(ptile);
400 /**************************************************************************
401 Add unit to list of units currently in focus.
402 **************************************************************************/
403 static void current_focus_append(struct unit *punit)
405 unit_list_append(current_focus, punit);
407 punit->client.focus_status = FOCUS_AVAIL;
408 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
410 if (should_ask_server_for_actions(punit)
411 && can_ask_server_for_actions()) {
412 ask_server_for_actions(punit);
415 if (gui_options.unit_selection_clears_orders) {
416 clear_unit_orders(punit);
420 /**************************************************************************
421 Remove focus from unit.
422 **************************************************************************/
423 static void current_focus_remove(struct unit *punit)
425 /* Close the action selection dialog if the actor unit lose focus. */
426 if (action_selection_actor_unit() == punit->id) {
427 action_selection_close();
430 unit_list_remove(current_focus, punit);
431 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
434 /**************************************************************************
435 Clear all orders for the given unit.
436 **************************************************************************/
437 void clear_unit_orders(struct unit *punit)
439 if (!punit) {
440 return;
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);
454 /**************************************************************************
455 Sets the focus unit directly. The unit given will be given the
456 focus; if NULL the focus will be cleared.
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 **************************************************************************/
462 void unit_focus_set(struct unit *punit)
464 bool focus_changed = FALSE;
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;
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;
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();
487 } unit_list_iterate_end;
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);
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;
503 if (NULL != punit) {
504 current_focus_append(punit);
505 auto_center_on_focus_unit();
508 if (focus_changed) {
509 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
510 focus_units_changed();
514 /**************************************************************************
515 Adds this unit to the list of units in focus.
516 **************************************************************************/
517 void unit_focus_add(struct unit *punit)
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;
526 if (NULL == punit || !can_client_change_view()) {
527 return;
530 if (unit_is_in_focus(punit)) {
531 return;
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);
540 current_focus_append(punit);
541 focus_units_changed();
544 /**************************************************************************
545 Removes this unit from the list of units in focus.
546 **************************************************************************/
547 void unit_focus_remove(struct unit *punit)
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;
556 if (NULL == punit || !can_client_change_view()) {
557 return;
560 if (!unit_is_in_focus(punit)) {
561 return;
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);
570 current_focus_remove(punit);
571 if (get_num_units_in_focus() > 0) {
572 focus_units_changed();
573 } else {
574 unit_focus_advance();
578 /**************************************************************************
579 The only difference is that here we draw the "cross".
580 **************************************************************************/
581 void unit_focus_set_and_select(struct unit *punit)
583 unit_focus_set(punit);
584 if (punit) {
585 put_cross_overlay_tile(unit_tile(punit));
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 **************************************************************************/
594 static struct unit *find_best_focus_candidate(bool accept_current)
596 struct tile *ptile = get_center_tile_mapcanvas();
598 if (!get_focus_unit_on_tile(ptile)) {
599 struct unit *pfirst = head_of_units_in_focus();
601 if (pfirst) {
602 ptile = unit_tile(pfirst);
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;
618 } unit_list_iterate_end;
619 } iterate_outward_end;
621 return NULL;
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.
629 FIXME: Add feature to focus only units of a certain category.
630 **************************************************************************/
631 void unit_focus_advance(void)
633 struct unit *candidate = NULL;
634 const int num_units_in_old_focus = get_num_units_in_focus();
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;
643 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
645 unit_list_iterate(get_units_in_focus(), punit) {
647 * Is the unit which just lost focus a non-AI unit? If yes this
648 * enables the auto end turn.
650 if (!punit->ai_controlled) {
651 non_ai_unit_focus = TRUE;
652 break;
654 } unit_list_iterate_end;
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);
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;
678 } unit_list_both_iterate_end;
680 if (NULL != candidate) {
681 unit_list_remove(urgent_focus_queue, candidate);
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));
691 if (NULL == candidate) {
692 candidate = find_best_focus_candidate(FALSE);
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;
700 } unit_list_iterate_end;
701 candidate = find_best_focus_candidate(FALSE);
703 if (!candidate) {
704 /* Accept current focus unit as last resort. */
705 candidate = find_best_focus_candidate(TRUE);
710 unit_focus_set(candidate);
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.
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();
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 **************************************************************************/
732 void unit_focus_update(void)
734 if (NULL == client.conn.playing || !can_client_change_view()) {
735 return;
738 if (!can_ask_server_for_actions()) {
739 fc_assert(get_num_units_in_focus() > 0);
741 /* An actor unit is asking the player what to do. Don't steal his
742 * focus. */
743 return;
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;
757 } unit_list_iterate_end;
759 unit_focus_advance();
762 /**************************************************************************
763 Return a pointer to a visible unit, if there is one.
764 **************************************************************************/
765 struct unit *find_visible_unit(struct tile *ptile)
767 struct unit *panyowned = NULL, *panyother = NULL, *ptptother = NULL;
769 /* If no units here, return nothing. */
770 if (unit_list_size(ptile->units)==0) {
771 return NULL;
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;
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;
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;
793 } unit_list_iterate_end;
795 /* If a city is here, return nothing (unit hidden by city). */
796 if (tile_city(ptile)) {
797 return NULL;
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;
815 } else if (!ptptother && !unit_transported(punit)) {
816 if (get_transporter_capacity(punit) > 0) {
817 ptptother = punit;
818 } else if (!panyother) {
819 panyother = punit;
822 unit_list_iterate_end;
824 return (panyowned ? panyowned : (ptptother ? ptptother : panyother));
827 /**************************************************************************
828 Blink the active unit (if necessary). Return the time until the next
829 blink (in seconds).
830 **************************************************************************/
831 double blink_active_unit(void)
833 static struct timer *blink_timer = NULL;
834 const double blink_time = get_focus_unit_toggle_timeout(tileset);
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);
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);
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;
853 return blink_time - timer_read_seconds(blink_timer);
856 return blink_time;
859 /****************************************************************************
860 Blink the turn done button (if necessary). Return the time until the next
861 blink (in seconds).
862 ****************************************************************************/
863 double blink_turn_done_button(void)
865 static struct timer *blink_timer = NULL;
866 const double blink_time = 0.5; /* half-second blink interval */
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;
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;
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++;
893 } players_iterate_alive_end;
895 if (is_moving == 1 && is_waiting > 0) {
896 update_turn_done_button(FALSE); /* stress the slow player! */
898 blink_timer = timer_renew(blink_timer, TIMER_USER, TIMER_ACTIVE);
899 timer_start(blink_timer);
901 return blink_time - timer_read_seconds(blink_timer);
904 return blink_time;
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.
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?
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 **************************************************************************/
922 void update_unit_pix_label(struct unit_list *punitlist)
924 int i;
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);
937 set_unit_icon(-1, punit);
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);
945 i++;
948 unit_list_iterate_end;
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);
958 } else {
959 for(i=-1; i<num_units_below; i++) {
960 set_unit_icon(i, NULL);
962 set_unit_icons_more_arrow(FALSE);
966 /**************************************************************************
967 Adjusts way combatants are displayed suitable for combat.
968 **************************************************************************/
969 void set_units_in_combat(struct unit *pattacker, struct unit *pdefender)
971 punit_attacking = pattacker;
972 punit_defending = pdefender;
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);
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 **************************************************************************/
988 void action_selection_no_longer_in_progress(const int old_actor_id)
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);
997 /* Stop objecting to allowing the next unit to ask. */
998 action_selection_in_progress_for = IDENTITY_NUMBER_ZERO;
1001 /**************************************************************************
1002 Have the server record that a decision no longer is wanted for the
1003 specified unit.
1004 **************************************************************************/
1005 void action_decision_clear_want(const int old_actor_id)
1007 struct unit *old;
1009 if ((old = game_unit_by_number(old_actor_id))) {
1010 /* Have the server record that a decision no longer is wanted. */
1011 request_do_action(ACTION_COUNT, old_actor_id, IDENTITY_NUMBER_ZERO,
1012 ACTSIG_UNQUEUE);
1016 /**************************************************************************
1017 Move on to the next unit in focus that needs an action decision.
1018 **************************************************************************/
1019 void action_selection_next_in_focus(const int old_actor_id)
1021 struct unit *old;
1023 old = game_unit_by_number(old_actor_id);
1025 /* Go to the next unit in focus that needs a decision. */
1026 unit_list_iterate(get_units_in_focus(), funit) {
1027 if (old != funit && should_ask_server_for_actions(funit)) {
1028 ask_server_for_actions(funit);
1029 return;
1031 } unit_list_iterate_end;
1034 /**************************************************************************
1035 Request that the player makes a decision for the specified unit.
1036 **************************************************************************/
1037 void action_decision_request(struct unit *actor_unit)
1039 fc_assert_ret(actor_unit);
1040 fc_assert_ret(actor_unit->action_decision_tile);
1042 if (!unit_is_in_focus(actor_unit)) {
1043 /* Getting feed back may be urgent. A unit standing next to an enemy
1044 * could be killed while waiting. */
1045 unit_focus_urgent(actor_unit);
1046 } else if (can_client_issue_orders()
1047 && can_ask_server_for_actions()) {
1048 /* No need to wait. The actor unit is in focus. No other actor unit
1049 * is currently asking about action selection. */
1050 ask_server_for_actions(actor_unit);
1054 /**************************************************************************
1055 Do a goto with an order at the end (or ORDER_LAST).
1056 **************************************************************************/
1057 void request_unit_goto(enum unit_orders last_order)
1059 struct unit_list *punits = get_units_in_focus();
1061 if (unit_list_size(punits) == 0) {
1062 return;
1065 if (hover_state != HOVER_GOTO) {
1066 set_hover_state(punits, HOVER_GOTO, ACTIVITY_LAST, NULL,
1067 last_order);
1068 enter_goto_state(punits);
1069 create_line_at_mouse_pos();
1070 update_unit_info_label(punits);
1071 control_mouse_cursor(NULL);
1072 } else {
1073 fc_assert_ret(goto_is_active());
1074 goto_add_waypoint();
1078 /****************************************************************************
1079 Return TRUE if at least one of the untis can do an attack at the tile.
1080 ****************************************************************************/
1081 static bool can_units_attack_at(struct unit_list *punits,
1082 const struct tile *ptile)
1084 unit_list_iterate(punits, punit) {
1085 if (is_attack_unit(punit)
1086 && can_unit_attack_tile(punit, ptile)) {
1087 return TRUE;
1089 } unit_list_iterate_end;
1091 return FALSE;
1094 /**************************************************************************
1095 Determines which mouse cursor should be used, according to hover_state,
1096 and the information gathered from the tile which is under the mouse
1097 cursor (ptile).
1098 **************************************************************************/
1099 void control_mouse_cursor(struct tile *ptile)
1101 struct unit *punit = NULL;
1102 struct city *pcity = NULL;
1103 struct unit_list *active_units = get_units_in_focus();
1104 enum cursor_type mouse_cursor_type = CURSOR_DEFAULT;
1106 if (!gui_options.enable_cursor_changes) {
1107 return;
1110 if (C_S_RUNNING != client_state()) {
1111 update_mouse_cursor(CURSOR_DEFAULT);
1112 return;
1115 if (is_server_busy()) {
1116 /* Server will not accept any commands. */
1117 update_mouse_cursor(CURSOR_WAIT);
1118 return;
1121 if (!ptile) {
1122 if (hover_tile) {
1123 /* hover_tile is the tile that was previously under the mouse cursor. */
1124 ptile = hover_tile;
1125 } else {
1126 update_mouse_cursor(CURSOR_DEFAULT);
1127 return;
1129 } else {
1130 hover_tile = ptile;
1133 punit = find_visible_unit(ptile);
1134 pcity = ptile ? tile_city(ptile) : NULL;
1136 switch (hover_state) {
1137 case HOVER_NONE:
1138 if (NULL != punit
1139 && unit_owner(punit) == client_player()) {
1140 /* Set mouse cursor to select a unit. */
1141 mouse_cursor_type = CURSOR_SELECT;
1142 } else if (NULL != pcity
1143 && can_player_see_city_internals(client.conn.playing, pcity)) {
1144 /* Set mouse cursor to select a city. */
1145 mouse_cursor_type = CURSOR_SELECT;
1146 } else {
1147 /* Set default mouse cursor, because nothing selectable found. */
1149 break;
1150 case HOVER_GOTO:
1151 /* Determine if the goto is valid, invalid or will attack. */
1152 if (is_valid_goto_destination(ptile)) {
1153 if (can_units_attack_at(active_units, ptile)) {
1154 /* Goto results in military attack. */
1155 mouse_cursor_type = CURSOR_ATTACK;
1156 } else if (is_enemy_city_tile(ptile, client.conn.playing)) {
1157 /* Goto results in attack of enemy city. */
1158 mouse_cursor_type = CURSOR_ATTACK;
1159 } else {
1160 mouse_cursor_type = CURSOR_GOTO;
1162 } else {
1163 mouse_cursor_type = CURSOR_INVALID;
1165 break;
1166 case HOVER_PATROL:
1167 if (is_valid_goto_destination(ptile)) {
1168 mouse_cursor_type = CURSOR_PATROL;
1169 } else {
1170 mouse_cursor_type = CURSOR_INVALID;
1172 break;
1173 case HOVER_CONNECT:
1174 if (is_valid_goto_destination(ptile)) {
1175 mouse_cursor_type = CURSOR_GOTO;
1176 } else {
1177 mouse_cursor_type = CURSOR_INVALID;
1179 break;
1180 case HOVER_NUKE:
1181 if (is_valid_goto_destination(ptile)) {
1182 mouse_cursor_type = CURSOR_NUKE;
1183 } else {
1184 mouse_cursor_type = CURSOR_INVALID;
1186 break;
1187 case HOVER_PARADROP:
1188 /* FIXME: check for invalid tiles. */
1189 mouse_cursor_type = CURSOR_PARADROP;
1190 break;
1191 case HOVER_ACT_SEL_TGT:
1192 /* Select a tile to target / find targets on. */
1193 mouse_cursor_type = CURSOR_SELECT;
1194 break;
1197 update_mouse_cursor(mouse_cursor_type);
1200 /**************************************************************************
1201 Return TRUE if there are any units doing the activity on the tile.
1202 **************************************************************************/
1203 static bool is_activity_on_tile(struct tile *ptile,
1204 enum unit_activity activity)
1206 unit_list_iterate(ptile->units, punit) {
1207 if (punit->activity == activity) {
1208 return TRUE;
1210 } unit_list_iterate_end;
1212 return FALSE;
1215 /**************************************************************************
1216 Fill orders to build recursive roads. This modifies ptile, so virtual
1217 copy of the real tile should be passed.
1218 **************************************************************************/
1219 int check_recursive_road_connect(struct tile *ptile, const struct extra_type *pextra,
1220 const struct unit *punit, const struct player *pplayer, int rec)
1222 int activity_mc = 0;
1223 struct terrain *pterrain = tile_terrain(ptile);
1225 if (rec > MAX_EXTRA_TYPES) {
1226 return -1;
1229 if (!is_extra_caused_by(pextra, EC_ROAD)) {
1230 return -1;
1233 extra_deps_iterate(&(pextra->reqs), pdep) {
1234 if (!tile_has_extra(ptile, pdep)) {
1235 int single_mc;
1237 single_mc = check_recursive_road_connect(ptile, pdep, punit, pplayer, rec + 1);
1239 if (single_mc < 0) {
1240 return -1;
1243 activity_mc += single_mc;
1245 } extra_deps_iterate_end;
1247 /* Can build road after that? */
1248 if (punit != NULL) {
1249 if (!can_build_road(extra_road_get(pextra), punit, ptile)) {
1250 return -1;
1252 } else if (pplayer != NULL) {
1253 if (!player_can_build_road(extra_road_get(pextra), pplayer, ptile)) {
1254 return -1;
1258 tile_add_extra(ptile, pextra);
1260 activity_mc += terrain_extra_build_time(pterrain, ACTIVITY_GEN_ROAD, pextra);
1262 return activity_mc;
1265 /**************************************************************************
1266 Return whether the unit can connect with given activity (or with
1267 any activity if activity arg is set to ACTIVITY_IDLE)
1269 This function is client-specific.
1270 **************************************************************************/
1271 bool can_unit_do_connect(struct unit *punit,
1272 enum unit_activity activity,
1273 struct extra_type *tgt)
1275 struct tile *ptile = unit_tile(punit);
1276 struct terrain *pterrain = tile_terrain(ptile);
1277 struct road_type *proad = NULL;
1279 /* HACK: This code duplicates that in
1280 * can_unit_do_activity_targeted_at(). The general logic here is that
1281 * the connect is allowed if both:
1282 * (1) the unit can do that activity type, in general
1283 * (2) either
1284 * (a) the activity has already been completed at this tile
1285 * (b) it can be done by the unit at this tile. */
1286 switch (activity) {
1287 case ACTIVITY_GEN_ROAD:
1289 struct tile *vtile;
1290 int build_time;
1292 fc_assert(is_extra_caused_by(tgt, EC_ROAD));
1294 proad = extra_road_get(tgt);
1296 if (tile_has_road(ptile, proad)) {
1297 /* This tile has road, can unit build road to other tiles too? */
1298 return are_reqs_active(NULL, NULL, NULL, NULL, NULL,
1299 punit, unit_type_get(punit), NULL, NULL,
1300 &tgt->reqs, RPT_POSSIBLE);
1303 /* To start connect, unit must be able to build road to this
1304 * particular tile. */
1305 vtile = tile_virtual_new(ptile);
1306 build_time = check_recursive_road_connect(vtile, tgt, punit, NULL, 0);
1307 tile_virtual_destroy(vtile);
1309 return build_time >= 0;
1312 case ACTIVITY_IRRIGATE:
1313 /* Special case for irrigation: only irrigate to make S_IRRIGATION,
1314 * never to transform tiles. */
1315 if (!unit_has_type_flag(punit, UTYF_SETTLERS)) {
1316 return FALSE;
1318 if (tile_has_extra(ptile, tgt)) {
1319 return are_reqs_active(NULL, NULL, NULL, NULL, NULL,
1320 punit, unit_type_get(punit), NULL, NULL,
1321 &tgt->reqs, RPT_POSSIBLE);
1324 return pterrain == pterrain->irrigation_result
1325 && can_be_irrigated(ptile, punit)
1326 && can_build_extra(tgt, punit, ptile)
1327 && !is_activity_on_tile(ptile,
1328 ACTIVITY_MINE);
1329 default:
1330 break;
1333 return FALSE;
1336 /**************************************************************************
1337 Prompt player for entering destination point for unit connect
1338 (e.g. connecting with roads)
1339 **************************************************************************/
1340 void request_unit_connect(enum unit_activity activity,
1341 struct extra_type *tgt)
1343 struct unit_list *punits = get_units_in_focus();
1345 if (!can_units_do_connect(punits, activity, tgt)) {
1346 return;
1349 if (hover_state != HOVER_CONNECT || connect_activity != activity
1350 || (connect_tgt != tgt
1351 && (activity == ACTIVITY_GEN_ROAD
1352 || activity == ACTIVITY_IRRIGATE))) {
1353 set_hover_state(punits, HOVER_CONNECT, activity, tgt, ORDER_LAST);
1354 enter_goto_state(punits);
1355 create_line_at_mouse_pos();
1356 update_unit_info_label(punits);
1357 control_mouse_cursor(NULL);
1358 } else {
1359 fc_assert_ret(goto_is_active());
1360 goto_add_waypoint();
1364 /**************************************************************************
1365 Returns one of the unit of the transporter which can have focus next.
1366 **************************************************************************/
1367 struct unit *request_unit_unload_all(struct unit *punit)
1369 struct tile *ptile = unit_tile(punit);
1370 struct unit *plast = NULL;
1372 if (get_transporter_capacity(punit) == 0) {
1373 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1374 _("Only transporter units can be unloaded."));
1375 return NULL;
1378 unit_list_iterate(ptile->units, pcargo) {
1379 if (unit_transport_get(pcargo) == punit) {
1380 request_unit_unload(pcargo);
1382 if (pcargo->activity == ACTIVITY_SENTRY) {
1383 request_new_unit_activity(pcargo, ACTIVITY_IDLE);
1386 if (unit_owner(pcargo) == unit_owner(punit)) {
1387 plast = pcargo;
1390 } unit_list_iterate_end;
1392 return plast;
1395 /**************************************************************************
1396 Send unit airlift request to server.
1397 **************************************************************************/
1398 void request_unit_airlift(struct unit *punit, struct city *pcity)
1400 dsend_packet_unit_airlift(&client.conn, punit->id, pcity->id);
1403 /**************************************************************************
1404 Return-and-recover for a particular unit. This sets the unit to GOTO
1405 the nearest city.
1406 **************************************************************************/
1407 void request_unit_return(struct unit *punit)
1409 struct pf_path *path;
1411 if ((path = path_to_nearest_allied_city(punit))) {
1412 int turns = pf_path_last_position(path)->turn;
1413 int max_hp = unit_type_get(punit)->hp;
1415 if (punit->hp + turns *
1416 (get_unit_bonus(punit, EFT_UNIT_RECOVER)
1417 - (max_hp * unit_class_get(punit)->hp_loss_pct / 100))
1418 < max_hp) {
1419 struct unit_order order;
1421 order.order = ORDER_ACTIVITY;
1422 order.dir = DIR8_ORIGIN;
1423 order.activity = ACTIVITY_SENTRY;
1424 order.target = EXTRA_NONE;
1425 send_goto_path(punit, path, &order);
1426 } else {
1427 send_goto_path(punit, path, NULL);
1429 pf_path_destroy(path);
1433 /**************************************************************************
1434 Wakes all owned sentried units on tile.
1435 **************************************************************************/
1436 void wakeup_sentried_units(struct tile *ptile)
1438 if (!can_client_issue_orders()) {
1439 return;
1441 unit_list_iterate(ptile->units, punit) {
1442 if (punit->activity == ACTIVITY_SENTRY
1443 && unit_owner(punit) == client.conn.playing) {
1444 request_new_unit_activity(punit, ACTIVITY_IDLE);
1447 unit_list_iterate_end;
1450 /**************************************************************************
1451 (RP:) un-sentry all my own sentried units on punit's tile
1452 **************************************************************************/
1453 void request_unit_wakeup(struct unit *punit)
1455 wakeup_sentried_units(unit_tile(punit));
1458 /****************************************************************************
1459 Defines specific hash tables needed for request_unit_select().
1460 ****************************************************************************/
1461 #define SPECHASH_TAG unit_type
1462 #define SPECHASH_IKEY_TYPE struct unit_type *
1463 #define SPECHASH_IDATA_TYPE void *
1464 #include "spechash.h"
1466 #define SPECHASH_TAG continent
1467 #define SPECHASH_INT_KEY_TYPE
1468 #define SPECHASH_IDATA_TYPE void *
1469 #include "spechash.h"
1471 /****************************************************************************
1472 Select all units based on the given list of units and the selection modes.
1473 ****************************************************************************/
1474 void request_unit_select(struct unit_list *punits,
1475 enum unit_select_type_mode seltype,
1476 enum unit_select_location_mode selloc)
1478 const struct player *pplayer;
1479 const struct tile *ptile;
1480 struct unit *punit_first;
1481 struct tile_hash *tile_table;
1482 struct unit_type_hash *type_table;
1483 struct continent_hash *cont_table;
1485 if (!can_client_change_view() || !punits
1486 || unit_list_size(punits) < 1) {
1487 return;
1490 punit_first = unit_list_get(punits, 0);
1492 if (seltype == SELTYPE_SINGLE) {
1493 unit_focus_set(punit_first);
1494 return;
1497 pplayer = unit_owner(punit_first);
1498 tile_table = tile_hash_new();
1499 type_table = unit_type_hash_new();
1500 cont_table = continent_hash_new();
1502 unit_list_iterate(punits, punit) {
1503 if (seltype == SELTYPE_SAME) {
1504 unit_type_hash_insert(type_table, unit_type_get(punit), NULL);
1507 ptile = unit_tile(punit);
1508 if (selloc == SELLOC_TILE) {
1509 tile_hash_insert(tile_table, ptile, NULL);
1510 } else if (selloc == SELLOC_CONT) {
1511 continent_hash_insert(cont_table, tile_continent(ptile), NULL);
1513 } unit_list_iterate_end;
1515 if (selloc == SELLOC_TILE) {
1516 tile_hash_iterate(tile_table, hash_tile) {
1517 unit_list_iterate(hash_tile->units, punit) {
1518 if (unit_owner(punit) != pplayer) {
1519 continue;
1521 if (seltype == SELTYPE_SAME
1522 && !unit_type_hash_lookup(type_table, unit_type_get(punit), NULL)) {
1523 continue;
1525 unit_focus_add(punit);
1526 } unit_list_iterate_end;
1527 } tile_hash_iterate_end;
1528 } else {
1529 unit_list_iterate(pplayer->units, punit) {
1530 ptile = unit_tile(punit);
1531 if ((seltype == SELTYPE_SAME
1532 && !unit_type_hash_lookup(type_table, unit_type_get(punit), NULL))
1533 || (selloc == SELLOC_CONT
1534 && !continent_hash_lookup(cont_table, tile_continent(ptile),
1535 NULL))) {
1536 continue;
1539 unit_focus_add(punit);
1540 } unit_list_iterate_end;
1543 tile_hash_destroy(tile_table);
1544 unit_type_hash_destroy(type_table);
1545 continent_hash_destroy(cont_table);
1548 /**************************************************************************
1549 Request an actor unit to do a specific action.
1550 - action : The action to be requested.
1551 - actor_id : The unit ID of the actor unit.
1552 - target_id : The ID of the target unit, city or tile.
1553 - value : For ACTION_SPY_TARGETED_STEAL_TECH or
1554 ACTION_SPY_TARGETED_SABOTAGE_CITY, the technology or
1555 building to aim for.
1556 **************************************************************************/
1557 void request_do_action(enum gen_action action, int actor_id,
1558 int target_id, int value)
1560 dsend_packet_unit_do_action(&client.conn,
1561 actor_id, target_id, value, action);
1564 /**************************************************************************
1565 Request data for follow up questions about an action the unit can
1566 perform.
1567 - action : The action more details .
1568 - actor_id : The unit ID of the acting unit.
1569 - target_id : The ID of the target unit or city.
1570 **************************************************************************/
1571 void request_action_details(enum gen_action action, int actor_id,
1572 int target_id)
1574 dsend_packet_unit_action_query(&client.conn,
1575 actor_id, target_id, action);
1578 /**************************************************************************
1579 Player pressed 'b' or otherwise instructed unit to build or add to city.
1580 If the unit can build a city, we popup the appropriate dialog.
1581 Otherwise, we just send a packet to the server.
1582 If this action is not appropriate, the server will respond
1583 with an appropriate message. (This is to avoid duplicating
1584 all the server checks and messages here.)
1585 **************************************************************************/
1586 void request_unit_build_city(struct unit *punit)
1588 if (unit_can_build_city(punit)) {
1589 dsend_packet_city_name_suggestion_req(&client.conn, punit->id);
1590 /* the reply will trigger a dialog to name the new city */
1591 } else {
1592 char name[] = "";
1593 dsend_packet_unit_build_city(&client.conn, punit->id, name);
1597 /**************************************************************************
1598 Order a unit to move to a neighboring tile without performing an action.
1600 Does nothing it the destination tile isn't next to the tile where the
1601 unit currently is located.
1602 **************************************************************************/
1603 void request_unit_non_action_move(struct unit *punit,
1604 struct tile *dest_tile)
1606 struct packet_unit_orders p;
1607 int dir;
1609 dir = get_direction_for_step(unit_tile(punit), dest_tile);
1611 if (dir == -1) {
1612 /* The unit isn't located next to the destination tile. */
1613 return;
1616 memset(&p, 0, sizeof(p));
1618 p.repeat = FALSE;
1619 p.vigilant = FALSE;
1621 p.unit_id = punit->id;
1622 p.src_tile = tile_index(unit_tile(punit));
1623 p.dest_tile = tile_index(dest_tile);
1625 p.length = 1;
1626 p.orders[0] = ORDER_MOVE;
1627 p.dir[0] = dir;
1628 p.activity[0] = ACTIVITY_LAST;
1629 p.target[0] = EXTRA_NONE;
1631 send_packet_unit_orders(&client.conn, &p);
1634 /**************************************************************************
1635 This function is called whenever the player pressed an arrow key.
1637 We do NOT take into account that punit might be a caravan or a diplomat
1638 trying to move into a city, or a diplomat going into a tile with a unit;
1639 the server will catch those cases and send the client a package to pop up
1640 a dialog. (the server code has to be there anyway as goto's are entirely
1641 in the server)
1642 **************************************************************************/
1643 void request_move_unit_direction(struct unit *punit, int dir)
1645 struct packet_unit_orders p;
1646 struct tile *dest_tile;
1648 /* Catches attempts to move off map */
1649 dest_tile = mapstep(unit_tile(punit), dir);
1650 if (!dest_tile) {
1651 return;
1654 if (!can_unit_exist_at_tile(punit, dest_tile)) {
1655 if (request_transport(punit, dest_tile)) {
1656 return;
1660 /* The goto system isn't used to send the order because that would
1661 * prevent direction movement from overriding it.
1662 * Example of a situation when overriding the goto system is useful:
1663 * The goto system creates a longer path to make a move legal. The player
1664 * wishes to order the illegal move so the server will explain why the
1665 * short move is illegal. */
1667 memset(&p, 0, sizeof(p));
1669 p.repeat = FALSE;
1670 p.vigilant = FALSE;
1672 p.unit_id = punit->id;
1673 p.src_tile = tile_index(unit_tile(punit));
1674 p.dest_tile = tile_index(dest_tile);
1676 p.length = 1;
1677 p.orders[0] = ORDER_ACTION_MOVE;
1678 p.dir[0] = dir;
1679 p.activity[0] = ACTIVITY_LAST;
1680 p.target[0] = EXTRA_NONE;
1682 send_packet_unit_orders(&client.conn, &p);
1685 /**************************************************************************
1686 Send request for unit activity changing to server. If activity has
1687 target, use request_new_unit_activity_targeted() instead.
1688 **************************************************************************/
1689 void request_new_unit_activity(struct unit *punit, enum unit_activity act)
1691 request_new_unit_activity_targeted(punit, act, NULL);
1694 /**************************************************************************
1695 Send request for unit activity changing to server. This is for
1696 activities that are targeted to certain special or base type.
1697 **************************************************************************/
1698 void request_new_unit_activity_targeted(struct unit *punit,
1699 enum unit_activity act,
1700 struct extra_type *tgt)
1702 if (!can_client_issue_orders()) {
1703 return;
1706 if (tgt == NULL) {
1707 dsend_packet_unit_change_activity(&client.conn, punit->id, act, EXTRA_NONE);
1708 } else {
1709 dsend_packet_unit_change_activity(&client.conn, punit->id, act, extra_index(tgt));
1713 /**************************************************************************
1714 Send request to disband unit to server.
1715 **************************************************************************/
1716 void request_unit_disband(struct unit *punit)
1718 dsend_packet_unit_disband(&client.conn, punit->id);
1721 /**************************************************************************
1722 Send request to change unit homecity to server.
1723 **************************************************************************/
1724 void request_unit_change_homecity(struct unit *punit)
1726 struct city *pcity=tile_city(unit_tile(punit));
1728 if (pcity) {
1729 dsend_packet_unit_change_homecity(&client.conn, punit->id, pcity->id);
1733 /**************************************************************************
1734 Send request to upgrade unit to server.
1735 **************************************************************************/
1736 void request_unit_upgrade(struct unit *punit)
1738 struct city *pcity=tile_city(unit_tile(punit));
1740 if (pcity) {
1741 dsend_packet_unit_upgrade(&client.conn, punit->id);
1745 /**************************************************************************
1746 Sends unit convert packet.
1747 **************************************************************************/
1748 void request_unit_convert(struct unit *punit)
1750 request_new_unit_activity(punit, ACTIVITY_CONVERT);
1753 /****************************************************************************
1754 Call to request (from the server) that the settler unit is put into
1755 autosettler mode.
1756 ****************************************************************************/
1757 void request_unit_autosettlers(const struct unit *punit)
1759 if (punit && can_unit_do_autosettlers(punit)) {
1760 dsend_packet_unit_autosettlers(&client.conn, punit->id);
1761 } else if (punit) {
1762 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1763 _("Only settler units can be put into auto mode."));
1767 /****************************************************************************
1768 Send a request to the server that the cargo be loaded into the transporter.
1770 If ptransporter is NULL a suitable transporter will be chosen.
1771 ****************************************************************************/
1772 void request_unit_load(struct unit *pcargo, struct unit *ptrans,
1773 struct tile *ptile)
1775 if (!ptrans) {
1776 ptrans = transporter_for_unit(pcargo);
1779 if (ptrans
1780 && can_client_issue_orders()
1781 && could_unit_load(pcargo, ptrans)) {
1782 dsend_packet_unit_load(&client.conn, pcargo->id, ptrans->id,
1783 ptile->index);
1785 /* Sentry the unit. Don't request_unit_sentry since this can give a
1786 * recursive loop. */
1787 /* FIXME: Should not sentry if above loading fails (transport moved away,
1788 * or filled already in server side) */
1789 dsend_packet_unit_change_activity(&client.conn, pcargo->id,
1790 ACTIVITY_SENTRY, EXTRA_NONE);
1794 /****************************************************************************
1795 Send a request to the server that the cargo be unloaded from its current
1796 transporter.
1797 ****************************************************************************/
1798 void request_unit_unload(struct unit *pcargo)
1800 struct unit *ptrans = unit_transport_get(pcargo);
1802 if (can_client_issue_orders()
1803 && ptrans
1804 && can_unit_unload(pcargo, ptrans)
1805 && can_unit_survive_at_tile(pcargo, unit_tile(pcargo))) {
1806 dsend_packet_unit_unload(&client.conn, pcargo->id, ptrans->id);
1808 if (unit_owner(pcargo) == client.conn.playing
1809 && pcargo->activity == ACTIVITY_SENTRY) {
1810 /* Activate the unit. */
1811 dsend_packet_unit_change_activity(&client.conn, pcargo->id,
1812 ACTIVITY_IDLE, EXTRA_NONE);
1817 /**************************************************************************
1818 Send request to do caravan action - establishing traderoute or
1819 helping in wonder building - to server.
1820 **************************************************************************/
1821 void request_unit_caravan_action(struct unit *punit,
1822 enum gen_action action)
1824 struct city *target_city;
1826 if (!((target_city = tile_city(unit_tile(punit))))) {
1827 return;
1830 if (action == ACTION_TRADE_ROUTE) {
1831 request_do_action(ACTION_TRADE_ROUTE, punit->id,
1832 target_city->id, 0);
1833 } else if (action == ACTION_HELP_WONDER) {
1834 request_do_action(ACTION_HELP_WONDER, punit->id,
1835 target_city->id, 0);
1836 } else {
1837 log_error("request_unit_caravan_action() Bad action (%d)", action);
1841 /**************************************************************************
1842 Explode nuclear at a tile without enemy units
1843 **************************************************************************/
1844 void request_unit_nuke(struct unit_list *punits)
1846 if (unit_list_size(punits) == 0) {
1847 return;
1850 unit_list_iterate(punits, punit) {
1851 if (!unit_has_type_flag(punit, UTYF_NUCLEAR)) {
1852 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1853 _("Only nuclear units can do this."));
1854 return;
1856 } unit_list_iterate_end;
1858 if (hover_state != HOVER_NUKE) {
1859 set_hover_state(punits, HOVER_NUKE, ACTIVITY_LAST, NULL, ORDER_LAST);
1860 enter_goto_state(punits);
1861 create_line_at_mouse_pos();
1862 update_unit_info_label(punits);
1863 control_mouse_cursor(NULL);
1864 } else {
1865 fc_assert_ret(goto_is_active());
1866 goto_add_waypoint();
1870 /**************************************************************************
1871 Have the player select what tile to paradrop to. Once selected a
1872 paradrop request will be sent to server.
1873 **************************************************************************/
1874 void request_unit_paradrop(struct unit_list *punits)
1876 bool can = FALSE;
1877 struct tile *offender = NULL;
1879 if (unit_list_size(punits) == 0) {
1880 return;
1882 unit_list_iterate(punits, punit) {
1883 if (can_unit_paradrop(punit)) {
1884 can = TRUE;
1885 break;
1887 if (!offender) { /* Take first offender tile/unit */
1888 offender = unit_tile(punit);
1890 } unit_list_iterate_end;
1891 if (can) {
1892 set_hover_state(punits, HOVER_PARADROP, ACTIVITY_LAST, NULL,
1893 ORDER_LAST);
1894 update_unit_info_label(punits);
1895 } else {
1896 create_event(offender, E_BAD_COMMAND, ftc_client,
1897 _("Only paratrooper units can do this."));
1901 /**************************************************************************
1902 Either start new patrol route planning, or add waypoint to current one.
1903 **************************************************************************/
1904 void request_unit_patrol(void)
1906 struct unit_list *punits = get_units_in_focus();
1908 if (unit_list_size(punits) == 0) {
1909 return;
1912 if (hover_state != HOVER_PATROL) {
1913 set_hover_state(punits, HOVER_PATROL, ACTIVITY_LAST, NULL,
1914 ORDER_LAST);
1915 update_unit_info_label(punits);
1916 enter_goto_state(punits);
1917 create_line_at_mouse_pos();
1918 } else {
1919 fc_assert_ret(goto_is_active());
1920 goto_add_waypoint();
1924 /****************************************************************
1925 Try to sentry unit.
1926 *****************************************************************/
1927 void request_unit_sentry(struct unit *punit)
1929 if(punit->activity!=ACTIVITY_SENTRY &&
1930 can_unit_do_activity(punit, ACTIVITY_SENTRY))
1931 request_new_unit_activity(punit, ACTIVITY_SENTRY);
1934 /****************************************************************
1935 Try to fortify unit.
1936 *****************************************************************/
1937 void request_unit_fortify(struct unit *punit)
1939 if(punit->activity!=ACTIVITY_FORTIFYING &&
1940 can_unit_do_activity(punit, ACTIVITY_FORTIFYING))
1941 request_new_unit_activity(punit, ACTIVITY_FORTIFYING);
1944 /**************************************************************************
1945 Send pillage request to server.
1946 **************************************************************************/
1947 void request_unit_pillage(struct unit *punit)
1949 if (!game.info.pillage_select) {
1950 /* Leave choice up to the server */
1951 request_new_unit_activity_targeted(punit, ACTIVITY_PILLAGE, NULL);
1952 } else {
1953 struct tile *ptile = unit_tile(punit);
1954 bv_extras pspossible;
1955 int count = 0;
1957 BV_CLR_ALL(pspossible);
1958 extra_type_iterate(potential) {
1959 if (can_unit_do_activity_targeted_at(punit, ACTIVITY_PILLAGE,
1960 potential, ptile)) {
1961 BV_SET(pspossible, extra_index(potential));
1962 count++;
1964 } extra_type_iterate_end;
1966 if (count > 1) {
1967 popup_pillage_dialog(punit, pspossible);
1968 } else {
1969 /* Should be only one choice... */
1970 struct extra_type *target = get_preferred_pillage(pspossible);
1972 if (target != NULL) {
1973 request_new_unit_activity_targeted(punit, ACTIVITY_PILLAGE, target);
1979 /**************************************************************************
1980 Toggle display of city outlines on the map
1981 **************************************************************************/
1982 void request_toggle_city_outlines(void)
1984 if (!can_client_change_view()) {
1985 return;
1988 gui_options.draw_city_outlines = !gui_options.draw_city_outlines;
1989 update_map_canvas_visible();
1992 /**************************************************************************
1993 Toggle display of worker output of cities on the map
1994 **************************************************************************/
1995 void request_toggle_city_output(void)
1997 if (!can_client_change_view()) {
1998 return;
2001 gui_options.draw_city_output = !gui_options.draw_city_output;
2002 update_map_canvas_visible();
2005 /**************************************************************************
2006 Toggle display of grid lines on the map
2007 **************************************************************************/
2008 void request_toggle_map_grid(void)
2010 if (!can_client_change_view()) {
2011 return;
2014 gui_options.draw_map_grid ^= 1;
2015 update_map_canvas_visible();
2018 /**************************************************************************
2019 Toggle display of national borders on the map
2020 **************************************************************************/
2021 void request_toggle_map_borders(void)
2023 if (!can_client_change_view()) {
2024 return;
2027 gui_options.draw_borders ^= 1;
2028 update_map_canvas_visible();
2031 /**************************************************************************
2032 Toggle display of native tiles on the map
2033 **************************************************************************/
2034 void request_toggle_map_native(void)
2036 if (!can_client_change_view()) {
2037 return;
2040 gui_options.draw_native ^= 1;
2041 update_map_canvas_visible();
2044 /**************************************************************************
2045 Toggle display of city full bar.
2046 **************************************************************************/
2047 void request_toggle_city_full_bar(void)
2049 if (!can_client_change_view()) {
2050 return;
2053 gui_options.draw_full_citybar ^= 1;
2054 update_map_canvas_visible();
2057 /**************************************************************************
2058 Toggle display of city names
2059 **************************************************************************/
2060 void request_toggle_city_names(void)
2062 if (!can_client_change_view()) {
2063 return;
2066 gui_options.draw_city_names ^= 1;
2067 update_map_canvas_visible();
2070 /**************************************************************************
2071 Toggle display of city growth (turns-to-grow)
2072 **************************************************************************/
2073 void request_toggle_city_growth(void)
2075 if (!can_client_change_view()) {
2076 return;
2079 gui_options.draw_city_growth ^= 1;
2080 update_map_canvas_visible();
2083 /**************************************************************************
2084 Toggle display of city productions
2085 **************************************************************************/
2086 void request_toggle_city_productions(void)
2088 if (!can_client_change_view()) {
2089 return;
2092 gui_options.draw_city_productions ^= 1;
2093 update_map_canvas_visible();
2096 /**************************************************************************
2097 Toggle display of city buycost
2098 **************************************************************************/
2099 void request_toggle_city_buycost(void)
2101 if (!can_client_change_view()) {
2102 return;
2105 gui_options.draw_city_buycost ^= 1;
2106 update_map_canvas_visible();
2109 /**************************************************************************
2110 Toggle display of city trade routes
2111 **************************************************************************/
2112 void request_toggle_city_trade_routes(void)
2114 if (!can_client_change_view()) {
2115 return;
2118 gui_options.draw_city_trade_routes ^= 1;
2119 update_map_canvas_visible();
2122 /**************************************************************************
2123 Toggle display of terrain
2124 **************************************************************************/
2125 void request_toggle_terrain(void)
2127 if (!can_client_change_view()) {
2128 return;
2131 gui_options.draw_terrain ^= 1;
2132 update_map_canvas_visible();
2135 /**************************************************************************
2136 Toggle display of coastline
2137 **************************************************************************/
2138 void request_toggle_coastline(void)
2140 if (!can_client_change_view()) {
2141 return;
2144 gui_options.draw_coastline ^= 1;
2145 update_map_canvas_visible();
2148 /**************************************************************************
2149 Toggle display of roads and rails
2150 **************************************************************************/
2151 void request_toggle_roads_rails(void)
2153 if (!can_client_change_view()) {
2154 return;
2157 gui_options.draw_roads_rails ^= 1;
2158 update_map_canvas_visible();
2161 /**************************************************************************
2162 Toggle display of irrigation
2163 **************************************************************************/
2164 void request_toggle_irrigation(void)
2166 if (!can_client_change_view()) {
2167 return;
2170 gui_options.draw_irrigation ^= 1;
2171 update_map_canvas_visible();
2174 /**************************************************************************
2175 Toggle display of mines
2176 **************************************************************************/
2177 void request_toggle_mines(void)
2179 if (!can_client_change_view()) {
2180 return;
2183 gui_options.draw_mines ^= 1;
2184 update_map_canvas_visible();
2187 /**************************************************************************
2188 Toggle display of bases
2189 **************************************************************************/
2190 void request_toggle_bases(void)
2192 if (!can_client_change_view()) {
2193 return;
2196 gui_options.draw_fortress_airbase ^= 1;
2197 update_map_canvas_visible();
2200 /**************************************************************************
2201 Toggle display of resources
2202 **************************************************************************/
2203 void request_toggle_resources(void)
2205 if (!can_client_change_view()) {
2206 return;
2209 gui_options.draw_specials ^= 1;
2210 update_map_canvas_visible();
2213 /**************************************************************************
2214 Toggle display of huts
2215 **************************************************************************/
2216 void request_toggle_huts(void)
2218 if (!can_client_change_view()) {
2219 return;
2222 gui_options.draw_huts ^= 1;
2223 update_map_canvas_visible();
2226 /**************************************************************************
2227 Toggle display of pollution
2228 **************************************************************************/
2229 void request_toggle_pollution(void)
2231 if (!can_client_change_view()) {
2232 return;
2235 gui_options.draw_pollution ^= 1;
2236 update_map_canvas_visible();
2239 /**************************************************************************
2240 Toggle display of cities
2241 **************************************************************************/
2242 void request_toggle_cities(void)
2244 if (!can_client_change_view()) {
2245 return;
2248 gui_options.draw_cities ^= 1;
2249 update_map_canvas_visible();
2252 /**************************************************************************
2253 Toggle display of units
2254 **************************************************************************/
2255 void request_toggle_units(void)
2257 if (!can_client_change_view()) {
2258 return;
2261 gui_options.draw_units ^= 1;
2262 update_map_canvas_visible();
2265 /**************************************************************************
2266 Toggle display of unit solid background.
2267 **************************************************************************/
2268 void request_toggle_unit_solid_bg(void)
2270 if (!can_client_change_view()) {
2271 return;
2274 gui_options.solid_color_behind_units ^= 1;
2275 update_map_canvas_visible();
2278 /**************************************************************************
2279 Toggle display of unit shields.
2280 **************************************************************************/
2281 void request_toggle_unit_shields(void)
2283 if (!can_client_change_view()) {
2284 return;
2287 gui_options.draw_unit_shields ^= 1;
2288 update_map_canvas_visible();
2291 /**************************************************************************
2292 Toggle display of focus unit
2293 **************************************************************************/
2294 void request_toggle_focus_unit(void)
2296 if (!can_client_change_view()) {
2297 return;
2300 gui_options.draw_focus_unit ^= 1;
2301 update_map_canvas_visible();
2304 /**************************************************************************
2305 Toggle display of fog of war
2306 **************************************************************************/
2307 void request_toggle_fog_of_war(void)
2309 if (!can_client_change_view()) {
2310 return;
2313 gui_options.draw_fog_of_war ^= 1;
2314 update_map_canvas_visible();
2315 refresh_overview_canvas();
2318 /**************************************************************************
2319 Center to focus unit.
2320 **************************************************************************/
2321 void request_center_focus_unit(void)
2323 struct tile *ptile = find_a_focus_unit_tile_to_center_on();
2325 if (ptile) {
2326 center_tile_mapcanvas(ptile);
2330 /**************************************************************************
2331 Set units in list to waiting focus. If they are current focus units,
2332 advance focus.
2333 **************************************************************************/
2334 void request_units_wait(struct unit_list *punits)
2336 unit_list_iterate(punits, punit) {
2337 punit->client.focus_status = FOCUS_WAIT;
2338 } unit_list_iterate_end;
2339 if (punits == get_units_in_focus()) {
2340 unit_focus_advance();
2344 /**************************************************************************
2345 Set focus units to FOCUS_DONE state.
2346 **************************************************************************/
2347 void request_unit_move_done(void)
2349 if (get_num_units_in_focus() > 0) {
2350 enum unit_focus_status new_status = FOCUS_DONE;
2351 unit_list_iterate(get_units_in_focus(), punit) {
2352 /* If any of the focused units are busy, keep all of them
2353 * in focus; another tap of the key will dismiss them */
2354 if (punit->activity != ACTIVITY_IDLE) {
2355 new_status = FOCUS_WAIT;
2357 } unit_list_iterate_end;
2358 unit_list_iterate(get_units_in_focus(), punit) {
2359 clear_unit_orders(punit);
2360 punit->client.focus_status = new_status;
2361 } unit_list_iterate_end;
2362 if (new_status == FOCUS_DONE) {
2363 unit_focus_advance();
2368 /**************************************************************************
2369 Called to have the client move a unit from one location to another,
2370 updating the graphics if necessary. The caller must redraw the target
2371 location after the move.
2372 **************************************************************************/
2373 void do_move_unit(struct unit *punit, struct unit *target_unit)
2375 struct tile *src_tile = unit_tile(punit);
2376 struct tile *dst_tile = unit_tile(target_unit);
2377 bool was_teleported, do_animation;
2378 bool in_focus = unit_is_in_focus(punit);
2380 was_teleported = !is_tiles_adjacent(src_tile, dst_tile);
2381 do_animation = (!was_teleported && gui_options.smooth_move_unit_msec > 0);
2383 if (!was_teleported
2384 && punit->activity != ACTIVITY_SENTRY
2385 && !unit_transported(punit)) {
2386 audio_play_sound(unit_type_get(punit)->sound_move,
2387 unit_type_get(punit)->sound_move_alt);
2390 if (unit_owner(punit) == client.conn.playing
2391 && gui_options.auto_center_on_unit
2392 && !unit_has_orders(punit)
2393 && punit->activity != ACTIVITY_GOTO
2394 && punit->activity != ACTIVITY_SENTRY
2395 && ((gui_options.auto_center_on_automated == TRUE
2396 && punit->ai_controlled == TRUE)
2397 || (punit->ai_controlled == FALSE))
2398 && !tile_visible_and_not_on_border_mapcanvas(dst_tile)) {
2399 center_tile_mapcanvas(dst_tile);
2402 if (hover_state != HOVER_NONE && in_focus) {
2403 /* Cancel current goto/patrol/connect/nuke command. */
2404 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2405 update_unit_info_label(get_units_in_focus());
2408 unit_list_remove(src_tile->units, punit);
2410 if (!unit_transported(punit)) {
2411 /* Mark the unit as moving unit, then find_visible_unit() won't return
2412 * it. It is especially useful to don't draw many times the unit when
2413 * refreshing the canvas. */
2414 punit_moving = punit;
2416 /* We have to refresh the tile before moving. This will draw
2417 * the tile without the unit (because it was unlinked above). */
2418 refresh_unit_mapcanvas(punit, src_tile, TRUE, FALSE);
2420 if (gui_options.auto_center_on_automated == FALSE
2421 && punit->ai_controlled == TRUE) {
2422 /* Dont animate automatic units */
2423 } else if (do_animation) {
2424 int dx, dy;
2426 /* For the duration of the animation the unit exists at neither
2427 * tile. */
2428 map_distance_vector(&dx, &dy, src_tile, dst_tile);
2429 move_unit_map_canvas(punit, src_tile, dx, dy);
2433 unit_tile_set(punit, dst_tile);
2434 unit_list_prepend(dst_tile->units, punit);
2436 if (!unit_transported(punit)) {
2437 /* For find_visible_unit(), see above. */
2438 punit_moving = NULL;
2440 refresh_unit_mapcanvas(punit, dst_tile, TRUE, FALSE);
2443 /* With the "full" city bar we have to update the city bar when units move
2444 * into or out of a city. For foreign cities this is handled separately,
2445 * via the occupied field of the short-city packet. */
2446 if (NULL != tile_city(src_tile)
2447 && can_player_see_units_in_city(client.conn.playing, tile_city(src_tile))) {
2448 update_city_description(tile_city(src_tile));
2450 if (NULL != tile_city(dst_tile)
2451 && can_player_see_units_in_city(client.conn.playing, tile_city(dst_tile))) {
2452 update_city_description(tile_city(dst_tile));
2455 if (in_focus) {
2456 menus_update();
2460 /**************************************************************************
2461 An action selection dialog for the selected units against the specified
2462 tile is wanted.
2463 **************************************************************************/
2464 static void do_unit_act_sel_vs(struct tile *ptile)
2466 unit_list_iterate(get_units_in_focus(), punit) {
2467 if (utype_may_act_at_all(unit_type_get(punit))) {
2468 /* Have the server record that an action decision is wanted for
2469 * this unit against this tile. */
2470 request_do_action(ACTION_COUNT, punit->id, tile_index(ptile),
2471 ACTSIG_QUEUE);
2473 } unit_list_iterate_end;
2476 /**************************************************************************
2477 Handles everything when the user clicked a tile
2478 **************************************************************************/
2479 void do_map_click(struct tile *ptile, enum quickselect_type qtype)
2481 struct city *pcity = tile_city(ptile);
2482 struct unit_list *punits = get_units_in_focus();
2483 bool maybe_goto = FALSE;
2485 if (hover_state != HOVER_NONE) {
2486 switch (hover_state) {
2487 case HOVER_NONE:
2488 break;
2489 case HOVER_GOTO:
2490 do_unit_goto(ptile);
2491 break;
2492 case HOVER_NUKE:
2493 do_unit_nuke(ptile);
2494 break;
2495 case HOVER_PARADROP:
2496 unit_list_iterate(punits, punit) {
2497 do_unit_paradrop_to(punit, ptile);
2498 } unit_list_iterate_end;
2499 break;
2500 case HOVER_CONNECT:
2501 do_unit_connect(ptile, connect_activity, connect_tgt);
2502 break;
2503 case HOVER_PATROL:
2504 do_unit_patrol_to(ptile);
2505 break;
2506 case HOVER_ACT_SEL_TGT:
2507 do_unit_act_sel_vs(ptile);
2508 break;
2511 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2512 update_unit_info_label(get_units_in_focus());
2515 /* Bypass stack or city popup if quickselect is specified. */
2516 else if (qtype != SELECT_POPUP && qtype != SELECT_APPEND) {
2517 struct unit *qunit = quickselect(ptile, qtype);
2518 if (qunit) {
2519 unit_focus_set_and_select(qunit);
2520 maybe_goto = gui_options.keyboardless_goto;
2523 /* Otherwise use popups. */
2524 else if (NULL != pcity
2525 && can_player_see_city_internals(client.conn.playing, pcity)) {
2526 popup_city_dialog(pcity);
2528 else if (unit_list_size(ptile->units) == 0
2529 && NULL == pcity
2530 && get_num_units_in_focus() > 0) {
2531 maybe_goto = gui_options.keyboardless_goto;
2533 else if (unit_list_size(ptile->units) == 1
2534 && !get_transporter_occupancy(unit_list_get(ptile->units, 0))) {
2535 struct unit *punit = unit_list_get(ptile->units, 0);
2537 if (unit_owner(punit) == client.conn.playing) {
2538 if(can_unit_do_activity(punit, ACTIVITY_IDLE)) {
2539 maybe_goto = gui_options.keyboardless_goto;
2540 if (qtype == SELECT_APPEND) {
2541 unit_focus_add(punit);
2542 } else {
2543 unit_focus_set_and_select(punit);
2546 } else if (pcity) {
2547 /* Don't hide the unit in the city. */
2548 unit_select_dialog_popup(ptile);
2551 else if(unit_list_size(ptile->units) > 0) {
2552 /* The stack list is always popped up, even if it includes enemy units.
2553 * If the server doesn't want the player to know about them it shouldn't
2554 * tell him! The previous behavior would only pop up the stack if you
2555 * owned a unit on the tile. This gave cheating clients an advantage,
2556 * and also showed you allied units if (and only if) you had a unit on
2557 * the tile (inconsistent). */
2558 unit_select_dialog_popup(ptile);
2561 /* See mapctrl_common.c */
2562 keyboardless_goto_start_tile = maybe_goto ? ptile : NULL;
2563 keyboardless_goto_button_down = maybe_goto;
2564 keyboardless_goto_active = FALSE;
2567 /**************************************************************************
2568 Quickselecting a unit is normally done with <control> left, right click,
2569 for the current tile. Bypassing the stack popup is quite convenient,
2570 and can be tactically important in furious multiplayer games.
2571 **************************************************************************/
2572 static struct unit *quickselect(struct tile *ptile,
2573 enum quickselect_type qtype)
2575 int listsize = unit_list_size(ptile->units);
2576 struct unit *panytransporter = NULL,
2577 *panymovesea = NULL, *panysea = NULL,
2578 *panymoveland = NULL, *panyland = NULL,
2579 *panymoveunit = NULL, *panyunit = NULL;
2581 fc_assert_ret_val(qtype > SELECT_POPUP, NULL);
2583 if (listsize == 0) {
2584 return NULL;
2585 } else if (listsize == 1) {
2586 struct unit *punit = unit_list_get(ptile->units, 0);
2587 return (unit_owner(punit) == client.conn.playing) ? punit : NULL;
2590 /* Quickselect priorities. Units with moves left
2591 * before exhausted. Focus unit is excluded.
2593 * SEA: Transporter
2594 * Sea unit
2595 * Any unit
2597 * LAND: Military land unit
2598 * Non-combatant
2599 * Sea unit
2600 * Any unit
2603 unit_list_iterate(ptile->units, punit) {
2604 if (unit_owner(punit) != client.conn.playing || unit_is_in_focus(punit)) {
2605 continue;
2607 if (qtype == SELECT_SEA) {
2608 /* Transporter. */
2609 if (get_transporter_capacity(punit)) {
2610 if (punit->moves_left > 0) {
2611 return punit;
2612 } else if (!panytransporter) {
2613 panytransporter = punit;
2616 /* Any sea, pref. moves left. */
2617 else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
2618 if (punit->moves_left > 0) {
2619 if (!panymovesea) {
2620 panymovesea = punit;
2622 } else if (!panysea) {
2623 panysea = punit;
2626 } else if (qtype == SELECT_LAND) {
2627 if (utype_move_type(unit_type_get(punit)) == UMT_LAND) {
2628 if (punit->moves_left > 0) {
2629 if (is_military_unit(punit)) {
2630 return punit;
2631 } else if (!panymoveland) {
2632 panymoveland = punit;
2634 } else if (!panyland) {
2635 panyland = punit;
2638 else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
2639 if (punit->moves_left > 0) {
2640 panymovesea = punit;
2641 } else {
2642 panysea = punit;
2646 if (punit->moves_left > 0 && !panymoveunit) {
2647 panymoveunit = punit;
2649 if (!panyunit) {
2650 panyunit = punit;
2652 } unit_list_iterate_end;
2654 if (qtype == SELECT_SEA) {
2655 if (panytransporter) {
2656 return panytransporter;
2657 } else if (panymovesea) {
2658 return panymovesea;
2659 } else if (panysea) {
2660 return panysea;
2661 } else if (panymoveunit) {
2662 return panymoveunit;
2663 } else if (panyunit) {
2664 return panyunit;
2667 else if (qtype == SELECT_LAND) {
2668 if (panymoveland) {
2669 return panymoveland;
2670 } else if (panyland) {
2671 return panyland;
2672 } else if (panymovesea) {
2673 return panymovesea;
2674 } else if (panysea) {
2675 return panysea;
2676 } else if (panymoveunit) {
2677 return panymoveunit;
2678 } else if (panyunit) {
2679 return panyunit;
2682 return NULL;
2685 /**************************************************************************
2686 Finish the goto mode and let the units stored in goto_map_list move
2687 to a given location.
2688 **************************************************************************/
2689 void do_unit_goto(struct tile *ptile)
2691 if (hover_state != HOVER_GOTO) {
2692 return;
2695 if (is_valid_goto_draw_line(ptile)) {
2696 send_goto_route();
2697 } else {
2698 create_event(ptile, E_BAD_COMMAND, ftc_client,
2699 _("Didn't find a route to the destination!"));
2703 /****************************************************************************
2704 Destroy the client nuke data.
2705 ****************************************************************************/
2706 static void client_nuke_data_destroy(void *p)
2708 struct client_nuke_data *data = p;
2710 free(data->units_id);
2711 free(data);
2714 /****************************************************************************
2715 Explode nuclear at a tile without enemy units.
2716 ****************************************************************************/
2717 static void do_real_unit_nuke(void *p)
2719 struct client_nuke_data *data = p;
2720 struct tile *ptile = index_to_tile(data->tile_idx);
2721 struct unit *punit;
2722 int i;
2724 fc_assert_ret(can_client_issue_orders());
2725 fc_assert_ret(ptile != NULL);
2727 for (i = 0; i < data->units_num; i++) {
2728 /* Ensure we have reached destination. */
2729 punit = player_unit_by_number(client_player(), data->units_id[i]);
2730 if (punit != NULL && unit_tile(punit) == ptile) {
2731 dsend_packet_unit_nuke(&client.conn, punit->id);
2736 /****************************************************************************
2737 Send units to 'ptile' and nuke there!
2738 ****************************************************************************/
2739 void do_unit_nuke(struct tile *ptile)
2741 if (hover_state != HOVER_NUKE) {
2742 return;
2745 if (is_valid_goto_draw_line(ptile)) {
2746 struct client_nuke_data *data = fc_malloc(sizeof(*data));
2747 int last_request_id_used = client.conn.client.last_request_id_used;
2748 int i = 0;
2750 data->units_id = fc_malloc(sizeof(*data->units_id)
2751 * get_num_units_in_focus());
2752 unit_list_iterate(get_units_in_focus(), punit) {
2753 data->units_id[i++] = punit->id;
2754 } unit_list_iterate_end;
2755 data->units_num = i;
2756 data->tile_idx = tile_index(ptile);
2758 send_goto_route();
2760 if (last_request_id_used != client.conn.client.last_request_id_used) {
2761 /* We sent some packets, let's wait the server to process them to know
2762 * where our units hold. */
2763 update_queue_connect_processing_finished_full
2764 (client.conn.client.last_request_id_used,
2765 do_real_unit_nuke, data, client_nuke_data_destroy);
2766 } else {
2767 /* We didn't sent the packets, that mean that the route was nil, or
2768 * an internal error occurred. Process nuke units now. */
2769 do_real_unit_nuke(data);
2770 client_nuke_data_destroy(data);
2772 } else {
2773 create_event(ptile, E_BAD_COMMAND, ftc_client,
2774 _("Didn't find a route to the destination!"));
2778 /**************************************************************************
2779 Paradrop to a location.
2780 **************************************************************************/
2781 void do_unit_paradrop_to(struct unit *punit, struct tile *ptile)
2783 dsend_packet_unit_paradrop_to(&client.conn, punit->id, tile_index(ptile));
2786 /**************************************************************************
2787 Patrol to a location.
2788 **************************************************************************/
2789 void do_unit_patrol_to(struct tile *ptile)
2791 if (is_valid_goto_draw_line(ptile)
2792 && !is_non_allied_unit_tile(ptile, client.conn.playing)) {
2793 send_patrol_route();
2794 } else {
2795 create_event(ptile, E_BAD_COMMAND, ftc_client,
2796 _("Didn't find a route to the destination!"));
2799 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2802 /**************************************************************************
2803 "Connect" to the given location.
2804 **************************************************************************/
2805 void do_unit_connect(struct tile *ptile,
2806 enum unit_activity activity,
2807 struct extra_type *tgt)
2809 if (is_valid_goto_draw_line(ptile)) {
2810 send_connect_route(activity, tgt);
2811 } else {
2812 create_event(ptile, E_BAD_COMMAND, ftc_client,
2813 _("Didn't find a route to the destination!"));
2816 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2819 /**************************************************************************
2820 The 'Escape' key.
2821 **************************************************************************/
2822 void key_cancel_action(void)
2824 cancel_tile_hiliting();
2826 switch (hover_state) {
2827 case HOVER_GOTO:
2828 case HOVER_PATROL:
2829 case HOVER_CONNECT:
2830 case HOVER_NUKE:
2831 if (goto_pop_waypoint()) {
2832 break;
2834 /* else fall through: */
2835 case HOVER_PARADROP:
2836 case HOVER_ACT_SEL_TGT:
2837 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2838 update_unit_info_label(get_units_in_focus());
2840 keyboardless_goto_button_down = FALSE;
2841 keyboardless_goto_active = FALSE;
2842 keyboardless_goto_start_tile = NULL;
2843 break;
2844 case HOVER_NONE:
2845 break;
2849 /**************************************************************************
2850 Center the mapview on the player's capital, or print a failure message.
2851 **************************************************************************/
2852 void key_center_capital(void)
2854 struct city *capital = player_capital(client_player());
2856 if (capital) {
2857 /* Center on the tile, and pop up the crosshair overlay. */
2858 center_tile_mapcanvas(capital->tile);
2859 put_cross_overlay_tile(capital->tile);
2860 } else {
2861 create_event(NULL, E_BAD_COMMAND, ftc_client,
2862 _("Oh my! You seem to have no capital!"));
2866 /**************************************************************************
2867 Handle user 'end turn' input.
2868 **************************************************************************/
2869 void key_end_turn(void)
2871 send_turn_done();
2874 /**************************************************************************
2875 Recall the previous focus unit(s). See store_previous_focus().
2876 **************************************************************************/
2877 void key_recall_previous_focus_unit(void)
2879 int i = 0;
2881 /* Could use unit_list_copy here instead. Just having safe genlists
2882 * wouldn't be sufficient since we don't want to skip units already
2883 * removed from focus... */
2884 unit_list_iterate_safe(previous_focus, punit) {
2885 if (i == 0) {
2886 unit_focus_set(punit);
2887 } else {
2888 unit_focus_add(punit);
2890 i++;
2891 } unit_list_iterate_safe_end;
2894 /**************************************************************************
2895 Move the focus unit in the given direction. Here directions are
2896 defined according to the GUI, so that north is "up" in the interface.
2897 **************************************************************************/
2898 void key_unit_move(enum direction8 gui_dir)
2900 unit_list_iterate(get_units_in_focus(), punit) {
2901 enum direction8 map_dir = gui_to_map_dir(gui_dir);
2903 request_move_unit_direction(punit, map_dir);
2904 } unit_list_iterate_end;
2907 /**************************************************************************
2908 Handle use 'build city' input.
2909 **************************************************************************/
2910 void key_unit_build_city(void)
2912 unit_list_iterate(get_units_in_focus(), punit) {
2913 request_unit_build_city(punit);
2914 } unit_list_iterate_end;
2917 /**************************************************************************
2918 Handle user 'help build wonder' input
2919 **************************************************************************/
2920 void key_unit_build_wonder(void)
2922 unit_list_iterate(get_units_in_focus(), punit) {
2923 if (unit_can_do_action(punit, ACTION_HELP_WONDER)) {
2924 request_unit_caravan_action(punit, ACTION_HELP_WONDER);
2926 } unit_list_iterate_end;
2929 /**************************************************************************
2930 handle user pressing key for 'Connect' command
2931 **************************************************************************/
2932 void key_unit_connect(enum unit_activity activity,
2933 struct extra_type *tgt)
2935 request_unit_connect(activity, tgt);
2938 /**************************************************************************
2939 Handle user 'Do...' input
2940 **************************************************************************/
2941 void key_unit_action_select(void)
2943 struct tile *ptile;
2945 if (!can_ask_server_for_actions()) {
2946 /* Looks like another action selection dialog is open. */
2947 return;
2950 unit_list_iterate(get_units_in_focus(), punit) {
2951 if (utype_may_act_at_all(unit_type_get(punit))
2952 && (ptile = unit_tile(punit))) {
2953 /* Have the server record that an action decision is wanted for this
2954 * unit. */
2955 request_do_action(ACTION_COUNT, punit->id, tile_index(ptile),
2956 ACTSIG_QUEUE);
2958 } unit_list_iterate_end;
2961 /**************************************************************************
2962 Have the user select what action the unit(s) in focus should perform to
2963 the targets at the tile the user will specify by clicking on it.
2965 Will stop asking for a target tile and have each actor unit act against
2966 its own tile if called twice.
2967 **************************************************************************/
2968 void key_unit_action_select_tgt(void)
2970 struct unit_list *punits = get_units_in_focus();
2972 if (hover_state == HOVER_ACT_SEL_TGT) {
2973 /* The 2nd key press means that the actor should target its own
2974 * tile. */
2975 key_unit_action_select();
2977 /* Target tile selected. Clean up hover state. */
2978 set_hover_state(NULL, HOVER_NONE, ACTIVITY_LAST, NULL, ORDER_LAST);
2979 update_unit_info_label(punits);
2981 return;
2984 set_hover_state(punits, HOVER_ACT_SEL_TGT, ACTIVITY_LAST, NULL,
2985 ORDER_LAST);
2988 /**************************************************************************
2989 Handle user 'unit done' input
2990 **************************************************************************/
2991 void key_unit_done(void)
2993 request_unit_move_done();
2996 /**************************************************************************
2997 Handle user 'unit goto' input
2998 **************************************************************************/
2999 void key_unit_goto(void)
3001 request_unit_goto(ORDER_LAST);
3004 /**************************************************************************
3005 Explode nuclear at a tile without enemy units
3006 **************************************************************************/
3007 void key_unit_nuke(void)
3009 request_unit_nuke(get_units_in_focus());
3012 /**************************************************************************
3013 Handle user 'paradrop' input
3014 **************************************************************************/
3015 void key_unit_paradrop(void)
3017 request_unit_paradrop(get_units_in_focus());
3020 /**************************************************************************
3021 Handle user 'patrol' input
3022 **************************************************************************/
3023 void key_unit_patrol(void)
3025 request_unit_patrol();
3028 /**************************************************************************
3029 Handle user 'establish traderoute' input
3030 **************************************************************************/
3031 void key_unit_trade_route(void)
3033 unit_list_iterate(get_units_in_focus(), punit) {
3034 /* TODO: Is falling back on ACTION_MARKETPLACE if not able to establish
3035 * a trade route trade a good idea or an unplecant surprice? */
3036 if (unit_can_do_action(punit, ACTION_TRADE_ROUTE)) {
3037 request_unit_caravan_action(punit, ACTION_TRADE_ROUTE);
3039 } unit_list_iterate_end;
3042 /**************************************************************************
3043 Handle user 'unload all' input
3044 **************************************************************************/
3045 void key_unit_unload_all(void)
3047 struct unit *pnext_focus = NULL, *plast;
3049 unit_list_iterate(get_units_in_focus(), punit) {
3050 if ((plast = request_unit_unload_all(punit))) {
3051 pnext_focus = plast;
3053 } unit_list_iterate_end;
3055 if (pnext_focus) {
3056 unit_list_iterate(get_units_in_focus(), punit) {
3057 /* Unfocus the ships, and advance the focus to the last unloaded unit.
3058 * If there is no unit unloaded (which shouldn't happen, but could if
3059 * the caller doesn't check if the transporter is loaded), the we
3060 * don't do anything. */
3061 punit->client.focus_status = FOCUS_WAIT;
3062 } unit_list_iterate_end;
3063 unit_focus_set(pnext_focus);
3067 /**************************************************************************
3068 Handle user 'wait' input
3069 **************************************************************************/
3070 void key_unit_wait(void)
3072 request_units_wait(get_units_in_focus());
3075 /**************************************************************************
3076 Handle user 'wakeup others' input
3077 ***************************************************************************/
3078 void key_unit_wakeup_others(void)
3080 unit_list_iterate(get_units_in_focus(), punit) {
3081 request_unit_wakeup(punit);
3082 } unit_list_iterate_end;
3085 /**************************************************************************
3086 Handle user 'build base of class airbase' input
3087 **************************************************************************/
3088 void key_unit_airbase(void)
3090 unit_list_iterate(get_units_in_focus(), punit) {
3091 struct base_type *pbase =
3092 get_base_by_gui_type(BASE_GUI_AIRBASE, punit, unit_tile(punit));
3094 if (pbase) {
3095 struct extra_type *pextra = base_extra_get(pbase);
3097 request_new_unit_activity_targeted(punit, ACTIVITY_BASE, pextra);
3099 } unit_list_iterate_end;
3102 /**************************************************************************
3103 Handle user 'autoexplore' input
3104 **************************************************************************/
3105 void key_unit_auto_explore(void)
3107 unit_list_iterate(get_units_in_focus(), punit) {
3108 if (can_unit_do_activity(punit, ACTIVITY_EXPLORE)) {
3109 request_new_unit_activity(punit, ACTIVITY_EXPLORE);
3111 } unit_list_iterate_end;
3114 /**************************************************************************
3115 Call to request (from the server) that the focus unit is put into
3116 autosettler mode.
3117 **************************************************************************/
3118 void key_unit_auto_settle(void)
3120 unit_list_iterate(get_units_in_focus(), punit) {
3121 if (can_unit_do_autosettlers(punit)) {
3122 request_unit_autosettlers(punit);
3124 } unit_list_iterate_end;
3127 /**************************************************************************
3128 Unit convert key pressed or respective menu entry selected.
3129 **************************************************************************/
3130 void key_unit_convert(void)
3132 unit_list_iterate(get_units_in_focus(), punit) {
3133 request_unit_convert(punit);
3134 } unit_list_iterate_end;
3137 /**************************************************************************
3138 Handle user 'clean fallout' input
3139 **************************************************************************/
3140 void key_unit_fallout(void)
3142 key_unit_clean(ACTIVITY_FALLOUT, ERM_CLEANFALLOUT);
3145 /**************************************************************************
3146 Handle user 'fortify' input
3147 **************************************************************************/
3148 void key_unit_fortify(void)
3150 unit_list_iterate(get_units_in_focus(), punit) {
3151 if (can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
3152 request_new_unit_activity(punit, ACTIVITY_FORTIFYING);
3154 } unit_list_iterate_end;
3157 /**************************************************************************
3158 Handle user 'build base of class fortress' input
3159 **************************************************************************/
3160 void key_unit_fortress(void)
3162 unit_list_iterate(get_units_in_focus(), punit) {
3163 struct base_type *pbase =
3164 get_base_by_gui_type(BASE_GUI_FORTRESS, punit, unit_tile(punit));
3166 if (pbase) {
3167 struct extra_type *pextra = base_extra_get(pbase);
3169 request_new_unit_activity_targeted(punit, ACTIVITY_BASE, pextra);
3171 } unit_list_iterate_end;
3174 /**************************************************************************
3175 Handle user 'change homecity' input
3176 **************************************************************************/
3177 void key_unit_homecity(void)
3179 unit_list_iterate(get_units_in_focus(), punit) {
3180 request_unit_change_homecity(punit);
3181 } unit_list_iterate_end;
3184 /**************************************************************************
3185 Handle user extra building input of given type
3186 **************************************************************************/
3187 static void key_unit_extra(enum unit_activity act, enum extra_cause cause)
3189 unit_list_iterate(get_units_in_focus(), punit) {
3190 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
3191 cause,
3192 unit_owner(punit),
3193 punit);
3195 if (can_unit_do_activity_targeted(punit, act, tgt)) {
3196 request_new_unit_activity_targeted(punit, act, tgt);
3198 } unit_list_iterate_end;
3201 /**************************************************************************
3202 Handle user extra cleaning input of given type
3203 **************************************************************************/
3204 static void key_unit_clean(enum unit_activity act, enum extra_rmcause rmcause)
3206 unit_list_iterate(get_units_in_focus(), punit) {
3207 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
3208 rmcause,
3209 unit_owner(punit),
3210 punit);
3212 if (tgt != NULL
3213 && can_unit_do_activity_targeted(punit, act, tgt)) {
3214 request_new_unit_activity_targeted(punit, act, tgt);
3216 } unit_list_iterate_end;
3219 /**************************************************************************
3220 Handle user 'irrigate' input
3221 **************************************************************************/
3222 void key_unit_irrigate(void)
3224 key_unit_extra(ACTIVITY_IRRIGATE, EC_IRRIGATION);
3227 /**************************************************************************
3228 Handle user 'build mine' input
3229 **************************************************************************/
3230 void key_unit_mine(void)
3232 key_unit_extra(ACTIVITY_MINE, EC_MINE);
3235 /**************************************************************************
3236 Handle user 'pillage' input
3237 **************************************************************************/
3238 void key_unit_pillage(void)
3240 unit_list_iterate(get_units_in_focus(), punit) {
3241 if (can_unit_do_activity(punit, ACTIVITY_PILLAGE)) {
3242 request_unit_pillage(punit);
3244 } unit_list_iterate_end;
3247 /**************************************************************************
3248 Handle user 'clean pollution' input
3249 **************************************************************************/
3250 void key_unit_pollution(void)
3252 key_unit_clean(ACTIVITY_POLLUTION, ERM_CLEANPOLLUTION);
3255 /**************************************************************************
3256 Handle user 'build road or railroad' input
3257 **************************************************************************/
3258 void key_unit_road(void)
3260 unit_list_iterate(get_units_in_focus(), punit) {
3261 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
3262 EC_ROAD,
3263 unit_owner(punit),
3264 punit);
3266 if (tgt != NULL
3267 && can_unit_do_activity_targeted(punit, ACTIVITY_GEN_ROAD, tgt)) {
3268 request_new_unit_activity_targeted(punit, ACTIVITY_GEN_ROAD, tgt);
3270 } unit_list_iterate_end;
3273 /**************************************************************************
3274 Handle user 'sentry' input
3275 **************************************************************************/
3276 void key_unit_sentry(void)
3278 unit_list_iterate(get_units_in_focus(), punit) {
3279 if (can_unit_do_activity(punit, ACTIVITY_SENTRY)) {
3280 request_new_unit_activity(punit, ACTIVITY_SENTRY);
3282 } unit_list_iterate_end;
3285 /**************************************************************************
3286 Handle user 'transform unit' input
3287 **************************************************************************/
3288 void key_unit_transform(void)
3290 unit_list_iterate(get_units_in_focus(), punit) {
3291 if (can_unit_do_activity(punit, ACTIVITY_TRANSFORM)) {
3292 request_new_unit_activity(punit, ACTIVITY_TRANSFORM);
3294 } unit_list_iterate_end;
3297 /****************************************************************************
3298 Assign all focus units to this battlegroup.
3299 ****************************************************************************/
3300 void key_unit_assign_battlegroup(int battlegroup, bool append)
3302 if (NULL != client.conn.playing && can_client_issue_orders()
3303 && battlegroups >= 0 && battlegroup < MAX_NUM_BATTLEGROUPS) {
3304 if (!append) {
3305 unit_list_iterate_safe(battlegroups[battlegroup], punit) {
3306 if (!unit_is_in_focus(punit)) {
3307 punit->battlegroup = BATTLEGROUP_NONE;
3308 dsend_packet_unit_battlegroup(&client.conn,
3309 punit->id, BATTLEGROUP_NONE);
3310 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
3311 unit_list_remove(battlegroups[battlegroup], punit);
3313 } unit_list_iterate_safe_end;
3315 unit_list_iterate(get_units_in_focus(), punit) {
3316 if (punit->battlegroup != battlegroup) {
3317 if (punit->battlegroup >= 0
3318 && punit->battlegroup < MAX_NUM_BATTLEGROUPS) {
3319 unit_list_remove(battlegroups[punit->battlegroup], punit);
3321 punit->battlegroup = battlegroup;
3322 dsend_packet_unit_battlegroup(&client.conn,
3323 punit->id, battlegroup);
3324 unit_list_append(battlegroups[battlegroup], punit);
3325 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
3327 } unit_list_iterate_end;
3328 unit_list_iterate(battlegroups[battlegroup], punit) {
3329 unit_focus_add(punit);
3330 } unit_list_iterate_end;
3334 /****************************************************************************
3335 Bring this battlegroup into focus.
3336 ****************************************************************************/
3337 void key_unit_select_battlegroup(int battlegroup, bool append)
3339 if (NULL != client.conn.playing && can_client_change_view()
3340 && battlegroups >= 0 && battlegroup < MAX_NUM_BATTLEGROUPS) {
3341 int i = 0;
3343 if (unit_list_size(battlegroups[battlegroup]) == 0 && !append) {
3344 unit_focus_set(NULL);
3345 return;
3348 /* FIXME: this is very inefficient and can be improved. */
3349 unit_list_iterate(battlegroups[battlegroup], punit) {
3350 if (i == 0 && !append) {
3351 unit_focus_set(punit);
3352 } else {
3353 unit_focus_add(punit);
3355 i++;
3356 } unit_list_iterate_end;
3360 /**************************************************************************
3361 Toggle drawing of city outlines.
3362 **************************************************************************/
3363 void key_city_outlines_toggle(void)
3365 request_toggle_city_outlines();
3368 /**************************************************************************
3369 Toggle drawing of city output produced by workers of the city.
3370 **************************************************************************/
3371 void key_city_output_toggle(void)
3373 request_toggle_city_output();
3376 /**************************************************************************
3377 Handle user 'toggle map grid' input
3378 **************************************************************************/
3379 void key_map_grid_toggle(void)
3381 request_toggle_map_grid();
3384 /**************************************************************************
3385 Toggle map borders on the mapview on/off based on a keypress.
3386 **************************************************************************/
3387 void key_map_borders_toggle(void)
3389 request_toggle_map_borders();
3392 /**************************************************************************
3393 Toggle native tiles on the mapview on/off based on a keypress.
3394 **************************************************************************/
3395 void key_map_native_toggle(void)
3397 request_toggle_map_native();
3400 /**************************************************************************
3401 Toggle the "Draw the city bar" option.
3402 **************************************************************************/
3403 void key_city_full_bar_toggle(void)
3405 request_toggle_city_full_bar();
3408 /**************************************************************************
3409 Handle user 'toggle city names display' input
3410 **************************************************************************/
3411 void key_city_names_toggle(void)
3413 request_toggle_city_names();
3416 /**************************************************************************
3417 Toggles the "show city growth turns" option by passing off the
3418 request to another function...
3419 **************************************************************************/
3420 void key_city_growth_toggle(void)
3422 request_toggle_city_growth();
3425 /**************************************************************************
3426 Toggles the showing of the buy cost of the current production in the
3427 city descriptions.
3428 **************************************************************************/
3429 void key_city_buycost_toggle(void)
3431 request_toggle_city_buycost();
3434 /**************************************************************************
3435 Handle user 'toggle city production display' input
3436 **************************************************************************/
3437 void key_city_productions_toggle(void)
3439 request_toggle_city_productions();
3442 /**************************************************************************
3443 Handle client request to toggle drawing of trade route information
3444 by the city name for cities visible on the main map view.
3445 **************************************************************************/
3446 void key_city_trade_routes_toggle(void)
3448 request_toggle_city_trade_routes();
3451 /**************************************************************************
3452 Handle user 'toggle terrain display' input
3453 **************************************************************************/
3454 void key_terrain_toggle(void)
3456 request_toggle_terrain();
3459 /**************************************************************************
3460 Handle user 'toggle coastline display' input
3461 **************************************************************************/
3462 void key_coastline_toggle(void)
3464 request_toggle_coastline();
3467 /**************************************************************************
3468 Handle user 'toggle road/railroad display' input
3469 **************************************************************************/
3470 void key_roads_rails_toggle(void)
3472 request_toggle_roads_rails();
3475 /**************************************************************************
3476 Handle user 'toggle irrigation display' input
3477 **************************************************************************/
3478 void key_irrigation_toggle(void)
3480 request_toggle_irrigation();
3483 /**************************************************************************
3484 Handle user 'toggle mine display' input
3485 **************************************************************************/
3486 void key_mines_toggle(void)
3488 request_toggle_mines();
3491 /**************************************************************************
3492 Handle user 'toggle bases display' input
3493 **************************************************************************/
3494 void key_bases_toggle(void)
3496 request_toggle_bases();
3499 /**************************************************************************
3500 Handle user 'toggle resources display' input
3501 **************************************************************************/
3502 void key_resources_toggle(void)
3504 request_toggle_resources();
3507 /**************************************************************************
3508 Handle user 'toggle huts display' input
3509 **************************************************************************/
3510 void key_huts_toggle(void)
3512 request_toggle_huts();
3515 /**************************************************************************
3516 Handle user 'toggle pollution display' input
3517 **************************************************************************/
3518 void key_pollution_toggle(void)
3520 request_toggle_pollution();
3523 /**************************************************************************
3524 Handle user 'toggle cities display' input
3525 **************************************************************************/
3526 void key_cities_toggle(void)
3528 request_toggle_cities();
3531 /**************************************************************************
3532 Handle user 'toggle units display' input
3533 **************************************************************************/
3534 void key_units_toggle(void)
3536 request_toggle_units();
3539 /**************************************************************************
3540 Toggle the "Solid unit background color" option.
3541 **************************************************************************/
3542 void key_unit_solid_bg_toggle(void)
3544 request_toggle_unit_solid_bg();
3547 /**************************************************************************
3548 Toggle the "Draw shield graphics for units" option.
3549 **************************************************************************/
3550 void key_unit_shields_toggle(void)
3552 request_toggle_unit_shields();
3555 /**************************************************************************
3556 Handle user 'toggle key units display' input
3557 **************************************************************************/
3558 void key_focus_unit_toggle(void)
3560 request_toggle_focus_unit();
3563 /**************************************************************************
3564 Handle user 'toggle fog of war display' input
3565 **************************************************************************/
3566 void key_fog_of_war_toggle(void)
3568 request_toggle_fog_of_war();
3571 /**************************************************************************
3572 Toggle editor mode in the server.
3573 **************************************************************************/
3574 void key_editor_toggle(void)
3576 dsend_packet_edit_mode(&client.conn, !game.info.is_edit_mode);
3579 /**************************************************************************
3580 Recalculate borders.
3581 **************************************************************************/
3582 void key_editor_recalculate_borders(void)
3584 send_packet_edit_recalculate_borders(&client.conn);
3587 /**************************************************************************
3588 Send a request to the server to toggle fog-of-war for the current
3589 player (only applies in edit mode).
3590 **************************************************************************/
3591 void key_editor_toggle_fogofwar(void)
3593 if (client_has_player()) {
3594 dsend_packet_edit_toggle_fogofwar(&client.conn, client_player_number());
3598 /**************************************************************************
3599 All units ready to build city to the tile should now proceed.
3600 **************************************************************************/
3601 void finish_city(struct tile *ptile, const char *name)
3603 unit_list_iterate(ptile->units, punit) {
3604 if (punit->client.asking_city_name) {
3605 /* Unit will disappear only in case city building still success.
3606 * Cancel city building status just in case something has changed
3607 * to prevent city building in the meanwhile and unit will remain
3608 * alive. */
3609 punit->client.asking_city_name = FALSE;
3610 dsend_packet_unit_build_city(&client.conn, punit->id, name);
3612 } unit_list_iterate_end;
3615 /**************************************************************************
3616 Do not build city after all. Cancel city building mark from all units
3617 prepared for it.
3618 **************************************************************************/
3619 void cancel_city(struct tile *ptile)
3621 unit_list_iterate(ptile->units, punit) {
3622 punit->client.asking_city_name = FALSE;
3623 } unit_list_iterate_end;