Split "Establish Embassy".
[freeciv.git] / client / gui-gtk-3.22 / action_dialog.c
blob9c220a7c4db3cc42be724b4ace9794b599eaefd5
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 build city from the choice dialog
167 *****************************************************************/
168 static void found_city_callback(GtkWidget *w, gpointer data)
170 struct action_data *args = (struct action_data *)data;
172 dsend_packet_city_name_suggestion_req(&client.conn,
173 args->actor_unit_id);
175 gtk_widget_destroy(act_sel_dialog);
176 free(args);
179 /****************************************************************
180 User selected "Explode Nuclear" from the choice dialog
181 *****************************************************************/
182 static void nuke_callback(GtkWidget *w, gpointer data)
184 struct action_data *args = (struct action_data *)data;
186 if (NULL != game_unit_by_number(args->actor_unit_id)
187 && NULL != index_to_tile(&(wld.map), args->target_tile_id)) {
188 request_do_action(ACTION_NUKE, args->actor_unit_id,
189 args->target_tile_id, 0, "");
192 gtk_widget_destroy(act_sel_dialog);
193 free(args);
196 /****************************************************************
197 User selected "Paradrop Unit" from the choice dialog
198 *****************************************************************/
199 static void paradrop_callback(GtkWidget *w, gpointer data)
201 struct action_data *args = (struct action_data *)data;
203 if (NULL != game_unit_by_number(args->actor_unit_id)
204 && NULL != index_to_tile(&(wld.map), args->target_tile_id)) {
205 request_do_action(ACTION_PARADROP, args->actor_unit_id,
206 args->target_tile_id, 0, "");
209 gtk_widget_destroy(act_sel_dialog);
210 free(args);
213 /****************************************************************
214 User selected "Attack" from the choice dialog
215 *****************************************************************/
216 static void attack_callback(GtkWidget *w, gpointer data)
218 struct action_data *args = (struct action_data *)data;
220 if (NULL != game_unit_by_number(args->actor_unit_id)
221 && NULL != index_to_tile(&(wld.map), args->target_tile_id)) {
222 request_do_action(ACTION_ATTACK, args->actor_unit_id,
223 args->target_tile_id, 0, "");
226 gtk_widget_destroy(act_sel_dialog);
227 free(args);
230 /****************************************************************
231 User selected join city from caravan dialog
232 *****************************************************************/
233 static void join_city_callback(GtkWidget *w, gpointer data)
235 struct action_data *args = (struct action_data *)data;
237 if (NULL != game_unit_by_number(args->actor_unit_id)
238 && NULL != game_city_by_number(args->target_city_id)) {
239 request_do_action(ACTION_JOIN_CITY, args->actor_unit_id,
240 args->target_city_id, 0, "");
243 gtk_widget_destroy(act_sel_dialog);
244 free(args);
247 /****************************************************************
248 User selected enter market place from caravan dialog
249 *****************************************************************/
250 static void caravan_marketplace_callback(GtkWidget *w, gpointer data)
252 struct action_data *args = (struct action_data *)data;
254 if (NULL != game_unit_by_number(args->actor_unit_id)
255 && NULL != game_city_by_number(args->target_city_id)) {
256 request_do_action(ACTION_MARKETPLACE, args->actor_unit_id,
257 args->target_city_id, 0, "");
260 gtk_widget_destroy(act_sel_dialog);
261 free(args);
264 /****************************************************************
265 User selected traderoute from caravan dialog
266 *****************************************************************/
267 static void caravan_establish_trade_callback(GtkWidget *w, gpointer data)
269 struct action_data *args = (struct action_data *)data;
271 if (NULL != game_unit_by_number(args->actor_unit_id)
272 && NULL != game_city_by_number(args->target_city_id)) {
273 request_do_action(ACTION_TRADE_ROUTE, args->actor_unit_id,
274 args->target_city_id, 0, "");
277 gtk_widget_destroy(act_sel_dialog);
278 free(args);
281 /****************************************************************
282 User selected wonder building helping from caravan dialog
283 *****************************************************************/
284 static void caravan_help_build_wonder_callback(GtkWidget *w, gpointer data)
286 struct action_data *args = (struct action_data *)data;
288 if (NULL != game_unit_by_number(args->actor_unit_id)
289 && NULL != game_city_by_number(args->target_city_id)) {
290 request_do_action(ACTION_HELP_WONDER, args->actor_unit_id,
291 args->target_city_id, 0, "");
294 gtk_widget_destroy(act_sel_dialog);
295 free(args);
298 /****************************************************************
299 User selected recycle unit from choice dialog
300 *****************************************************************/
301 static void recycle_unit_callback(GtkWidget *w, gpointer data)
303 struct action_data *args = (struct action_data *)data;
305 request_do_action(ACTION_RECYCLE_UNIT, args->actor_unit_id,
306 args->target_city_id, 0, "");
308 gtk_widget_destroy(act_sel_dialog);
309 free(args);
312 /****************************************************************
313 User selected set home city from choice dialog.
314 *****************************************************************/
315 static void home_city_callback(GtkWidget *w, gpointer data)
317 struct action_data *args = (struct action_data *)data;
319 if (NULL != game_unit_by_number(args->actor_unit_id)
320 && NULL != game_city_by_number(args->target_city_id)) {
321 request_do_action(ACTION_HOME_CITY, args->actor_unit_id,
322 args->target_city_id, 0, "");
325 gtk_widget_destroy(act_sel_dialog);
326 free(args);
329 /****************************************************************
330 User selected "Upgrade Unit" from choice dialog.
331 *****************************************************************/
332 static void upgrade_callback(GtkWidget *w, gpointer data)
334 struct unit *punit;
336 struct action_data *args = (struct action_data *)data;
338 if ((punit = game_unit_by_number(args->actor_unit_id))
339 && NULL != game_city_by_number(args->target_city_id)) {
340 struct unit_list *as_list;
342 as_list = unit_list_new();
343 unit_list_append(as_list, punit);
344 popup_upgrade_dialog(as_list);
345 unit_list_destroy(as_list);
348 gtk_widget_destroy(act_sel_dialog);
349 free(args);
352 /****************************************************************
353 User selected "Airlift Unit" from choice dialog.
354 *****************************************************************/
355 static void airlift_callback(GtkWidget *w, gpointer data)
357 struct action_data *args = (struct action_data *)data;
359 if (NULL != game_unit_by_number(args->actor_unit_id)
360 && NULL != game_city_by_number(args->target_city_id)) {
361 request_do_action(ACTION_AIRLIFT, args->actor_unit_id,
362 args->target_city_id, 0, "");
365 gtk_widget_destroy(act_sel_dialog);
366 free(args);
369 /****************************************************************
370 User selected "Conquer City" from choice dialog.
371 *****************************************************************/
372 static void conquer_city_callback(GtkWidget *w, gpointer data)
374 struct action_data *args = (struct action_data *)data;
376 if (NULL != game_unit_by_number(args->actor_unit_id)
377 && NULL != game_city_by_number(args->target_city_id)) {
378 request_do_action(ACTION_CONQUER_CITY, args->actor_unit_id,
379 args->target_city_id, 0, "");
382 gtk_widget_destroy(act_sel_dialog);
383 free(args);
387 /**************************************************************************
388 Returns a string with how many shields remains of the current production.
389 This is useful as custom information on the help build wonder button.
390 **************************************************************************/
391 static const gchar *city_prod_remaining(struct city* destcity)
393 if (destcity == NULL
394 || city_owner(destcity) != client.conn.playing) {
395 /* Can't give remaining production for a foreign or non existing
396 * city. */
397 return NULL;
400 return g_strdup_printf(_("%d remaining"),
401 impr_build_shield_cost(
402 destcity->production.value.building)
403 - destcity->shield_stock);
406 /**********************************************************************
407 User responded to bribe dialog
408 **********************************************************************/
409 static void bribe_response(GtkWidget *w, gint response, gpointer data)
411 struct action_data *args = (struct action_data *)data;
413 if (response == GTK_RESPONSE_YES) {
414 request_do_action(ACTION_SPY_BRIBE_UNIT, args->actor_unit_id,
415 args->target_unit_id, 0, "");
418 gtk_widget_destroy(w);
419 free(args);
421 /* The user have answered the follow up question. Move on. */
422 diplomat_queue_handle_secondary();
425 /****************************************************************
426 Ask the server how much the bribe is
427 *****************************************************************/
428 static void diplomat_bribe_callback(GtkWidget *w, gpointer data)
430 struct action_data *args = (struct action_data *)data;
432 if (NULL != game_unit_by_number(args->actor_unit_id)
433 && NULL != game_unit_by_number(args->target_unit_id)) {
434 request_action_details(ACTION_SPY_BRIBE_UNIT, args->actor_unit_id,
435 args->target_unit_id);
438 /* Wait for the server's reply before moving on to the next unit that
439 * needs to know what action to take. */
440 is_more_user_input_needed = TRUE;
442 gtk_widget_destroy(act_sel_dialog);
443 free(args);
446 /*************************************************************************
447 Popup unit bribe dialog
448 **************************************************************************/
449 void popup_bribe_dialog(struct unit *actor, struct unit *punit, int cost)
451 GtkWidget *shell;
452 char buf[1024];
454 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
455 "Treasury contains %d gold.",
456 client_player()->economic.gold),
457 client_player()->economic.gold);
459 if (cost <= client_player()->economic.gold) {
460 shell = gtk_message_dialog_new(NULL, 0,
461 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
462 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
463 PL_("Bribe unit for %d gold?\n%s",
464 "Bribe unit for %d gold?\n%s", cost), cost, buf);
465 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
466 setup_dialog(shell, toplevel);
467 } else {
468 shell = gtk_message_dialog_new(NULL, 0,
469 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
470 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
471 PL_("Bribing the unit costs %d gold.\n%s",
472 "Bribing the unit costs %d gold.\n%s", cost), cost, buf);
473 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
474 setup_dialog(shell, toplevel);
476 gtk_window_present(GTK_WINDOW(shell));
478 g_signal_connect(shell, "response", G_CALLBACK(bribe_response),
479 act_data(actor->id, 0, punit->id, 0, cost));
482 /****************************************************************
483 User selected sabotaging from choice dialog
484 *****************************************************************/
485 static void diplomat_sabotage_callback(GtkWidget *w, gpointer data)
487 struct action_data *args = (struct action_data *)data;
489 if (NULL != game_unit_by_number(args->actor_unit_id)
490 && NULL != game_city_by_number(args->target_city_id)) {
491 request_do_action(ACTION_SPY_SABOTAGE_CITY, args->actor_unit_id,
492 args->target_city_id, B_LAST + 1, "");
495 gtk_widget_destroy(act_sel_dialog);
496 free(args);
499 /****************************************************************
500 User selected investigating from choice dialog
501 *****************************************************************/
502 static void spy_investigate_callback(GtkWidget *w, gpointer data)
504 struct action_data *args = (struct action_data *)data;
506 if (NULL != game_city_by_number(args->target_city_id)
507 && NULL != game_unit_by_number(args->actor_unit_id)) {
508 request_do_action(ACTION_SPY_INVESTIGATE_CITY, args->actor_unit_id,
509 args->target_city_id, 0, "");
512 gtk_widget_destroy(act_sel_dialog);
513 free(args);
516 /****************************************************************
517 User selected investigating from choice dialog
518 *****************************************************************/
519 static void diplomat_investigate_callback(GtkWidget *w, gpointer data)
521 struct action_data *args = (struct action_data *)data;
523 if (NULL != game_city_by_number(args->target_city_id)
524 && NULL != game_unit_by_number(args->actor_unit_id)) {
525 request_do_action(ACTION_INV_CITY_SPEND, args->actor_unit_id,
526 args->target_city_id, 0, "");
529 gtk_widget_destroy(act_sel_dialog);
530 free(args);
533 /****************************************************************
534 User selected unit sabotaging from choice dialog
535 *****************************************************************/
536 static void spy_sabotage_unit_callback(GtkWidget *w, gpointer data)
538 struct action_data *args = (struct action_data *)data;
540 request_do_action(ACTION_SPY_SABOTAGE_UNIT, args->actor_unit_id,
541 args->target_unit_id, 0, "");
543 gtk_widget_destroy(act_sel_dialog);
544 free(args);
547 /*****************************************************************
548 User selected "Heal Unit" from choice dialog
549 *****************************************************************/
550 static void heal_unit_callback(GtkWidget *w, gpointer data)
552 struct action_data *args = (struct action_data *)data;
554 request_do_action(ACTION_HEAL_UNIT, args->actor_unit_id,
555 args->target_unit_id, 0, "");
557 gtk_widget_destroy(act_sel_dialog);
558 free(args);
561 /****************************************************************
562 User selected capture units from choice dialog
563 *****************************************************************/
564 static void capture_units_callback(GtkWidget *w, gpointer data)
566 struct action_data *args = (struct action_data *)data;
568 request_do_action(ACTION_CAPTURE_UNITS, args->actor_unit_id,
569 args->target_tile_id, 0, "");
571 gtk_widget_destroy(act_sel_dialog);
572 free(args);
575 /****************************************************************
576 User selected expel unit from choice dialog
577 *****************************************************************/
578 static void expel_unit_callback(GtkWidget *w, gpointer data)
580 struct action_data *args = (struct action_data *)data;
582 request_do_action(ACTION_EXPEL_UNIT, args->actor_unit_id,
583 args->target_unit_id, 0, "");
585 gtk_widget_destroy(act_sel_dialog);
586 free(args);
589 /****************************************************************
590 User selected disband unit from choice dialog
591 *****************************************************************/
592 static void disband_unit_callback(GtkWidget *w, gpointer data)
594 struct action_data *args = (struct action_data *)data;
596 request_do_action(ACTION_DISBAND_UNIT, args->actor_unit_id,
597 args->target_unit_id, 0, "");
599 gtk_widget_destroy(act_sel_dialog);
600 free(args);
603 /****************************************************************
604 User selected bombard from choice dialog
605 *****************************************************************/
606 static void bombard_callback(GtkWidget *w, gpointer data)
608 struct action_data *args = (struct action_data *)data;
610 request_do_action(ACTION_BOMBARD, args->actor_unit_id,
611 args->target_tile_id, 0, "");
613 gtk_widget_destroy(act_sel_dialog);
614 free(args);
617 /****************************************************************
618 User selected embassy establishing from choice dialog
619 *****************************************************************/
620 static void spy_embassy_callback(GtkWidget *w, gpointer data)
622 struct action_data *args = (struct action_data *)data;
624 if (NULL != game_unit_by_number(args->actor_unit_id)
625 && NULL != game_city_by_number(args->target_city_id)) {
626 request_do_action(ACTION_ESTABLISH_EMBASSY, args->actor_unit_id,
627 args->target_city_id, 0, "");
630 gtk_widget_destroy(act_sel_dialog);
631 free(args);
634 /****************************************************************
635 User selected embassy establishing from choice dialog
636 *****************************************************************/
637 static void diplomat_embassy_callback(GtkWidget *w, gpointer data)
639 struct action_data *args = (struct action_data *)data;
641 if (NULL != game_unit_by_number(args->actor_unit_id)
642 && NULL != game_city_by_number(args->target_city_id)) {
643 request_do_action(ACTION_ESTABLISH_EMBASSY_STAY, args->actor_unit_id,
644 args->target_city_id, 0, "");
647 gtk_widget_destroy(act_sel_dialog);
648 free(args);
651 /****************************************************************
652 User selected to steal gold from choice dialog
653 *****************************************************************/
654 static void spy_steal_gold_callback(GtkWidget *w, gpointer data)
656 struct action_data *args = (struct action_data *)data;
658 if (NULL != game_unit_by_number(args->actor_unit_id)
659 && NULL != game_city_by_number(args->target_city_id)) {
660 request_do_action(ACTION_SPY_STEAL_GOLD, args->actor_unit_id,
661 args->target_city_id, 0, "");
664 gtk_widget_destroy(act_sel_dialog);
665 free(args);
668 /****************************************************************
669 User selected to steal maps from choice dialog
670 *****************************************************************/
671 static void spy_steal_maps_callback(GtkWidget *w, gpointer data)
673 struct action_data *args = (struct action_data *)data;
675 if (NULL != game_unit_by_number(args->actor_unit_id)
676 && NULL != game_city_by_number(args->target_city_id)) {
677 request_do_action(ACTION_STEAL_MAPS, args->actor_unit_id,
678 args->target_city_id, 0, "");
681 gtk_widget_destroy(act_sel_dialog);
682 free(args);
685 /****************************************************************
686 User selected poisoning from choice dialog
687 *****************************************************************/
688 static void spy_poison_callback(GtkWidget *w, gpointer data)
690 struct action_data *args = (struct action_data *)data;
692 if (NULL != game_unit_by_number(args->actor_unit_id)
693 && NULL != game_city_by_number(args->target_city_id)) {
694 request_do_action(ACTION_SPY_POISON, args->actor_unit_id,
695 args->target_city_id, 0, "");
698 gtk_widget_destroy(act_sel_dialog);
699 free(args);
702 /****************************************************************
703 User selected suitcase nuke from choice dialog
704 *****************************************************************/
705 static void spy_nuke_city_callback(GtkWidget *w, gpointer data)
707 struct action_data *args = (struct action_data *)data;
709 if (NULL != game_unit_by_number(args->actor_unit_id)
710 && NULL != game_city_by_number(args->target_city_id)) {
711 request_do_action(ACTION_SPY_NUKE, args->actor_unit_id,
712 args->target_city_id, 0, "");
715 gtk_widget_destroy(act_sel_dialog);
716 free(args);
719 /****************************************************************
720 User selected destroy city from choice dialog
721 *****************************************************************/
722 static void destroy_city_callback(GtkWidget *w, gpointer data)
724 struct action_data *args = (struct action_data *)data;
726 if (NULL != game_unit_by_number(args->actor_unit_id)
727 && NULL != game_city_by_number(args->target_city_id)) {
728 request_do_action(ACTION_DESTROY_CITY, args->actor_unit_id,
729 args->target_city_id, 0, "");
732 gtk_widget_destroy(act_sel_dialog);
733 free(args);
736 /****************************************************************
737 User selected stealing from choice dialog
738 *****************************************************************/
739 static void diplomat_steal_callback(GtkWidget *w, gpointer data)
741 struct action_data *args = (struct action_data *)data;
743 if (NULL != game_unit_by_number(args->actor_unit_id)
744 && NULL != game_city_by_number(args->target_city_id)) {
745 request_do_action(ACTION_SPY_STEAL_TECH, args->actor_unit_id,
746 args->target_city_id, A_UNSET, "");
749 gtk_widget_destroy(act_sel_dialog);
750 free(args);
753 /****************************************************************
754 User responded to steal advances dialog
755 *****************************************************************/
756 static void spy_advances_response(GtkWidget *w, gint response,
757 gpointer data)
759 struct action_data *args = (struct action_data *)data;
761 if (response == GTK_RESPONSE_ACCEPT && args->value > 0) {
762 if (NULL != game_unit_by_number(args->actor_unit_id)
763 && NULL != game_city_by_number(args->target_city_id)) {
764 if (args->value == A_UNSET) {
765 /* This is the untargeted version. */
766 request_do_action(ACTION_SPY_STEAL_TECH,
767 args->actor_unit_id, args->target_city_id,
768 args->value, "");
769 } else {
770 /* This is the targeted version. */
771 request_do_action(ACTION_SPY_TARGETED_STEAL_TECH,
772 args->actor_unit_id, args->target_city_id,
773 args->value, "");
778 gtk_widget_destroy(spy_tech_shell);
779 spy_tech_shell = NULL;
780 free(data);
782 /* The user have answered the follow up question. Move on. */
783 diplomat_queue_handle_secondary();
786 /****************************************************************
787 User selected entry in steal advances dialog
788 *****************************************************************/
789 static void spy_advances_callback(GtkTreeSelection *select,
790 gpointer data)
792 struct action_data *args = (struct action_data *)data;
794 GtkTreeModel *model;
795 GtkTreeIter it;
797 if (gtk_tree_selection_get_selected(select, &model, &it)) {
798 gtk_tree_model_get(model, &it, 1, &(args->value), -1);
800 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
801 GTK_RESPONSE_ACCEPT, TRUE);
802 } else {
803 args->value = 0;
805 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
806 GTK_RESPONSE_ACCEPT, FALSE);
810 /****************************************************************
811 Create spy's tech stealing dialog
812 *****************************************************************/
813 static void create_advances_list(struct player *pplayer,
814 struct player *pvictim,
815 struct action_data *args)
817 GtkWidget *sw, *label, *vbox, *view;
818 GtkListStore *store;
819 GtkCellRenderer *rend;
820 GtkTreeViewColumn *col;
822 struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
824 spy_tech_shell = gtk_dialog_new_with_buttons(_("Steal Technology"),
825 NULL, 0,
826 _("Cancel"), GTK_RESPONSE_CANCEL,
827 _("_Steal"), GTK_RESPONSE_ACCEPT,
828 NULL);
829 setup_dialog(spy_tech_shell, toplevel);
830 gtk_window_set_position(GTK_WINDOW(spy_tech_shell), GTK_WIN_POS_MOUSE);
832 gtk_dialog_set_default_response(GTK_DIALOG(spy_tech_shell),
833 GTK_RESPONSE_ACCEPT);
835 label = gtk_frame_new(_("Select Advance to Steal"));
836 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell))), label);
838 vbox = gtk_grid_new();
839 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
840 GTK_ORIENTATION_VERTICAL);
841 gtk_grid_set_row_spacing(GTK_GRID(vbox), 6);
842 gtk_container_add(GTK_CONTAINER(label), vbox);
844 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
846 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
847 gtk_widget_set_hexpand(view, TRUE);
848 gtk_widget_set_vexpand(view, TRUE);
849 g_object_unref(store);
850 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
852 rend = gtk_cell_renderer_text_new();
853 col = gtk_tree_view_column_new_with_attributes(NULL, rend,
854 "text", 0, NULL);
855 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
857 label = g_object_new(GTK_TYPE_LABEL,
858 "use-underline", TRUE,
859 "mnemonic-widget", view,
860 "label", _("_Advances:"),
861 "xalign", 0.0,
862 "yalign", 0.5,
863 NULL);
864 gtk_container_add(GTK_CONTAINER(vbox), label);
866 sw = gtk_scrolled_window_new(NULL, NULL);
867 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
868 GTK_SHADOW_ETCHED_IN);
869 gtk_container_add(GTK_CONTAINER(sw), view);
871 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
872 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
873 gtk_widget_set_size_request(sw, -1, 200);
875 gtk_container_add(GTK_CONTAINER(vbox), sw);
877 /* Now populate the list */
878 if (pvictim) { /* you don't want to know what lag can do -- Syela */
879 const struct research *presearch = research_get(pplayer);
880 const struct research *vresearch = research_get(pvictim);
881 GtkTreeIter it;
882 GValue value = { 0, };
884 advance_index_iterate(A_FIRST, i) {
885 if (research_invention_gettable(presearch, i,
886 game.info.tech_steal_allow_holes)
887 && research_invention_state(vresearch, i) == TECH_KNOWN
888 && research_invention_state(presearch, i) != TECH_KNOWN) {
889 gtk_list_store_append(store, &it);
891 g_value_init(&value, G_TYPE_STRING);
892 g_value_set_static_string(&value, research_advance_name_translation
893 (presearch, i));
894 gtk_list_store_set_value(store, &it, 0, &value);
895 g_value_unset(&value);
896 gtk_list_store_set(store, &it, 1, i, -1);
898 } advance_index_iterate_end;
900 if (action_prob_possible(
901 actor_unit->client.act_prob_cache[ACTION_SPY_STEAL_TECH])) {
902 gtk_list_store_append(store, &it);
904 g_value_init(&value, G_TYPE_STRING);
906 struct astring str = ASTRING_INIT;
907 /* TRANS: %s is a unit name, e.g., Spy */
908 astr_set(&str, _("At %s's Discretion"),
909 unit_name_translation(actor_unit));
910 g_value_set_string(&value, astr_str(&str));
911 astr_free(&str);
913 gtk_list_store_set_value(store, &it, 0, &value);
914 g_value_unset(&value);
915 gtk_list_store_set(store, &it, 1, A_UNSET, -1);
919 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_tech_shell),
920 GTK_RESPONSE_ACCEPT, FALSE);
922 gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(spy_tech_shell)));
924 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), "changed",
925 G_CALLBACK(spy_advances_callback), args);
926 g_signal_connect(spy_tech_shell, "response",
927 G_CALLBACK(spy_advances_response), args);
929 args->value = 0;
931 gtk_tree_view_focus(GTK_TREE_VIEW(view));
934 /****************************************************************
935 User has responded to spy's sabotage building dialog
936 *****************************************************************/
937 static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
939 struct action_data *args = (struct action_data *)data;
941 if (response == GTK_RESPONSE_ACCEPT && args->value > -2) {
942 if (NULL != game_unit_by_number(args->actor_unit_id)
943 && NULL != game_city_by_number(args->target_city_id)) {
944 if (args->value == B_LAST) {
945 /* This is the untargeted version. */
946 request_do_action(ACTION_SPY_SABOTAGE_CITY,
947 args->actor_unit_id,
948 args->target_city_id,
949 args->value + 1, "");
950 } else {
951 /* This is the targeted version. */
952 request_do_action(ACTION_SPY_TARGETED_SABOTAGE_CITY,
953 args->actor_unit_id,
954 args->target_city_id,
955 args->value + 1, "");
960 gtk_widget_destroy(spy_sabotage_shell);
961 spy_sabotage_shell = NULL;
962 free(args);
964 /* The user have answered the follow up question. Move on. */
965 diplomat_queue_handle_secondary();
968 /****************************************************************
969 User has selected new building from spy's sabotage dialog
970 *****************************************************************/
971 static void spy_improvements_callback(GtkTreeSelection *select, gpointer data)
973 struct action_data *args = (struct action_data *)data;
975 GtkTreeModel *model;
976 GtkTreeIter it;
978 if (gtk_tree_selection_get_selected(select, &model, &it)) {
979 gtk_tree_model_get(model, &it, 1, &(args->value), -1);
981 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
982 GTK_RESPONSE_ACCEPT, TRUE);
983 } else {
984 args->value = -2;
986 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
987 GTK_RESPONSE_ACCEPT, FALSE);
991 /****************************************************************
992 Creates spy's building sabotaging dialog
993 *****************************************************************/
994 static void create_improvements_list(struct player *pplayer,
995 struct city *pcity,
996 struct action_data *args)
998 GtkWidget *sw, *label, *vbox, *view;
999 GtkListStore *store;
1000 GtkCellRenderer *rend;
1001 GtkTreeViewColumn *col;
1002 GtkTreeIter it;
1004 struct unit *actor_unit = game_unit_by_number(args->actor_unit_id);
1006 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
1007 NULL, 0,
1008 _("Cancel"), GTK_RESPONSE_CANCEL,
1009 _("_Sabotage"), GTK_RESPONSE_ACCEPT,
1010 NULL);
1011 setup_dialog(spy_sabotage_shell, toplevel);
1012 gtk_window_set_position(GTK_WINDOW(spy_sabotage_shell), GTK_WIN_POS_MOUSE);
1014 gtk_dialog_set_default_response(GTK_DIALOG(spy_sabotage_shell),
1015 GTK_RESPONSE_ACCEPT);
1017 label = gtk_frame_new(_("Select Improvement to Sabotage"));
1018 gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(spy_sabotage_shell))), label);
1020 vbox = gtk_grid_new();
1021 gtk_orientable_set_orientation(GTK_ORIENTABLE(vbox),
1022 GTK_ORIENTATION_VERTICAL);
1023 gtk_grid_set_row_spacing(GTK_GRID(vbox), 6);
1024 gtk_container_add(GTK_CONTAINER(label), vbox);
1026 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
1028 view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1029 gtk_widget_set_hexpand(view, TRUE);
1030 gtk_widget_set_vexpand(view, TRUE);
1031 g_object_unref(store);
1032 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
1034 rend = gtk_cell_renderer_text_new();
1035 col = gtk_tree_view_column_new_with_attributes(NULL, rend,
1036 "text", 0, NULL);
1037 gtk_tree_view_append_column(GTK_TREE_VIEW(view), col);
1039 label = g_object_new(GTK_TYPE_LABEL,
1040 "use-underline", TRUE,
1041 "mnemonic-widget", view,
1042 "label", _("_Improvements:"),
1043 "xalign", 0.0,
1044 "yalign", 0.5,
1045 NULL);
1046 gtk_container_add(GTK_CONTAINER(vbox), label);
1048 sw = gtk_scrolled_window_new(NULL, NULL);
1049 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
1050 GTK_SHADOW_ETCHED_IN);
1051 gtk_container_add(GTK_CONTAINER(sw), view);
1053 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
1054 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1055 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(sw), 200);
1057 gtk_container_add(GTK_CONTAINER(vbox), sw);
1059 /* Now populate the list */
1060 gtk_list_store_append(store, &it);
1061 gtk_list_store_set(store, &it, 0, _("City Production"), 1, -1, -1);
1063 city_built_iterate(pcity, pimprove) {
1064 if (pimprove->sabotage > 0) {
1065 gtk_list_store_append(store, &it);
1066 gtk_list_store_set(store, &it,
1067 0, city_improvement_name_translation(pcity, pimprove),
1068 1, improvement_number(pimprove),
1069 -1);
1071 } city_built_iterate_end;
1073 if (action_prob_possible(
1074 actor_unit->client.act_prob_cache[ACTION_SPY_SABOTAGE_CITY])) {
1075 struct astring str = ASTRING_INIT;
1077 gtk_list_store_append(store, &it);
1079 /* TRANS: %s is a unit name, e.g., Spy */
1080 astr_set(&str, _("At %s's Discretion"),
1081 unit_name_translation(actor_unit));
1082 gtk_list_store_set(store, &it, 0, astr_str(&str), 1, B_LAST, -1);
1084 astr_free(&str);
1087 gtk_dialog_set_response_sensitive(GTK_DIALOG(spy_sabotage_shell),
1088 GTK_RESPONSE_ACCEPT, FALSE);
1090 gtk_widget_show_all(gtk_dialog_get_content_area(GTK_DIALOG(spy_sabotage_shell)));
1092 g_signal_connect(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), "changed",
1093 G_CALLBACK(spy_improvements_callback), args);
1094 g_signal_connect(spy_sabotage_shell, "response",
1095 G_CALLBACK(spy_improvements_response), args);
1097 args->value = -2;
1099 gtk_tree_view_focus(GTK_TREE_VIEW(view));
1102 /****************************************************************
1103 Popup tech stealing dialog with list of possible techs
1104 *****************************************************************/
1105 static void spy_steal_popup(GtkWidget *w, gpointer data)
1107 struct action_data *args = (struct action_data *)data;
1109 struct city *pvcity = game_city_by_number(args->target_city_id);
1110 struct player *pvictim = NULL;
1112 if (pvcity) {
1113 pvictim = city_owner(pvcity);
1116 /* it is concievable that pvcity will not be found, because something
1117 has happened to the city during latency. Therefore we must initialize
1118 pvictim to NULL and account for !pvictim in create_advances_list. -- Syela */
1120 /* FIXME: Don't discard the second tech choice dialog. */
1121 if (!spy_tech_shell) {
1122 create_advances_list(client.conn.playing, pvictim, args);
1123 gtk_window_present(GTK_WINDOW(spy_tech_shell));
1124 } else {
1125 free(args);
1128 /* Wait for the server's reply before moving on to the next unit that
1129 * needs to know what action to take. */
1130 is_more_user_input_needed = TRUE;
1132 gtk_widget_destroy(act_sel_dialog);
1135 /****************************************************************
1136 Requests up-to-date list of improvements, the return of
1137 which will trigger the popup_sabotage_dialog() function.
1138 *****************************************************************/
1139 static void spy_request_sabotage_list(GtkWidget *w, gpointer data)
1141 struct action_data *args = (struct action_data *)data;
1143 if (NULL != game_unit_by_number(args->actor_unit_id)
1144 && NULL != game_city_by_number(args->target_city_id)) {
1145 request_action_details(ACTION_SPY_TARGETED_SABOTAGE_CITY,
1146 args->actor_unit_id,
1147 args->target_city_id);
1150 /* Wait for the server's reply before moving on to the next unit that
1151 * needs to know what action to take. */
1152 is_more_user_input_needed = TRUE;
1154 gtk_widget_destroy(act_sel_dialog);
1155 free(args);
1158 /*************************************************************************
1159 Pops-up the Spy sabotage dialog, upon return of list of
1160 available improvements requested by the above function.
1161 **************************************************************************/
1162 void popup_sabotage_dialog(struct unit *actor, struct city *pcity)
1164 /* FIXME: Don't discard the second target choice dialog. */
1165 if (!spy_sabotage_shell) {
1166 create_improvements_list(client.conn.playing, pcity,
1167 act_data(actor->id, pcity->id, 0, 0, 0));
1168 gtk_window_present(GTK_WINDOW(spy_sabotage_shell));
1172 /****************************************************************
1173 ... Ask the server how much the revolt is going to cost us
1174 *****************************************************************/
1175 static void diplomat_incite_callback(GtkWidget *w, gpointer data)
1177 struct action_data *args = (struct action_data *)data;
1179 if (NULL != game_unit_by_number(args->actor_unit_id)
1180 && NULL != game_city_by_number(args->target_city_id)) {
1181 request_action_details(ACTION_SPY_INCITE_CITY, args->actor_unit_id,
1182 args->target_city_id);
1185 /* Wait for the server's reply before moving on to the next unit that
1186 * needs to know what action to take. */
1187 is_more_user_input_needed = TRUE;
1189 gtk_widget_destroy(act_sel_dialog);
1190 free(args);
1193 /************************************************************************
1194 User has responded to incite dialog
1195 ************************************************************************/
1196 static void incite_response(GtkWidget *w, gint response, gpointer data)
1198 struct action_data *args = (struct action_data *)data;
1200 if (response == GTK_RESPONSE_YES) {
1201 request_do_action(ACTION_SPY_INCITE_CITY, args->actor_unit_id,
1202 args->target_city_id, 0, "");
1205 gtk_widget_destroy(w);
1206 free(args);
1208 /* The user have answered the follow up question. Move on. */
1209 diplomat_queue_handle_secondary();
1212 /*************************************************************************
1213 Popup the yes/no dialog for inciting, since we know the cost now
1214 **************************************************************************/
1215 void popup_incite_dialog(struct unit *actor, struct city *pcity, int cost)
1217 GtkWidget *shell;
1218 char buf[1024];
1220 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
1221 "Treasury contains %d gold.",
1222 client_player()->economic.gold),
1223 client_player()->economic.gold);
1225 if (INCITE_IMPOSSIBLE_COST == cost) {
1226 shell = gtk_message_dialog_new(NULL, 0,
1227 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1228 _("You can't incite a revolt in %s."),
1229 city_name_get(pcity));
1230 gtk_window_set_title(GTK_WINDOW(shell), _("City can't be incited!"));
1231 setup_dialog(shell, toplevel);
1232 } else if (cost <= client_player()->economic.gold) {
1233 shell = gtk_message_dialog_new(NULL, 0,
1234 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1235 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1236 PL_("Incite a revolt for %d gold?\n%s",
1237 "Incite a revolt for %d gold?\n%s", cost), cost, buf);
1238 gtk_window_set_title(GTK_WINDOW(shell), _("Incite a Revolt!"));
1239 setup_dialog(shell, toplevel);
1240 } else {
1241 shell = gtk_message_dialog_new(NULL,
1243 GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
1244 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1245 PL_("Inciting a revolt costs %d gold.\n%s",
1246 "Inciting a revolt costs %d gold.\n%s", cost), cost, buf);
1247 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
1248 setup_dialog(shell, toplevel);
1250 gtk_window_present(GTK_WINDOW(shell));
1252 g_signal_connect(shell, "response", G_CALLBACK(incite_response),
1253 act_data(actor->id, pcity->id, 0, 0, cost));
1256 /**************************************************************************
1257 Callback from the unit target selection dialog.
1258 **************************************************************************/
1259 static void tgt_unit_change_callback(GtkWidget *dlg, gint arg)
1261 int act_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
1263 if (arg == GTK_RESPONSE_YES) {
1264 struct unit *actor = game_unit_by_number(act_id);
1266 if (actor != NULL) {
1267 int tgt_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg),
1268 "target"));
1269 struct unit *tgt_unit = game_unit_by_number(tgt_id);
1270 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
1272 if (tgt_unit == NULL) {
1273 /* Make the action dialog pop up again. */
1274 dsend_packet_unit_get_actions(&client.conn,
1275 actor->id,
1276 /* Let the server choose the target
1277 * unit. */
1278 IDENTITY_NUMBER_ZERO,
1279 tgt_tile->index,
1280 TRUE);
1281 } else {
1282 dsend_packet_unit_get_actions(&client.conn,
1283 actor->id,
1284 tgt_id,
1285 tgt_tile->index,
1286 TRUE);
1289 } else {
1290 /* Dialog canceled. This ends the action selection process. */
1291 action_selection_no_longer_in_progress(act_id);
1294 gtk_widget_destroy(dlg);
1297 /**************************************************************************
1298 Callback from action selection dialog for "Change unit target".
1299 **************************************************************************/
1300 static void act_sel_new_unit_tgt_callback(GtkWidget *w, gpointer data)
1302 struct action_data *args = (struct action_data *)data;
1304 struct unit *punit;
1305 struct unit *tunit;
1306 struct tile *ptile;
1308 if ((punit = game_unit_by_number(args->actor_unit_id))
1309 && (ptile = index_to_tile(&(wld.map), args->target_tile_id))
1310 && (tunit = game_unit_by_number(args->target_unit_id))) {
1311 select_tgt_unit(punit, ptile, ptile->units, tunit,
1312 _("Target unit selection"),
1313 _("Looking for target unit:"),
1314 _("Units at tile:"),
1315 _("Select"),
1316 G_CALLBACK(tgt_unit_change_callback));
1319 did_not_decide = TRUE;
1320 action_selection_restart = TRUE;
1321 gtk_widget_destroy(act_sel_dialog);
1322 free(args);
1325 /**************************************************************************
1326 Callback from action selection dialog for "Show Location".
1327 **************************************************************************/
1328 static void act_sel_location_callback(GtkWidget *w, gpointer data)
1330 struct action_data *args = (struct action_data *)data;
1332 struct unit *punit;
1334 if ((punit = game_unit_by_number(args->actor_unit_id))) {
1335 center_tile_mapcanvas(unit_tile(punit));
1339 /**************************************************************************
1340 Callback from action selection dialog for "keep moving".
1341 (This should only occur when entering a tile that has an allied city or
1342 an allied unit.)
1343 **************************************************************************/
1344 static void act_sel_keep_moving_callback(GtkWidget *w, gpointer data)
1346 struct action_data *args = (struct action_data *)data;
1348 struct unit *punit;
1349 struct tile *ptile;
1351 if ((punit = game_unit_by_number(args->actor_unit_id))
1352 && (ptile = index_to_tile(&(wld.map), args->target_tile_id))
1353 && !same_pos(unit_tile(punit), ptile)) {
1354 request_unit_non_action_move(punit, ptile);
1357 gtk_widget_destroy(act_sel_dialog);
1358 free(args);
1361 /**************************************************************************
1362 Delay selection of what action to take.
1363 **************************************************************************/
1364 static void act_sel_wait_callback(GtkWidget *w, gpointer data)
1366 struct action_data *args = (struct action_data *)data;
1368 key_unit_wait();
1370 /* the dialog was destroyed when key_unit_wait() resulted in
1371 * action_selection_close() being called. */
1373 free(args);
1376 /****************************************************************
1377 Action selection dialog has been destroyed
1378 *****************************************************************/
1379 static void act_sel_destroy_callback(GtkWidget *w, gpointer data)
1381 act_sel_dialog = NULL;
1382 diplomat_queue_handle_primary();
1385 /****************************************************************
1386 Action selection dialog has been canceled
1387 *****************************************************************/
1388 static void act_sel_cancel_callback(GtkWidget *w, gpointer data)
1390 gtk_widget_destroy(act_sel_dialog);
1391 free(data);
1394 /****************************************************************
1395 Action selection dialog has been closed
1396 *****************************************************************/
1397 static void act_sel_close_callback(GtkWidget *w,
1398 gint response_id,
1399 gpointer data)
1401 gtk_widget_destroy(act_sel_dialog);
1402 free(data);
1405 /* Mapping from an action to the function to call when its button is
1406 * pushed. */
1407 static const GCallback af_map[ACTION_COUNT] = {
1408 /* Unit acting against a city target. */
1409 [ACTION_ESTABLISH_EMBASSY] = (GCallback)spy_embassy_callback,
1410 [ACTION_ESTABLISH_EMBASSY_STAY] = (GCallback)diplomat_embassy_callback,
1411 [ACTION_SPY_INVESTIGATE_CITY] = (GCallback)spy_investigate_callback,
1412 [ACTION_INV_CITY_SPEND] = (GCallback)diplomat_investigate_callback,
1413 [ACTION_SPY_POISON] = (GCallback)spy_poison_callback,
1414 [ACTION_SPY_STEAL_GOLD] = (GCallback)spy_steal_gold_callback,
1415 [ACTION_STEAL_MAPS] = (GCallback)spy_steal_maps_callback,
1416 [ACTION_SPY_SABOTAGE_CITY] = (GCallback)diplomat_sabotage_callback,
1417 [ACTION_SPY_TARGETED_SABOTAGE_CITY] =
1418 (GCallback)spy_request_sabotage_list,
1419 [ACTION_SPY_STEAL_TECH] = (GCallback)diplomat_steal_callback,
1420 [ACTION_SPY_TARGETED_STEAL_TECH] = (GCallback)spy_steal_popup,
1421 [ACTION_SPY_INCITE_CITY] = (GCallback)diplomat_incite_callback,
1422 [ACTION_TRADE_ROUTE] = (GCallback)caravan_establish_trade_callback,
1423 [ACTION_MARKETPLACE] = (GCallback)caravan_marketplace_callback,
1424 [ACTION_HELP_WONDER] = (GCallback)caravan_help_build_wonder_callback,
1425 [ACTION_JOIN_CITY] = (GCallback)join_city_callback,
1426 [ACTION_SPY_NUKE] = (GCallback)spy_nuke_city_callback,
1427 [ACTION_DESTROY_CITY] = (GCallback)destroy_city_callback,
1428 [ACTION_RECYCLE_UNIT] = (GCallback)recycle_unit_callback,
1429 [ACTION_HOME_CITY] = (GCallback)home_city_callback,
1430 [ACTION_UPGRADE_UNIT] = (GCallback)upgrade_callback,
1431 [ACTION_AIRLIFT] = (GCallback)airlift_callback,
1432 [ACTION_CONQUER_CITY] = (GCallback)conquer_city_callback,
1434 /* Unit acting against a unit target. */
1435 [ACTION_SPY_BRIBE_UNIT] = (GCallback)diplomat_bribe_callback,
1436 [ACTION_SPY_SABOTAGE_UNIT] = (GCallback)spy_sabotage_unit_callback,
1437 [ACTION_EXPEL_UNIT] = (GCallback)expel_unit_callback,
1438 [ACTION_HEAL_UNIT] = (GCallback)heal_unit_callback,
1440 /* Unit acting against all units at a tile. */
1441 [ACTION_CAPTURE_UNITS] = (GCallback)capture_units_callback,
1442 [ACTION_BOMBARD] = (GCallback)bombard_callback,
1444 /* Unit acting against a tile. */
1445 [ACTION_FOUND_CITY] = (GCallback)found_city_callback,
1446 [ACTION_NUKE] = (GCallback)nuke_callback,
1447 [ACTION_PARADROP] = (GCallback)paradrop_callback,
1448 [ACTION_ATTACK] = (GCallback)attack_callback,
1450 /* Unit acting with no target except itself. */
1451 [ACTION_DISBAND_UNIT] = (GCallback)disband_unit_callback,
1454 /******************************************************************
1455 Show the user the action if it is enabled.
1456 *******************************************************************/
1457 static void action_entry(GtkWidget *shl,
1458 int action_id,
1459 const struct act_prob *act_probs,
1460 const gchar *custom,
1461 struct action_data *handler_args)
1463 const gchar *label;
1464 const gchar *tooltip;
1466 if (action_id == ACTION_SPY_SABOTAGE_CITY
1467 && action_prob_possible(
1468 act_probs[ACTION_SPY_TARGETED_SABOTAGE_CITY])) {
1469 /* The player can select Sabotage City from the target selection dialog
1470 * of Targeted Sabotage City. */
1471 return;
1474 if (action_id == ACTION_SPY_STEAL_TECH
1475 && action_prob_possible(
1476 act_probs[ACTION_SPY_TARGETED_STEAL_TECH])) {
1477 /* The player can select Steal Tech from the target selection dialog of
1478 * Targeted Steal Tech. */
1479 return;
1482 if (af_map[action_id] == NULL) {
1483 /* This client doesn't support ordering this action from the
1484 * action selection dialog. */
1485 return;
1488 /* Don't show disabled actions. */
1489 if (!action_prob_possible(act_probs[action_id])) {
1490 return;
1493 label = action_prepare_ui_name(action_id, "",
1494 act_probs[action_id],
1495 custom);
1497 tooltip = action_get_tool_tip(action_id,
1498 act_probs[action_id]);
1500 action_button_map[action_id] = choice_dialog_get_number_of_buttons(shl);
1501 choice_dialog_add(shl, label, af_map[action_id], handler_args,
1502 FALSE, tooltip);
1505 /******************************************************************
1506 Update an existing button.
1507 *******************************************************************/
1508 static void action_entry_update(GtkWidget *shl,
1509 int action_id,
1510 const struct act_prob *act_probs,
1511 const gchar *custom,
1512 struct action_data *handler_args)
1514 const gchar *label;
1515 const gchar *tooltip;
1517 /* An action that just became impossible has its button disabled.
1518 * An action that became possible again must be reenabled. */
1519 choice_dialog_button_set_sensitive(act_sel_dialog,
1520 action_button_map[action_id],
1521 action_prob_possible(act_probs[action_id]));
1523 /* The probability may have changed. */
1524 label = action_prepare_ui_name(action_id, "",
1525 act_probs[action_id], custom);
1527 tooltip = action_get_tool_tip(action_id,
1528 act_probs[action_id]);
1530 choice_dialog_button_set_label(act_sel_dialog,
1531 action_button_map[action_id],
1532 label);
1533 choice_dialog_button_set_tooltip(act_sel_dialog,
1534 action_button_map[action_id],
1535 tooltip);
1538 /**************************************************************************
1539 Popup a dialog that allows the player to select what action a unit
1540 should take.
1541 **************************************************************************/
1542 void popup_action_selection(struct unit *actor_unit,
1543 struct city *target_city,
1544 struct unit *target_unit,
1545 struct tile *target_tile,
1546 const struct act_prob *act_probs)
1548 GtkWidget *shl;
1549 struct astring title = ASTRING_INIT, text = ASTRING_INIT;
1550 struct city *actor_homecity;
1552 int button_id;
1554 struct action_data *data =
1555 act_data(actor_unit->id,
1556 (target_city) ? target_city->id : 0,
1557 (target_unit) ? target_unit->id : 0,
1558 (target_tile) ? target_tile->index : 0,
1561 /* Could be caused by the server failing to reply to a request for more
1562 * information or a bug in the client code. */
1563 fc_assert_msg(!is_more_user_input_needed,
1564 "Diplomat queue problem. Is another diplomat window open?");
1566 /* No extra input is required as no action has been chosen yet. */
1567 is_more_user_input_needed = FALSE;
1569 /* No buttons are added yet. */
1570 for (button_id = 0; button_id < BUTTON_COUNT; button_id++) {
1571 action_button_map[button_id] = BUTTON_NOT_THERE;
1574 actor_homecity = game_city_by_number(actor_unit->homecity);
1576 actor_unit_id = actor_unit->id;
1577 target_ids[ATK_SELF] = actor_unit_id;
1578 target_ids[ATK_CITY] = target_city ?
1579 target_city->id :
1580 IDENTITY_NUMBER_ZERO;
1581 target_ids[ATK_UNIT] = target_unit ?
1582 target_unit->id :
1583 IDENTITY_NUMBER_ZERO;
1584 target_ids[ATK_UNITS] = target_tile ?
1585 tile_index(target_tile) :
1586 IDENTITY_NUMBER_ZERO;
1587 target_ids[ATK_TILE] = target_tile ?
1588 tile_index(target_tile) :
1589 IDENTITY_NUMBER_ZERO;
1591 astr_set(&title,
1592 /* TRANS: %s is a unit name, e.g., Spy */
1593 _("Choose Your %s's Strategy"),
1594 unit_name_translation(actor_unit));
1596 if (target_city && actor_homecity) {
1597 astr_set(&text,
1598 _("Your %s from %s reaches the city of %s.\nWhat now?"),
1599 unit_name_translation(actor_unit),
1600 city_name_get(actor_homecity),
1601 city_name_get(target_city));
1602 } else if (target_city) {
1603 astr_set(&text,
1604 _("Your %s has arrived at %s.\nWhat is your command?"),
1605 unit_name_translation(actor_unit),
1606 city_name_get(target_city));
1607 } else if (target_unit) {
1608 astr_set(&text,
1609 /* TRANS: Your Spy is ready to act against Roman Freight. */
1610 _("Your %s is ready to act against %s %s."),
1611 unit_name_translation(actor_unit),
1612 nation_adjective_for_player(unit_owner(target_unit)),
1613 unit_name_translation(target_unit));
1614 } else {
1615 fc_assert_msg(target_unit || target_city || target_tile,
1616 "No target specified.");
1617 astr_set(&text,
1618 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
1619 _("Your %s is waiting for your command."),
1620 unit_name_translation(actor_unit));
1623 shl = choice_dialog_start(GTK_WINDOW(toplevel), astr_str(&title),
1624 astr_str(&text));
1626 /* Unit acting against a city */
1628 action_iterate(act) {
1629 if (action_id_get_actor_kind(act) == AAK_UNIT
1630 && action_id_get_target_kind(act) == ATK_CITY) {
1631 action_entry(shl,
1632 (enum gen_action)act,
1633 act_probs,
1634 act == ACTION_HELP_WONDER ?
1635 city_prod_remaining(target_city) : NULL,
1636 data);
1638 } action_iterate_end;
1640 /* Unit acting against another unit */
1642 action_iterate(act) {
1643 if (action_id_get_actor_kind(act) == AAK_UNIT
1644 && action_id_get_target_kind(act) == ATK_UNIT) {
1645 action_entry(shl,
1646 (enum gen_action)act,
1647 act_probs,
1648 NULL,
1649 data);
1651 } action_iterate_end;
1653 /* Unit acting against all units at a tile */
1655 action_iterate(act) {
1656 if (action_id_get_actor_kind(act) == AAK_UNIT
1657 && action_id_get_target_kind(act) == ATK_UNITS) {
1658 action_entry(shl,
1659 (enum gen_action)act,
1660 act_probs,
1661 NULL,
1662 data);
1664 } action_iterate_end;
1666 /* Unit acting against a tile */
1668 action_iterate(act) {
1669 if (action_id_get_actor_kind(act) == AAK_UNIT
1670 && action_id_get_target_kind(act) == ATK_TILE) {
1671 action_entry(shl,
1672 (enum gen_action)act,
1673 act_probs,
1674 NULL,
1675 data);
1677 } action_iterate_end;
1679 /* Unit acting against itself. */
1681 action_iterate(act) {
1682 if (action_id_get_actor_kind(act) == AAK_UNIT
1683 && action_id_get_target_kind(act) == ATK_SELF) {
1684 action_entry(shl,
1685 (enum gen_action)act,
1686 act_probs,
1687 NULL,
1688 data);
1690 } action_iterate_end;
1692 if (unit_can_move_to_tile(actor_unit, target_tile, FALSE, FALSE)) {
1693 action_button_map[BUTTON_MOVE] =
1694 choice_dialog_get_number_of_buttons(shl);
1695 choice_dialog_add(shl, _("Keep moving"),
1696 (GCallback)act_sel_keep_moving_callback,
1697 data, FALSE, NULL);
1700 if (target_unit != NULL
1701 && unit_list_size(target_tile->units) > 1) {
1702 action_button_map[BUTTON_NEW_UNIT_TGT] =
1703 choice_dialog_get_number_of_buttons(shl);
1704 choice_dialog_add(shl, _("Change unit target"),
1705 (GCallback)act_sel_new_unit_tgt_callback,
1706 data, TRUE, NULL);
1709 action_button_map[BUTTON_LOCATION] =
1710 choice_dialog_get_number_of_buttons(shl);
1711 choice_dialog_add(shl, _("Show Location"),
1712 (GCallback)act_sel_location_callback, data,
1713 TRUE, NULL);
1715 action_button_map[BUTTON_WAIT] =
1716 choice_dialog_get_number_of_buttons(shl);
1717 choice_dialog_add(shl, _("Wait"),
1718 (GCallback)act_sel_wait_callback, data,
1719 TRUE, NULL);
1721 action_button_map[BUTTON_CANCEL] =
1722 choice_dialog_get_number_of_buttons(shl);
1723 choice_dialog_add(shl, _("Cancel"),
1724 (GCallback)act_sel_cancel_callback, data,
1725 FALSE, NULL);
1727 choice_dialog_end(shl);
1729 act_sel_dialog = shl;
1731 choice_dialog_set_hide(shl, TRUE);
1732 g_signal_connect(shl, "destroy",
1733 G_CALLBACK(act_sel_destroy_callback), NULL);
1734 g_signal_connect(shl, "delete_event",
1735 G_CALLBACK(act_sel_close_callback), data);
1737 /* Give follow up questions access to action probabilities. */
1738 client_unit_init_act_prob_cache(actor_unit);
1739 action_iterate(act) {
1740 actor_unit->client.act_prob_cache[act] = act_probs[act];
1741 } action_iterate_end;
1743 astr_free(&title);
1744 astr_free(&text);
1747 /**************************************************************************
1748 Returns the id of the actor unit currently handled in action selection
1749 dialog when the action selection dialog is open.
1750 Returns IDENTITY_NUMBER_ZERO if no action selection dialog is open.
1751 **************************************************************************/
1752 int action_selection_actor_unit(void)
1754 if (act_sel_dialog == NULL) {
1755 return IDENTITY_NUMBER_ZERO;
1757 return actor_unit_id;
1760 /**************************************************************************
1761 Returns id of the target city of the actions currently handled in action
1762 selection dialog when the action selection dialog is open and it has a
1763 city target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1764 is open or no city target is present in the action selection dialog.
1765 **************************************************************************/
1766 int action_selection_target_city(void)
1768 if (act_sel_dialog == NULL) {
1769 return IDENTITY_NUMBER_ZERO;
1771 return target_ids[ATK_CITY];
1774 /**************************************************************************
1775 Returns id of the target unit of the actions currently handled in action
1776 selection dialog when the action selection dialog is open and it has a
1777 unit target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1778 is open or no unit target is present in the action selection dialog.
1779 **************************************************************************/
1780 int action_selection_target_unit(void)
1782 if (act_sel_dialog == NULL) {
1783 return IDENTITY_NUMBER_ZERO;
1786 return target_ids[ATK_UNIT];
1789 /**************************************************************************
1790 Updates the action selection dialog with new information.
1791 **************************************************************************/
1792 void action_selection_refresh(struct unit *actor_unit,
1793 struct city *target_city,
1794 struct unit *target_unit,
1795 struct tile *target_tile,
1796 const struct act_prob *act_probs)
1798 struct action_data *data;
1800 if (act_sel_dialog == NULL) {
1801 fc_assert_msg(act_sel_dialog != NULL,
1802 "The action selection dialog should have been open");
1803 return;
1806 if (actor_unit->id != action_selection_actor_unit()) {
1807 fc_assert_msg(actor_unit->id == action_selection_actor_unit(),
1808 "The action selection dialog is for another actor unit.");
1809 return;
1812 data = act_data(actor_unit->id,
1813 (target_city) ? target_city->id : IDENTITY_NUMBER_ZERO,
1814 (target_unit) ? target_unit->id : IDENTITY_NUMBER_ZERO,
1815 (target_tile) ? target_tile->index : 0,
1818 action_iterate(act) {
1819 const gchar *custom;
1821 if (action_id_get_actor_kind(act) != AAK_UNIT) {
1822 /* Not relevant. */
1823 continue;
1826 if (action_prob_possible(act_probs[act])
1827 && act == ACTION_HELP_WONDER) {
1828 /* Add information about how far along the wonder is. */
1829 custom = city_prod_remaining(target_city);
1830 } else {
1831 custom = NULL;
1834 if (BUTTON_NOT_THERE == action_button_map[act]) {
1835 /* Add the button (unless its probability is 0). */
1836 action_entry(act_sel_dialog, act, act_probs, custom, data);
1837 } else {
1838 /* Update the existing button. */
1839 action_entry_update(act_sel_dialog, act, act_probs, custom, data);
1841 } action_iterate_end;
1843 /* DO NOT change the action_button_map[] for any button to reflect its
1844 * new position. A button keeps its choice dialog internal name when its
1845 * position changes. A button's id number is therefore based on when
1846 * it was added, not on its current position. */
1848 if (BUTTON_NOT_THERE != action_button_map[BUTTON_WAIT]) {
1849 /* Move the wait button below the recently added button. */
1850 choice_dialog_button_move_to_the_end(act_sel_dialog,
1851 action_button_map[BUTTON_WAIT]);
1854 if (BUTTON_NOT_THERE != action_button_map[BUTTON_CANCEL]) {
1855 /* Move the cancel button below the recently added button. */
1856 choice_dialog_button_move_to_the_end(act_sel_dialog,
1857 action_button_map[BUTTON_CANCEL]);
1860 choice_dialog_end(act_sel_dialog);
1863 /****************************************************************
1864 Closes the action selection dialog
1865 ****************************************************************/
1866 void action_selection_close(void)
1868 if (act_sel_dialog != NULL) {
1869 did_not_decide = TRUE;
1870 gtk_widget_destroy(act_sel_dialog);