Rulesave saves trade.type and trade.bonus correctly.
[freeciv.git] / client / gui-gtk-3.22 / action_dialog.c
blobf748355d8f17b8ae25f86fcd089021225cbfdc89
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team
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 #include <gtk/gtk.h>
20 /* utility */
21 #include "astring.h"
22 #include "support.h"
24 /* common */
25 #include "actions.h"
26 #include "game.h"
27 #include "traderoutes.h"
28 #include "movement.h"
29 #include "research.h"
30 #include "unit.h"
31 #include "unitlist.h"
33 /* client */
34 #include "dialogs_g.h"
35 #include "chatline.h"
36 #include "choice_dialog.h"
37 #include "client_main.h"
38 #include "climisc.h"
39 #include "connectdlg_common.h"
40 #include "control.h"
41 #include "gui_main.h"
42 #include "gui_stuff.h"
43 #include "mapview.h"
44 #include "packhand.h"
46 /* client/gui-gtk-3.22 */
47 #include "citydlg.h"
48 #include "dialogs.h"
49 #include "unitselunitdlg.h"
50 #include "wldlg.h"
52 /* Locations for non action enabler controlled buttons. */
53 #define BUTTON_MOVE ACTION_COUNT
54 #define BUTTON_NEW_UNIT_TGT BUTTON_MOVE + 1
55 #define BUTTON_LOCATION BUTTON_MOVE + 2
56 #define BUTTON_WAIT BUTTON_MOVE + 3
57 #define BUTTON_CANCEL BUTTON_MOVE + 4
58 #define BUTTON_COUNT BUTTON_MOVE + 5
60 #define BUTTON_NOT_THERE -1
63 static GtkWidget *act_sel_dialog;
64 static int action_button_map[BUTTON_COUNT];
66 static int actor_unit_id;
67 static int target_ids[ATK_COUNT];
68 static bool is_more_user_input_needed = FALSE;
69 static bool did_not_decide = FALSE;
70 static bool action_selection_restart = FALSE;
72 static GtkWidget *spy_tech_shell;
74 static GtkWidget *spy_sabotage_shell;
76 /* A structure to hold parameters for actions inside the GUI in stead of
77 * storing the needed data in a global variable. */
78 struct action_data {
79 int actor_unit_id;
80 int target_city_id;
81 int target_unit_id;
82 int target_tile_id;
83 int value;
86 /****************************************************************
87 Create a new action data structure that can be stored in the
88 dialogs.
89 *****************************************************************/
90 static struct action_data *act_data(int actor_id,
91 int target_city_id,
92 int target_unit_id,
93 int target_tile_id,
94 int value)
96 struct action_data *data = fc_malloc(sizeof(*data));
98 data->actor_unit_id = actor_id;
99 data->target_city_id = target_city_id;
100 data->target_unit_id = target_unit_id;
101 data->target_tile_id = target_tile_id;
102 data->value = value;
104 return data;
107 /**************************************************************************
108 Move the queue of units that need user input forward unless the current
109 unit are going to need more input.
110 **************************************************************************/
111 static void diplomat_queue_handle_primary(void)
113 if (!is_more_user_input_needed) {
114 /* The client isn't waiting for information for any unanswered follow
115 * up questions. */
117 struct unit *actor_unit;
119 if ((actor_unit = game_unit_by_number(actor_unit_id))) {
120 /* The action selection dialog wasn't closed because the actor unit
121 * was lost. */
123 /* The probabilities didn't just disappear, right? */
124 fc_assert_action(actor_unit->client.act_prob_cache,
125 client_unit_init_act_prob_cache(actor_unit));
127 FC_FREE(actor_unit->client.act_prob_cache);
130 if (action_selection_restart) {
131 /* The action selection dialog was closed but only so it can be
132 * redrawn with fresh data. */
134 action_selection_restart = FALSE;
135 } else {
136 /* The action selection process is over, at least for now. */
137 action_selection_no_longer_in_progress(actor_unit_id);
140 if (did_not_decide) {
141 /* The action selection dialog was closed but the player didn't
142 * decide what the unit should do. */
144 /* Reset so the next action selection dialog does the right thing. */
145 did_not_decide = FALSE;
146 } else {
147 /* An action, or no action at all, was selected. */
148 action_decision_clear_want(actor_unit_id);
149 action_selection_next_in_focus(actor_unit_id);
154 /**************************************************************************
155 Move the queue of diplomats that need user input forward since the
156 current diplomat got the extra input that was required.
157 **************************************************************************/
158 static void diplomat_queue_handle_secondary(void)
160 /* Stop waiting. Move on to the next queued diplomat. */
161 is_more_user_input_needed = FALSE;
162 diplomat_queue_handle_primary();
165 /****************************************************************
166 User selected enter market place from caravan dialog
167 *****************************************************************/
168 static void caravan_marketplace_callback(GtkWidget *w, gpointer data)
170 struct action_data *args = (struct action_data *)data;
172 if (NULL != game_unit_by_number(args->actor_unit_id)
173 && NULL != game_city_by_number(args->target_city_id)) {
174 request_do_action(ACTION_MARKETPLACE, args->actor_unit_id,
175 args->target_city_id, 0);
178 gtk_widget_destroy(act_sel_dialog);
179 free(args);
182 /****************************************************************
183 User selected traderoute from caravan dialog
184 *****************************************************************/
185 static void caravan_establish_trade_callback(GtkWidget *w, gpointer data)
187 struct action_data *args = (struct action_data *)data;
189 if (NULL != game_unit_by_number(args->actor_unit_id)
190 && NULL != game_city_by_number(args->target_city_id)) {
191 request_do_action(ACTION_TRADE_ROUTE, args->actor_unit_id,
192 args->target_city_id, 0);
195 gtk_widget_destroy(act_sel_dialog);
196 free(args);
199 /****************************************************************
200 User selected wonder building helping from caravan dialog
201 *****************************************************************/
202 static void caravan_help_build_wonder_callback(GtkWidget *w, gpointer data)
204 struct action_data *args = (struct action_data *)data;
206 if (NULL != game_unit_by_number(args->actor_unit_id)
207 && NULL != game_city_by_number(args->target_city_id)) {
208 request_do_action(ACTION_HELP_WONDER, args->actor_unit_id,
209 args->target_city_id, 0);
212 gtk_widget_destroy(act_sel_dialog);
213 free(args);
216 /**************************************************************************
217 Returns a string with how many shields remains of the current production.
218 This is useful as custom information on the help build wonder button.
219 **************************************************************************/
220 static const gchar *city_prod_remaining(struct city* destcity)
222 if (destcity == NULL
223 || city_owner(destcity) != client.conn.playing) {
224 /* Can't give remaining production for a foreign or non existing
225 * city. */
226 return NULL;
229 return g_strdup_printf(_("%d remaining"),
230 impr_build_shield_cost(
231 destcity->production.value.building)
232 - destcity->shield_stock);
235 /**********************************************************************
236 User responded to bribe dialog
237 **********************************************************************/
238 static void bribe_response(GtkWidget *w, gint response, gpointer data)
240 struct action_data *args = (struct action_data *)data;
242 if (response == GTK_RESPONSE_YES) {
243 request_do_action(ACTION_SPY_BRIBE_UNIT, args->actor_unit_id,
244 args->target_unit_id, 0);
247 gtk_widget_destroy(w);
248 free(args);
250 /* The user have answered the follow up question. Move on. */
251 diplomat_queue_handle_secondary();
254 /****************************************************************
255 Ask the server how much the bribe is
256 *****************************************************************/
257 static void diplomat_bribe_callback(GtkWidget *w, gpointer data)
259 struct action_data *args = (struct action_data *)data;
261 if (NULL != game_unit_by_number(args->actor_unit_id)
262 && NULL != game_unit_by_number(args->target_unit_id)) {
263 request_action_details(ACTION_SPY_BRIBE_UNIT, args->actor_unit_id,
264 args->target_unit_id);
267 /* Wait for the server's reply before moving on to the next unit that
268 * needs to know what action to take. */
269 is_more_user_input_needed = TRUE;
271 gtk_widget_destroy(act_sel_dialog);
272 free(args);
275 /*************************************************************************
276 Popup unit bribe dialog
277 **************************************************************************/
278 void popup_bribe_dialog(struct unit *actor, struct unit *punit, int cost)
280 GtkWidget *shell;
281 char buf[1024];
283 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
284 "Treasury contains %d gold.",
285 client_player()->economic.gold),
286 client_player()->economic.gold);
288 if (cost <= client_player()->economic.gold) {
289 shell = gtk_message_dialog_new(NULL, 0,
290 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
291 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
292 PL_("Bribe unit for %d gold?\n%s",
293 "Bribe unit for %d gold?\n%s", cost), cost, buf);
294 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
295 setup_dialog(shell, toplevel);
296 } else {
297 shell = gtk_message_dialog_new(NULL, 0,
298 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
299 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
300 PL_("Bribing the unit costs %d gold.\n%s",
301 "Bribing the unit costs %d gold.\n%s", cost), cost, buf);
302 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
303 setup_dialog(shell, toplevel);
305 gtk_window_present(GTK_WINDOW(shell));
307 g_signal_connect(shell, "response", G_CALLBACK(bribe_response),
308 act_data(actor->id, 0, punit->id, 0, cost));
311 /****************************************************************
312 User selected sabotaging from choice dialog
313 *****************************************************************/
314 static void diplomat_sabotage_callback(GtkWidget *w, gpointer data)
316 struct action_data *args = (struct action_data *)data;
318 if (NULL != game_unit_by_number(args->actor_unit_id)
319 && NULL != game_city_by_number(args->target_city_id)) {
320 request_do_action(ACTION_SPY_SABOTAGE_CITY, args->actor_unit_id,
321 args->target_city_id, B_LAST + 1);
324 gtk_widget_destroy(act_sel_dialog);
325 free(args);
328 /****************************************************************
329 User selected investigating from choice dialog
330 *****************************************************************/
331 static void diplomat_investigate_callback(GtkWidget *w, gpointer data)
333 struct action_data *args = (struct action_data *)data;
335 if (NULL != game_city_by_number(args->target_city_id)
336 && NULL != game_unit_by_number(args->actor_unit_id)) {
337 request_do_action(ACTION_SPY_INVESTIGATE_CITY, args->actor_unit_id,
338 args->target_city_id, 0);
341 gtk_widget_destroy(act_sel_dialog);
342 free(args);
345 /****************************************************************
346 User selected unit sabotaging from choice dialog
347 *****************************************************************/
348 static void spy_sabotage_unit_callback(GtkWidget *w, gpointer data)
350 struct action_data *args = (struct action_data *)data;
352 request_do_action(ACTION_SPY_SABOTAGE_UNIT, args->actor_unit_id,
353 args->target_unit_id, 0);
355 gtk_widget_destroy(act_sel_dialog);
356 free(args);
359 /****************************************************************
360 User selected embassy establishing from choice dialog
361 *****************************************************************/
362 static void diplomat_embassy_callback(GtkWidget *w, gpointer data)
364 struct action_data *args = (struct action_data *)data;
366 if (NULL != game_unit_by_number(args->actor_unit_id)
367 && NULL != game_city_by_number(args->target_city_id)) {
368 request_do_action(ACTION_ESTABLISH_EMBASSY, args->actor_unit_id,
369 args->target_city_id, 0);
372 gtk_widget_destroy(act_sel_dialog);
373 free(args);
376 /****************************************************************
377 User selected to steal gold from choice dialog
378 *****************************************************************/
379 static void spy_steal_gold_callback(GtkWidget *w, gpointer data)
381 struct action_data *args = (struct action_data *)data;
383 if (NULL != game_unit_by_number(args->actor_unit_id)
384 && NULL != game_city_by_number(args->target_city_id)) {
385 request_do_action(ACTION_SPY_STEAL_GOLD, args->actor_unit_id,
386 args->target_city_id, 0);
389 gtk_widget_destroy(act_sel_dialog);
390 free(args);
393 /****************************************************************
394 User selected poisoning from choice dialog
395 *****************************************************************/
396 static void spy_poison_callback(GtkWidget *w, gpointer data)
398 struct action_data *args = (struct action_data *)data;
400 if (NULL != game_unit_by_number(args->actor_unit_id)
401 && NULL != game_city_by_number(args->target_city_id)) {
402 request_do_action(ACTION_SPY_POISON, args->actor_unit_id,
403 args->target_city_id, 0);
406 gtk_widget_destroy(act_sel_dialog);
407 free(args);
410 /****************************************************************
411 User selected stealing from choice dialog
412 *****************************************************************/
413 static void diplomat_steal_callback(GtkWidget *w, gpointer data)
415 struct action_data *args = (struct action_data *)data;
417 if (NULL != game_unit_by_number(args->actor_unit_id)
418 && NULL != game_city_by_number(args->target_city_id)) {
419 request_do_action(ACTION_SPY_STEAL_TECH, args->actor_unit_id,
420 args->target_city_id, A_UNSET);
423 gtk_widget_destroy(act_sel_dialog);
424 free(args);
427 /****************************************************************
428 User responded to steal advances dialog
429 *****************************************************************/
430 static void spy_advances_response(GtkWidget *w, gint response,
431 gpointer data)
433 struct action_data *args = (struct action_data *)data;
435 if (response == GTK_RESPONSE_ACCEPT && args->value > 0) {
436 if (NULL != game_unit_by_number(args->actor_unit_id)
437 && NULL != game_city_by_number(args->target_city_id)) {
438 if (args->value == A_UNSET) {
439 /* This is the untargeted version. */
440 request_do_action(ACTION_SPY_STEAL_TECH,
441 args->actor_unit_id, args->target_city_id,
442 args->value);
443 } else {
444 /* This is the targeted version. */
445 request_do_action(ACTION_SPY_TARGETED_STEAL_TECH,
446 args->actor_unit_id, args->target_city_id,
447 args->value);
452 gtk_widget_destroy(spy_tech_shell);
453 spy_tech_shell = NULL;
454 free(data);
456 /* The user have answered the follow up question. Move on. */
457 diplomat_queue_handle_secondary();
460 /****************************************************************
461 User selected entry in steal advances dialog
462 *****************************************************************/
463 static void spy_advances_callback(GtkTreeSelection *select,
464 gpointer data)
466 struct action_data *args = (struct action_data *)data;
468 GtkTreeModel *model;
469 GtkTreeIter it;
471 if (gtk_tree_selection_get_selected(select, &model, &it)) {
472 gtk_tree_model_get(model, &it, 1, &(args->value), -1);
474 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
475 GTK_RESPONSE_ACCEPT, TRUE);
476 } else {
477 args->value = 0;
479 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
480 GTK_RESPONSE_ACCEPT, FALSE);
484 /****************************************************************
485 Create spy's tech stealing dialog
486 *****************************************************************/
487 static void create_advances_list(struct player *pplayer,
488 struct player *pvictim,
489 struct action_data *args)
491 GtkWidget *sw, *label, *vbox, *view;
492 GtkListStore *store;
493 GtkCellRenderer *rend;
494 GtkTreeViewColumn *col;
496 struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
498 spy_tech_shell = gtk_dialog_new_with_buttons(_("Steal Technology"),
499 NULL, 0,
500 _("Cancel"), GTK_RESPONSE_CANCEL,
501 _("_Steal"), GTK_RESPONSE_ACCEPT,
502 NULL);
503 setup_dialog(spy_tech_shell, toplevel);
504 gtk_window_set_position(GTK_WINDOW(spy_tech_shell), GTK_WIN_POS_MOUSE);
506 gtk_dialog_set_default_response(GTK_DIALOG(spy_tech_shell),
507 GTK_RESPONSE_ACCEPT);
509 label = gtk_frame_new(_("Select Advance to Steal"));
510 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell))), label);
512 vbox = gtk_grid_new();
513 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
514 GTK_ORIENTATION_VERTICAL);
515 gtk_grid_set_row_spacing(GTK_GRID(vbox), 6);
516 gtk_container_add(GTK_CONTAINER(label), vbox);
518 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
520 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
521 gtk_widget_set_hexpand(view, TRUE);
522 gtk_widget_set_vexpand(view, TRUE);
523 g_object_unref(store);
524 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
526 rend = gtk_cell_renderer_text_new();
527 col = gtk_tree_view_column_new_with_attributes(NULL, rend,
528 "text", 0, NULL);
529 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
531 label = g_object_new(GTK_TYPE_LABEL,
532 "use-underline", TRUE,
533 "mnemonic-widget", view,
534 "label", _("_Advances:"),
535 "xalign", 0.0,
536 "yalign", 0.5,
537 NULL);
538 gtk_container_add(GTK_CONTAINER(vbox), label);
540 sw = gtk_scrolled_window_new(NULL, NULL);
541 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
542 GTK_SHADOW_ETCHED_IN);
543 gtk_container_add(GTK_CONTAINER(sw), view);
545 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
546 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
547 gtk_widget_set_size_request(sw, -1, 200);
549 gtk_container_add(GTK_CONTAINER(vbox), sw);
551 /* Now populate the list */
552 if (pvictim) { /* you don't want to know what lag can do -- Syela */
553 const struct research *presearch = research_get(pplayer);
554 const struct research *vresearch = research_get(pvictim);
555 GtkTreeIter it;
556 GValue value = { 0, };
558 advance_index_iterate(A_FIRST, i) {
559 if (research_invention_gettable(presearch, i,
560 game.info.tech_steal_allow_holes)
561 && research_invention_state(vresearch, i) == TECH_KNOWN
562 && research_invention_state(presearch, i) != TECH_KNOWN) {
563 gtk_list_store_append(store, &it);
565 g_value_init(&value, G_TYPE_STRING);
566 g_value_set_static_string(&value, research_advance_name_translation
567 (presearch, i));
568 gtk_list_store_set_value(store, &it, 0, &value);
569 g_value_unset(&value);
570 gtk_list_store_set(store, &it, 1, i, -1);
572 } advance_index_iterate_end;
574 if (action_prob_possible(
575 actor_unit->client.act_prob_cache[ACTION_SPY_STEAL_TECH])) {
576 gtk_list_store_append(store, &it);
578 g_value_init(&value, G_TYPE_STRING);
580 struct astring str = ASTRING_INIT;
581 /* TRANS: %s is a unit name, e.g., Spy */
582 astr_set(&str, _("At %s's Discretion"),
583 unit_name_translation(actor_unit));
584 g_value_set_string(&value, astr_str(&str));
585 astr_free(&str);
587 gtk_list_store_set_value(store, &it, 0, &value);
588 g_value_unset(&value);
589 gtk_list_store_set(store, &it, 1, A_UNSET, -1);
593 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
594 GTK_RESPONSE_ACCEPT, FALSE);
596 gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell)));
598 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), "changed",
599 G_CALLBACK(spy_advances_callback), args);
600 g_signal_connect(spy_tech_shell, "response",
601 G_CALLBACK(spy_advances_response), args);
603 args->value = 0;
605 gtk_tree_view_focus(GTK_TREE_VIEW(view));
608 /****************************************************************
609 User has responded to spy's sabotage building dialog
610 *****************************************************************/
611 static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
613 struct action_data *args = (struct action_data *)data;
615 if (response == GTK_RESPONSE_ACCEPT && args->value > -2) {
616 if (NULL != game_unit_by_number(args->actor_unit_id)
617 && NULL != game_city_by_number(args->target_city_id)) {
618 if (args->value == B_LAST) {
619 /* This is the untargeted version. */
620 request_do_action(ACTION_SPY_SABOTAGE_CITY,
621 args->actor_unit_id,
622 args->target_city_id,
623 args->value + 1);
624 } else {
625 /* This is the targeted version. */
626 request_do_action(ACTION_SPY_TARGETED_SABOTAGE_CITY,
627 args->actor_unit_id,
628 args->target_city_id,
629 args->value + 1);
634 gtk_widget_destroy(spy_sabotage_shell);
635 spy_sabotage_shell = NULL;
636 free(args);
638 /* The user have answered the follow up question. Move on. */
639 diplomat_queue_handle_secondary();
642 /****************************************************************
643 User has selected new building from spy's sabotage dialog
644 *****************************************************************/
645 static void spy_improvements_callback(GtkTreeSelection *select, gpointer data)
647 struct action_data *args = (struct action_data *)data;
649 GtkTreeModel *model;
650 GtkTreeIter it;
652 if (gtk_tree_selection_get_selected(select, &model, &it)) {
653 gtk_tree_model_get(model, &it, 1, &(args->value), -1);
655 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
656 GTK_RESPONSE_ACCEPT, TRUE);
657 } else {
658 args->value = -2;
660 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
661 GTK_RESPONSE_ACCEPT, FALSE);
665 /****************************************************************
666 Creates spy's building sabotaging dialog
667 *****************************************************************/
668 static void create_improvements_list(struct player *pplayer,
669 struct city *pcity,
670 struct action_data *args)
672 GtkWidget *sw, *label, *vbox, *view;
673 GtkListStore *store;
674 GtkCellRenderer *rend;
675 GtkTreeViewColumn *col;
676 GtkTreeIter it;
678 struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
680 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
681 NULL, 0,
682 _("Cancel"), GTK_RESPONSE_CANCEL,
683 _("_Sabotage"), GTK_RESPONSE_ACCEPT,
684 NULL);
685 setup_dialog(spy_sabotage_shell, toplevel);
686 gtk_window_set_position(GTK_WINDOW(spy_sabotage_shell), GTK_WIN_POS_MOUSE);
688 gtk_dialog_set_default_response(GTK_DIALOG(spy_sabotage_shell),
689 GTK_RESPONSE_ACCEPT);
691 label = gtk_frame_new(_("Select Improvement to Sabotage"));
692 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(spy_sabotage_shell))), label);
694 vbox = gtk_grid_new();
695 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
696 GTK_ORIENTATION_VERTICAL);
697 gtk_grid_set_row_spacing(GTK_GRID(vbox), 6);
698 gtk_container_add(GTK_CONTAINER(label), vbox);
700 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
702 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
703 gtk_widget_set_hexpand(view, TRUE);
704 gtk_widget_set_vexpand(view, TRUE);
705 g_object_unref(store);
706 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
708 rend = gtk_cell_renderer_text_new();
709 col = gtk_tree_view_column_new_with_attributes(NULL, rend,
710 "text", 0, NULL);
711 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
713 label = g_object_new(GTK_TYPE_LABEL,
714 "use-underline", TRUE,
715 "mnemonic-widget", view,
716 "label", _("_Improvements:"),
717 "xalign", 0.0,
718 "yalign", 0.5,
719 NULL);
720 gtk_container_add(GTK_CONTAINER(vbox), label);
722 sw = gtk_scrolled_window_new(NULL, NULL);
723 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
724 GTK_SHADOW_ETCHED_IN);
725 gtk_container_add(GTK_CONTAINER(sw), view);
727 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
728 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
729 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw), 200);
731 gtk_container_add(GTK_CONTAINER(vbox), sw);
733 /* Now populate the list */
734 gtk_list_store_append(store, &it);
735 gtk_list_store_set(store, &it, 0, _("City Production"), 1, -1, -1);
737 city_built_iterate(pcity, pimprove) {
738 if (pimprove->sabotage > 0) {
739 gtk_list_store_append(store, &it);
740 gtk_list_store_set(store, &it,
741 0, city_improvement_name_translation(pcity, pimprove),
742 1, improvement_number(pimprove),
743 -1);
745 } city_built_iterate_end;
747 if (action_prob_possible(
748 actor_unit->client.act_prob_cache[ACTION_SPY_SABOTAGE_CITY])) {
749 struct astring str = ASTRING_INIT;
751 gtk_list_store_append(store, &it);
753 /* TRANS: %s is a unit name, e.g., Spy */
754 astr_set(&str, _("At %s's Discretion"),
755 unit_name_translation(actor_unit));
756 gtk_list_store_set(store, &it, 0, astr_str(&str), 1, B_LAST, -1);
758 astr_free(&str);
761 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
762 GTK_RESPONSE_ACCEPT, FALSE);
764 gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(spy_sabotage_shell)));
766 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), "changed",
767 G_CALLBACK(spy_improvements_callback), args);
768 g_signal_connect(spy_sabotage_shell, "response",
769 G_CALLBACK(spy_improvements_response), args);
771 args->value = -2;
773 gtk_tree_view_focus(GTK_TREE_VIEW(view));
776 /****************************************************************
777 Popup tech stealing dialog with list of possible techs
778 *****************************************************************/
779 static void spy_steal_popup(GtkWidget *w, gpointer data)
781 struct action_data *args = (struct action_data *)data;
783 struct city *pvcity = game_city_by_number(args->target_city_id);
784 struct player *pvictim = NULL;
786 if (pvcity) {
787 pvictim = city_owner(pvcity);
790 /* it is concievable that pvcity will not be found, because something
791 has happened to the city during latency. Therefore we must initialize
792 pvictim to NULL and account for !pvictim in create_advances_list. -- Syela */
794 /* FIXME: Don't discard the second tech choice dialog. */
795 if (!spy_tech_shell) {
796 create_advances_list(client.conn.playing, pvictim, args);
797 gtk_window_present(GTK_WINDOW(spy_tech_shell));
798 } else {
799 free(args);
802 /* Wait for the server's reply before moving on to the next unit that
803 * needs to know what action to take. */
804 is_more_user_input_needed = TRUE;
806 gtk_widget_destroy(act_sel_dialog);
809 /****************************************************************
810 Requests up-to-date list of improvements, the return of
811 which will trigger the popup_sabotage_dialog() function.
812 *****************************************************************/
813 static void spy_request_sabotage_list(GtkWidget *w, gpointer data)
815 struct action_data *args = (struct action_data *)data;
817 if (NULL != game_unit_by_number(args->actor_unit_id)
818 && NULL != game_city_by_number(args->target_city_id)) {
819 request_action_details(ACTION_SPY_TARGETED_SABOTAGE_CITY,
820 args->actor_unit_id,
821 args->target_city_id);
824 /* Wait for the server's reply before moving on to the next unit that
825 * needs to know what action to take. */
826 is_more_user_input_needed = TRUE;
828 gtk_widget_destroy(act_sel_dialog);
829 free(args);
832 /*************************************************************************
833 Pops-up the Spy sabotage dialog, upon return of list of
834 available improvements requested by the above function.
835 **************************************************************************/
836 void popup_sabotage_dialog(struct unit *actor, struct city *pcity)
838 /* FIXME: Don't discard the second target choice dialog. */
839 if (!spy_sabotage_shell) {
840 create_improvements_list(client.conn.playing, pcity,
841 act_data(actor->id, pcity->id, 0, 0, 0));
842 gtk_window_present(GTK_WINDOW(spy_sabotage_shell));
846 /****************************************************************
847 ... Ask the server how much the revolt is going to cost us
848 *****************************************************************/
849 static void diplomat_incite_callback(GtkWidget *w, gpointer data)
851 struct action_data *args = (struct action_data *)data;
853 if (NULL != game_unit_by_number(args->actor_unit_id)
854 && NULL != game_city_by_number(args->target_city_id)) {
855 request_action_details(ACTION_SPY_INCITE_CITY, args->actor_unit_id,
856 args->target_city_id);
859 /* Wait for the server's reply before moving on to the next unit that
860 * needs to know what action to take. */
861 is_more_user_input_needed = TRUE;
863 gtk_widget_destroy(act_sel_dialog);
864 free(args);
867 /************************************************************************
868 User has responded to incite dialog
869 ************************************************************************/
870 static void incite_response(GtkWidget *w, gint response, gpointer data)
872 struct action_data *args = (struct action_data *)data;
874 if (response == GTK_RESPONSE_YES) {
875 request_do_action(ACTION_SPY_INCITE_CITY, args->actor_unit_id,
876 args->target_city_id, 0);
879 gtk_widget_destroy(w);
880 free(args);
882 /* The user have answered the follow up question. Move on. */
883 diplomat_queue_handle_secondary();
886 /*************************************************************************
887 Popup the yes/no dialog for inciting, since we know the cost now
888 **************************************************************************/
889 void popup_incite_dialog(struct unit *actor, struct city *pcity, int cost)
891 GtkWidget *shell;
892 char buf[1024];
894 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
895 "Treasury contains %d gold.",
896 client_player()->economic.gold),
897 client_player()->economic.gold);
899 if (INCITE_IMPOSSIBLE_COST == cost) {
900 shell = gtk_message_dialog_new(NULL, 0,
901 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
902 _("You can't incite a revolt in %s."),
903 city_name_get(pcity));
904 gtk_window_set_title(GTK_WINDOW(shell), _("City can't be incited!"));
905 setup_dialog(shell, toplevel);
906 } else if (cost <= client_player()->economic.gold) {
907 shell = gtk_message_dialog_new(NULL, 0,
908 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
909 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
910 PL_("Incite a revolt for %d gold?\n%s",
911 "Incite a revolt for %d gold?\n%s", cost), cost, buf);
912 gtk_window_set_title(GTK_WINDOW(shell), _("Incite a Revolt!"));
913 setup_dialog(shell, toplevel);
914 } else {
915 shell = gtk_message_dialog_new(NULL,
917 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
918 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
919 PL_("Inciting a revolt costs %d gold.\n%s",
920 "Inciting a revolt costs %d gold.\n%s", cost), cost, buf);
921 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
922 setup_dialog(shell, toplevel);
924 gtk_window_present(GTK_WINDOW(shell));
926 g_signal_connect(shell, "response", G_CALLBACK(incite_response),
927 act_data(actor->id, pcity->id, 0, 0, cost));
930 /**************************************************************************
931 Callback from the unit target selection dialog.
932 **************************************************************************/
933 static void tgt_unit_change_callback(GtkWidget *dlg, gint arg)
935 int act_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
937 if (arg == GTK_RESPONSE_YES) {
938 struct unit *actor = game_unit_by_number(act_id);
940 if (actor != NULL) {
941 int tgt_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
942 "target"));
943 struct unit *tgt_unit = game_unit_by_number(tgt_id);
944 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
946 if (tgt_unit == NULL) {
947 /* Make the action dialog pop up again. */
948 dsend_packet_unit_get_actions(&client.conn,
949 actor->id,
950 /* Let the server choose the target
951 * unit. */
952 IDENTITY_NUMBER_ZERO,
953 /* Let the server choose the target
954 * city. */
955 IDENTITY_NUMBER_ZERO,
956 tgt_tile->index,
957 TRUE);
958 } else {
959 dsend_packet_unit_get_actions(&client.conn,
960 actor->id,
961 tgt_id,
962 /* Let the server choose the target
963 * city. */
964 IDENTITY_NUMBER_ZERO,
965 tgt_tile->index,
966 TRUE);
969 } else {
970 /* Dialog canceled. This ends the action selection process. */
971 action_selection_no_longer_in_progress(act_id);
974 gtk_widget_destroy(dlg);
977 /**************************************************************************
978 Callback from action selection dialog for "Change unit target".
979 **************************************************************************/
980 static void act_sel_new_unit_tgt_callback(GtkWidget *w, gpointer data)
982 struct action_data *args = (struct action_data *)data;
984 struct unit *punit;
985 struct unit *tunit;
986 struct tile *ptile;
988 if ((punit = game_unit_by_number(args->actor_unit_id))
989 && (ptile = index_to_tile(args->target_tile_id))
990 && (tunit = game_unit_by_number(args->target_unit_id))) {
991 select_tgt_unit(punit, ptile, ptile->units, tunit,
992 _("Target unit selection"),
993 _("Looking for target unit:"),
994 _("Units at tile:"),
995 _("Select"),
996 G_CALLBACK(tgt_unit_change_callback));
999 did_not_decide = TRUE;
1000 action_selection_restart = TRUE;
1001 gtk_widget_destroy(act_sel_dialog);
1002 free(args);
1005 /**************************************************************************
1006 Callback from action selection dialog for "Show Location".
1007 **************************************************************************/
1008 static void act_sel_location_callback(GtkWidget *w, gpointer data)
1010 struct action_data *args = (struct action_data *)data;
1012 struct unit *punit;
1014 if ((punit = game_unit_by_number(args->actor_unit_id))) {
1015 center_tile_mapcanvas(unit_tile(punit));
1019 /**************************************************************************
1020 Callback from action selection dialog for "keep moving".
1021 (This should only occur when entering a tile that has an allied city or
1022 an allied unit.)
1023 **************************************************************************/
1024 static void act_sel_keep_moving_callback(GtkWidget *w, gpointer data)
1026 struct action_data *args = (struct action_data *)data;
1028 struct unit *punit;
1029 struct tile *ptile;
1031 if ((punit = game_unit_by_number(args->actor_unit_id))
1032 && (ptile = index_to_tile(args->target_tile_id))
1033 && !same_pos(unit_tile(punit), ptile)) {
1034 request_unit_non_action_move(punit, ptile);
1037 gtk_widget_destroy(act_sel_dialog);
1038 free(args);
1041 /**************************************************************************
1042 Delay selection of what action to take.
1043 **************************************************************************/
1044 static void act_sel_wait_callback(GtkWidget *w, gpointer data)
1046 struct action_data *args = (struct action_data *)data;
1048 key_unit_wait();
1050 /* the dialog was destroyed when key_unit_wait() resulted in
1051 * action_selection_close() being called. */
1053 free(args);
1056 /****************************************************************
1057 Action selection dialog has been destroyed
1058 *****************************************************************/
1059 static void act_sel_destroy_callback(GtkWidget *w, gpointer data)
1061 act_sel_dialog = NULL;
1062 diplomat_queue_handle_primary();
1065 /****************************************************************
1066 Action selection dialog has been canceled
1067 *****************************************************************/
1068 static void act_sel_cancel_callback(GtkWidget *w, gpointer data)
1070 gtk_widget_destroy(act_sel_dialog);
1071 free(data);
1074 /****************************************************************
1075 Action selection dialog has been closed
1076 *****************************************************************/
1077 static void act_sel_close_callback(GtkWidget *w,
1078 gint response_id,
1079 gpointer data)
1081 gtk_widget_destroy(act_sel_dialog);
1082 free(data);
1085 /* Mapping from an action to the function to call when its button is
1086 * pushed. */
1087 static const GCallback af_map[ACTION_COUNT] = {
1088 /* Unit acting against a city target. */
1089 [ACTION_ESTABLISH_EMBASSY] = (GCallback)diplomat_embassy_callback,
1090 [ACTION_SPY_INVESTIGATE_CITY] = (GCallback)diplomat_investigate_callback,
1091 [ACTION_SPY_POISON] = (GCallback)spy_poison_callback,
1092 [ACTION_SPY_STEAL_GOLD] = (GCallback)spy_steal_gold_callback,
1093 [ACTION_SPY_SABOTAGE_CITY] = (GCallback)diplomat_sabotage_callback,
1094 [ACTION_SPY_TARGETED_SABOTAGE_CITY] =
1095 (GCallback)spy_request_sabotage_list,
1096 [ACTION_SPY_STEAL_TECH] = (GCallback)diplomat_steal_callback,
1097 [ACTION_SPY_TARGETED_STEAL_TECH] = (GCallback)spy_steal_popup,
1098 [ACTION_SPY_INCITE_CITY] = (GCallback)diplomat_incite_callback,
1099 [ACTION_TRADE_ROUTE] = (GCallback)caravan_establish_trade_callback,
1100 [ACTION_MARKETPLACE] = (GCallback)caravan_marketplace_callback,
1101 [ACTION_HELP_WONDER] = (GCallback)caravan_help_build_wonder_callback,
1103 /* Unit acting against a unit target. */
1104 [ACTION_SPY_BRIBE_UNIT] = (GCallback)diplomat_bribe_callback,
1105 [ACTION_SPY_SABOTAGE_UNIT] = (GCallback)spy_sabotage_unit_callback
1108 /******************************************************************
1109 Show the user the action if it is enabled.
1110 *******************************************************************/
1111 static void action_entry(GtkWidget *shl,
1112 int action_id,
1113 const struct act_prob *act_probs,
1114 const gchar *custom,
1115 struct action_data *handler_args)
1117 const gchar *label;
1118 const gchar *tooltip;
1120 if (action_id == ACTION_SPY_SABOTAGE_CITY
1121 && action_prob_possible(
1122 act_probs[ACTION_SPY_TARGETED_SABOTAGE_CITY])) {
1123 /* The player can select Sabotage City from the target selection dialog
1124 * of Targeted Sabotage City. */
1125 return;
1128 if (action_id == ACTION_SPY_STEAL_TECH
1129 && action_prob_possible(
1130 act_probs[ACTION_SPY_TARGETED_STEAL_TECH])) {
1131 /* The player can select Steal Tech from the target selection dialog of
1132 * Targeted Steal Tech. */
1133 return;
1136 /* Don't show disabled actions. */
1137 if (!action_prob_possible(act_probs[action_id])) {
1138 return;
1141 label = action_prepare_ui_name(action_id, "_",
1142 act_probs[action_id],
1143 custom);
1145 tooltip = action_get_tool_tip(action_id,
1146 act_probs[action_id]);
1148 action_button_map[action_id] = choice_dialog_get_number_of_buttons(shl);
1149 choice_dialog_add(shl, label, af_map[action_id], handler_args,
1150 FALSE, tooltip);
1153 /******************************************************************
1154 Update an existing button.
1155 *******************************************************************/
1156 static void action_entry_update(GtkWidget *shl,
1157 int action_id,
1158 const struct act_prob *act_probs,
1159 const gchar *custom,
1160 struct action_data *handler_args)
1162 const gchar *label;
1163 const gchar *tooltip;
1165 /* An action that just became impossible has its button disabled.
1166 * An action that became possible again must be reenabled. */
1167 choice_dialog_button_set_sensitive(act_sel_dialog,
1168 action_button_map[action_id],
1169 action_prob_possible(act_probs[action_id]));
1171 /* The probability may have changed. */
1172 label = action_prepare_ui_name(action_id, "_",
1173 act_probs[action_id], custom);
1175 tooltip = action_get_tool_tip(action_id,
1176 act_probs[action_id]);
1178 choice_dialog_button_set_label(act_sel_dialog,
1179 action_button_map[action_id],
1180 label);
1181 choice_dialog_button_set_tooltip(act_sel_dialog,
1182 action_button_map[action_id],
1183 tooltip);
1186 /**************************************************************************
1187 Popup a dialog that allows the player to select what action a unit
1188 should take.
1189 **************************************************************************/
1190 void popup_action_selection(struct unit *actor_unit,
1191 struct city *target_city,
1192 struct unit *target_unit,
1193 struct tile *target_tile,
1194 const struct act_prob *act_probs)
1196 GtkWidget *shl;
1197 struct astring title = ASTRING_INIT, text = ASTRING_INIT;
1198 struct city *actor_homecity;
1200 int button_id;
1202 struct action_data *data =
1203 act_data(actor_unit->id,
1204 (target_city) ? target_city->id : 0,
1205 (target_unit) ? target_unit->id : 0,
1206 (target_tile) ? target_tile->index : 0,
1209 /* Could be caused by the server failing to reply to a request for more
1210 * information or a bug in the client code. */
1211 fc_assert_msg(!is_more_user_input_needed,
1212 "Diplomat queue problem. Is another diplomat window open?");
1214 /* No extra input is required as no action has been chosen yet. */
1215 is_more_user_input_needed = FALSE;
1217 /* No buttons are added yet. */
1218 for (button_id = 0; button_id < BUTTON_COUNT; button_id++) {
1219 action_button_map[button_id] = BUTTON_NOT_THERE;
1222 actor_homecity = game_city_by_number(actor_unit->homecity);
1224 actor_unit_id = actor_unit->id;
1225 target_ids[ATK_CITY] = target_city ?
1226 target_city->id :
1227 IDENTITY_NUMBER_ZERO;
1228 target_ids[ATK_UNIT] = target_unit ?
1229 target_unit->id :
1230 IDENTITY_NUMBER_ZERO;
1232 astr_set(&title,
1233 /* TRANS: %s is a unit name, e.g., Spy */
1234 _("Choose Your %s's Strategy"),
1235 unit_name_translation(actor_unit));
1237 if (target_city && actor_homecity) {
1238 astr_set(&text,
1239 _("Your %s from %s reaches the city of %s.\nWhat now?"),
1240 unit_name_translation(actor_unit),
1241 city_name_get(actor_homecity),
1242 city_name_get(target_city));
1243 } else if (target_city) {
1244 astr_set(&text,
1245 _("Your %s has arrived at %s.\nWhat is your command?"),
1246 unit_name_translation(actor_unit),
1247 city_name_get(target_city));
1248 } else if (target_unit) {
1249 astr_set(&text,
1250 /* TRANS: Your Spy is ready to act against Roman Freight. */
1251 _("Your %s is ready to act against %s %s."),
1252 unit_name_translation(actor_unit),
1253 nation_adjective_for_player(unit_owner(target_unit)),
1254 unit_name_translation(target_unit));
1255 } else {
1256 fc_assert_msg(target_unit || target_city,
1257 "No target unit or target city specified.");
1258 astr_set(&text,
1259 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
1260 _("Your %s is waiting for your command."),
1261 unit_name_translation(actor_unit));
1264 shl = choice_dialog_start(GTK_WINDOW(toplevel), astr_str(&title),
1265 astr_str(&text));
1267 /* Unit acting against a city */
1269 action_iterate(act) {
1270 if (action_id_get_actor_kind(act) == AAK_UNIT
1271 && action_id_get_target_kind(act) == ATK_CITY) {
1272 action_entry(shl,
1273 (enum gen_action)act,
1274 act_probs,
1275 act == ACTION_HELP_WONDER ?
1276 city_prod_remaining(target_city) : NULL,
1277 data);
1279 } action_iterate_end;
1281 /* Unit acting against another unit */
1283 action_iterate(act) {
1284 if (action_id_get_actor_kind(act) == AAK_UNIT
1285 && action_id_get_target_kind(act) == ATK_UNIT) {
1286 action_entry(shl,
1287 (enum gen_action)act,
1288 act_probs,
1289 NULL,
1290 data);
1292 } action_iterate_end;
1294 if (unit_can_move_to_tile(actor_unit, target_tile, FALSE)
1295 || (is_military_unit(actor_unit) || is_attack_unit(actor_unit))
1296 || (can_unit_bombard(actor_unit) && !is_ocean_tile(target_tile))
1297 || (!target_city && unit_has_type_flag(actor_unit, UTYF_CAPTURER))) {
1298 action_button_map[BUTTON_MOVE] =
1299 choice_dialog_get_number_of_buttons(shl);
1300 choice_dialog_add(shl, _("Keep moving"),
1301 (GCallback)act_sel_keep_moving_callback,
1302 data, FALSE, NULL);
1305 if (target_unit != NULL
1306 && unit_list_size(target_tile->units) > 1) {
1307 action_button_map[BUTTON_NEW_UNIT_TGT] =
1308 choice_dialog_get_number_of_buttons(shl);
1309 choice_dialog_add(shl, _("Change unit target"),
1310 (GCallback)act_sel_new_unit_tgt_callback,
1311 data, TRUE, NULL);
1314 action_button_map[BUTTON_LOCATION] =
1315 choice_dialog_get_number_of_buttons(shl);
1316 choice_dialog_add(shl, _("Show Location"),
1317 (GCallback)act_sel_location_callback, data,
1318 TRUE, NULL);
1320 action_button_map[BUTTON_WAIT] =
1321 choice_dialog_get_number_of_buttons(shl);
1322 choice_dialog_add(shl, _("_Wait"),
1323 (GCallback)act_sel_wait_callback, data,
1324 TRUE, NULL);
1326 action_button_map[BUTTON_CANCEL] =
1327 choice_dialog_get_number_of_buttons(shl);
1328 choice_dialog_add(shl, _("Cancel"),
1329 (GCallback)act_sel_cancel_callback, data,
1330 FALSE, NULL);
1332 choice_dialog_end(shl);
1334 act_sel_dialog = shl;
1336 choice_dialog_set_hide(shl, TRUE);
1337 g_signal_connect(shl, "destroy",
1338 G_CALLBACK(act_sel_destroy_callback), NULL);
1339 g_signal_connect(shl, "delete_event",
1340 G_CALLBACK(act_sel_close_callback), data);
1342 /* Give follow up questions access to action probabilities. */
1343 client_unit_init_act_prob_cache(actor_unit);
1344 action_iterate(act) {
1345 actor_unit->client.act_prob_cache[act] = act_probs[act];
1346 } action_iterate_end;
1348 astr_free(&title);
1349 astr_free(&text);
1352 /**************************************************************************
1353 Returns the id of the actor unit currently handled in action selection
1354 dialog when the action selection dialog is open.
1355 Returns IDENTITY_NUMBER_ZERO if no action selection dialog is open.
1356 **************************************************************************/
1357 int action_selection_actor_unit(void)
1359 if (act_sel_dialog == NULL) {
1360 return IDENTITY_NUMBER_ZERO;
1362 return actor_unit_id;
1365 /**************************************************************************
1366 Returns id of the target city of the actions currently handled in action
1367 selection dialog when the action selection dialog is open and it has a
1368 city target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1369 is open or no city target is present in the action selection dialog.
1370 **************************************************************************/
1371 int action_selection_target_city(void)
1373 if (act_sel_dialog == NULL) {
1374 return IDENTITY_NUMBER_ZERO;
1376 return target_ids[ATK_CITY];
1379 /**************************************************************************
1380 Returns id of the target unit of the actions currently handled in action
1381 selection dialog when the action selection dialog is open and it has a
1382 unit target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1383 is open or no unit target is present in the action selection dialog.
1384 **************************************************************************/
1385 int action_selection_target_unit(void)
1387 if (act_sel_dialog == NULL) {
1388 return IDENTITY_NUMBER_ZERO;
1391 return target_ids[ATK_UNIT];
1394 /**************************************************************************
1395 Updates the action selection dialog with new information.
1396 **************************************************************************/
1397 void action_selection_refresh(struct unit *actor_unit,
1398 struct city *target_city,
1399 struct unit *target_unit,
1400 struct tile *target_tile,
1401 const struct act_prob *act_probs)
1403 struct action_data *data;
1405 if (act_sel_dialog == NULL) {
1406 fc_assert_msg(act_sel_dialog != NULL,
1407 "The action selection dialog should have been open");
1408 return;
1411 if (actor_unit->id != action_selection_actor_unit()) {
1412 fc_assert_msg(actor_unit->id == action_selection_actor_unit(),
1413 "The action selection dialog is for another actor unit.");
1414 return;
1417 data = act_data(actor_unit->id,
1418 (target_city) ? target_city->id : IDENTITY_NUMBER_ZERO,
1419 (target_unit) ? target_unit->id : IDENTITY_NUMBER_ZERO,
1420 (target_tile) ? target_tile->index : 0,
1423 action_iterate(act) {
1424 const gchar *custom;
1426 if (action_id_get_actor_kind(act) != AAK_UNIT) {
1427 /* Not relevant. */
1428 continue;
1431 if (action_prob_possible(act_probs[act])
1432 && act == ACTION_HELP_WONDER) {
1433 /* Add information about how far along the wonder is. */
1434 custom = city_prod_remaining(target_city);
1435 } else {
1436 custom = NULL;
1439 if (BUTTON_NOT_THERE == action_button_map[act]) {
1440 /* Add the button (unless its probability is 0). */
1441 action_entry(act_sel_dialog, act, act_probs, custom, data);
1442 } else {
1443 /* Update the existing button. */
1444 action_entry_update(act_sel_dialog, act, act_probs, custom, data);
1446 } action_iterate_end;
1448 /* DO NOT change the action_button_map[] for any button to reflect its
1449 * new position. A button keeps its choice dialog internal name when its
1450 * position changes. A button's id number is therefore based on when
1451 * it was added, not on its current position. */
1453 if (BUTTON_NOT_THERE != action_button_map[BUTTON_WAIT]) {
1454 /* Move the wait button below the recently added button. */
1455 choice_dialog_button_move_to_the_end(act_sel_dialog,
1456 action_button_map[BUTTON_WAIT]);
1459 if (BUTTON_NOT_THERE != action_button_map[BUTTON_CANCEL]) {
1460 /* Move the cancel button below the recently added button. */
1461 choice_dialog_button_move_to_the_end(act_sel_dialog,
1462 action_button_map[BUTTON_CANCEL]);
1465 choice_dialog_end(act_sel_dialog);
1468 /****************************************************************
1469 Closes the action selection dialog
1470 ****************************************************************/
1471 void action_selection_close(void)
1473 if (act_sel_dialog != NULL) {
1474 did_not_decide = TRUE;
1475 gtk_widget_destroy(act_sel_dialog);