Freeciv-3.4
Loading...
Searching...
No Matches
action_dialog.c
Go to the documentation of this file.
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.
7
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***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <gtk/gtk.h>
19
20/* utility */
21#include "astring.h"
22#include "support.h"
23
24/* common */
25#include "actions.h"
26#include "game.h"
27#include "traderoutes.h"
28#include "movement.h"
29#include "research.h"
30#include "specialist.h"
31#include "unit.h"
32#include "unitlist.h"
33
34/* client */
35#include "dialogs_g.h"
36#include "chatline.h"
37#include "choice_dialog.h"
38#include "client_main.h"
39#include "climisc.h"
40#include "connectdlg_common.h"
41#include "control.h"
42#include "gui_main.h"
43#include "gui_stuff.h"
44#include "mapview.h"
45#include "packhand.h"
46#include "text.h"
47
48/* client/gui-gtk-3.22 */
49#include "citydlg.h"
50#include "dialogs.h"
51#include "unitselextradlg.h"
52#include "unitselunitdlg.h"
53#include "wldlg.h"
54
55/* Locations for non action enabler controlled buttons. */
56#define BUTTON_NEW_UNIT_TGT (ACTION_COUNT + 1)
57#define BUTTON_NEW_EXTRA_TGT (BUTTON_NEW_UNIT_TGT + 1)
58#define BUTTON_LOCATION (BUTTON_NEW_EXTRA_TGT + 1)
59#define BUTTON_WAIT (BUTTON_LOCATION + 1)
60#define BUTTON_CANCEL (BUTTON_WAIT + 1)
61#define BUTTON_COUNT (BUTTON_CANCEL + 1)
62
63#define BUTTON_NOT_THERE -1
64
65
68
69static int actor_unit_id;
71static int target_extra_id;
73static bool did_not_decide = FALSE;
75
77
79
80/* A structure to hold parameters for actions inside the GUI instead of
81 * storing the needed data in a global variable. */
93
94/* TODO: maybe this should be in the dialog itself? */
96
97/**********************************************************************/
102 int actor_id,
103 int target_city_id,
104 int target_unit_id,
105 int target_tile_id,
107 int target_tech_id,
109 int tgt_extra_id)
110{
111 struct action_data *data = fc_malloc(sizeof(*data));
112
113 data->act_id = act_id;
114 data->actor_unit_id = actor_id;
122
123 return data;
124}
125
126/**********************************************************************/
131{
133 /* The client isn't waiting for information for any unanswered follow
134 * up questions. */
135
136 struct unit *actor_unit;
137
139 /* The action selection dialog wasn't closed because the actor unit
140 * was lost. */
141
142 /* The probabilities didn't just disappear, right? */
145
147 }
148
150 /* The action selection dialog was closed but only so it can be
151 * redrawn with fresh data. */
152
154 } else {
155 /* The action selection process is over, at least for now. */
157 }
158
159 if (did_not_decide) {
160 /* The action selection dialog was closed but the player didn't
161 * decide what the unit should do. */
162
163 /* Reset so the next action selection dialog does the right thing. */
165 } else {
166 /* An action, or no action at all, was selected. */
169 }
170 }
171}
172
173/**********************************************************************/
178{
179 /* Stop waiting. Move on to the next queued unit. */
182}
183
184/**********************************************************************/
191{
192 /* Stop assuming the answer to a follow up question will arrive. */
194}
195
196/**********************************************************************/
201{
202 /* Don't add an action mapping here unless the non targeted version is
203 * selectable in the targeted version's target selection dialog. */
204 switch ((enum gen_action)tgt_action_id) {
213 default:
214 /* No non targeted version found. */
215 return ACTION_NONE;
216 }
217}
218
219/**********************************************************************/
224{
225 /* Don't add an action mapping here unless the non targeted version is
226 * selectable in the targeted version's target selection dialog. */
227 switch ((enum gen_action)tgt_action_id) {
234 default:
235 /* No non targeted version found. */
236 return ACTION_NONE;
237 }
238}
239
240/**********************************************************************/
245{
246 int actor_id, target_id, sub_target;
247 struct action *paction;
248
249 struct action_data *args = act_sel_dialog_data;
250
251 bool failed = FALSE;
252
253 /* Data */
254 args->act_id = GPOINTER_TO_INT(data);
256
257 /* Actor */
259 actor_id = args->actor_unit_id;
260 if (NULL == game_unit_by_number(actor_id)) {
261 /* Probably dead. */
262 failed = TRUE;
263 }
264
265 /* Target */
266 target_id = IDENTITY_NUMBER_ZERO;
268 case ATK_CITY:
269 target_id = args->target_city_id;
270 if (NULL == game_city_by_number(target_id)) {
271 /* Probably destroyed. */
272 failed = TRUE;
273 }
274 break;
275 case ATK_UNIT:
276 target_id = args->target_unit_id;
277 if (NULL == game_unit_by_number(target_id)) {
278 /* Probably dead. */
279 failed = TRUE;
280 }
281 break;
282 case ATK_STACK:
283 case ATK_TILE:
284 case ATK_EXTRAS:
285 target_id = args->target_tile_id;
286 if (NULL == index_to_tile(&(wld.map), target_id)) {
287 /* TODO: Should this be possible at all? If not: add assertion. */
288 failed = TRUE;
289 }
290 break;
291 case ATK_SELF:
292 target_id = IDENTITY_NUMBER_ZERO;
293 break;
294 case ATK_COUNT:
296 failed = TRUE;
297 }
298
299 /* Sub target. */
300 sub_target = NO_TARGET;
301 if (paction->target_complexity != ACT_TGT_COMPL_SIMPLE) {
303 case ASTK_BUILDING:
304 sub_target = args->target_building_id;
305 if (NULL == improvement_by_number(sub_target)) {
306 /* Did the ruleset change? */
307 failed = TRUE;
308 }
309 break;
310 case ASTK_TECH:
311 sub_target = args->target_tech_id;
312 if (NULL == valid_advance_by_number(sub_target)) {
313 /* Did the ruleset change? */
314 failed = TRUE;
315 }
316 break;
317 case ASTK_EXTRA:
319 /* TODO: validate if the extra is there? */
320 sub_target = args->target_extra_id;
321 if (NULL == extra_by_number(sub_target)) {
322 /* Did the ruleset change? */
323 failed = TRUE;
324 }
325 break;
326 case ASTK_SPECIALIST:
327 sub_target = args->target_specialist_id;
328 if (nullptr == specialist_by_number(sub_target)) {
329 /* Did the ruleset change? */
330 failed = TRUE;
331 }
332 break;
333 case ASTK_NONE:
334 case ASTK_COUNT:
335 /* Shouldn't happen. */
337 failed = TRUE;
338 break;
339 }
340 }
341
342 /* Send request. */
343 if (!failed) {
344 request_do_action(paction->id, actor_id, target_id, sub_target, "");
345 }
346
347 /* Clean up. */
349 /* No follow up questions. */
351 FC_FREE(args);
352}
353
354/**********************************************************************/
359{
360 int actor_id, target_id;
361 struct action *paction;
362
363 struct action_data *args = act_sel_dialog_data;
364
365 bool failed = FALSE;
366
367 /* Data */
368 args->act_id = GPOINTER_TO_INT(data);
370
371 /* Actor */
373 actor_id = args->actor_unit_id;
374 if (NULL == game_unit_by_number(actor_id)) {
375 /* Probably dead. */
376 failed = TRUE;
377 }
378
379 /* Target */
380 target_id = IDENTITY_NUMBER_ZERO;
382 case ATK_CITY:
383 target_id = args->target_city_id;
384 if (NULL == game_city_by_number(target_id)) {
385 /* Probably destroyed. */
386 failed = TRUE;
387 }
388 break;
389 case ATK_UNIT:
390 target_id = args->target_unit_id;
391 if (NULL == game_unit_by_number(target_id)) {
392 /* Probably dead. */
393 failed = TRUE;
394 }
395 break;
396 case ATK_STACK:
397 case ATK_TILE:
398 case ATK_EXTRAS:
399 target_id = args->target_tile_id;
400 if (NULL == index_to_tile(&(wld.map), target_id)) {
401 /* TODO: Should this be possible at all? If not: add assertion. */
402 failed = TRUE;
403 }
404 break;
405 case ATK_SELF:
406 target_id = IDENTITY_NUMBER_ZERO;
407 break;
408 case ATK_COUNT:
410 failed = TRUE;
411 }
412
413 /* Send request. */
414 if (!failed) {
415 request_action_details(paction->id, actor_id, target_id);
416 }
417
418 /* Wait for the server's reply before moving on to the next unit that
419 * needs to know what action to take. */
421
422 /* Clean up. */
424 /* No client side follow up questions. */
426 FC_FREE(args);
427}
428
429/**********************************************************************/
442
443/**********************************************************************/
447{
448 struct unit *punit;
449
450 struct action_data *args = act_sel_dialog_data;
451
454 struct unit_list *as_list;
455
460 }
461
463 free(args);
464}
465
466/**********************************************************************/
469static void bribe_unit_response(GtkWidget *w, gint response, gpointer data)
470{
471 struct action_data *args = (struct action_data *)data;
472
473 if (response == GTK_RESPONSE_YES) {
475 args->target_unit_id, 0, "");
476 }
477
479 free(args);
480
481 /* The user have answered the follow up question. Move on. */
483}
484
485/**********************************************************************/
488static void bribe_stack_response(GtkWidget *w, gint response, gpointer data)
489{
490 struct action_data *args = (struct action_data *)data;
491
492 if (response == GTK_RESPONSE_YES) {
494 args->target_tile_id, 0, "");
495 }
496
498 free(args);
499
500 /* The user have answered the follow up question. Move on. */
502}
503
504/**********************************************************************/
507void popup_bribe_unit_dialog(struct unit *actor, struct unit *punit, int cost,
508 const struct action *paction)
509{
511 char buf[1024];
512
513 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
514 "Treasury contains %d gold.",
515 client_player()->economic.gold),
516 client_player()->economic.gold);
517
518 if (cost <= client_player()->economic.gold) {
521 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
522 PL_("Bribe unit for %d gold?\n%s",
523 "Bribe unit for %d gold?\n%s", cost), cost, buf);
524 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
526 } else {
529 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
530 PL_("Bribing the unit costs %d gold.\n%s",
531 "Bribing the unit costs %d gold.\n%s", cost), cost, buf);
532 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
534 }
536
538 act_data(paction->id, actor->id,
539 0, punit->id, 0,
540 0, 0, 0, 0));
541}
542
543/**********************************************************************/
546void popup_bribe_stack_dialog(struct unit *actor, struct tile *ptile, int cost,
547 const struct action *paction)
548{
550 char buf[1024];
551
552 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
553 "Treasury contains %d gold.",
554 client_player()->economic.gold),
555 client_player()->economic.gold);
556
557 if (cost <= client_player()->economic.gold) {
560 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
561 PL_("Bribe unit stack for %d gold?\n%s",
562 "Bribe unit stack for %d gold?\n%s", cost), cost, buf);
563 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
565 } else {
568 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
569 PL_("Bribing units costs %d gold.\n%s",
570 "Bribing units costs %d gold.\n%s", cost), cost, buf);
571 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
573 }
575
577 act_data(paction->id, actor->id,
578 0, 0, ptile->index,
579 0, 0, 0, 0));
580}
581
582/**********************************************************************/
585static void spy_advances_response(GtkWidget *w, gint response,
586 gpointer data)
587{
588 struct action_data *args = (struct action_data *)data;
589
590 if (response == GTK_RESPONSE_ACCEPT && args->target_tech_id > 0) {
593 if (args->target_tech_id == A_UNSET) {
594 /* This is the untargeted version. */
596 args->actor_unit_id, args->target_city_id,
597 args->target_tech_id, "");
598 } else {
599 /* This is the targeted version. */
601 args->actor_unit_id, args->target_city_id,
602 args->target_tech_id, "");
603 }
604 }
605 }
606
609 free(data);
610
611 /* The user have answered the follow up question. Move on. */
613}
614
615/**********************************************************************/
619 gpointer data)
620{
621 struct action_data *args = (struct action_data *)data;
622
623 GtkTreeModel *model;
624 GtkTreeIter it;
625
626 if (gtk_tree_selection_get_selected(select, &model, &it)) {
627 gtk_tree_model_get(model, &it, 1, &(args->target_tech_id), -1);
628
631 } else {
632 args->target_tech_id = 0;
633
636 }
637}
638
639/**********************************************************************/
642static void create_advances_list(struct player *pplayer,
643 struct player *pvictim,
644 struct action_data *args)
645{
646 GtkWidget *sw, *label, *vbox, *view;
647 GtkListStore *store;
650
652
653 spy_tech_shell = gtk_dialog_new_with_buttons(_("Steal Technology"),
654 NULL, 0,
655 _("_Cancel"), GTK_RESPONSE_CANCEL,
656 _("_Steal"), GTK_RESPONSE_ACCEPT,
657 NULL);
660
663
664 label = gtk_frame_new(_("Select Advance to Steal"));
666
667 vbox = gtk_grid_new();
671 gtk_container_add(GTK_CONTAINER(label), vbox);
672
674
678 g_object_unref(store);
680
683 "text", 0, NULL);
685
687 "use-underline", TRUE,
688 "mnemonic-widget", view,
689 "label", _("_Advances:"),
690 "xalign", 0.0,
691 "yalign", 0.5,
692 NULL);
693 gtk_container_add(GTK_CONTAINER(vbox), label);
694
699
702 gtk_widget_set_size_request(sw, -1, 200);
703
705
706 /* Now populate the list */
707 if (pvictim) { /* you don't want to know what lag can do -- Syela */
708 const struct research *presearch = research_get(pplayer);
709 const struct research *vresearch = research_get(pvictim);
710 GtkTreeIter it;
711 GValue value = { 0, };
712
718 gtk_list_store_append(store, &it);
719
722 (presearch, i));
723 gtk_list_store_set_value(store, &it, 0, &value);
724 g_value_unset(&value);
725 gtk_list_store_set(store, &it, 1, i, -1);
726 }
728
731 gtk_list_store_append(store, &it);
732
734 {
735 struct astring str = ASTRING_INIT;
736 /* TRANS: %s is a unit name, e.g., Spy */
737 astr_set(&str, _("At %s's Discretion"),
740 astr_free(&str);
741 }
742 gtk_list_store_set_value(store, &it, 0, &value);
743 g_value_unset(&value);
744 gtk_list_store_set(store, &it, 1, A_UNSET, -1);
745 }
746 }
747
750
752
757
758 args->target_tech_id = 0;
759
761}
762
763/**********************************************************************/
766static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
767{
768 struct action_data *args = (struct action_data *)data;
769
770 if (response == GTK_RESPONSE_ACCEPT && args->target_building_id > -2) {
773 if (args->target_building_id == B_LAST) {
774 /* This is the untargeted version. */
776 args->actor_unit_id,
777 args->target_city_id,
778 args->target_building_id, "");
779 } else if (args->target_building_id == -1) {
780 /* This is the city production version. */
782 args->actor_unit_id,
783 args->target_city_id,
784 args->target_building_id, "");
785 } else {
786 /* This is the targeted version. */
788 args->actor_unit_id,
789 args->target_city_id,
790 args->target_building_id, "");
791 }
792 }
793 }
794
797 free(args);
798
799 /* The user have answered the follow up question. Move on. */
801}
802
803/**********************************************************************/
807{
808 struct action_data *args = (struct action_data *)data;
809
810 GtkTreeModel *model;
811 GtkTreeIter it;
812
813 if (gtk_tree_selection_get_selected(select, &model, &it)) {
814 gtk_tree_model_get(model, &it, 1, &(args->target_building_id), -1);
815
818 } else {
819 args->target_building_id = -2;
820
823 }
824}
825
826/**********************************************************************/
829static void create_improvements_list(struct player *pplayer,
830 struct city *pcity,
831 struct action_data *args)
832{
833 GtkWidget *sw, *label, *vbox, *view;
834 GtkListStore *store;
837 GtkTreeIter it;
838 struct action *paction = action_by_number(args->act_id);
840
841 if (paction->result == ACTRES_STRIKE_BUILDING) {
842 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Strike Improvements"),
843 NULL, 0,
844 _("_Cancel"), GTK_RESPONSE_CANCEL,
845 _("_Strike"), GTK_RESPONSE_ACCEPT,
846 NULL);
847 } else {
848 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
849 NULL, 0,
850 _("_Cancel"), GTK_RESPONSE_CANCEL,
851 _("_Sabotage"), GTK_RESPONSE_ACCEPT,
852 NULL);
853 }
856
859
860 if (paction->result == ACTRES_STRIKE_BUILDING) {
861 label = gtk_frame_new(_("Select Improvement to Strike"));
862 } else {
863 label = gtk_frame_new(_("Select Improvement to Sabotage"));
864 }
866 label);
867
868 vbox = gtk_grid_new();
872 gtk_container_add(GTK_CONTAINER(label), vbox);
873
875
879 g_object_unref(store);
881
884 "text", 0, NULL);
886
888 "use-underline", TRUE,
889 "mnemonic-widget", view,
890 "label", _("_Improvements:"),
891 "xalign", 0.0,
892 "yalign", 0.5,
893 NULL);
894 gtk_container_add(GTK_CONTAINER(vbox), label);
895
900
904
906
907 /* Now populate the list */
910 args->act_id)])) {
911 gtk_list_store_append(store, &it);
912 gtk_list_store_set(store, &it, 0, _("City Production"), 1, -1, -1);
913 }
914
915 city_built_iterate(pcity, pimprove) {
916 if (pimprove->sabotage > 0) {
917 gtk_list_store_append(store, &it);
918 gtk_list_store_set(store, &it,
920 1, improvement_number(pimprove),
921 -1);
922 }
924
927 struct astring str = ASTRING_INIT;
928
929 gtk_list_store_append(store, &it);
930
931 /* TRANS: %s is a unit name, e.g., Spy */
932 astr_set(&str, _("At %s's Discretion"),
934 gtk_list_store_set(store, &it, 0, astr_str(&str), 1, B_LAST, -1);
935
936 astr_free(&str);
937 }
938
941
943
948
949 args->target_building_id = -2;
950
952}
953
954/**********************************************************************/
958{
959 struct action_data *args = (struct action_data *)data;
960
962 struct player *pvictim = NULL;
963
964 if (pvcity) {
966 }
967
968/* it is concievable that pvcity will not be found, because something
969has happened to the city during latency. Therefore we must initialize
970pvictim to NULL and account for !pvictim in create_advances_list. -- Syela */
971
972 /* FIXME: Don't discard the second tech choice dialog. */
973 if (!spy_tech_shell) {
976 } else {
977 free(args);
978 }
979
980 /* Wait for the player's reply before moving on to the next unit that
981 * needs to know what action to take. */
983
985}
986
987/**********************************************************************/
996
997/**********************************************************************/
1006
1007/**********************************************************************/
1012 const struct action *paction)
1013{
1014 /* FIXME: Don't discard the second target choice dialog. */
1015 if (!spy_sabotage_shell) {
1017 act_data(paction->id,
1018 actor->id, pcity->id, 0, 0,
1019 0, 0, 0, 0));
1021 }
1022}
1023
1024/**********************************************************************/
1027static void incite_response(GtkWidget *w, gint response, gpointer data)
1028{
1029 struct action_data *args = (struct action_data *)data;
1030
1031 if (response == GTK_RESPONSE_YES) {
1033 args->target_city_id, 0, "");
1034 }
1035
1037 free(args);
1038
1039 /* The user have answered the follow up question. Move on. */
1041}
1042
1043/**********************************************************************/
1046void popup_incite_dialog(struct unit *actor, struct city *pcity, int cost,
1047 const struct action *paction)
1048{
1050 char buf[1024];
1051
1052 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
1053 "Treasury contains %d gold.",
1054 client_player()->economic.gold),
1055 client_player()->economic.gold);
1056
1060 _("You can't incite a revolt in %s."),
1062 gtk_window_set_title(GTK_WINDOW(shell), _("City can't be incited!"));
1064 } else if (cost <= client_player()->economic.gold) {
1067 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1068 PL_("Incite a revolt for %d gold?\n%s",
1069 "Incite a revolt for %d gold?\n%s", cost), cost, buf);
1070 gtk_window_set_title(GTK_WINDOW(shell), _("Incite a Revolt!"));
1072 } else {
1074 0,
1076 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1077 PL_("Inciting a revolt costs %d gold.\n%s",
1078 "Inciting a revolt costs %d gold.\n%s", cost), cost, buf);
1079 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
1081 }
1083
1085 act_data(paction->id, actor->id,
1086 pcity->id, 0, 0,
1087 0, 0, 0, 0));
1088}
1089
1090/**********************************************************************/
1094{
1095 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
1096
1097 if (arg == GTK_RESPONSE_YES) {
1099
1100 if (actor != NULL) {
1102 "target"));
1104 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
1105
1106 if (tgt_unit == NULL) {
1107 /* Make the action dialog pop up again. */
1109 actor->id,
1110 /* Let the server choose the target
1111 * unit. */
1113 tgt_tile->index,
1116 } else {
1118 actor->id,
1119 tgt_id,
1120 tgt_tile->index,
1123 }
1124 }
1125 } else {
1126 /* Dialog canceled. This ends the action selection process. */
1128 }
1129
1130 gtk_widget_destroy(dlg);
1131}
1132
1133/**********************************************************************/
1137{
1138 struct action_data *args = act_sel_dialog_data;
1139
1140 struct unit *punit;
1141 struct unit *tunit;
1142 struct tile *ptile;
1143
1145 && (ptile = index_to_tile(&(wld.map), args->target_tile_id))
1146 && (tunit = game_unit_by_number(args->target_unit_id))) {
1147 select_tgt_unit(punit, ptile, ptile->units, tunit,
1148 _("Target unit selection"),
1149 _("Looking for target unit:"),
1150 _("Units at tile:"),
1151 _("Select"),
1153 }
1154
1158 free(args);
1159}
1160
1161/**********************************************************************/
1165{
1166 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
1167
1168 if (arg == GTK_RESPONSE_YES) {
1170
1171 if (actor != NULL) {
1173 "target"));
1175 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
1176
1177 if (tgt_extra == NULL) {
1178 /* Make the action dialog pop up again. */
1180 actor->id,
1182 tgt_tile->index,
1183 /* Let the server choose the target
1184 * extra. */
1187 } else {
1189 actor->id,
1191 tgt_tile->index,
1192 tgt_id,
1194 }
1195 }
1196 } else {
1197 /* Dialog canceled. This ends the action selection process. */
1199 }
1200
1201 gtk_widget_destroy(dlg);
1202}
1203
1204/**********************************************************************/
1208{
1209 struct action_data *args = act_sel_dialog_data;
1210
1211 struct unit *act_unit;
1212 struct extra_type *tgt_extra;
1213 struct tile *tgt_tile;
1214
1216 && (tgt_tile = index_to_tile(&(wld.map), args->target_tile_id))
1219
1220 /* Start with the extras at the tile */
1222
1224 if (BV_ISSET(potential_targets, extra_number(pextra))) {
1225 /* This extra is at the tile. Can anything be done to it? */
1227 pextra)) {
1229 }
1230 } else {
1231 /* This extra isn't at the tile yet. Can it be created? */
1233 pextra)) {
1235 }
1236 }
1238
1240 /* TRANS: GTK action selection dialog extra target
1241 * selection dialog title. */
1242 _("Target extra selection"),
1243 /* TRANS: GTK action selection dialog extra target
1244 * selection dialog actor unit label. */
1245 _("Looking for target extra:"),
1246 /* TRANS: GTK action selection dialog extra target
1247 * selection dialog extra list label. */
1248 _("Extra targets:"),
1249 _("Select"),
1251 }
1252
1256 free(args);
1257}
1258
1259/**********************************************************************/
1263{
1264 struct action_data *args = act_sel_dialog_data;
1265
1266 struct unit *punit;
1267
1268 if ((punit = game_unit_by_number(args->actor_unit_id))) {
1270 }
1271}
1272
1273/**********************************************************************/
1277{
1278 struct action_data *args = act_sel_dialog_data;
1279
1280 key_unit_wait();
1281
1282 /* the dialog was destroyed when key_unit_wait() resulted in
1283 * action_selection_close() being called. */
1284
1285 free(args);
1286}
1287
1288/**********************************************************************/
1296
1297/**********************************************************************/
1305
1306/**********************************************************************/
1316
1317/* Mapping from an action to the function to call when its button is
1318 * pushed. */
1320 /* Unit acting against a city target. */
1331
1332 /* Unit acting against a unit target. */
1334
1335 /* Unit acting against all units at a tile. */
1337
1338 /* Unit acting against a tile. */
1340
1341 /* Unit acting with no target except itself. */
1342 /* No special callback functions needed for any self targeted actions. */
1343};
1344
1345/**********************************************************************/
1350 const struct act_prob *act_probs,
1351 const char *custom,
1353{
1354 const gchar *label;
1355 const gchar *tooltip;
1356 GCallback cb;
1357
1358 if (af_map[act_id] == NULL) {
1359 /* No special call back function needed for this action. */
1361 } else {
1362 /* Special action specific callback function specified. */
1363 cb = af_map[act_id];
1364 }
1365
1366 /* Don't show disabled actions. */
1368 return;
1369 }
1370
1371 label = action_prepare_ui_name(act_id, "_",
1373 custom);
1374
1376 act_probs[act_id]);
1377
1380 FALSE, tooltip);
1381}
1382
1383/**********************************************************************/
1388 const struct act_prob *act_probs,
1389 const char *custom,
1391{
1392 const gchar *label;
1393 const gchar *tooltip;
1394
1395 /* An action that just became impossible has its button disabled.
1396 * An action that became possible again must be re-enabled. */
1400
1401 /* The probability may have changed. */
1402 label = action_prepare_ui_name(act_id, "_",
1404
1406 act_probs[act_id]);
1407
1410 label);
1413 tooltip);
1414}
1415
1416/**********************************************************************/
1421 struct city *target_city,
1422 struct unit *target_unit,
1423 struct tile *target_tile,
1424 struct extra_type *target_extra,
1425 const struct act_prob *act_probs)
1426{
1427 GtkWidget *shl;
1428 struct astring title = ASTRING_INIT, text = ASTRING_INIT;
1429 struct city *actor_homecity;
1430
1431 int button_id;
1432
1434 act_data(ACTION_ANY, /* Not decided yet */
1435 actor_unit->id,
1439 /* No target_building or target_tech supplied. (Dec 2019) */
1440 B_LAST, A_UNSET, -1,
1442
1443 /* Could be caused by the server failing to reply to a request for more
1444 * information or a bug in the client code. */
1446 "Diplomat queue problem. Is another diplomat window open?");
1447
1448 /* No extra input is required as no action has been chosen yet. */
1450
1451 /* No buttons are added yet. */
1452 for (button_id = 0; button_id < BUTTON_COUNT; button_id++) {
1454 }
1455
1457
1461 target_city->id :
1464 target_unit->id :
1477 EXTRA_NONE;
1478
1479 astr_set(&title,
1480 /* TRANS: %s is a unit name, e.g., Spy */
1481 _("Choose Your %s's Strategy"),
1483
1484 if (target_city && actor_homecity) {
1485 astr_set(&text,
1486 _("Your %s from %s reaches the city of %s.\nWhat now?"),
1490 } else if (target_city) {
1491 astr_set(&text,
1492 _("Your %s has arrived at %s.\nWhat is your command?"),
1495 } else if (target_unit != nullptr) {
1497
1498 if (owner != nullptr) {
1499 astr_set(&text,
1500 /* TRANS: Your Spy is ready to act against Roman Freight. */
1501 _("Your %s is ready to act against %s %s."),
1505 } else {
1506 /* Flagless unit */
1507 astr_set(&text,
1508 /* TRANS: Your Spy is ready to act against Freight. */
1509 _("Your %s is ready to act against %s."),
1512 }
1513 } else {
1515 "No target specified.");
1516 astr_set(&text,
1517 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
1518 _("Your %s is waiting for your command."),
1520 }
1521
1523 astr_str(&text));
1524
1525 /* Unit acting against a city */
1526
1527 action_iterate(act) {
1532 act_probs[act],
1533 actor_unit,
1534 target_city),
1535 act);
1536 }
1538
1539 /* Unit acting against another unit */
1540
1541 action_iterate(act) {
1546 act_probs[act],
1547 actor_unit,
1548 target_city),
1549 act);
1550 }
1552
1553 /* Unit acting against all units at a tile */
1554
1555 action_iterate(act) {
1560 act_probs[act],
1561 actor_unit,
1562 target_city),
1563 act);
1564 }
1566
1567 /* Unit acting against a tile */
1568
1569 action_iterate(act) {
1574 act_probs[act],
1575 actor_unit,
1576 target_city),
1577 act);
1578 }
1580
1581 /* Unit acting against a tile's extras */
1582
1583 action_iterate(act) {
1588 act_probs[act],
1589 actor_unit,
1590 target_city),
1591 act);
1592 }
1594
1595 /* Unit acting against itself. */
1596
1597 action_iterate(act) {
1602 act_probs[act],
1603 actor_unit,
1604 target_city),
1605 act);
1606 }
1608
1609 if (target_unit != NULL
1610 && unit_list_size(target_tile->units) > 1) {
1613 choice_dialog_add(shl, _("Change unit target"),
1616 }
1617
1618 if (target_extra != NULL) {
1621 choice_dialog_add(shl, _("Change extra target"),
1624 }
1625
1628 choice_dialog_add(shl, _("Show Location"),
1631 TRUE, NULL);
1632
1635 choice_dialog_add(shl, _("_Wait"),
1638 TRUE, NULL);
1639
1642 choice_dialog_add(shl, _("_Cancel"),
1645 FALSE, NULL);
1646
1648
1650
1652 g_signal_connect(shl, "destroy",
1654 g_signal_connect(shl, "delete_event",
1657
1658 /* Give follow up questions access to action probabilities. */
1660 action_iterate(act) {
1663
1664 astr_free(&title);
1665 astr_free(&text);
1666}
1667
1668/**********************************************************************/
1674{
1675 if (act_sel_dialog == NULL) {
1676 return IDENTITY_NUMBER_ZERO;
1677 }
1678 return actor_unit_id;
1679}
1680
1681/**********************************************************************/
1688{
1689 if (act_sel_dialog == NULL) {
1690 return IDENTITY_NUMBER_ZERO;
1691 }
1692 return target_ids[ATK_CITY];
1693}
1694
1695/**********************************************************************/
1702{
1703 if (act_sel_dialog == NULL) {
1704 return IDENTITY_NUMBER_ZERO;
1705 }
1706
1707 return target_ids[ATK_UNIT];
1708}
1709
1710/**********************************************************************/
1717{
1718 if (act_sel_dialog == NULL) {
1719 return TILE_INDEX_NONE;
1720 }
1721
1722 return target_ids[ATK_TILE];
1723}
1724
1725/**********************************************************************/
1732{
1733 if (act_sel_dialog == NULL) {
1734 return EXTRA_NONE;
1735 }
1736
1737 return target_extra_id;
1738}
1739
1740/**********************************************************************/
1744 struct city *target_city,
1745 struct unit *target_unit,
1746 struct tile *target_tile,
1747 struct extra_type *target_extra,
1748 const struct act_prob *act_probs)
1749{
1750 if (act_sel_dialog == NULL) {
1752 "The action selection dialog should have been open");
1753 return;
1754 }
1755
1758 "The action selection dialog is for another actor unit.");
1759 return;
1760 }
1761
1762 /* A new target may have appeared. */
1763 if (target_city) {
1765 }
1766 if (target_unit) {
1768 }
1769 if (target_tile) {
1771 }
1772 /* No target_building or target_tech supplied. (Dec 2019) */
1773 if (target_extra) {
1775 }
1776
1777 action_iterate(act) {
1778 const char *custom;
1779
1780 if (action_id_get_actor_kind(act) != AAK_UNIT) {
1781 /* Not relevant. */
1782 continue;
1783 }
1784
1786 act_probs[act],
1787 actor_unit,
1788 target_city);
1789
1790 if (BUTTON_NOT_THERE == action_button_map[act]) {
1791 /* Add the button (unless its probability is 0). */
1793 } else {
1794 /* Update the existing button. */
1796 }
1798
1799 /* DO NOT change the action_button_map[] for any button to reflect its
1800 * new position. A button keeps its choice dialog internal name when its
1801 * position changes. A button's id number is therefore based on when
1802 * it was added, not on its current position. */
1803
1805 /* Move the wait button below the recently added button. */
1808 }
1809
1811 /* Move the cancel button below the recently added button. */
1814 }
1815
1817}
1818
1819/**********************************************************************/
1823{
1824 if (act_sel_dialog != NULL) {
1827 }
1828}
const char * action_prepare_ui_name(action_id act_id, const char *mnemonic, const struct act_prob prob, const char *custom)
Definition actions.c:1333
enum action_actor_kind action_get_actor_kind(const struct action *paction)
Definition actions.c:1119
bool action_prob_possible(const struct act_prob probability)
Definition actions.c:5317
enum action_sub_target_kind action_get_sub_target_kind(const struct action *paction)
Definition actions.c:1140
enum action_target_kind action_get_target_kind(const struct action *paction)
Definition actions.c:1129
static struct action * action_by_number(action_id act_id)
Definition actions.h:400
#define action_iterate_end
Definition actions.h:218
#define action_id_get_actor_kind(act_id)
Definition actions.h:413
#define action_iterate(_act_)
Definition actions.h:214
#define ACTION_ANY
Definition actions.h:56
#define action_id_get_target_kind(act_id)
Definition actions.h:417
#define ACTION_NONE
Definition actions.h:59
void astr_free(struct astring *astr)
Definition astring.c:148
void astr_set(struct astring *astr, const char *format,...)
Definition astring.c:251
#define str
Definition astring.c:76
static const char * astr_str(const struct astring *astr) fc__attribute((nonnull(1)))
Definition astring.h:93
#define ASTRING_INIT
Definition astring.h:44
#define BV_SET(bv, bit)
Definition bitvector.h:89
#define BV_ISSET(bv, bit)
Definition bitvector.h:86
#define BV_CLR(bv, bit)
Definition bitvector.h:94
const char * city_improvement_name_translation(const struct city *pcity, const struct impr_type *pimprove)
Definition city.c:666
const char * city_name_get(const struct city *pcity)
Definition city.c:1157
#define INCITE_IMPOSSIBLE_COST
Definition city.h:94
#define city_owner(_pcity_)
Definition city.h:564
#define city_built_iterate(_pcity, _p)
Definition city.h:842
#define city_built_iterate_end
Definition city.h:848
struct civclient client
#define client_player()
void client_unit_init_act_prob_cache(struct unit *punit)
Definition climisc.c:1264
char * incite_cost
Definition comments.c:77
void action_selection_no_longer_in_progress(const int old_actor_id)
Definition control.c:1063
void request_do_action(action_id action, int actor_id, int target_id, int sub_tgt, const char *name)
Definition control.c:1742
void request_action_details(action_id action, int actor_id, int target_id)
Definition control.c:1810
void action_decision_clear_want(const int old_actor_id)
Definition control.c:1092
void key_unit_wait(void)
Definition control.c:3554
void action_selection_next_in_focus(const int old_actor_id)
Definition control.c:1104
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id popup_bribe_unit_dialog
Definition dialogs_g.h:72
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction popup_sabotage_dialog
Definition dialogs_g.h:76
struct unit struct city struct unit * target_unit
Definition dialogs_g.h:55
popup_action_selection
Definition dialogs_g.h:54
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit * actor
Definition dialogs_g.h:72
struct unit * actor_unit
Definition dialogs_g.h:54
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs action_selection_no_longer_in_progress_gui_specific
Definition dialogs_g.h:68
struct unit struct city struct unit struct tile * target_tile
Definition dialogs_g.h:56
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:73
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction struct unit struct city * pcity
Definition dialogs_g.h:77
struct unit struct city * target_city
Definition dialogs_g.h:55
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int cost
Definition dialogs_g.h:73
struct unit struct city struct unit struct tile struct extra_type * target_extra
Definition dialogs_g.h:56
int extra_number(const struct extra_type *pextra)
Definition extras.c:161
struct extra_type * extra_by_number(int id)
Definition extras.c:183
#define EXTRA_NONE
Definition extras.h:85
#define extra_type_re_active_iterate_end
Definition extras.h:329
#define extra_type_re_active_iterate(_p)
Definition extras.h:325
#define NO_TARGET
Definition fc_types.h:215
int action_id
Definition fc_types.h:250
#define IDENTITY_NUMBER_ZERO
Definition fc_types.h:94
#define PL_(String1, String2, n)
Definition fcintl.h:71
#define _(String)
Definition fcintl.h:67
struct civ_game game
Definition game.c:62
struct world wld
Definition game.c:63
struct unit * game_unit_by_number(int id)
Definition game.c:115
struct city * game_city_by_number(int id)
Definition game.c:106
static GtkWidget * spy_sabotage_shell
int action_selection_target_extra(void)
static void incite_response(GtkWidget *w, gint response, gpointer data)
static int action_button_map[BUTTON_COUNT]
static void spy_improvements_callback(GtkTreeSelection *select, gpointer data)
static int actor_unit_id
#define BUTTON_NEW_EXTRA_TGT
static void act_sel_new_extra_tgt_callback(GtkWidget *w, gpointer data)
int action_selection_target_tile(void)
static void create_improvements_list(struct player *pplayer, struct city *pcity, struct action_data *args)
static void act_sel_destroy_callback(GtkWidget *w, gpointer data)
int action_selection_actor_unit(void)
void popup_bribe_stack_dialog(struct unit *actor, struct tile *ptile, int cost, const struct action *paction)
static void spy_advances_response(GtkWidget *w, gint response, gpointer data)
static void tgt_extra_change_callback(GtkWidget *dlg, gint arg)
static GtkWidget * act_sel_dialog
static void spy_steal_popup_shared(GtkWidget *w, gpointer data)
static void diplomat_queue_handle_primary(void)
void action_selection_close(void)
static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
int action_selection_target_city(void)
#define BUTTON_WAIT
static void action_entry(GtkWidget *shl, action_id act_id, const struct act_prob *act_probs, const char *custom, action_id act_num)
static void spy_steal_esc_popup(GtkWidget *w, gpointer data)
static void spy_steal_popup(GtkWidget *w, gpointer data)
static void act_sel_close_callback(GtkWidget *w, gint response_id, gpointer data)
static void diplomat_queue_handle_secondary(void)
static action_id get_non_targeted_action_id(action_id tgt_action_id)
static void request_action_details_callback(GtkWidget *w, gpointer data)
static bool action_selection_restart
#define BUTTON_NEW_UNIT_TGT
#define BUTTON_COUNT
static struct action_data * act_sel_dialog_data
static void found_city_callback(GtkWidget *w, gpointer data)
static void bribe_stack_response(GtkWidget *w, gint response, gpointer data)
static void act_sel_location_callback(GtkWidget *w, gpointer data)
void action_selection_refresh(struct unit *actor_unit, struct city *target_city, struct unit *target_unit, struct tile *target_tile, struct extra_type *target_extra, const struct act_prob *act_probs)
static void simple_action_callback(GtkWidget *w, gpointer data)
static void create_advances_list(struct player *pplayer, struct player *pvictim, struct action_data *args)
static bool is_more_user_input_needed
static int target_extra_id
static void act_sel_wait_callback(GtkWidget *w, gpointer data)
static void act_sel_new_unit_tgt_callback(GtkWidget *w, gpointer data)
static void tgt_unit_change_callback(GtkWidget *dlg, gint arg)
#define BUTTON_NOT_THERE
static action_id get_production_targeted_action_id(action_id tgt_action_id)
static bool did_not_decide
#define BUTTON_CANCEL
static GtkWidget * spy_tech_shell
static int target_ids[ATK_COUNT]
static struct action_data * act_data(action_id act_id, int actor_id, int target_city_id, int target_unit_id, int target_tile_id, int target_building_id, int target_tech_id, int target_specialist_id, int tgt_extra_id)
static void act_sel_cancel_callback(GtkWidget *w, gpointer data)
static void action_entry_update(GtkWidget *shl, action_id act_id, const struct act_prob *act_probs, const char *custom, action_id act_num)
int action_selection_target_unit(void)
void popup_incite_dialog(struct unit *actor, struct city *pcity, int cost, const struct action *paction)
static const GCallback af_map[ACTION_COUNT]
static void upgrade_callback(GtkWidget *w, gpointer data)
static void bribe_unit_response(GtkWidget *w, gint response, gpointer data)
static void spy_advances_callback(GtkTreeSelection *select, gpointer data)
#define BUTTON_LOCATION
GtkWidget * choice_dialog_start(GtkWindow *parent, const gchar *name, const gchar *text)
void choice_dialog_end(GtkWidget *dshell)
int choice_dialog_get_number_of_buttons(GtkWidget *cd)
void choice_dialog_button_set_tooltip(GtkWidget *cd, int number, const char *tool_tip)
void choice_dialog_button_move_to_the_end(GtkWidget *cd, const int number)
void choice_dialog_set_hide(GtkWidget *dshell, gboolean setting)
void choice_dialog_add(GtkWidget *dshell, const gchar *label, GCallback handler, gpointer data, bool meta, const gchar *tool_tip)
void choice_dialog_button_set_label(GtkWidget *cd, int number, const char *label)
void choice_dialog_button_set_sensitive(GtkWidget *cd, int button, gboolean state)
struct city * owner
Definition citydlg.c:226
void popup_upgrade_dialog(struct unit_list *punits)
Definition dialogs.c:1435
GtkWidget * toplevel
Definition gui_main.c:126
void gtk_tree_view_focus(GtkTreeView *view)
Definition gui_stuff.c:236
void setup_dialog(GtkWidget *shell, GtkWidget *parent)
Definition gui_stuff.c:287
static struct gui_dialog * shell
Definition messagedlg.c:39
const char * tooltip
Definition repodlgs.c:1315
const char * title
Definition repodlgs.c:1314
bool select_tgt_extra(struct unit *actor, struct tile *ptile, bv_extras potential_tgt_extras, struct extra_type *suggested_tgt_extra, const gchar *dlg_title, const gchar *actor_label, const gchar *tgt_label, const gchar *do_label, GCallback do_callback)
bool select_tgt_unit(struct unit *actor, struct tile *ptile, struct unit_list *potential_tgt_units, struct unit *suggested_tgt_unit, const gchar *dlg_title, const gchar *actor_label, const gchar *tgt_label, const gchar *do_label, GCallback do_callback)
struct impr_type * improvement_by_number(const Impr_type_id id)
Impr_type_id improvement_number(const struct impr_type *pimprove)
#define B_LAST
Definition improvement.h:42
#define fc_assert_msg(condition, message,...)
Definition log.h:182
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_action(condition, action)
Definition log.h:188
int dsend_packet_unit_get_actions(struct connection *pc, int actor_unit_id, int target_unit_id, int target_tile_id, int target_extra_id, int request_kind)
int dsend_packet_city_name_suggestion_req(struct connection *pc, int unit_id)
struct tile * index_to_tile(const struct civ_map *imap, int mindex)
Definition map.c:471
void center_tile_mapcanvas(const struct tile *ptile)
#define FC_FREE(ptr)
Definition mem.h:41
#define fc_malloc(sz)
Definition mem.h:34
const char * nation_adjective_for_player(const struct player *pplayer)
Definition nation.c:169
#define REQEST_PLAYER_INITIATED
Definition packets.h:63
const char * research_advance_name_translation(const struct research *presearch, Tech_type_id tech)
Definition research.c:276
struct research * research_get(const struct player *pplayer)
Definition research.c:130
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:622
bool research_invention_gettable(const struct research *presearch, const Tech_type_id tech, bool allow_holes)
Definition research.c:696
#define ARRAY_SIZE(x)
Definition shared.h:85
struct specialist * specialist_by_number(const Specialist_type_id id)
Definition specialist.c:110
int target_building_id
int target_specialist_id
action_id act_id
Definition city.h:318
struct packet_game_info info
Definition game.h:89
struct connection conn
Definition client_main.h:96
struct player * playing
Definition connection.h:151
bool tech_steal_allow_holes
Definition tile.h:50
int index
Definition tile.h:51
struct unit_list * units
Definition tile.h:58
Definition unit.h:139
int id
Definition unit.h:146
int index
Definition unit.h:197
struct unit::@84::@86 client
struct act_prob * act_prob_cache
Definition unit.h:230
int homecity
Definition unit.h:147
struct civ_map map
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:960
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
struct advance * valid_advance_by_number(const Tech_type_id id)
Definition tech.c:181
#define advance_index_iterate_end
Definition tech.h:246
#define A_FIRST
Definition tech.h:44
#define A_UNSET
Definition tech.h:48
#define advance_index_iterate(_start, _index)
Definition tech.h:242
const char * get_act_sel_action_custom_text(struct action *paction, const struct act_prob prob, const struct unit *actor_unit, const struct city *target_city)
Definition text.c:1763
const char * act_sel_action_tool_tip(const struct action *paction, const struct act_prob prob)
Definition text.c:1868
#define tile_index(_pt_)
Definition tile.h:89
static const bv_extras * tile_extras(const struct tile *ptile)
Definition tile.h:125
#define TILE_INDEX_NONE
Definition tile.h:48
#define unit_tile(_pu)
Definition unit.h:407
#define unit_owner(_pu)
Definition unit.h:406
const struct unit_type * unit_type_get(const struct unit *punit)
Definition unittype.c:126
bool utype_can_remove_extra(const struct unit_type *putype, const struct extra_type *pextra)
Definition unittype.c:266
const char * unit_name_translation(const struct unit *punit)
Definition unittype.c:1595
bool utype_can_create_extra(const struct unit_type *putype, const struct extra_type *pextra)
Definition unittype.c:242