Stop sharing requirement_unit_state_ereq().
[freeciv.git] / client / control.c
blob2a5b2e3a202075a7fe3b134a812e7fbb5e776657
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 "astring.h"
20 #include "bitvector.h"
21 #include "fcintl.h"
22 #include "log.h"
23 #include "mem.h"
24 #include "timing.h"
26 /* common */
27 #include "combat.h"
28 #include "game.h"
29 #include "map.h"
30 #include "movement.h"
31 #include "unitlist.h"
33 /* common/aicore */
34 #include "path_finding.h"
36 /* client/include */
37 #include "chatline_g.h"
38 #include "citydlg_g.h"
39 #include "dialogs_g.h"
40 #include "gui_main_g.h"
41 #include "mapctrl_g.h"
42 #include "mapview_g.h"
43 #include "menu_g.h"
45 /* client */
46 #include "audio.h"
47 #include "client_main.h"
48 #include "climap.h"
49 #include "climisc.h"
50 #include "editor.h"
51 #include "goto.h"
52 #include "options.h"
53 #include "overview_common.h"
54 #include "tilespec.h"
55 #include "update_queue.h"
57 #include "control.h"
60 struct client_disband_unit_data {
61 int unit_id;
62 int alt;
65 /* Ways to disband a unit. Sorted by preference. Starts with the worst. */
66 /* TODO: Should other actions that consumes the unit be considered?
67 * Join City may be an appealing alternative. Perhaps it should be a
68 * user configurable client option? */
69 static int disband_unit_alternatives[3] = {
70 ACTION_DISBAND_UNIT,
71 ACTION_RECYCLE_UNIT,
72 ACTION_HELP_WONDER,
75 /* gui-dep code may adjust depending on tile size etc: */
76 int num_units_below = MAX_NUM_UNITS_BELOW;
78 /* current_focus points to the current unit(s) in focus */
79 static struct unit_list *current_focus = NULL;
81 /* The previously focused unit(s). Focus can generally be recalled
82 * with keypad 5 (or the equivalent). */
83 static struct unit_list *previous_focus = NULL;
85 /* The priority unit(s) for unit_focus_advance(). */
86 static struct unit_list *urgent_focus_queue = NULL;
88 /* These should be set via set_hover_state() */
89 enum cursor_hover_state hover_state = HOVER_NONE;
90 enum unit_activity connect_activity;
91 struct extra_type *connect_tgt;
93 int goto_last_action;
94 int goto_last_tgt;
95 enum unit_orders goto_last_order; /* Last order for goto */
97 static struct tile *hover_tile = NULL;
98 static struct unit_list *battlegroups[MAX_NUM_BATTLEGROUPS];
100 /* Current moving unit. */
101 static struct unit *punit_moving = NULL;
103 /* units involved in current combat */
104 static struct unit *punit_attacking = NULL;
105 static struct unit *punit_defending = NULL;
107 /* The ID of the unit that currently is in the action selection process.
109 * The action selection process begins when the client asks the server what
110 * actions a unit can take. It ends when the last follow up question is
111 * answered.
113 * No common client code using client supports more than one action
114 * selection process at once. The interface between the common client code
115 * and the clients would have to change before that could happen. (See
116 * action_selection_actor_unit() etc)
118 static int action_selection_in_progress_for = IDENTITY_NUMBER_ZERO;
121 * This variable is TRUE iff a NON-AI controlled unit was focused this
122 * turn.
124 bool non_ai_unit_focus;
126 static void key_unit_clean(enum unit_activity act, enum extra_rmcause rmcause);
128 /*************************************************************************/
130 static struct unit *quickselect(struct tile *ptile,
131 enum quickselect_type qtype);
133 /**************************************************************************
134 Called only by client_game_init() in client/client_main.c
135 **************************************************************************/
136 void control_init(void)
138 int i;
140 current_focus = unit_list_new();
141 previous_focus = unit_list_new();
142 urgent_focus_queue = unit_list_new();
144 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
145 battlegroups[i] = unit_list_new();
147 hover_tile = NULL;
150 /**************************************************************************
151 Called only by client_game_free() in client/client_main.c
152 **************************************************************************/
153 void control_free(void)
155 int i;
157 unit_list_destroy(current_focus);
158 current_focus = NULL;
159 unit_list_destroy(previous_focus);
160 previous_focus = NULL;
161 unit_list_destroy(urgent_focus_queue);
162 urgent_focus_queue = NULL;
164 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
165 unit_list_destroy(battlegroups[i]);
166 battlegroups[i] = NULL;
169 set_hover_state(NULL, HOVER_NONE,
170 ACTIVITY_LAST, NULL,
171 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
172 free_client_goto();
175 /**************************************************************************
176 Returns list of units currently in focus.
177 **************************************************************************/
178 struct unit_list *get_units_in_focus(void)
180 return current_focus;
183 /****************************************************************************
184 Return the number of units currently in focus (0 or more).
185 ****************************************************************************/
186 int get_num_units_in_focus(void)
188 return (NULL != current_focus ? unit_list_size(current_focus) : 0);
191 /**************************************************************************
192 Store the focus unit(s). This is used so that we can return to the
193 previously focused unit with an appropriate keypress.
194 **************************************************************************/
195 static void store_previous_focus(void)
197 if (get_num_units_in_focus() > 0) {
198 unit_list_clear(previous_focus);
199 unit_list_iterate(get_units_in_focus(), punit) {
200 unit_list_append(previous_focus, punit);
201 } unit_list_iterate_end;
205 /****************************************************************************
206 Store a priority focus unit.
207 ****************************************************************************/
208 void unit_focus_urgent(struct unit *punit)
210 unit_list_append(urgent_focus_queue, punit);
213 /**************************************************************************
214 Do various updates required when the set of units in focus changes.
215 **************************************************************************/
216 static void focus_units_changed(void)
218 update_unit_info_label(get_units_in_focus());
219 menus_update();
220 /* Notify the GUI */
221 real_focus_units_changed();
224 /**************************************************************************
225 Called when a unit is killed; this removes it from the control lists.
226 **************************************************************************/
227 void control_unit_killed(struct unit *punit)
229 int i;
231 goto_unit_killed(punit);
233 unit_list_remove(get_units_in_focus(), punit);
234 if (get_num_units_in_focus() < 1) {
235 set_hover_state(NULL, HOVER_NONE,
236 ACTIVITY_LAST, NULL,
237 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
240 unit_list_remove(previous_focus, punit);
241 unit_list_remove(urgent_focus_queue, punit);
243 for (i = 0; i < MAX_NUM_BATTLEGROUPS; i++) {
244 unit_list_remove(battlegroups[i], punit);
247 focus_units_changed();
250 /**************************************************************************
251 Change the battlegroup for this unit.
252 **************************************************************************/
253 void unit_change_battlegroup(struct unit *punit, int battlegroup)
255 if (battlegroup < 0 || battlegroup >= MAX_NUM_BATTLEGROUPS) {
256 battlegroup = BATTLEGROUP_NONE;
259 if (punit->battlegroup != battlegroup) {
260 if (battlegroup != BATTLEGROUP_NONE) {
261 unit_list_append(battlegroups[battlegroup], punit);
263 if (punit->battlegroup != BATTLEGROUP_NONE) {
264 unit_list_remove(battlegroups[punit->battlegroup], punit);
266 punit->battlegroup = battlegroup;
270 /**************************************************************************
271 Call this on new units to enter them in the battlegroup lists.
272 **************************************************************************/
273 void unit_register_battlegroup(struct unit *punit)
275 if (punit->battlegroup < 0 || punit->battlegroup >= MAX_NUM_BATTLEGROUPS) {
276 punit->battlegroup = BATTLEGROUP_NONE;
277 } else {
278 unit_list_append(battlegroups[punit->battlegroup], punit);
282 /**************************************************************************
283 Enter the given hover state.
285 activity => The connect activity (ACTIVITY_IRRIGATE, etc.)
286 order => The last order (ORDER_PERFORM_ACTION, ORDER_LAST, etc.)
287 **************************************************************************/
288 void set_hover_state(struct unit_list *punits, enum cursor_hover_state state,
289 enum unit_activity activity,
290 struct extra_type *tgt,
291 int last_tgt,
292 int action,
293 enum unit_orders order)
295 fc_assert_ret((punits && unit_list_size(punits) > 0)
296 || state == HOVER_NONE);
297 fc_assert_ret(state == HOVER_CONNECT || activity == ACTIVITY_LAST);
298 fc_assert_ret(state == HOVER_GOTO || order == ORDER_LAST);
299 fc_assert_ret(state == HOVER_GOTO || action == ACTION_NONE);
300 exit_goto_state();
301 hover_state = state;
302 connect_activity = activity;
303 if (tgt) {
304 connect_tgt = tgt;
305 } else {
306 connect_tgt = NULL;
308 goto_last_order = order;
309 goto_last_action = action;
310 goto_last_tgt = last_tgt;
313 /**************************************************************************
314 Returns TRUE iff the client should ask the server about what actions a
315 unit can perform.
316 **************************************************************************/
317 bool should_ask_server_for_actions(const struct unit *punit)
319 return (punit->action_decision_want == ACT_DEC_ACTIVE
320 /* The player is interested in getting a pop up for a mere
321 * arrival. */
322 || (punit->action_decision_want == ACT_DEC_PASSIVE
323 && gui_options.popup_actor_arrival));
326 /**************************************************************************
327 Returns TRUE iff it is OK to ask the server about what actions a unit
328 can perform.
329 **************************************************************************/
330 static bool can_ask_server_for_actions(void)
332 /* OK as long as no other unit already asked and aren't done yet. */
333 return (action_selection_in_progress_for == IDENTITY_NUMBER_ZERO
334 && action_selection_actor_unit() == IDENTITY_NUMBER_ZERO);
337 /**************************************************************************
338 Ask the server about what actions punit may be able to perform against
339 it's stored target tile.
341 The server's reply will pop up the action selection dialog unless no
342 alternatives exists.
343 **************************************************************************/
344 static void ask_server_for_actions(struct unit *punit)
346 fc_assert_ret(punit);
347 fc_assert_ret(punit->action_decision_tile);
349 /* Only one action selection dialog at a time is supported. */
350 fc_assert_msg(action_selection_in_progress_for == IDENTITY_NUMBER_ZERO,
351 "Unit %d started action selection before unit %d was done",
352 action_selection_in_progress_for, punit->id);
353 action_selection_in_progress_for = punit->id;
355 dsend_packet_unit_get_actions(&client.conn,
356 punit->id,
357 IDENTITY_NUMBER_ZERO,
358 tile_index(punit->action_decision_tile),
359 TRUE);
362 /****************************************************************************
363 Return TRUE iff this unit is in focus.
364 ****************************************************************************/
365 bool unit_is_in_focus(const struct unit *punit)
367 return unit_list_search(get_units_in_focus(), punit) != NULL;
370 /****************************************************************************
371 Return TRUE iff a unit on this tile is in focus.
372 ****************************************************************************/
373 struct unit *get_focus_unit_on_tile(const struct tile *ptile)
375 unit_list_iterate(get_units_in_focus(), punit) {
376 if (unit_tile(punit) == ptile) {
377 return punit;
379 } unit_list_iterate_end;
381 return NULL;
384 /****************************************************************************
385 Return head of focus units list.
386 ****************************************************************************/
387 struct unit *head_of_units_in_focus(void)
389 return unit_list_get(current_focus, 0);
392 /****************************************************************************
393 Finds a single focus unit that we can center on. May return NULL.
394 ****************************************************************************/
395 static struct tile *find_a_focus_unit_tile_to_center_on(void)
397 struct unit *punit;
399 if (NULL != (punit = get_focus_unit_on_tile(get_center_tile_mapcanvas()))) {
400 return unit_tile(punit);
401 } else if (get_num_units_in_focus() > 0) {
402 return unit_tile(head_of_units_in_focus());
403 } else {
404 return NULL;
408 /**************************************************************************
409 Center on the focus unit, if off-screen and auto_center_on_unit is true.
410 **************************************************************************/
411 void auto_center_on_focus_unit(void)
413 struct tile *ptile = find_a_focus_unit_tile_to_center_on();
415 if (ptile && gui_options.auto_center_on_unit &&
416 !tile_visible_and_not_on_border_mapcanvas(ptile)) {
417 center_tile_mapcanvas(ptile);
421 /**************************************************************************
422 Add unit to list of units currently in focus.
423 **************************************************************************/
424 static void current_focus_append(struct unit *punit)
426 unit_list_append(current_focus, punit);
428 punit->client.focus_status = FOCUS_AVAIL;
429 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
431 if (should_ask_server_for_actions(punit)
432 && can_ask_server_for_actions()) {
433 ask_server_for_actions(punit);
436 if (gui_options.unit_selection_clears_orders) {
437 clear_unit_orders(punit);
441 /**************************************************************************
442 Remove focus from unit.
443 **************************************************************************/
444 static void current_focus_remove(struct unit *punit)
446 /* Close the action selection dialog if the actor unit lose focus. */
447 if (action_selection_actor_unit() == punit->id) {
448 action_selection_close();
451 unit_list_remove(current_focus, punit);
452 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
455 /**************************************************************************
456 Clear all orders for the given unit.
457 **************************************************************************/
458 void clear_unit_orders(struct unit *punit)
460 if (!punit) {
461 return;
464 if (punit->activity != ACTIVITY_IDLE
465 || punit->ai_controlled) {
466 punit->ai_controlled = FALSE;
467 refresh_unit_city_dialogs(punit);
468 request_new_unit_activity(punit, ACTIVITY_IDLE);
469 } else if (unit_has_orders(punit)) {
470 /* Clear the focus unit's orders. */
471 request_orders_cleared(punit);
475 /**************************************************************************
476 Sets the focus unit directly. The unit given will be given the
477 focus; if NULL the focus will be cleared.
479 This function is called for several reasons. Sometimes a fast-focus
480 happens immediately as a result of a client action. Other times it
481 happens because of a server-sent packet that wakes up a unit.
482 **************************************************************************/
483 void unit_focus_set(struct unit *punit)
485 bool focus_changed = FALSE;
487 if (NULL != punit
488 && NULL != client.conn.playing
489 && unit_owner(punit) != client.conn.playing) {
490 /* Callers should make sure this never happens. */
491 return;
494 /* FIXME: this won't work quite right; for instance activating a
495 * battlegroup twice in a row will store the focus erronously. The only
496 * solution would be a set_units_focus() */
497 if (!(get_num_units_in_focus() == 1
498 && punit == head_of_units_in_focus())) {
499 store_previous_focus();
500 focus_changed = TRUE;
503 /* Close the action selection dialog if the actor unit lose focus. */
504 unit_list_iterate(current_focus, punit_old) {
505 if (action_selection_actor_unit() == punit_old->id) {
506 action_selection_close();
508 } unit_list_iterate_end;
510 /* Redraw the old focus unit (to fix blinking or remove the selection
511 * circle). */
512 unit_list_iterate(current_focus, punit_old) {
513 refresh_unit_mapcanvas(punit_old, unit_tile(punit_old), TRUE, FALSE);
514 } unit_list_iterate_end;
515 unit_list_clear(current_focus);
517 if (!can_client_change_view()) {
518 /* This function can be called to set the focus to NULL when
519 * disconnecting. In this case we don't want any other actions! */
520 fc_assert(punit == NULL);
521 return;
524 if (NULL != punit) {
525 current_focus_append(punit);
526 auto_center_on_focus_unit();
529 if (focus_changed) {
530 set_hover_state(NULL, HOVER_NONE,
531 ACTIVITY_LAST, NULL,
532 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
533 focus_units_changed();
537 /**************************************************************************
538 Adds this unit to the list of units in focus.
539 **************************************************************************/
540 void unit_focus_add(struct unit *punit)
542 if (NULL != punit
543 && NULL != client.conn.playing
544 && unit_owner(punit) != client.conn.playing) {
545 /* Callers should make sure this never happens. */
546 return;
549 if (NULL == punit || !can_client_change_view()) {
550 return;
553 if (unit_is_in_focus(punit)) {
554 return;
557 if (hover_state != HOVER_NONE) {
558 /* Can't continue with current goto if set of focus units
559 * change. Cancel it. */
560 set_hover_state(NULL, HOVER_NONE,
561 ACTIVITY_LAST, NULL,
562 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
565 current_focus_append(punit);
566 focus_units_changed();
569 /**************************************************************************
570 Removes this unit from the list of units in focus.
571 **************************************************************************/
572 void unit_focus_remove(struct unit *punit)
574 if (NULL != punit
575 && NULL != client.conn.playing
576 && unit_owner(punit) != client.conn.playing) {
577 /* Callers should make sure this never happens. */
578 return;
581 if (NULL == punit || !can_client_change_view()) {
582 return;
585 if (!unit_is_in_focus(punit)) {
586 return;
589 if (hover_state != HOVER_NONE) {
590 /* Can't continue with current goto if set of focus units
591 * change. Cancel it. */
592 set_hover_state(NULL, HOVER_NONE,
593 ACTIVITY_LAST, NULL,
594 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
597 current_focus_remove(punit);
598 if (get_num_units_in_focus() > 0) {
599 focus_units_changed();
600 } else {
601 unit_focus_advance();
605 /**************************************************************************
606 The only difference is that here we draw the "cross".
607 **************************************************************************/
608 void unit_focus_set_and_select(struct unit *punit)
610 unit_focus_set(punit);
611 if (punit) {
612 put_cross_overlay_tile(unit_tile(punit));
616 /**************************************************************************
617 Find the nearest available unit for focus, excluding any current unit
618 in focus unless "accept_current" is TRUE. If the current focus unit
619 is the only possible unit, or if there is no possible unit, returns NULL.
620 **************************************************************************/
621 static struct unit *find_best_focus_candidate(bool accept_current)
623 struct tile *ptile = get_center_tile_mapcanvas();
625 if (!get_focus_unit_on_tile(ptile)) {
626 struct unit *pfirst = head_of_units_in_focus();
628 if (pfirst) {
629 ptile = unit_tile(pfirst);
633 iterate_outward(ptile, FC_INFINITY, ptile2) {
634 unit_list_iterate(ptile2->units, punit) {
635 if ((!unit_is_in_focus(punit) || accept_current)
636 && unit_owner(punit) == client.conn.playing
637 && punit->client.focus_status == FOCUS_AVAIL
638 && punit->activity == ACTIVITY_IDLE
639 && !unit_has_orders(punit)
640 && (punit->moves_left > 0 || unit_type_get(punit)->move_rate == 0)
641 && !punit->done_moving
642 && !punit->ai_controlled) {
643 return punit;
645 } unit_list_iterate_end;
646 } iterate_outward_end;
648 return NULL;
651 /**************************************************************************
652 This function may be called from packhand.c, via unit_focus_update(),
653 as a result of packets indicating change in activity for a unit. Also
654 called when user press the "Wait" command.
656 FIXME: Add feature to focus only units of a certain category.
657 **************************************************************************/
658 void unit_focus_advance(void)
660 struct unit *candidate = NULL;
661 const int num_units_in_old_focus = get_num_units_in_focus();
663 if (NULL == client.conn.playing
664 || !is_player_phase(client.conn.playing, game.info.phase)
665 || !can_client_change_view()) {
666 unit_focus_set(NULL);
667 return;
670 set_hover_state(NULL, HOVER_NONE,
671 ACTIVITY_LAST, NULL,
672 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
674 unit_list_iterate(get_units_in_focus(), punit) {
676 * Is the unit which just lost focus a non-AI unit? If yes this
677 * enables the auto end turn.
679 if (!punit->ai_controlled) {
680 non_ai_unit_focus = TRUE;
681 break;
683 } unit_list_iterate_end;
685 if (unit_list_size(urgent_focus_queue) > 0) {
686 /* Try top of the urgent list. */
687 struct tile *focus_tile = (get_num_units_in_focus() > 0
688 ? unit_tile(head_of_units_in_focus())
689 : NULL);
691 unit_list_both_iterate(urgent_focus_queue, plink, punit) {
692 if ((ACTIVITY_IDLE != punit->activity
693 || unit_has_orders(punit))
694 /* This isn't an action decision needed because of an
695 * ORDER_ACTION_MOVE located in the middle of an order. */
696 && !should_ask_server_for_actions(punit)) {
697 /* We have assigned new orders to this unit since, remove it. */
698 unit_list_erase(urgent_focus_queue, plink);
699 } else if (NULL == focus_tile
700 || focus_tile == unit_tile(punit)) {
701 /* Use the first one found */
702 candidate = punit;
703 break;
704 } else if (NULL == candidate) {
705 candidate = punit;
707 } unit_list_both_iterate_end;
709 if (NULL != candidate) {
710 unit_list_remove(urgent_focus_queue, candidate);
712 /* Autocenter on Wakeup, regardless of the local option
713 * "auto_center_on_unit". */
714 if (!tile_visible_and_not_on_border_mapcanvas(unit_tile(candidate))) {
715 center_tile_mapcanvas(unit_tile(candidate));
720 if (NULL == candidate) {
721 candidate = find_best_focus_candidate(FALSE);
723 if (!candidate) {
724 /* Try for "waiting" units. */
725 unit_list_iterate(client.conn.playing->units, punit) {
726 if (punit->client.focus_status == FOCUS_WAIT) {
727 punit->client.focus_status = FOCUS_AVAIL;
729 } unit_list_iterate_end;
730 candidate = find_best_focus_candidate(FALSE);
732 if (!candidate) {
733 /* Accept current focus unit as last resort. */
734 candidate = find_best_focus_candidate(TRUE);
739 unit_focus_set(candidate);
742 * Handle auto-turn-done mode: If a unit was in focus (did move),
743 * but now none are (no more to move) and there was at least one
744 * non-AI unit this turn which was focused, then fake a Turn Done
745 * keypress.
747 if (gui_options.auto_turn_done
748 && num_units_in_old_focus > 0
749 && get_num_units_in_focus() == 0
750 && non_ai_unit_focus) {
751 key_end_turn();
755 /**************************************************************************
756 If there is no unit currently in focus, or if the current unit in
757 focus should not be in focus, then get a new focus unit.
758 We let GOTO-ing units stay in focus, so that if they have moves left
759 at the end of the goto, then they are still in focus.
760 **************************************************************************/
761 void unit_focus_update(void)
763 if (NULL == client.conn.playing || !can_client_change_view()) {
764 return;
767 if (!can_ask_server_for_actions()) {
768 fc_assert(get_num_units_in_focus() > 0);
770 /* An actor unit is asking the player what to do. Don't steal his
771 * focus. */
772 return;
775 /* iterate zero times for no units in focus,
776 * otherwise quit for any of the conditions. */
777 unit_list_iterate(get_units_in_focus(), punit) {
778 if ((punit->activity == ACTIVITY_IDLE
779 || punit->activity == ACTIVITY_GOTO
780 || unit_has_orders(punit))
781 && punit->moves_left > 0
782 && !punit->done_moving
783 && !punit->ai_controlled) {
784 return;
786 } unit_list_iterate_end;
788 unit_focus_advance();
791 /**************************************************************************
792 Return a pointer to a visible unit, if there is one.
793 **************************************************************************/
794 struct unit *find_visible_unit(struct tile *ptile)
796 struct unit *panyowned = NULL, *panyother = NULL, *ptptother = NULL;
798 /* If no units here, return nothing. */
799 if (unit_list_size(ptile->units) == 0) {
800 return NULL;
803 /* If a unit is attacking we should show that on top */
804 if (punit_attacking && same_pos(unit_tile(punit_attacking), ptile)) {
805 unit_list_iterate(ptile->units, punit) {
806 if (punit == punit_attacking) {
807 return punit;
809 } unit_list_iterate_end;
812 /* If a unit is defending we should show that on top */
813 if (punit_defending && same_pos(unit_tile(punit_defending), ptile)) {
814 unit_list_iterate(ptile->units, punit) {
815 if (punit == punit_defending) {
816 return punit;
818 } unit_list_iterate_end;
821 /* If the unit in focus is at this tile, show that on top */
822 unit_list_iterate(get_units_in_focus(), punit) {
823 if (punit != punit_moving && unit_tile(punit) == ptile) {
824 return punit;
826 } unit_list_iterate_end;
828 /* If a city is here, return nothing (unit hidden by city). */
829 if (tile_city(ptile)) {
830 return NULL;
833 /* Iterate through the units to find the best one we prioritize this way:
834 1: owned transporter.
835 2: any owned unit
836 3: any transporter
837 4: any unit
838 (always return first in stack). */
839 unit_list_iterate(ptile->units, punit)
840 if (unit_owner(punit) == client.conn.playing) {
841 if (!unit_transported(punit)) {
842 if (get_transporter_capacity(punit) > 0) {
843 return punit;
844 } else if (!panyowned) {
845 panyowned = punit;
848 } else if (!ptptother && !unit_transported(punit)) {
849 if (get_transporter_capacity(punit) > 0) {
850 ptptother = punit;
851 } else if (!panyother) {
852 panyother = punit;
855 unit_list_iterate_end;
857 return (panyowned ? panyowned : (ptptother ? ptptother : panyother));
860 /**************************************************************************
861 Blink the active unit (if necessary). Return the time until the next
862 blink (in seconds).
863 **************************************************************************/
864 double blink_active_unit(void)
866 static struct timer *blink_timer = NULL;
867 const double blink_time = get_focus_unit_toggle_timeout(tileset);
869 if (get_num_units_in_focus() > 0) {
870 if (!blink_timer || timer_read_seconds(blink_timer) > blink_time) {
871 toggle_focus_unit_state(tileset);
873 /* If we lag, we don't try to catch up. Instead we just start a
874 * new blink_time on every update. */
875 blink_timer = timer_renew(blink_timer, TIMER_USER, TIMER_ACTIVE);
876 timer_start(blink_timer);
878 unit_list_iterate(get_units_in_focus(), punit) {
879 /* We flush to screen directly here. This is most likely faster
880 * since these drawing operations are all small but may be spread
881 * out widely. */
882 refresh_unit_mapcanvas(punit, unit_tile(punit), FALSE, TRUE);
883 } unit_list_iterate_end;
886 return blink_time - timer_read_seconds(blink_timer);
889 return blink_time;
892 /****************************************************************************
893 Blink the turn done button (if necessary). Return the time until the next
894 blink (in seconds).
895 ****************************************************************************/
896 double blink_turn_done_button(void)
898 static struct timer *blink_timer = NULL;
899 const double blink_time = 0.5; /* half-second blink interval */
901 if (NULL != client.conn.playing
902 && client.conn.playing->is_alive
903 && !client.conn.playing->phase_done
904 && is_player_phase(client.conn.playing, game.info.phase)) {
905 if (!blink_timer || timer_read_seconds(blink_timer) > blink_time) {
906 int is_waiting = 0, is_moving = 0;
907 bool blocking_mode;
908 struct option *opt;
910 opt = optset_option_by_name(server_optset, "turnblock");
911 if (opt != NULL) {
912 blocking_mode = option_bool_get(opt);
913 } else {
914 blocking_mode = FALSE;
917 players_iterate_alive(pplayer) {
918 if ((pplayer->is_connected || blocking_mode)
919 && is_player_phase(pplayer, game.info.phase)) {
920 if (pplayer->phase_done) {
921 is_waiting++;
922 } else {
923 is_moving++;
926 } players_iterate_alive_end;
928 if (is_moving == 1 && is_waiting > 0) {
929 update_turn_done_button(FALSE); /* stress the slow player! */
931 blink_timer = timer_renew(blink_timer, TIMER_USER, TIMER_ACTIVE);
932 timer_start(blink_timer);
934 return blink_time - timer_read_seconds(blink_timer);
937 return blink_time;
940 /**************************************************************************
941 Update unit icons (and arrow) in the information display, for specified
942 punit as the active unit and other units on the same square. In practice
943 punit is almost always (or maybe strictly always?) the focus unit.
945 Static vars store some info on current (ie previous) state, to avoid
946 unnecessary redraws; initialise to "flag" values to always redraw first
947 time. In principle we _might_ need more info (eg ai.control, connecting),
948 but in practice this is enough?
950 Used to store unit_ids for below units, to use for callbacks (now done
951 inside gui-dep set_unit_icon()), but even with ids here they would not
952 be enough information to know whether to redraw -- instead redraw every
953 time. (Could store enough info to know, but is it worth it?)
954 **************************************************************************/
955 void update_unit_pix_label(struct unit_list *punitlist)
957 int i;
959 /* Check for any change in the unit's state. This assumes that a unit's
960 * orders cannot be changed directly but must be removed and then reset. */
961 if (punitlist && unit_list_size(punitlist) > 0
962 && C_S_OVER != client_state()) {
963 /* There used to be a complicated and bug-prone check here to see if
964 * the unit had actually changed. This was misguided since the stacked
965 * units (below) are redrawn in any case. Unless we write a general
966 * system for unit updates here we might as well just redraw it every
967 * time. */
968 struct unit *punit = unit_list_get(punitlist, 0);
970 set_unit_icon(-1, punit);
972 i = 0; /* index into unit_below_canvas */
973 unit_list_iterate(unit_tile(punit)->units, aunit) {
974 if (aunit != punit) {
975 if (i < num_units_below) {
976 set_unit_icon(i, aunit);
978 i++;
981 unit_list_iterate_end;
983 if (i > num_units_below) {
984 set_unit_icons_more_arrow(TRUE);
985 } else {
986 set_unit_icons_more_arrow(FALSE);
987 for (; i < num_units_below; i++) {
988 set_unit_icon(i, NULL);
991 } else {
992 for (i = -1; i < num_units_below; i++) {
993 set_unit_icon(i, NULL);
995 set_unit_icons_more_arrow(FALSE);
999 /**************************************************************************
1000 Adjusts way combatants are displayed suitable for combat.
1001 **************************************************************************/
1002 void set_units_in_combat(struct unit *pattacker, struct unit *pdefender)
1004 punit_attacking = pattacker;
1005 punit_defending = pdefender;
1007 if (unit_is_in_focus(punit_attacking)
1008 || unit_is_in_focus(punit_defending)) {
1009 /* If one of the units is the focus unit, make sure hidden-focus is
1010 * disabled. We don't just do this as a check later because then
1011 * with a blinking unit it would just disappear again right after the
1012 * battle. */
1013 focus_unit_in_combat(tileset);
1017 /**************************************************************************
1018 The action selection process is no longer in progres for the specified
1019 unit. It is safe to let another unit enter it.
1020 **************************************************************************/
1021 void action_selection_no_longer_in_progress(const int old_actor_id)
1023 /* IDENTITY_NUMBER_ZERO is accepted for cases where the unit is gone
1024 * without a trace. */
1025 fc_assert_msg(old_actor_id == action_selection_in_progress_for
1026 || old_actor_id == IDENTITY_NUMBER_ZERO,
1027 "Decision taken for %d but selection is for %d.",
1028 old_actor_id, action_selection_in_progress_for);
1030 /* Stop objecting to allowing the next unit to ask. */
1031 action_selection_in_progress_for = IDENTITY_NUMBER_ZERO;
1034 /**************************************************************************
1035 Have the server record that a decision no longer is wanted for the
1036 specified unit.
1037 **************************************************************************/
1038 void action_decision_clear_want(const int old_actor_id)
1040 struct unit *old;
1042 if ((old = game_unit_by_number(old_actor_id))) {
1043 /* Have the server record that a decision no longer is wanted. */
1044 dsend_packet_unit_sscs_set(&client.conn, old_actor_id,
1045 USSDT_UNQUEUE, IDENTITY_NUMBER_ZERO);
1049 /**************************************************************************
1050 Move on to the next unit in focus that needs an action decision.
1051 **************************************************************************/
1052 void action_selection_next_in_focus(const int old_actor_id)
1054 struct unit *old;
1056 old = game_unit_by_number(old_actor_id);
1058 /* Go to the next unit in focus that needs a decision. */
1059 unit_list_iterate(get_units_in_focus(), funit) {
1060 if (old != funit && should_ask_server_for_actions(funit)) {
1061 ask_server_for_actions(funit);
1062 return;
1064 } unit_list_iterate_end;
1067 /**************************************************************************
1068 Request that the player makes a decision for the specified unit.
1069 **************************************************************************/
1070 void action_decision_request(struct unit *actor_unit)
1072 fc_assert_ret(actor_unit);
1073 fc_assert_ret(actor_unit->action_decision_tile);
1075 if (!unit_is_in_focus(actor_unit)) {
1076 /* Getting feed back may be urgent. A unit standing next to an enemy
1077 * could be killed while waiting. */
1078 unit_focus_urgent(actor_unit);
1079 } else if (can_client_issue_orders()
1080 && can_ask_server_for_actions()) {
1081 /* No need to wait. The actor unit is in focus. No other actor unit
1082 * is currently asking about action selection. */
1083 ask_server_for_actions(actor_unit);
1087 /**************************************************************************
1088 Do a goto with an order at the end (or ORDER_LAST).
1089 **************************************************************************/
1090 void request_unit_goto(enum unit_orders last_order,
1091 int action_id, int tgt_id)
1093 struct unit_list *punits = get_units_in_focus();
1095 fc_assert_ret(action_id == ACTION_NONE
1096 || last_order == ORDER_PERFORM_ACTION);
1098 if (unit_list_size(punits) == 0) {
1099 return;
1102 if (last_order == ORDER_PERFORM_ACTION) {
1103 /* An action has been specified. */
1104 fc_assert_ret(action_id_exists(action_id));
1106 /* The order system doesn't support actions that can be done to a
1107 * target that isn't at or next to the actor unit's tile.
1109 * Full explanation in handle_unit_orders(). */
1110 fc_assert_ret(!action_id_distance_inside_max(action_id, 2));
1112 unit_list_iterate(punits, punit) {
1113 if (!unit_can_do_action(punit, action_id)) {
1114 /* This unit can't perform the action specified in the last
1115 * order. */
1117 struct astring astr = ASTRING_INIT;
1119 if (role_units_translations(&astr,
1120 action_id_get_role(action_id),
1121 TRUE)) {
1122 /* ...but other units can perform it. */
1124 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1125 /* TRANS: Only Nuclear or ICBM can do Explode
1126 * Nuclear. */
1127 _("Only %s can do %s."),
1128 astr_str(&astr),
1129 action_id_name_translation(action_id));
1131 astr_free(&astr);
1132 } else {
1133 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1134 /* TRANS: Spy can't do Explode Nuclear. */
1135 _("%s can't do %s."),
1136 unit_name_translation(punit),
1137 action_id_name_translation(action_id));
1140 return;
1142 } unit_list_iterate_end;
1145 if (hover_state != HOVER_GOTO) {
1146 set_hover_state(punits, HOVER_GOTO, ACTIVITY_LAST, NULL,
1147 tgt_id, action_id, last_order);
1148 enter_goto_state(punits);
1149 create_line_at_mouse_pos();
1150 update_unit_info_label(punits);
1151 control_mouse_cursor(NULL);
1152 } else {
1153 fc_assert_ret(goto_is_active());
1154 goto_add_waypoint();
1158 /****************************************************************************
1159 Return TRUE if at least one of the untis can do an attack at the tile.
1160 ****************************************************************************/
1161 static bool can_units_attack_at(struct unit_list *punits,
1162 const struct tile *ptile)
1164 unit_list_iterate(punits, punit) {
1165 if (is_attack_unit(punit)
1166 && can_unit_attack_tile(punit, ptile)) {
1167 return TRUE;
1169 } unit_list_iterate_end;
1171 return FALSE;
1174 /**************************************************************************
1175 Determines which mouse cursor should be used, according to hover_state,
1176 and the information gathered from the tile which is under the mouse
1177 cursor (ptile).
1178 **************************************************************************/
1179 void control_mouse_cursor(struct tile *ptile)
1181 struct unit *punit = NULL;
1182 struct city *pcity = NULL;
1183 struct unit_list *active_units = get_units_in_focus();
1184 enum cursor_type mouse_cursor_type = CURSOR_DEFAULT;
1186 if (!gui_options.enable_cursor_changes) {
1187 return;
1190 if (C_S_RUNNING != client_state()) {
1191 update_mouse_cursor(CURSOR_DEFAULT);
1192 return;
1195 if (is_server_busy()) {
1196 /* Server will not accept any commands. */
1197 update_mouse_cursor(CURSOR_WAIT);
1198 return;
1201 if (!ptile) {
1202 if (hover_tile) {
1203 /* hover_tile is the tile that was previously under the mouse cursor. */
1204 ptile = hover_tile;
1205 } else {
1206 update_mouse_cursor(CURSOR_DEFAULT);
1207 return;
1209 } else {
1210 hover_tile = ptile;
1213 punit = find_visible_unit(ptile);
1214 pcity = ptile ? tile_city(ptile) : NULL;
1216 switch (hover_state) {
1217 case HOVER_NONE:
1218 if (NULL != punit
1219 && unit_owner(punit) == client_player()) {
1220 /* Set mouse cursor to select a unit. */
1221 mouse_cursor_type = CURSOR_SELECT;
1222 } else if (NULL != pcity
1223 && can_player_see_city_internals(client.conn.playing, pcity)) {
1224 /* Set mouse cursor to select a city. */
1225 mouse_cursor_type = CURSOR_SELECT;
1226 } else {
1227 /* Set default mouse cursor, because nothing selectable found. */
1229 break;
1230 case HOVER_GOTO:
1231 /* Determine if the goto is valid, invalid, nuke or will attack. */
1232 if (is_valid_goto_destination(ptile)) {
1233 if (goto_last_action == ACTION_NUKE) {
1234 /* Goto results in nuclear attack. */
1235 mouse_cursor_type = CURSOR_NUKE;
1236 } else if (can_units_attack_at(active_units, ptile)) {
1237 /* Goto results in military attack. */
1238 mouse_cursor_type = CURSOR_ATTACK;
1239 } else if (is_enemy_city_tile(ptile, client.conn.playing)) {
1240 /* Goto results in attack of enemy city. */
1241 mouse_cursor_type = CURSOR_ATTACK;
1242 } else {
1243 mouse_cursor_type = CURSOR_GOTO;
1245 } else {
1246 mouse_cursor_type = CURSOR_INVALID;
1248 break;
1249 case HOVER_PATROL:
1250 if (is_valid_goto_destination(ptile)) {
1251 mouse_cursor_type = CURSOR_PATROL;
1252 } else {
1253 mouse_cursor_type = CURSOR_INVALID;
1255 break;
1256 case HOVER_CONNECT:
1257 if (is_valid_goto_destination(ptile)) {
1258 mouse_cursor_type = CURSOR_GOTO;
1259 } else {
1260 mouse_cursor_type = CURSOR_INVALID;
1262 break;
1263 case HOVER_PARADROP:
1264 /* FIXME: check for invalid tiles. */
1265 mouse_cursor_type = CURSOR_PARADROP;
1266 break;
1267 case HOVER_ACT_SEL_TGT:
1268 /* Select a tile to target / find targets on. */
1269 mouse_cursor_type = CURSOR_SELECT;
1270 break;
1273 update_mouse_cursor(mouse_cursor_type);
1276 /**************************************************************************
1277 Return TRUE if there are any units doing the activity on the tile.
1278 **************************************************************************/
1279 static bool is_activity_on_tile(struct tile *ptile,
1280 enum unit_activity activity)
1282 unit_list_iterate(ptile->units, punit) {
1283 if (punit->activity == activity) {
1284 return TRUE;
1286 } unit_list_iterate_end;
1288 return FALSE;
1291 /**************************************************************************
1292 Fill orders to build recursive roads. This modifies ptile, so virtual
1293 copy of the real tile should be passed.
1294 **************************************************************************/
1295 int check_recursive_road_connect(struct tile *ptile, const struct extra_type *pextra,
1296 const struct unit *punit, const struct player *pplayer, int rec)
1298 int activity_mc = 0;
1299 struct terrain *pterrain = tile_terrain(ptile);
1301 if (rec > MAX_EXTRA_TYPES) {
1302 return -1;
1305 if (!is_extra_caused_by(pextra, EC_ROAD)) {
1306 return -1;
1309 extra_deps_iterate(&(pextra->reqs), pdep) {
1310 if (!tile_has_extra(ptile, pdep)) {
1311 int single_mc;
1313 single_mc = check_recursive_road_connect(ptile, pdep, punit, pplayer, rec + 1);
1315 if (single_mc < 0) {
1316 return -1;
1319 activity_mc += single_mc;
1321 } extra_deps_iterate_end;
1323 /* Can build road after that? */
1324 if (punit != NULL) {
1325 if (!can_build_road(extra_road_get(pextra), punit, ptile)) {
1326 return -1;
1328 } else if (pplayer != NULL) {
1329 if (!player_can_build_road(extra_road_get(pextra), pplayer, ptile)) {
1330 return -1;
1334 tile_add_extra(ptile, pextra);
1336 activity_mc += terrain_extra_build_time(pterrain, ACTIVITY_GEN_ROAD, pextra);
1338 return activity_mc;
1341 /**************************************************************************
1342 Return whether the unit can connect with given activity (or with
1343 any activity if activity arg is set to ACTIVITY_IDLE)
1345 This function is client-specific.
1346 **************************************************************************/
1347 bool can_unit_do_connect(struct unit *punit,
1348 enum unit_activity activity,
1349 struct extra_type *tgt)
1351 struct tile *ptile = unit_tile(punit);
1352 struct terrain *pterrain = tile_terrain(ptile);
1353 struct road_type *proad = NULL;
1355 /* HACK: This code duplicates that in
1356 * can_unit_do_activity_targeted_at(). The general logic here is that
1357 * the connect is allowed if both:
1358 * (1) the unit can do that activity type, in general
1359 * (2) either
1360 * (a) the activity has already been completed at this tile
1361 * (b) it can be done by the unit at this tile. */
1362 switch (activity) {
1363 case ACTIVITY_GEN_ROAD:
1365 struct tile *vtile;
1366 int build_time;
1368 fc_assert(is_extra_caused_by(tgt, EC_ROAD));
1370 proad = extra_road_get(tgt);
1372 if (tile_has_road(ptile, proad)) {
1373 /* This tile has road, can unit build road to other tiles too? */
1374 return are_reqs_active(NULL, NULL, NULL, NULL, NULL,
1375 punit, unit_type_get(punit), NULL, NULL, NULL,
1376 &tgt->reqs, RPT_POSSIBLE);
1379 /* To start connect, unit must be able to build road to this
1380 * particular tile. */
1381 vtile = tile_virtual_new(ptile);
1382 build_time = check_recursive_road_connect(vtile, tgt, punit, NULL, 0);
1383 tile_virtual_destroy(vtile);
1385 return build_time >= 0;
1388 case ACTIVITY_IRRIGATE:
1389 /* Special case for irrigation: only irrigate to make S_IRRIGATION,
1390 * never to transform tiles. */
1391 if (!unit_has_type_flag(punit, UTYF_SETTLERS)) {
1392 return FALSE;
1394 if (tile_has_extra(ptile, tgt)) {
1395 return are_reqs_active(NULL, NULL, NULL, NULL, NULL,
1396 punit, unit_type_get(punit), NULL, NULL, NULL,
1397 &tgt->reqs, RPT_POSSIBLE);
1400 return pterrain == pterrain->irrigation_result
1401 && can_be_irrigated(ptile, punit)
1402 && can_build_extra(tgt, punit, ptile)
1403 && !is_activity_on_tile(ptile,
1404 ACTIVITY_MINE);
1405 default:
1406 break;
1409 return FALSE;
1412 /**************************************************************************
1413 Prompt player for entering destination point for unit connect
1414 (e.g. connecting with roads)
1415 **************************************************************************/
1416 void request_unit_connect(enum unit_activity activity,
1417 struct extra_type *tgt)
1419 struct unit_list *punits = get_units_in_focus();
1421 if (!can_units_do_connect(punits, activity, tgt)) {
1422 return;
1425 if (hover_state != HOVER_CONNECT || connect_activity != activity
1426 || (connect_tgt != tgt
1427 && (activity == ACTIVITY_GEN_ROAD
1428 || activity == ACTIVITY_IRRIGATE))) {
1429 set_hover_state(punits, HOVER_CONNECT,
1430 activity, tgt, EXTRA_NONE, ACTION_NONE, ORDER_LAST);
1431 enter_goto_state(punits);
1432 create_line_at_mouse_pos();
1433 update_unit_info_label(punits);
1434 control_mouse_cursor(NULL);
1435 } else {
1436 fc_assert_ret(goto_is_active());
1437 goto_add_waypoint();
1441 /**************************************************************************
1442 Returns one of the unit of the transporter which can have focus next.
1443 **************************************************************************/
1444 struct unit *request_unit_unload_all(struct unit *punit)
1446 struct tile *ptile = unit_tile(punit);
1447 struct unit *plast = NULL;
1449 if (get_transporter_capacity(punit) == 0) {
1450 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1451 _("Only transporter units can be unloaded."));
1452 return NULL;
1455 unit_list_iterate(ptile->units, pcargo) {
1456 if (unit_transport_get(pcargo) == punit) {
1457 request_unit_unload(pcargo);
1459 if (pcargo->activity == ACTIVITY_SENTRY) {
1460 request_new_unit_activity(pcargo, ACTIVITY_IDLE);
1463 if (unit_owner(pcargo) == unit_owner(punit)) {
1464 plast = pcargo;
1467 } unit_list_iterate_end;
1469 return plast;
1472 /**************************************************************************
1473 Send unit airlift request to server.
1474 **************************************************************************/
1475 void request_unit_airlift(struct unit *punit, struct city *pcity)
1477 request_do_action(ACTION_AIRLIFT, punit->id, pcity->id, 0, "");
1480 /**************************************************************************
1481 Return-and-recover for a particular unit. This sets the unit to GOTO
1482 the nearest city.
1483 **************************************************************************/
1484 void request_unit_return(struct unit *punit)
1486 struct pf_path *path;
1488 if ((path = path_to_nearest_allied_city(punit))) {
1489 int turns = pf_path_last_position(path)->turn;
1490 int max_hp = unit_type_get(punit)->hp;
1492 if (punit->hp + turns *
1493 (get_unit_bonus(punit, EFT_UNIT_RECOVER)
1494 - (max_hp * unit_class_get(punit)->hp_loss_pct / 100))
1495 < max_hp) {
1496 struct unit_order order;
1498 order.order = ORDER_ACTIVITY;
1499 order.dir = DIR8_ORIGIN;
1500 order.activity = ACTIVITY_SENTRY;
1501 order.target = EXTRA_NONE;
1502 order.action = ACTION_NONE;
1503 send_goto_path(punit, path, &order);
1504 } else {
1505 send_goto_path(punit, path, NULL);
1507 pf_path_destroy(path);
1511 /**************************************************************************
1512 Wakes all owned sentried units on tile.
1513 **************************************************************************/
1514 void wakeup_sentried_units(struct tile *ptile)
1516 if (!can_client_issue_orders()) {
1517 return;
1519 unit_list_iterate(ptile->units, punit) {
1520 if (punit->activity == ACTIVITY_SENTRY
1521 && unit_owner(punit) == client.conn.playing) {
1522 request_new_unit_activity(punit, ACTIVITY_IDLE);
1525 unit_list_iterate_end;
1528 /**************************************************************************
1529 (RP:) un-sentry all my own sentried units on punit's tile
1530 **************************************************************************/
1531 void request_unit_wakeup(struct unit *punit)
1533 wakeup_sentried_units(unit_tile(punit));
1536 /****************************************************************************
1537 Defines specific hash tables needed for request_unit_select().
1538 ****************************************************************************/
1539 #define SPECHASH_TAG unit_type
1540 #define SPECHASH_IKEY_TYPE struct unit_type *
1541 #define SPECHASH_IDATA_TYPE void *
1542 #include "spechash.h"
1544 #define SPECHASH_TAG continent
1545 #define SPECHASH_INT_KEY_TYPE
1546 #define SPECHASH_IDATA_TYPE void *
1547 #include "spechash.h"
1549 /****************************************************************************
1550 Select all units based on the given list of units and the selection modes.
1551 ****************************************************************************/
1552 void request_unit_select(struct unit_list *punits,
1553 enum unit_select_type_mode seltype,
1554 enum unit_select_location_mode selloc)
1556 const struct player *pplayer;
1557 const struct tile *ptile;
1558 struct unit *punit_first;
1559 struct tile_hash *tile_table;
1560 struct unit_type_hash *type_table;
1561 struct continent_hash *cont_table;
1563 if (!can_client_change_view() || !punits
1564 || unit_list_size(punits) < 1) {
1565 return;
1568 punit_first = unit_list_get(punits, 0);
1570 if (seltype == SELTYPE_SINGLE) {
1571 unit_focus_set(punit_first);
1572 return;
1575 pplayer = unit_owner(punit_first);
1576 tile_table = tile_hash_new();
1577 type_table = unit_type_hash_new();
1578 cont_table = continent_hash_new();
1580 unit_list_iterate(punits, punit) {
1581 if (seltype == SELTYPE_SAME) {
1582 unit_type_hash_insert(type_table, unit_type_get(punit), NULL);
1585 ptile = unit_tile(punit);
1586 if (selloc == SELLOC_TILE) {
1587 tile_hash_insert(tile_table, ptile, NULL);
1588 } else if (selloc == SELLOC_CONT) {
1589 continent_hash_insert(cont_table, tile_continent(ptile), NULL);
1591 } unit_list_iterate_end;
1593 if (selloc == SELLOC_TILE) {
1594 tile_hash_iterate(tile_table, hash_tile) {
1595 unit_list_iterate(hash_tile->units, punit) {
1596 if (unit_owner(punit) != pplayer) {
1597 continue;
1599 if (seltype == SELTYPE_SAME
1600 && !unit_type_hash_lookup(type_table, unit_type_get(punit), NULL)) {
1601 continue;
1603 unit_focus_add(punit);
1604 } unit_list_iterate_end;
1605 } tile_hash_iterate_end;
1606 } else {
1607 unit_list_iterate(pplayer->units, punit) {
1608 ptile = unit_tile(punit);
1609 if ((seltype == SELTYPE_SAME
1610 && !unit_type_hash_lookup(type_table, unit_type_get(punit), NULL))
1611 || (selloc == SELLOC_CONT
1612 && !continent_hash_lookup(cont_table, tile_continent(ptile),
1613 NULL))) {
1614 continue;
1617 unit_focus_add(punit);
1618 } unit_list_iterate_end;
1621 tile_hash_destroy(tile_table);
1622 unit_type_hash_destroy(type_table);
1623 continent_hash_destroy(cont_table);
1626 /**************************************************************************
1627 Request an actor unit to do a specific action.
1628 - action : The action to be requested.
1629 - actor_id : The unit ID of the actor unit.
1630 - target_id : The ID of the target unit, city or tile.
1631 - value : For ACTION_SPY_TARGETED_STEAL_TECH or
1632 ACTION_SPY_TARGETED_SABOTAGE_CITY, the technology or
1633 building to aim for.
1634 - name : Used by ACTION_FOUND_CITY to specify city name.
1635 **************************************************************************/
1636 void request_do_action(enum gen_action action, int actor_id,
1637 int target_id, int value, const char *name)
1639 dsend_packet_unit_do_action(&client.conn,
1640 actor_id, target_id, value, name,
1641 action);
1644 /**************************************************************************
1645 Request data for follow up questions about an action the unit can
1646 perform.
1647 - action : The action more details .
1648 - actor_id : The unit ID of the acting unit.
1649 - target_id : The ID of the target unit or city.
1650 **************************************************************************/
1651 void request_action_details(enum gen_action action, int actor_id,
1652 int target_id)
1654 dsend_packet_unit_action_query(&client.conn,
1655 actor_id, target_id, action);
1658 /**************************************************************************
1659 Player pressed 'b' or otherwise instructed unit to build or add to city.
1660 If the unit can build a city, we popup the appropriate dialog.
1661 Otherwise, we just send a packet to the server.
1662 If this action is not appropriate, the server will respond
1663 with an appropriate message. (This is to avoid duplicating
1664 all the server checks and messages here.)
1665 **************************************************************************/
1666 void request_unit_build_city(struct unit *punit)
1668 struct city *pcity;
1670 if ((pcity = tile_city(unit_tile(punit)))) {
1671 /* Try to join the city. */
1672 request_do_action(ACTION_JOIN_CITY, punit->id, pcity->id, 0, "");
1673 } else {
1674 /* The reply will trigger a dialog to name the new city. */
1675 dsend_packet_city_name_suggestion_req(&client.conn, punit->id);
1679 /**************************************************************************
1680 Order a unit to move to a neighboring tile without performing an action.
1682 Does nothing it the destination tile isn't next to the tile where the
1683 unit currently is located.
1684 **************************************************************************/
1685 void request_unit_non_action_move(struct unit *punit,
1686 struct tile *dest_tile)
1688 struct packet_unit_orders p;
1689 int dir;
1691 dir = get_direction_for_step(unit_tile(punit), dest_tile);
1693 if (dir == -1) {
1694 /* The unit isn't located next to the destination tile. */
1695 return;
1698 memset(&p, 0, sizeof(p));
1700 p.repeat = FALSE;
1701 p.vigilant = FALSE;
1703 p.unit_id = punit->id;
1704 p.src_tile = tile_index(unit_tile(punit));
1705 p.dest_tile = tile_index(dest_tile);
1707 p.length = 1;
1708 p.orders[0] = ORDER_MOVE;
1709 p.dir[0] = dir;
1710 p.activity[0] = ACTIVITY_LAST;
1711 p.target[0] = EXTRA_NONE;
1712 p.action[0] = ACTION_NONE;
1714 send_packet_unit_orders(&client.conn, &p);
1717 /**************************************************************************
1718 This function is called whenever the player pressed an arrow key.
1720 We do NOT take into account that punit might be a caravan or a diplomat
1721 trying to move into a city, or a diplomat going into a tile with a unit;
1722 the server will catch those cases and send the client a package to pop up
1723 a dialog. (the server code has to be there anyway as goto's are entirely
1724 in the server)
1725 **************************************************************************/
1726 void request_move_unit_direction(struct unit *punit, int dir)
1728 struct packet_unit_orders p;
1729 struct tile *dest_tile;
1731 /* Catches attempts to move off map */
1732 dest_tile = mapstep(unit_tile(punit), dir);
1733 if (!dest_tile) {
1734 return;
1737 if (!can_unit_exist_at_tile(punit, dest_tile)) {
1738 if (request_transport(punit, dest_tile)) {
1739 return;
1743 /* The goto system isn't used to send the order because that would
1744 * prevent direction movement from overriding it.
1745 * Example of a situation when overriding the goto system is useful:
1746 * The goto system creates a longer path to make a move legal. The player
1747 * wishes to order the illegal move so the server will explain why the
1748 * short move is illegal. */
1750 memset(&p, 0, sizeof(p));
1752 p.repeat = FALSE;
1753 p.vigilant = FALSE;
1755 p.unit_id = punit->id;
1756 p.src_tile = tile_index(unit_tile(punit));
1757 p.dest_tile = tile_index(dest_tile);
1759 p.length = 1;
1760 p.orders[0] = ORDER_ACTION_MOVE;
1761 p.dir[0] = dir;
1762 p.activity[0] = ACTIVITY_LAST;
1763 p.target[0] = EXTRA_NONE;
1764 p.action[0] = ACTION_NONE;
1766 send_packet_unit_orders(&client.conn, &p);
1769 /**************************************************************************
1770 Send request for unit activity changing to server. If activity has
1771 target, use request_new_unit_activity_targeted() instead.
1772 **************************************************************************/
1773 void request_new_unit_activity(struct unit *punit, enum unit_activity act)
1775 request_new_unit_activity_targeted(punit, act, NULL);
1778 /**************************************************************************
1779 Send request for unit activity changing to server. This is for
1780 activities that are targeted to certain special or base type.
1781 **************************************************************************/
1782 void request_new_unit_activity_targeted(struct unit *punit,
1783 enum unit_activity act,
1784 struct extra_type *tgt)
1786 if (!can_client_issue_orders()) {
1787 return;
1790 if (tgt == NULL) {
1791 dsend_packet_unit_change_activity(&client.conn, punit->id, act, EXTRA_NONE);
1792 } else {
1793 dsend_packet_unit_change_activity(&client.conn, punit->id, act, extra_index(tgt));
1797 /**************************************************************************
1798 Destroy the client disband unit data.
1799 **************************************************************************/
1800 static void client_disband_unit_data_destroy(void *p)
1802 struct client_disband_unit_data *data = p;
1804 free(data);
1807 /**************************************************************************
1808 Try to disband a unit using actions ordered by preference.
1809 **************************************************************************/
1810 static void do_disband_alternative(void *p)
1812 struct unit *punit;
1813 struct city *pcity;
1814 struct tile *ptile;
1815 int last_request_id_used;
1816 struct client_disband_unit_data *next;
1817 struct client_disband_unit_data *data = p;
1818 const int act = disband_unit_alternatives[data->alt];
1820 fc_assert_ret(can_client_issue_orders());
1822 /* Fetch the unit to get rid of. */
1823 punit = player_unit_by_number(client_player(), data->unit_id);
1825 if (punit == NULL) {
1826 /* Success! It is gone. */
1827 return;
1830 if (data->alt == -1) {
1831 /* All alternatives have been tried. */
1832 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1833 /* TRANS: Unable to get rid of Leader. */
1834 _("Unable to get rid of %s."),
1835 unit_name_translation(punit));
1836 return;
1839 /* Prepare the data for the next try in case this try fails. */
1840 next = fc_malloc(sizeof(struct client_disband_unit_data));
1841 next->unit_id = data->unit_id;
1842 next->alt = data->alt - 1;
1844 /* Lates request ID before trying to send a request. */
1845 last_request_id_used = client.conn.client.last_request_id_used;
1847 /* Send a request to the server unless it is known to be pointless. */
1848 switch (action_id_get_target_kind(act)) {
1849 case ATK_CITY:
1850 if ((pcity = tile_city(unit_tile(punit)))
1851 && action_prob_possible(action_prob_vs_city(punit, act, pcity))) {
1852 request_do_action(act, punit->id, pcity->id, 0, "");
1854 break;
1855 case ATK_UNIT:
1856 if (action_prob_possible(action_prob_vs_unit(punit, act, punit))) {
1857 request_do_action(act, punit->id, punit->id, 0, "");
1859 break;
1860 case ATK_UNITS:
1861 if ((ptile = unit_tile(punit))
1862 && action_prob_possible(action_prob_vs_units(punit, act, ptile))) {
1863 request_do_action(act, punit->id, ptile->index, 0, "");
1865 break;
1866 case ATK_TILE:
1867 if ((ptile = unit_tile(punit))
1868 && action_prob_possible(action_prob_vs_tile(punit, act, ptile))) {
1869 request_do_action(act, punit->id, ptile->index, 0, "");
1871 break;
1872 case ATK_SELF:
1873 if (action_prob_possible(action_prob_self(punit, act))) {
1874 request_do_action(act, punit->id, punit->id, 0, "");
1876 break;
1877 case ATK_COUNT:
1878 fc_assert(action_id_get_target_kind(act) != ATK_COUNT);
1879 break;
1882 if (last_request_id_used != client.conn.client.last_request_id_used) {
1883 /* A request was sent. */
1885 /* Check if it worked. Move on if it didn't. */
1886 update_queue_connect_processing_finished_full
1887 (client.conn.client.last_request_id_used,
1888 do_disband_alternative, next,
1889 client_disband_unit_data_destroy);
1890 } else {
1891 /* No request was sent. */
1893 /* Move on. */
1894 do_disband_alternative(next);
1896 /* Won't be freed by anyone else. */
1897 client_disband_unit_data_destroy(next);
1901 /**************************************************************************
1902 Send request to disband unit to server.
1903 **************************************************************************/
1904 void request_unit_disband(struct unit *punit)
1906 struct client_disband_unit_data *data;
1908 /* Set up disband data. Start at the end of the array. */
1909 data = fc_malloc(sizeof(struct client_disband_unit_data));
1910 data->unit_id = punit->id;
1911 data->alt = 2;
1913 /* Begin. */
1914 do_disband_alternative(data);
1916 /* Won't be freed by anyone else. */
1917 client_disband_unit_data_destroy(data);
1920 /**************************************************************************
1921 Send request to change unit homecity to server.
1922 **************************************************************************/
1923 void request_unit_change_homecity(struct unit *punit)
1925 struct city *pcity=tile_city(unit_tile(punit));
1927 if (pcity) {
1928 request_do_action(ACTION_HOME_CITY, punit->id, pcity->id, 0, "");
1932 /**************************************************************************
1933 Send request to upgrade unit to server.
1934 **************************************************************************/
1935 void request_unit_upgrade(struct unit *punit)
1937 struct city *pcity=tile_city(unit_tile(punit));
1939 if (pcity) {
1940 request_do_action(ACTION_UPGRADE_UNIT, punit->id, pcity->id, 0, "");
1944 /**************************************************************************
1945 Sends unit convert packet.
1946 **************************************************************************/
1947 void request_unit_convert(struct unit *punit)
1949 request_new_unit_activity(punit, ACTIVITY_CONVERT);
1952 /****************************************************************************
1953 Call to request (from the server) that the settler unit is put into
1954 autosettler mode.
1955 ****************************************************************************/
1956 void request_unit_autosettlers(const struct unit *punit)
1958 if (punit && can_unit_do_autosettlers(punit)) {
1959 dsend_packet_unit_autosettlers(&client.conn, punit->id);
1960 } else if (punit) {
1961 create_event(unit_tile(punit), E_BAD_COMMAND, ftc_client,
1962 _("Only settler units can be put into auto mode."));
1966 /****************************************************************************
1967 Send a request to the server that the cargo be loaded into the transporter.
1969 If ptransporter is NULL a suitable transporter will be chosen.
1970 ****************************************************************************/
1971 void request_unit_load(struct unit *pcargo, struct unit *ptrans,
1972 struct tile *ptile)
1974 if (!ptrans) {
1975 ptrans = transporter_for_unit(pcargo);
1978 if (ptrans
1979 && can_client_issue_orders()
1980 && could_unit_load(pcargo, ptrans)) {
1981 dsend_packet_unit_load(&client.conn, pcargo->id, ptrans->id,
1982 ptile->index);
1984 /* Sentry the unit. Don't request_unit_sentry since this can give a
1985 * recursive loop. */
1986 /* FIXME: Should not sentry if above loading fails (transport moved away,
1987 * or filled already in server side) */
1988 dsend_packet_unit_change_activity(&client.conn, pcargo->id,
1989 ACTIVITY_SENTRY, EXTRA_NONE);
1993 /****************************************************************************
1994 Send a request to the server that the cargo be unloaded from its current
1995 transporter.
1996 ****************************************************************************/
1997 void request_unit_unload(struct unit *pcargo)
1999 struct unit *ptrans = unit_transport_get(pcargo);
2001 if (can_client_issue_orders()
2002 && ptrans
2003 && can_unit_unload(pcargo, ptrans)
2004 && can_unit_survive_at_tile(pcargo, unit_tile(pcargo))) {
2005 dsend_packet_unit_unload(&client.conn, pcargo->id, ptrans->id);
2007 if (unit_owner(pcargo) == client.conn.playing
2008 && pcargo->activity == ACTIVITY_SENTRY) {
2009 /* Activate the unit. */
2010 dsend_packet_unit_change_activity(&client.conn, pcargo->id,
2011 ACTIVITY_IDLE, EXTRA_NONE);
2016 /**************************************************************************
2017 Send request to do caravan action - establishing traderoute or
2018 helping in wonder building - to server.
2019 **************************************************************************/
2020 void request_unit_caravan_action(struct unit *punit,
2021 enum gen_action action)
2023 struct city *target_city;
2025 if (!((target_city = tile_city(unit_tile(punit))))) {
2026 return;
2029 if (action == ACTION_TRADE_ROUTE) {
2030 request_do_action(ACTION_TRADE_ROUTE, punit->id,
2031 target_city->id, 0, "");
2032 } else if (action == ACTION_HELP_WONDER) {
2033 request_do_action(ACTION_HELP_WONDER, punit->id,
2034 target_city->id, 0, "");
2035 } else {
2036 log_error("request_unit_caravan_action() Bad action (%d)", action);
2040 /**************************************************************************
2041 Have the player select what tile to paradrop to. Once selected a
2042 paradrop request will be sent to server.
2043 **************************************************************************/
2044 void request_unit_paradrop(struct unit_list *punits)
2046 bool can = FALSE;
2047 struct tile *offender = NULL;
2049 if (unit_list_size(punits) == 0) {
2050 return;
2052 unit_list_iterate(punits, punit) {
2053 if (can_unit_paradrop(punit)) {
2054 can = TRUE;
2055 break;
2057 if (!offender) { /* Take first offender tile/unit */
2058 offender = unit_tile(punit);
2060 } unit_list_iterate_end;
2061 if (can) {
2062 create_event(unit_tile(unit_list_get(punits, 0)), E_BEGINNER_HELP,
2063 ftc_client,
2064 /* TRANS: paradrop target tile. */
2065 _("Click on a tile to paradrop to it."));
2067 set_hover_state(punits, HOVER_PARADROP, ACTIVITY_LAST, NULL,
2068 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2069 update_unit_info_label(punits);
2070 } else {
2071 create_event(offender, E_BAD_COMMAND, ftc_client,
2072 _("Only paratrooper units can do this."));
2076 /**************************************************************************
2077 Either start new patrol route planning, or add waypoint to current one.
2078 **************************************************************************/
2079 void request_unit_patrol(void)
2081 struct unit_list *punits = get_units_in_focus();
2083 if (unit_list_size(punits) == 0) {
2084 return;
2087 if (hover_state != HOVER_PATROL) {
2088 set_hover_state(punits, HOVER_PATROL, ACTIVITY_LAST, NULL,
2089 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2090 update_unit_info_label(punits);
2091 enter_goto_state(punits);
2092 create_line_at_mouse_pos();
2093 } else {
2094 fc_assert_ret(goto_is_active());
2095 goto_add_waypoint();
2099 /****************************************************************
2100 Try to sentry unit.
2101 *****************************************************************/
2102 void request_unit_sentry(struct unit *punit)
2104 if (punit->activity != ACTIVITY_SENTRY
2105 && can_unit_do_activity(punit, ACTIVITY_SENTRY)) {
2106 request_new_unit_activity(punit, ACTIVITY_SENTRY);
2110 /****************************************************************
2111 Try to fortify unit.
2112 *****************************************************************/
2113 void request_unit_fortify(struct unit *punit)
2115 if (punit->activity != ACTIVITY_FORTIFYING
2116 && can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
2117 request_new_unit_activity(punit, ACTIVITY_FORTIFYING);
2121 /**************************************************************************
2122 Send pillage request to server.
2123 **************************************************************************/
2124 void request_unit_pillage(struct unit *punit)
2126 if (!game.info.pillage_select) {
2127 /* Leave choice up to the server */
2128 request_new_unit_activity_targeted(punit, ACTIVITY_PILLAGE, NULL);
2129 } else {
2130 struct tile *ptile = unit_tile(punit);
2131 bv_extras pspossible;
2132 int count = 0;
2134 BV_CLR_ALL(pspossible);
2135 extra_type_iterate(potential) {
2136 if (can_unit_do_activity_targeted_at(punit, ACTIVITY_PILLAGE,
2137 potential, ptile)) {
2138 BV_SET(pspossible, extra_index(potential));
2139 count++;
2141 } extra_type_iterate_end;
2143 if (count > 1) {
2144 popup_pillage_dialog(punit, pspossible);
2145 } else {
2146 /* Should be only one choice... */
2147 struct extra_type *target = get_preferred_pillage(pspossible);
2149 if (target != NULL) {
2150 request_new_unit_activity_targeted(punit, ACTIVITY_PILLAGE, target);
2156 /**************************************************************************
2157 Toggle display of city outlines on the map
2158 **************************************************************************/
2159 void request_toggle_city_outlines(void)
2161 if (!can_client_change_view()) {
2162 return;
2165 gui_options.draw_city_outlines = !gui_options.draw_city_outlines;
2166 update_map_canvas_visible();
2169 /**************************************************************************
2170 Toggle display of worker output of cities on the map
2171 **************************************************************************/
2172 void request_toggle_city_output(void)
2174 if (!can_client_change_view()) {
2175 return;
2178 gui_options.draw_city_output = !gui_options.draw_city_output;
2179 update_map_canvas_visible();
2182 /**************************************************************************
2183 Toggle display of grid lines on the map
2184 **************************************************************************/
2185 void request_toggle_map_grid(void)
2187 if (!can_client_change_view()) {
2188 return;
2191 gui_options.draw_map_grid ^= 1;
2192 update_map_canvas_visible();
2195 /**************************************************************************
2196 Toggle display of national borders on the map
2197 **************************************************************************/
2198 void request_toggle_map_borders(void)
2200 if (!can_client_change_view()) {
2201 return;
2204 gui_options.draw_borders ^= 1;
2205 update_map_canvas_visible();
2208 /**************************************************************************
2209 Toggle display of native tiles on the map
2210 **************************************************************************/
2211 void request_toggle_map_native(void)
2213 if (!can_client_change_view()) {
2214 return;
2217 gui_options.draw_native ^= 1;
2218 update_map_canvas_visible();
2221 /**************************************************************************
2222 Toggle display of city full bar.
2223 **************************************************************************/
2224 void request_toggle_city_full_bar(void)
2226 if (!can_client_change_view()) {
2227 return;
2230 gui_options.draw_full_citybar ^= 1;
2231 update_map_canvas_visible();
2234 /**************************************************************************
2235 Toggle display of city names
2236 **************************************************************************/
2237 void request_toggle_city_names(void)
2239 if (!can_client_change_view()) {
2240 return;
2243 gui_options.draw_city_names ^= 1;
2244 update_map_canvas_visible();
2247 /**************************************************************************
2248 Toggle display of city growth (turns-to-grow)
2249 **************************************************************************/
2250 void request_toggle_city_growth(void)
2252 if (!can_client_change_view()) {
2253 return;
2256 gui_options.draw_city_growth ^= 1;
2257 update_map_canvas_visible();
2260 /**************************************************************************
2261 Toggle display of city productions
2262 **************************************************************************/
2263 void request_toggle_city_productions(void)
2265 if (!can_client_change_view()) {
2266 return;
2269 gui_options.draw_city_productions ^= 1;
2270 update_map_canvas_visible();
2273 /**************************************************************************
2274 Toggle display of city buycost
2275 **************************************************************************/
2276 void request_toggle_city_buycost(void)
2278 if (!can_client_change_view()) {
2279 return;
2282 gui_options.draw_city_buycost ^= 1;
2283 update_map_canvas_visible();
2286 /**************************************************************************
2287 Toggle display of city trade routes
2288 **************************************************************************/
2289 void request_toggle_city_trade_routes(void)
2291 if (!can_client_change_view()) {
2292 return;
2295 gui_options.draw_city_trade_routes ^= 1;
2296 update_map_canvas_visible();
2299 /**************************************************************************
2300 Toggle display of terrain
2301 **************************************************************************/
2302 void request_toggle_terrain(void)
2304 if (!can_client_change_view()) {
2305 return;
2308 gui_options.draw_terrain ^= 1;
2309 update_map_canvas_visible();
2312 /**************************************************************************
2313 Toggle display of coastline
2314 **************************************************************************/
2315 void request_toggle_coastline(void)
2317 if (!can_client_change_view()) {
2318 return;
2321 gui_options.draw_coastline ^= 1;
2322 update_map_canvas_visible();
2325 /**************************************************************************
2326 Toggle display of roads and rails
2327 **************************************************************************/
2328 void request_toggle_roads_rails(void)
2330 if (!can_client_change_view()) {
2331 return;
2334 gui_options.draw_roads_rails ^= 1;
2335 update_map_canvas_visible();
2338 /**************************************************************************
2339 Toggle display of irrigation
2340 **************************************************************************/
2341 void request_toggle_irrigation(void)
2343 if (!can_client_change_view()) {
2344 return;
2347 gui_options.draw_irrigation ^= 1;
2348 update_map_canvas_visible();
2351 /**************************************************************************
2352 Toggle display of mines
2353 **************************************************************************/
2354 void request_toggle_mines(void)
2356 if (!can_client_change_view()) {
2357 return;
2360 gui_options.draw_mines ^= 1;
2361 update_map_canvas_visible();
2364 /**************************************************************************
2365 Toggle display of bases
2366 **************************************************************************/
2367 void request_toggle_bases(void)
2369 if (!can_client_change_view()) {
2370 return;
2373 gui_options.draw_fortress_airbase ^= 1;
2374 update_map_canvas_visible();
2377 /**************************************************************************
2378 Toggle display of resources
2379 **************************************************************************/
2380 void request_toggle_resources(void)
2382 if (!can_client_change_view()) {
2383 return;
2386 gui_options.draw_specials ^= 1;
2387 update_map_canvas_visible();
2390 /**************************************************************************
2391 Toggle display of huts
2392 **************************************************************************/
2393 void request_toggle_huts(void)
2395 if (!can_client_change_view()) {
2396 return;
2399 gui_options.draw_huts ^= 1;
2400 update_map_canvas_visible();
2403 /**************************************************************************
2404 Toggle display of pollution
2405 **************************************************************************/
2406 void request_toggle_pollution(void)
2408 if (!can_client_change_view()) {
2409 return;
2412 gui_options.draw_pollution ^= 1;
2413 update_map_canvas_visible();
2416 /**************************************************************************
2417 Toggle display of cities
2418 **************************************************************************/
2419 void request_toggle_cities(void)
2421 if (!can_client_change_view()) {
2422 return;
2425 gui_options.draw_cities ^= 1;
2426 update_map_canvas_visible();
2429 /**************************************************************************
2430 Toggle display of units
2431 **************************************************************************/
2432 void request_toggle_units(void)
2434 if (!can_client_change_view()) {
2435 return;
2438 gui_options.draw_units ^= 1;
2439 update_map_canvas_visible();
2442 /**************************************************************************
2443 Toggle display of unit solid background.
2444 **************************************************************************/
2445 void request_toggle_unit_solid_bg(void)
2447 if (!can_client_change_view()) {
2448 return;
2451 gui_options.solid_color_behind_units ^= 1;
2452 update_map_canvas_visible();
2455 /**************************************************************************
2456 Toggle display of unit shields.
2457 **************************************************************************/
2458 void request_toggle_unit_shields(void)
2460 if (!can_client_change_view()) {
2461 return;
2464 gui_options.draw_unit_shields ^= 1;
2465 update_map_canvas_visible();
2468 /**************************************************************************
2469 Toggle display of focus unit
2470 **************************************************************************/
2471 void request_toggle_focus_unit(void)
2473 if (!can_client_change_view()) {
2474 return;
2477 gui_options.draw_focus_unit ^= 1;
2478 update_map_canvas_visible();
2481 /**************************************************************************
2482 Toggle display of fog of war
2483 **************************************************************************/
2484 void request_toggle_fog_of_war(void)
2486 if (!can_client_change_view()) {
2487 return;
2490 gui_options.draw_fog_of_war ^= 1;
2491 update_map_canvas_visible();
2492 refresh_overview_canvas();
2495 /**************************************************************************
2496 Center to focus unit.
2497 **************************************************************************/
2498 void request_center_focus_unit(void)
2500 struct tile *ptile = find_a_focus_unit_tile_to_center_on();
2502 if (ptile) {
2503 center_tile_mapcanvas(ptile);
2507 /**************************************************************************
2508 Set units in list to waiting focus. If they are current focus units,
2509 advance focus.
2510 **************************************************************************/
2511 void request_units_wait(struct unit_list *punits)
2513 unit_list_iterate(punits, punit) {
2514 punit->client.focus_status = FOCUS_WAIT;
2515 } unit_list_iterate_end;
2516 if (punits == get_units_in_focus()) {
2517 unit_focus_advance();
2521 /**************************************************************************
2522 Set focus units to FOCUS_DONE state.
2523 **************************************************************************/
2524 void request_unit_move_done(void)
2526 if (get_num_units_in_focus() > 0) {
2527 enum unit_focus_status new_status = FOCUS_DONE;
2528 unit_list_iterate(get_units_in_focus(), punit) {
2529 /* If any of the focused units are busy, keep all of them
2530 * in focus; another tap of the key will dismiss them */
2531 if (punit->activity != ACTIVITY_IDLE) {
2532 new_status = FOCUS_WAIT;
2534 } unit_list_iterate_end;
2535 unit_list_iterate(get_units_in_focus(), punit) {
2536 clear_unit_orders(punit);
2537 punit->client.focus_status = new_status;
2538 } unit_list_iterate_end;
2539 if (new_status == FOCUS_DONE) {
2540 unit_focus_advance();
2545 /**************************************************************************
2546 Called to have the client move a unit from one location to another,
2547 updating the graphics if necessary. The caller must redraw the target
2548 location after the move.
2549 **************************************************************************/
2550 void do_move_unit(struct unit *punit, struct unit *target_unit)
2552 struct tile *src_tile = unit_tile(punit);
2553 struct tile *dst_tile = unit_tile(target_unit);
2554 bool was_teleported, do_animation;
2555 bool in_focus = unit_is_in_focus(punit);
2557 was_teleported = !is_tiles_adjacent(src_tile, dst_tile);
2558 do_animation = (!was_teleported && gui_options.smooth_move_unit_msec > 0);
2560 if (!was_teleported
2561 && punit->activity != ACTIVITY_SENTRY
2562 && !unit_transported(punit)) {
2563 audio_play_sound(unit_type_get(punit)->sound_move,
2564 unit_type_get(punit)->sound_move_alt);
2567 if (unit_owner(punit) == client.conn.playing
2568 && gui_options.auto_center_on_unit
2569 && !unit_has_orders(punit)
2570 && punit->activity != ACTIVITY_GOTO
2571 && punit->activity != ACTIVITY_SENTRY
2572 && ((gui_options.auto_center_on_automated == TRUE
2573 && punit->ai_controlled == TRUE)
2574 || (punit->ai_controlled == FALSE))
2575 && !tile_visible_and_not_on_border_mapcanvas(dst_tile)) {
2576 center_tile_mapcanvas(dst_tile);
2579 if (hover_state != HOVER_NONE && in_focus) {
2580 /* Cancel current goto/patrol/connect/nuke command. */
2581 set_hover_state(NULL, HOVER_NONE,
2582 ACTIVITY_LAST, NULL,
2583 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2584 update_unit_info_label(get_units_in_focus());
2587 unit_list_remove(src_tile->units, punit);
2589 if (!unit_transported(punit)) {
2590 /* Mark the unit as moving unit, then find_visible_unit() won't return
2591 * it. It is especially useful to don't draw many times the unit when
2592 * refreshing the canvas. */
2593 punit_moving = punit;
2595 /* We have to refresh the tile before moving. This will draw
2596 * the tile without the unit (because it was unlinked above). */
2597 refresh_unit_mapcanvas(punit, src_tile, TRUE, FALSE);
2599 if (gui_options.auto_center_on_automated == FALSE
2600 && punit->ai_controlled == TRUE) {
2601 /* Dont animate automatic units */
2602 } else if (do_animation) {
2603 int dx, dy;
2605 /* For the duration of the animation the unit exists at neither
2606 * tile. */
2607 map_distance_vector(&dx, &dy, src_tile, dst_tile);
2608 move_unit_map_canvas(punit, src_tile, dx, dy);
2612 unit_tile_set(punit, dst_tile);
2613 unit_list_prepend(dst_tile->units, punit);
2615 if (!unit_transported(punit)) {
2616 /* For find_visible_unit(), see above. */
2617 punit_moving = NULL;
2619 refresh_unit_mapcanvas(punit, dst_tile, TRUE, FALSE);
2622 /* With the "full" city bar we have to update the city bar when units move
2623 * into or out of a city. For foreign cities this is handled separately,
2624 * via the occupied field of the short-city packet. */
2625 if (NULL != tile_city(src_tile)
2626 && can_player_see_units_in_city(client.conn.playing, tile_city(src_tile))) {
2627 update_city_description(tile_city(src_tile));
2629 if (NULL != tile_city(dst_tile)
2630 && can_player_see_units_in_city(client.conn.playing, tile_city(dst_tile))) {
2631 update_city_description(tile_city(dst_tile));
2634 if (in_focus) {
2635 menus_update();
2639 /**************************************************************************
2640 An action selection dialog for the selected units against the specified
2641 tile is wanted.
2642 **************************************************************************/
2643 static void do_unit_act_sel_vs(struct tile *ptile)
2645 unit_list_iterate(get_units_in_focus(), punit) {
2646 if (utype_may_act_at_all(unit_type_get(punit))) {
2647 /* Have the server record that an action decision is wanted for
2648 * this unit against this tile. */
2649 dsend_packet_unit_sscs_set(&client.conn, punit->id,
2650 USSDT_QUEUE, tile_index(ptile));
2652 } unit_list_iterate_end;
2655 /**************************************************************************
2656 Handles everything when the user clicked a tile
2657 **************************************************************************/
2658 void do_map_click(struct tile *ptile, enum quickselect_type qtype)
2660 struct city *pcity = tile_city(ptile);
2661 struct unit_list *punits = get_units_in_focus();
2662 bool maybe_goto = FALSE;
2664 if (hover_state != HOVER_NONE) {
2665 switch (hover_state) {
2666 case HOVER_NONE:
2667 break;
2668 case HOVER_GOTO:
2669 do_unit_goto(ptile);
2670 break;
2671 case HOVER_PARADROP:
2672 unit_list_iterate(punits, punit) {
2673 do_unit_paradrop_to(punit, ptile);
2674 } unit_list_iterate_end;
2675 break;
2676 case HOVER_CONNECT:
2677 do_unit_connect(ptile, connect_activity, connect_tgt);
2678 break;
2679 case HOVER_PATROL:
2680 do_unit_patrol_to(ptile);
2681 break;
2682 case HOVER_ACT_SEL_TGT:
2683 do_unit_act_sel_vs(ptile);
2684 break;
2687 set_hover_state(NULL, HOVER_NONE,
2688 ACTIVITY_LAST, NULL,
2689 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2690 update_unit_info_label(get_units_in_focus());
2693 /* Bypass stack or city popup if quickselect is specified. */
2694 else if (qtype != SELECT_POPUP && qtype != SELECT_APPEND) {
2695 struct unit *qunit = quickselect(ptile, qtype);
2696 if (qunit) {
2697 unit_focus_set_and_select(qunit);
2698 maybe_goto = gui_options.keyboardless_goto;
2701 /* Otherwise use popups. */
2702 else if (NULL != pcity
2703 && can_player_see_city_internals(client.conn.playing, pcity)) {
2704 popup_city_dialog(pcity);
2706 else if (unit_list_size(ptile->units) == 0
2707 && NULL == pcity
2708 && get_num_units_in_focus() > 0) {
2709 maybe_goto = gui_options.keyboardless_goto;
2711 else if (unit_list_size(ptile->units) == 1
2712 && !get_transporter_occupancy(unit_list_get(ptile->units, 0))) {
2713 struct unit *punit = unit_list_get(ptile->units, 0);
2715 if (unit_owner(punit) == client.conn.playing) {
2716 if (can_unit_do_activity(punit, ACTIVITY_IDLE)) {
2717 maybe_goto = gui_options.keyboardless_goto;
2718 if (qtype == SELECT_APPEND) {
2719 unit_focus_add(punit);
2720 } else {
2721 unit_focus_set_and_select(punit);
2724 } else if (pcity) {
2725 /* Don't hide the unit in the city. */
2726 unit_select_dialog_popup(ptile);
2728 } else if (unit_list_size(ptile->units) > 0) {
2729 /* The stack list is always popped up, even if it includes enemy units.
2730 * If the server doesn't want the player to know about them it shouldn't
2731 * tell him! The previous behavior would only pop up the stack if you
2732 * owned a unit on the tile. This gave cheating clients an advantage,
2733 * and also showed you allied units if (and only if) you had a unit on
2734 * the tile (inconsistent). */
2735 unit_select_dialog_popup(ptile);
2738 /* See mapctrl_common.c */
2739 keyboardless_goto_start_tile = maybe_goto ? ptile : NULL;
2740 keyboardless_goto_button_down = maybe_goto;
2741 keyboardless_goto_active = FALSE;
2744 /**************************************************************************
2745 Quickselecting a unit is normally done with <control> left, right click,
2746 for the current tile. Bypassing the stack popup is quite convenient,
2747 and can be tactically important in furious multiplayer games.
2748 **************************************************************************/
2749 static struct unit *quickselect(struct tile *ptile,
2750 enum quickselect_type qtype)
2752 int listsize = unit_list_size(ptile->units);
2753 struct unit *panytransporter = NULL,
2754 *panymovesea = NULL, *panysea = NULL,
2755 *panymoveland = NULL, *panyland = NULL,
2756 *panymoveunit = NULL, *panyunit = NULL;
2758 fc_assert_ret_val(qtype > SELECT_POPUP, NULL);
2760 if (qtype == SELECT_FOCUS) {
2761 return head_of_units_in_focus();
2764 if (listsize == 0) {
2765 return NULL;
2766 } else if (listsize == 1) {
2767 struct unit *punit = unit_list_get(ptile->units, 0);
2768 return (unit_owner(punit) == client.conn.playing) ? punit : NULL;
2771 /* Quickselect priorities. Units with moves left
2772 * before exhausted. Focus unit is excluded.
2774 * SEA: Transporter
2775 * Sea unit
2776 * Any unit
2778 * LAND: Military land unit
2779 * Non-combatant
2780 * Sea unit
2781 * Any unit
2784 unit_list_iterate(ptile->units, punit) {
2785 if (unit_owner(punit) != client.conn.playing || unit_is_in_focus(punit)) {
2786 continue;
2788 if (qtype == SELECT_SEA) {
2789 /* Transporter. */
2790 if (get_transporter_capacity(punit)) {
2791 if (punit->moves_left > 0) {
2792 return punit;
2793 } else if (!panytransporter) {
2794 panytransporter = punit;
2797 /* Any sea, pref. moves left. */
2798 else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
2799 if (punit->moves_left > 0) {
2800 if (!panymovesea) {
2801 panymovesea = punit;
2803 } else if (!panysea) {
2804 panysea = punit;
2807 } else if (qtype == SELECT_LAND) {
2808 if (utype_move_type(unit_type_get(punit)) == UMT_LAND) {
2809 if (punit->moves_left > 0) {
2810 if (is_military_unit(punit)) {
2811 return punit;
2812 } else if (!panymoveland) {
2813 panymoveland = punit;
2815 } else if (!panyland) {
2816 panyland = punit;
2819 else if (utype_move_type(unit_type_get(punit)) == UMT_SEA) {
2820 if (punit->moves_left > 0) {
2821 panymovesea = punit;
2822 } else {
2823 panysea = punit;
2827 if (punit->moves_left > 0 && !panymoveunit) {
2828 panymoveunit = punit;
2830 if (!panyunit) {
2831 panyunit = punit;
2833 } unit_list_iterate_end;
2835 if (qtype == SELECT_SEA) {
2836 if (panytransporter) {
2837 return panytransporter;
2838 } else if (panymovesea) {
2839 return panymovesea;
2840 } else if (panysea) {
2841 return panysea;
2842 } else if (panymoveunit) {
2843 return panymoveunit;
2844 } else if (panyunit) {
2845 return panyunit;
2848 else if (qtype == SELECT_LAND) {
2849 if (panymoveland) {
2850 return panymoveland;
2851 } else if (panyland) {
2852 return panyland;
2853 } else if (panymovesea) {
2854 return panymovesea;
2855 } else if (panysea) {
2856 return panysea;
2857 } else if (panymoveunit) {
2858 return panymoveunit;
2859 } else if (panyunit) {
2860 return panyunit;
2863 return NULL;
2866 /**************************************************************************
2867 Finish the goto mode and let the units stored in goto_map_list move
2868 to a given location.
2869 **************************************************************************/
2870 void do_unit_goto(struct tile *ptile)
2872 if (hover_state != HOVER_GOTO) {
2873 return;
2876 if (is_valid_goto_draw_line(ptile)) {
2877 send_goto_route();
2878 } else {
2879 create_event(ptile, E_BAD_COMMAND, ftc_client,
2880 _("Didn't find a route to the destination!"));
2884 /**************************************************************************
2885 Paradrop to a location.
2886 **************************************************************************/
2887 void do_unit_paradrop_to(struct unit *punit, struct tile *ptile)
2889 request_do_action(ACTION_PARADROP, punit->id, tile_index(ptile), 0 , "");
2892 /**************************************************************************
2893 Patrol to a location.
2894 **************************************************************************/
2895 void do_unit_patrol_to(struct tile *ptile)
2897 if (is_valid_goto_draw_line(ptile)
2898 && !is_non_allied_unit_tile(ptile, client.conn.playing)) {
2899 send_patrol_route();
2900 } else {
2901 create_event(ptile, E_BAD_COMMAND, ftc_client,
2902 _("Didn't find a route to the destination!"));
2905 set_hover_state(NULL, HOVER_NONE,
2906 ACTIVITY_LAST, NULL,
2907 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2910 /**************************************************************************
2911 "Connect" to the given location.
2912 **************************************************************************/
2913 void do_unit_connect(struct tile *ptile,
2914 enum unit_activity activity,
2915 struct extra_type *tgt)
2917 if (is_valid_goto_draw_line(ptile)) {
2918 send_connect_route(activity, tgt);
2919 } else {
2920 create_event(ptile, E_BAD_COMMAND, ftc_client,
2921 _("Didn't find a route to the destination!"));
2924 set_hover_state(NULL, HOVER_NONE,
2925 ACTIVITY_LAST, NULL,
2926 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2929 /**************************************************************************
2930 The 'Escape' key.
2931 **************************************************************************/
2932 void key_cancel_action(void)
2934 cancel_tile_hiliting();
2936 switch (hover_state) {
2937 case HOVER_GOTO:
2938 case HOVER_PATROL:
2939 case HOVER_CONNECT:
2940 if (goto_pop_waypoint()) {
2941 break;
2943 /* else fall through: */
2944 case HOVER_PARADROP:
2945 case HOVER_ACT_SEL_TGT:
2946 set_hover_state(NULL, HOVER_NONE,
2947 ACTIVITY_LAST, NULL,
2948 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
2949 update_unit_info_label(get_units_in_focus());
2951 keyboardless_goto_button_down = FALSE;
2952 keyboardless_goto_active = FALSE;
2953 keyboardless_goto_start_tile = NULL;
2954 break;
2955 case HOVER_NONE:
2956 break;
2960 /**************************************************************************
2961 Center the mapview on the player's capital, or print a failure message.
2962 **************************************************************************/
2963 void key_center_capital(void)
2965 struct city *capital = player_capital(client_player());
2967 if (capital) {
2968 /* Center on the tile, and pop up the crosshair overlay. */
2969 center_tile_mapcanvas(capital->tile);
2970 put_cross_overlay_tile(capital->tile);
2971 } else {
2972 create_event(NULL, E_BAD_COMMAND, ftc_client,
2973 _("Oh my! You seem to have no capital!"));
2977 /**************************************************************************
2978 Handle user 'end turn' input.
2979 **************************************************************************/
2980 void key_end_turn(void)
2982 send_turn_done();
2985 /**************************************************************************
2986 Recall the previous focus unit(s). See store_previous_focus().
2987 **************************************************************************/
2988 void key_recall_previous_focus_unit(void)
2990 int i = 0;
2992 /* Could use unit_list_copy here instead. Just having safe genlists
2993 * wouldn't be sufficient since we don't want to skip units already
2994 * removed from focus... */
2995 unit_list_iterate_safe(previous_focus, punit) {
2996 if (i == 0) {
2997 unit_focus_set(punit);
2998 } else {
2999 unit_focus_add(punit);
3001 i++;
3002 } unit_list_iterate_safe_end;
3005 /**************************************************************************
3006 Move the focus unit in the given direction. Here directions are
3007 defined according to the GUI, so that north is "up" in the interface.
3008 **************************************************************************/
3009 void key_unit_move(enum direction8 gui_dir)
3011 unit_list_iterate(get_units_in_focus(), punit) {
3012 enum direction8 map_dir = gui_to_map_dir(gui_dir);
3014 request_move_unit_direction(punit, map_dir);
3015 } unit_list_iterate_end;
3018 /**************************************************************************
3019 Handle use 'build city' input.
3020 **************************************************************************/
3021 void key_unit_build_city(void)
3023 unit_list_iterate(get_units_in_focus(), punit) {
3024 request_unit_build_city(punit);
3025 } unit_list_iterate_end;
3028 /**************************************************************************
3029 Handle user 'help build wonder' input
3030 **************************************************************************/
3031 void key_unit_build_wonder(void)
3033 unit_list_iterate(get_units_in_focus(), punit) {
3034 if (unit_can_do_action(punit, ACTION_HELP_WONDER)) {
3035 request_unit_caravan_action(punit, ACTION_HELP_WONDER);
3037 } unit_list_iterate_end;
3040 /**************************************************************************
3041 handle user pressing key for 'Connect' command
3042 **************************************************************************/
3043 void key_unit_connect(enum unit_activity activity,
3044 struct extra_type *tgt)
3046 request_unit_connect(activity, tgt);
3049 /**************************************************************************
3050 Handle user 'Do...' input
3051 **************************************************************************/
3052 void key_unit_action_select(void)
3054 struct tile *ptile;
3056 if (!can_ask_server_for_actions()) {
3057 /* Looks like another action selection dialog is open. */
3058 return;
3061 unit_list_iterate(get_units_in_focus(), punit) {
3062 if (utype_may_act_at_all(unit_type_get(punit))
3063 && (ptile = unit_tile(punit))) {
3064 /* Have the server record that an action decision is wanted for this
3065 * unit. */
3066 dsend_packet_unit_sscs_set(&client.conn, punit->id,
3067 USSDT_QUEUE, tile_index(ptile));
3069 } unit_list_iterate_end;
3072 /**************************************************************************
3073 Have the user select what action the unit(s) in focus should perform to
3074 the targets at the tile the user will specify by clicking on it.
3076 Will stop asking for a target tile and have each actor unit act against
3077 its own tile if called twice.
3078 **************************************************************************/
3079 void key_unit_action_select_tgt(void)
3081 struct unit_list *punits = get_units_in_focus();
3083 if (hover_state == HOVER_ACT_SEL_TGT) {
3084 /* The 2nd key press means that the actor should target its own
3085 * tile. */
3086 key_unit_action_select();
3088 /* Target tile selected. Clean up hover state. */
3089 set_hover_state(NULL, HOVER_NONE,
3090 ACTIVITY_LAST, NULL,
3091 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
3092 update_unit_info_label(punits);
3094 return;
3097 create_event(unit_tile(unit_list_get(punits, 0)), E_BEGINNER_HELP,
3098 ftc_client,
3099 /* TRANS: "Do..." action selection dialog target. */
3100 _("Click on a tile to act against it. "
3101 "Press 'd' again to act against own tile."));
3103 set_hover_state(punits, HOVER_ACT_SEL_TGT, ACTIVITY_LAST, NULL,
3104 EXTRA_NONE, ACTION_NONE, ORDER_LAST);
3107 /**************************************************************************
3108 Handle user 'unit done' input
3109 **************************************************************************/
3110 void key_unit_done(void)
3112 request_unit_move_done();
3115 /**************************************************************************
3116 Handle user 'unit goto' input
3117 **************************************************************************/
3118 void key_unit_goto(void)
3120 request_unit_goto(ORDER_LAST, ACTION_NONE, EXTRA_NONE);
3123 /**************************************************************************
3124 Explode nuclear at a tile without enemy units
3125 **************************************************************************/
3126 void key_unit_nuke(void)
3128 request_unit_goto(ORDER_PERFORM_ACTION, ACTION_NUKE, EXTRA_NONE);
3131 /**************************************************************************
3132 Handle user 'paradrop' input
3133 **************************************************************************/
3134 void key_unit_paradrop(void)
3136 request_unit_paradrop(get_units_in_focus());
3139 /**************************************************************************
3140 Handle user 'patrol' input
3141 **************************************************************************/
3142 void key_unit_patrol(void)
3144 request_unit_patrol();
3147 /**************************************************************************
3148 Handle user 'establish traderoute' input
3149 **************************************************************************/
3150 void key_unit_trade_route(void)
3152 unit_list_iterate(get_units_in_focus(), punit) {
3153 /* TODO: Is falling back on ACTION_MARKETPLACE if not able to establish
3154 * a trade route trade a good idea or an unplecant surprice? */
3155 if (unit_can_do_action(punit, ACTION_TRADE_ROUTE)) {
3156 request_unit_caravan_action(punit, ACTION_TRADE_ROUTE);
3158 } unit_list_iterate_end;
3161 /**************************************************************************
3162 Handle user 'unload all' input
3163 **************************************************************************/
3164 void key_unit_unload_all(void)
3166 struct unit *pnext_focus = NULL, *plast;
3168 unit_list_iterate(get_units_in_focus(), punit) {
3169 if ((plast = request_unit_unload_all(punit))) {
3170 pnext_focus = plast;
3172 } unit_list_iterate_end;
3174 if (pnext_focus) {
3175 unit_list_iterate(get_units_in_focus(), punit) {
3176 /* Unfocus the ships, and advance the focus to the last unloaded unit.
3177 * If there is no unit unloaded (which shouldn't happen, but could if
3178 * the caller doesn't check if the transporter is loaded), the we
3179 * don't do anything. */
3180 punit->client.focus_status = FOCUS_WAIT;
3181 } unit_list_iterate_end;
3182 unit_focus_set(pnext_focus);
3186 /**************************************************************************
3187 Handle user 'wait' input
3188 **************************************************************************/
3189 void key_unit_wait(void)
3191 request_units_wait(get_units_in_focus());
3194 /**************************************************************************
3195 Handle user 'wakeup others' input
3196 ***************************************************************************/
3197 void key_unit_wakeup_others(void)
3199 unit_list_iterate(get_units_in_focus(), punit) {
3200 request_unit_wakeup(punit);
3201 } unit_list_iterate_end;
3204 /**************************************************************************
3205 Handle user 'build base of class airbase' input
3206 **************************************************************************/
3207 void key_unit_airbase(void)
3209 unit_list_iterate(get_units_in_focus(), punit) {
3210 struct base_type *pbase =
3211 get_base_by_gui_type(BASE_GUI_AIRBASE, punit, unit_tile(punit));
3213 if (pbase) {
3214 struct extra_type *pextra = base_extra_get(pbase);
3216 request_new_unit_activity_targeted(punit, ACTIVITY_BASE, pextra);
3218 } unit_list_iterate_end;
3221 /**************************************************************************
3222 Handle user 'autoexplore' input
3223 **************************************************************************/
3224 void key_unit_auto_explore(void)
3226 unit_list_iterate(get_units_in_focus(), punit) {
3227 if (can_unit_do_activity(punit, ACTIVITY_EXPLORE)) {
3228 request_new_unit_activity(punit, ACTIVITY_EXPLORE);
3230 } unit_list_iterate_end;
3233 /**************************************************************************
3234 Call to request (from the server) that the focus unit is put into
3235 autosettler mode.
3236 **************************************************************************/
3237 void key_unit_auto_settle(void)
3239 unit_list_iterate(get_units_in_focus(), punit) {
3240 if (can_unit_do_autosettlers(punit)) {
3241 request_unit_autosettlers(punit);
3243 } unit_list_iterate_end;
3246 /**************************************************************************
3247 Unit convert key pressed or respective menu entry selected.
3248 **************************************************************************/
3249 void key_unit_convert(void)
3251 unit_list_iterate(get_units_in_focus(), punit) {
3252 request_unit_convert(punit);
3253 } unit_list_iterate_end;
3256 /**************************************************************************
3257 Handle user 'clean fallout' input
3258 **************************************************************************/
3259 void key_unit_fallout(void)
3261 key_unit_clean(ACTIVITY_FALLOUT, ERM_CLEANFALLOUT);
3264 /**************************************************************************
3265 Handle user 'fortify' input
3266 **************************************************************************/
3267 void key_unit_fortify(void)
3269 unit_list_iterate(get_units_in_focus(), punit) {
3270 if (can_unit_do_activity(punit, ACTIVITY_FORTIFYING)) {
3271 request_new_unit_activity(punit, ACTIVITY_FORTIFYING);
3273 } unit_list_iterate_end;
3276 /**************************************************************************
3277 Handle user 'build base of class fortress' input
3278 **************************************************************************/
3279 void key_unit_fortress(void)
3281 unit_list_iterate(get_units_in_focus(), punit) {
3282 struct base_type *pbase =
3283 get_base_by_gui_type(BASE_GUI_FORTRESS, punit, unit_tile(punit));
3285 if (pbase) {
3286 struct extra_type *pextra = base_extra_get(pbase);
3288 request_new_unit_activity_targeted(punit, ACTIVITY_BASE, pextra);
3290 } unit_list_iterate_end;
3293 /**************************************************************************
3294 Handle user 'change homecity' input
3295 **************************************************************************/
3296 void key_unit_homecity(void)
3298 unit_list_iterate(get_units_in_focus(), punit) {
3299 request_unit_change_homecity(punit);
3300 } unit_list_iterate_end;
3303 /**************************************************************************
3304 Handle user extra building input of given type
3305 **************************************************************************/
3306 static void key_unit_extra(enum unit_activity act, enum extra_cause cause)
3308 unit_list_iterate(get_units_in_focus(), punit) {
3309 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
3310 cause,
3311 unit_owner(punit),
3312 punit);
3314 if (can_unit_do_activity_targeted(punit, act, tgt)) {
3315 request_new_unit_activity_targeted(punit, act, tgt);
3317 } unit_list_iterate_end;
3320 /**************************************************************************
3321 Handle user extra cleaning input of given type
3322 **************************************************************************/
3323 static void key_unit_clean(enum unit_activity act, enum extra_rmcause rmcause)
3325 unit_list_iterate(get_units_in_focus(), punit) {
3326 struct extra_type *tgt = prev_extra_in_tile(unit_tile(punit),
3327 rmcause,
3328 unit_owner(punit),
3329 punit);
3331 if (tgt != NULL
3332 && can_unit_do_activity_targeted(punit, act, tgt)) {
3333 request_new_unit_activity_targeted(punit, act, tgt);
3335 } unit_list_iterate_end;
3338 /**************************************************************************
3339 Handle user 'irrigate' input
3340 **************************************************************************/
3341 void key_unit_irrigate(void)
3343 key_unit_extra(ACTIVITY_IRRIGATE, EC_IRRIGATION);
3346 /**************************************************************************
3347 Handle user 'build mine' input
3348 **************************************************************************/
3349 void key_unit_mine(void)
3351 key_unit_extra(ACTIVITY_MINE, EC_MINE);
3354 /**************************************************************************
3355 Handle user 'pillage' input
3356 **************************************************************************/
3357 void key_unit_pillage(void)
3359 unit_list_iterate(get_units_in_focus(), punit) {
3360 if (can_unit_do_activity(punit, ACTIVITY_PILLAGE)) {
3361 request_unit_pillage(punit);
3363 } unit_list_iterate_end;
3366 /**************************************************************************
3367 Handle user 'clean pollution' input
3368 **************************************************************************/
3369 void key_unit_pollution(void)
3371 key_unit_clean(ACTIVITY_POLLUTION, ERM_CLEANPOLLUTION);
3374 /**************************************************************************
3375 Handle user 'build road or railroad' input
3376 **************************************************************************/
3377 void key_unit_road(void)
3379 unit_list_iterate(get_units_in_focus(), punit) {
3380 struct extra_type *tgt = next_extra_for_tile(unit_tile(punit),
3381 EC_ROAD,
3382 unit_owner(punit),
3383 punit);
3385 if (tgt != NULL
3386 && can_unit_do_activity_targeted(punit, ACTIVITY_GEN_ROAD, tgt)) {
3387 request_new_unit_activity_targeted(punit, ACTIVITY_GEN_ROAD, tgt);
3389 } unit_list_iterate_end;
3392 /**************************************************************************
3393 Handle user 'sentry' input
3394 **************************************************************************/
3395 void key_unit_sentry(void)
3397 unit_list_iterate(get_units_in_focus(), punit) {
3398 if (can_unit_do_activity(punit, ACTIVITY_SENTRY)) {
3399 request_new_unit_activity(punit, ACTIVITY_SENTRY);
3401 } unit_list_iterate_end;
3404 /**************************************************************************
3405 Handle user 'transform unit' input
3406 **************************************************************************/
3407 void key_unit_transform(void)
3409 unit_list_iterate(get_units_in_focus(), punit) {
3410 if (can_unit_do_activity(punit, ACTIVITY_TRANSFORM)) {
3411 request_new_unit_activity(punit, ACTIVITY_TRANSFORM);
3413 } unit_list_iterate_end;
3416 /****************************************************************************
3417 Assign all focus units to this battlegroup.
3418 ****************************************************************************/
3419 void key_unit_assign_battlegroup(int battlegroup, bool append)
3421 if (NULL != client.conn.playing && can_client_issue_orders()
3422 && battlegroups >= 0 && battlegroup < MAX_NUM_BATTLEGROUPS) {
3423 if (!append) {
3424 unit_list_iterate_safe(battlegroups[battlegroup], punit) {
3425 if (!unit_is_in_focus(punit)) {
3426 punit->battlegroup = BATTLEGROUP_NONE;
3427 dsend_packet_unit_sscs_set(&client.conn, punit->id,
3428 USSDT_BATTLE_GROUP,
3429 BATTLEGROUP_NONE);
3430 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
3431 unit_list_remove(battlegroups[battlegroup], punit);
3433 } unit_list_iterate_safe_end;
3435 unit_list_iterate(get_units_in_focus(), punit) {
3436 if (punit->battlegroup != battlegroup) {
3437 if (punit->battlegroup >= 0
3438 && punit->battlegroup < MAX_NUM_BATTLEGROUPS) {
3439 unit_list_remove(battlegroups[punit->battlegroup], punit);
3441 punit->battlegroup = battlegroup;
3442 dsend_packet_unit_sscs_set(&client.conn, punit->id,
3443 USSDT_BATTLE_GROUP,
3444 battlegroup);
3445 unit_list_append(battlegroups[battlegroup], punit);
3446 refresh_unit_mapcanvas(punit, unit_tile(punit), TRUE, FALSE);
3448 } unit_list_iterate_end;
3449 unit_list_iterate(battlegroups[battlegroup], punit) {
3450 unit_focus_add(punit);
3451 } unit_list_iterate_end;
3455 /****************************************************************************
3456 Bring this battlegroup into focus.
3457 ****************************************************************************/
3458 void key_unit_select_battlegroup(int battlegroup, bool append)
3460 if (NULL != client.conn.playing && can_client_change_view()
3461 && battlegroups >= 0 && battlegroup < MAX_NUM_BATTLEGROUPS) {
3462 int i = 0;
3464 if (unit_list_size(battlegroups[battlegroup]) == 0 && !append) {
3465 unit_focus_set(NULL);
3466 return;
3469 /* FIXME: this is very inefficient and can be improved. */
3470 unit_list_iterate(battlegroups[battlegroup], punit) {
3471 if (i == 0 && !append) {
3472 unit_focus_set(punit);
3473 } else {
3474 unit_focus_add(punit);
3476 i++;
3477 } unit_list_iterate_end;
3481 /**************************************************************************
3482 Toggle drawing of city outlines.
3483 **************************************************************************/
3484 void key_city_outlines_toggle(void)
3486 request_toggle_city_outlines();
3489 /**************************************************************************
3490 Toggle drawing of city output produced by workers of the city.
3491 **************************************************************************/
3492 void key_city_output_toggle(void)
3494 request_toggle_city_output();
3497 /**************************************************************************
3498 Handle user 'toggle map grid' input
3499 **************************************************************************/
3500 void key_map_grid_toggle(void)
3502 request_toggle_map_grid();
3505 /**************************************************************************
3506 Toggle map borders on the mapview on/off based on a keypress.
3507 **************************************************************************/
3508 void key_map_borders_toggle(void)
3510 request_toggle_map_borders();
3513 /**************************************************************************
3514 Toggle native tiles on the mapview on/off based on a keypress.
3515 **************************************************************************/
3516 void key_map_native_toggle(void)
3518 request_toggle_map_native();
3521 /**************************************************************************
3522 Toggle the "Draw the city bar" option.
3523 **************************************************************************/
3524 void key_city_full_bar_toggle(void)
3526 request_toggle_city_full_bar();
3529 /**************************************************************************
3530 Handle user 'toggle city names display' input
3531 **************************************************************************/
3532 void key_city_names_toggle(void)
3534 request_toggle_city_names();
3537 /**************************************************************************
3538 Toggles the "show city growth turns" option by passing off the
3539 request to another function...
3540 **************************************************************************/
3541 void key_city_growth_toggle(void)
3543 request_toggle_city_growth();
3546 /**************************************************************************
3547 Toggles the showing of the buy cost of the current production in the
3548 city descriptions.
3549 **************************************************************************/
3550 void key_city_buycost_toggle(void)
3552 request_toggle_city_buycost();
3555 /**************************************************************************
3556 Handle user 'toggle city production display' input
3557 **************************************************************************/
3558 void key_city_productions_toggle(void)
3560 request_toggle_city_productions();
3563 /**************************************************************************
3564 Handle client request to toggle drawing of trade route information
3565 by the city name for cities visible on the main map view.
3566 **************************************************************************/
3567 void key_city_trade_routes_toggle(void)
3569 request_toggle_city_trade_routes();
3572 /**************************************************************************
3573 Handle user 'toggle terrain display' input
3574 **************************************************************************/
3575 void key_terrain_toggle(void)
3577 request_toggle_terrain();
3580 /**************************************************************************
3581 Handle user 'toggle coastline display' input
3582 **************************************************************************/
3583 void key_coastline_toggle(void)
3585 request_toggle_coastline();
3588 /**************************************************************************
3589 Handle user 'toggle road/railroad display' input
3590 **************************************************************************/
3591 void key_roads_rails_toggle(void)
3593 request_toggle_roads_rails();
3596 /**************************************************************************
3597 Handle user 'toggle irrigation display' input
3598 **************************************************************************/
3599 void key_irrigation_toggle(void)
3601 request_toggle_irrigation();
3604 /**************************************************************************
3605 Handle user 'toggle mine display' input
3606 **************************************************************************/
3607 void key_mines_toggle(void)
3609 request_toggle_mines();
3612 /**************************************************************************
3613 Handle user 'toggle bases display' input
3614 **************************************************************************/
3615 void key_bases_toggle(void)
3617 request_toggle_bases();
3620 /**************************************************************************
3621 Handle user 'toggle resources display' input
3622 **************************************************************************/
3623 void key_resources_toggle(void)
3625 request_toggle_resources();
3628 /**************************************************************************
3629 Handle user 'toggle huts display' input
3630 **************************************************************************/
3631 void key_huts_toggle(void)
3633 request_toggle_huts();
3636 /**************************************************************************
3637 Handle user 'toggle pollution display' input
3638 **************************************************************************/
3639 void key_pollution_toggle(void)
3641 request_toggle_pollution();
3644 /**************************************************************************
3645 Handle user 'toggle cities display' input
3646 **************************************************************************/
3647 void key_cities_toggle(void)
3649 request_toggle_cities();
3652 /**************************************************************************
3653 Handle user 'toggle units display' input
3654 **************************************************************************/
3655 void key_units_toggle(void)
3657 request_toggle_units();
3660 /**************************************************************************
3661 Toggle the "Solid unit background color" option.
3662 **************************************************************************/
3663 void key_unit_solid_bg_toggle(void)
3665 request_toggle_unit_solid_bg();
3668 /**************************************************************************
3669 Toggle the "Draw shield graphics for units" option.
3670 **************************************************************************/
3671 void key_unit_shields_toggle(void)
3673 request_toggle_unit_shields();
3676 /**************************************************************************
3677 Handle user 'toggle key units display' input
3678 **************************************************************************/
3679 void key_focus_unit_toggle(void)
3681 request_toggle_focus_unit();
3684 /**************************************************************************
3685 Handle user 'toggle fog of war display' input
3686 **************************************************************************/
3687 void key_fog_of_war_toggle(void)
3689 request_toggle_fog_of_war();
3692 /**************************************************************************
3693 Toggle editor mode in the server.
3694 **************************************************************************/
3695 void key_editor_toggle(void)
3697 dsend_packet_edit_mode(&client.conn, !game.info.is_edit_mode);
3700 /**************************************************************************
3701 Recalculate borders.
3702 **************************************************************************/
3703 void key_editor_recalculate_borders(void)
3705 send_packet_edit_recalculate_borders(&client.conn);
3708 /**************************************************************************
3709 Send a request to the server to toggle fog-of-war for the current
3710 player (only applies in edit mode).
3711 **************************************************************************/
3712 void key_editor_toggle_fogofwar(void)
3714 if (client_has_player()) {
3715 dsend_packet_edit_toggle_fogofwar(&client.conn, client_player_number());
3719 /**************************************************************************
3720 All units ready to build city to the tile should now proceed.
3721 **************************************************************************/
3722 void finish_city(struct tile *ptile, const char *name)
3724 unit_list_iterate(ptile->units, punit) {
3725 if (punit->client.asking_city_name) {
3726 /* Unit will disappear only in case city building still success.
3727 * Cancel city building status just in case something has changed
3728 * to prevent city building in the meanwhile and unit will remain
3729 * alive. */
3730 punit->client.asking_city_name = FALSE;
3731 request_do_action(ACTION_FOUND_CITY, punit->id, ptile->index,
3732 0, name);
3734 } unit_list_iterate_end;
3737 /**************************************************************************
3738 Do not build city after all. Cancel city building mark from all units
3739 prepared for it.
3740 **************************************************************************/
3741 void cancel_city(struct tile *ptile)
3743 unit_list_iterate(ptile->units, punit) {
3744 punit->client.asking_city_name = FALSE;
3745 } unit_list_iterate_end;