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)
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 ***********************************************************************/
15 #include <fc_config.h>
27 #include "traderoutes.h"
34 #include "dialogs_g.h"
36 #include "choice_dialog.h"
37 #include "client_main.h"
39 #include "connectdlg_common.h"
42 #include "gui_stuff.h"
46 /* client/gui-gtk-3.22 */
49 #include "unitselunitdlg.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. */
86 /****************************************************************
87 Create a new action data structure that can be stored in the
89 *****************************************************************/
90 static struct action_data
*act_data(int actor_id
,
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
;
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
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
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
;
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
;
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
329 /****************************************************************
330 User selected "Upgrade Unit" from choice dialog.
331 *****************************************************************/
332 static void upgrade_callback(GtkWidget
*w
, gpointer data
)
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
);
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
);
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
);
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
)
394 || city_owner(destcity
) != client
.conn
.playing
) {
395 /* Can't give remaining production for a foreign or non existing
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
);
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
);
446 /*************************************************************************
447 Popup unit bribe dialog
448 **************************************************************************/
449 void popup_bribe_dialog(struct unit
*actor
, struct unit
*punit
, int cost
)
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
753 /****************************************************************
754 User responded to steal advances dialog
755 *****************************************************************/
756 static void spy_advances_response(GtkWidget
*w
, gint response
,
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
,
770 /* This is the targeted version. */
771 request_do_action(ACTION_SPY_TARGETED_STEAL_TECH
,
772 args
->actor_unit_id
, args
->target_city_id
,
778 gtk_widget_destroy(spy_tech_shell
);
779 spy_tech_shell
= NULL
;
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
,
792 struct action_data
*args
= (struct action_data
*)data
;
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
);
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
;
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"),
826 _("Cancel"), GTK_RESPONSE_CANCEL
,
827 _("_Steal"), GTK_RESPONSE_ACCEPT
,
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
,
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:"),
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
);
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
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
));
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
);
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
,
948 args
->target_city_id
,
949 args
->value
+ 1, "");
951 /* This is the targeted version. */
952 request_do_action(ACTION_SPY_TARGETED_SABOTAGE_CITY
,
954 args
->target_city_id
,
955 args
->value
+ 1, "");
960 gtk_widget_destroy(spy_sabotage_shell
);
961 spy_sabotage_shell
= NULL
;
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
;
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
);
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
,
996 struct action_data
*args
)
998 GtkWidget
*sw
, *label
, *vbox
, *view
;
1000 GtkCellRenderer
*rend
;
1001 GtkTreeViewColumn
*col
;
1004 struct unit
*actor_unit
= game_unit_by_number(args
->actor_unit_id
);
1006 spy_sabotage_shell
= gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
1008 _("Cancel"), GTK_RESPONSE_CANCEL
,
1009 _("_Sabotage"), GTK_RESPONSE_ACCEPT
,
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
,
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:"),
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
),
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);
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
);
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
;
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
));
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
);
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
);
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
);
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
)
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
);
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
),
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
,
1276 /* Let the server choose the target
1278 IDENTITY_NUMBER_ZERO
,
1282 dsend_packet_unit_get_actions(&client
.conn
,
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
;
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:"),
1316 G_CALLBACK(tgt_unit_change_callback
));
1319 did_not_decide
= TRUE
;
1320 action_selection_restart
= TRUE
;
1321 gtk_widget_destroy(act_sel_dialog
);
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
;
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
1343 **************************************************************************/
1344 static void act_sel_keep_moving_callback(GtkWidget
*w
, gpointer data
)
1346 struct action_data
*args
= (struct action_data
*)data
;
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
);
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
;
1370 /* the dialog was destroyed when key_unit_wait() resulted in
1371 * action_selection_close() being called. */
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
);
1394 /****************************************************************
1395 Action selection dialog has been closed
1396 *****************************************************************/
1397 static void act_sel_close_callback(GtkWidget
*w
,
1401 gtk_widget_destroy(act_sel_dialog
);
1405 /* Mapping from an action to the function to call when its button is
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
,
1459 const struct act_prob
*act_probs
,
1460 const gchar
*custom
,
1461 struct action_data
*handler_args
)
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. */
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. */
1482 if (af_map
[action_id
] == NULL
) {
1483 /* This client doesn't support ordering this action from the
1484 * action selection dialog. */
1488 /* Don't show disabled actions. */
1489 if (!action_prob_possible(act_probs
[action_id
])) {
1493 label
= action_prepare_ui_name(action_id
, "",
1494 act_probs
[action_id
],
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
,
1505 /******************************************************************
1506 Update an existing button.
1507 *******************************************************************/
1508 static void action_entry_update(GtkWidget
*shl
,
1510 const struct act_prob
*act_probs
,
1511 const gchar
*custom
,
1512 struct action_data
*handler_args
)
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
],
1533 choice_dialog_button_set_tooltip(act_sel_dialog
,
1534 action_button_map
[action_id
],
1538 /**************************************************************************
1539 Popup a dialog that allows the player to select what action a unit
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
)
1549 struct astring title
= ASTRING_INIT
, text
= ASTRING_INIT
;
1550 struct city
*actor_homecity
;
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
?
1580 IDENTITY_NUMBER_ZERO
;
1581 target_ids
[ATK_UNIT
] = target_unit
?
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
;
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
) {
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
) {
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
) {
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
));
1615 fc_assert_msg(target_unit
|| target_city
|| target_tile
,
1616 "No target specified.");
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
),
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
) {
1632 (enum gen_action
)act
,
1634 act
== ACTION_HELP_WONDER
?
1635 city_prod_remaining(target_city
) : NULL
,
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
) {
1646 (enum gen_action
)act
,
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
) {
1659 (enum gen_action
)act
,
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
) {
1672 (enum gen_action
)act
,
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
) {
1685 (enum gen_action
)act
,
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
,
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
,
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
,
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
,
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
,
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
;
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");
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.");
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
) {
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
);
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
);
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
);