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-4.0 */
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. */
82struct action_data {
84 int actor_unit_id;
92};
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 struct action_data *args = act_sel_dialog_data;
450
453 struct unit_list *as_list;
454
459 }
460
462 free(args);
463}
464
465/**********************************************************************/
468static void bribe_unit_response(GtkWidget *w, gint response, gpointer data)
469{
470 struct action_data *args = (struct action_data *)data;
471
472 if (response == GTK_RESPONSE_YES) {
474 args->target_unit_id, 0, "");
475 }
476
478 free(args);
479
480 /* The user have answered the follow up question. Move on. */
482}
483
484/**********************************************************************/
487static void bribe_stack_response(GtkWidget *w, gint response, gpointer data)
488{
489 struct action_data *args = (struct action_data *)data;
490
491 if (response == GTK_RESPONSE_YES) {
493 args->target_tile_id, 0, "");
494 }
495
497 free(args);
498
499 /* The user have answered the follow up question. Move on. */
501}
502
503/**********************************************************************/
506void popup_bribe_unit_dialog(struct unit *actor, struct unit *punit, int cost,
507 const struct action *paction)
508{
510 char buf[1024];
511
512 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
513 "Treasury contains %d gold.",
514 client_player()->economic.gold),
515 client_player()->economic.gold);
516
517 if (cost <= client_player()->economic.gold) {
520 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
521 PL_("Bribe unit for %d gold?\n%s",
522 "Bribe unit for %d gold?\n%s", cost), cost, buf);
523 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
525 } else {
528 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
529 PL_("Bribing the unit costs %d gold.\n%s",
530 "Bribing the unit costs %d gold.\n%s", cost), cost, buf);
531 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
533 }
535
537 act_data(paction->id, actor->id,
538 0, punit->id, 0,
539 0, 0, 0, 0));
540}
541
542/**********************************************************************/
545void popup_bribe_stack_dialog(struct unit *actor, struct tile *ptile, int cost,
546 const struct action *paction)
547{
549 char buf[1024];
550
551 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
552 "Treasury contains %d gold.",
553 client_player()->economic.gold),
554 client_player()->economic.gold);
555
556 if (cost <= client_player()->economic.gold) {
559 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
560 PL_("Bribe unit stack for %d gold?\n%s",
561 "Bribe unit stack for %d gold?\n%s", cost), cost, buf);
562 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
564 } else {
567 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
568 PL_("Bribing units costs %d gold.\n%s",
569 "Bribing units costs %d gold.\n%s", cost), cost, buf);
570 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
572 }
574
576 act_data(paction->id, actor->id,
577 0, 0, ptile->index,
578 0, 0, 0, 0));
579}
580
581/**********************************************************************/
584static void spy_advances_response(GtkWidget *w, gint response,
585 gpointer data)
586{
587 struct action_data *args = (struct action_data *)data;
588
589 if (response == GTK_RESPONSE_ACCEPT && args->target_tech_id > 0) {
592 if (args->target_tech_id == A_UNSET) {
593 /* This is the untargeted version. */
595 args->actor_unit_id, args->target_city_id,
596 args->target_tech_id, "");
597 } else {
598 /* This is the targeted version. */
600 args->actor_unit_id, args->target_city_id,
601 args->target_tech_id, "");
602 }
603 }
604 }
605
608 free(data);
609
610 /* The user have answered the follow up question. Move on. */
612}
613
614/**********************************************************************/
618 gpointer data)
619{
620 struct action_data *args = (struct action_data *)data;
621
622 GtkTreeModel *model;
623 GtkTreeIter it;
624
625 if (gtk_tree_selection_get_selected(select, &model, &it)) {
626 gtk_tree_model_get(model, &it, 1, &(args->target_tech_id), -1);
627
630 } else {
631 args->target_tech_id = 0;
632
635 }
636}
637
638/**********************************************************************/
641static void create_advances_list(struct player *pplayer,
642 struct player *pvictim,
643 struct action_data *args)
644{
645 GtkWidget *sw, *frame, *label, *vgrid, *view;
646 GtkListStore *store;
649
651
652 spy_tech_shell = gtk_dialog_new_with_buttons(_("Steal Technology"),
653 NULL, 0,
654 _("_Cancel"), GTK_RESPONSE_CANCEL,
655 _("_Steal"), GTK_RESPONSE_ACCEPT,
656 NULL);
658
661
662 frame = gtk_frame_new(_("Select Advance to Steal"));
664
670
672
676 g_object_unref(store);
678
681 "text", 0, NULL);
683
685 "use-underline", TRUE,
686 "mnemonic-widget", view,
687 "label", _("_Advances:"),
688 "xalign", 0.0,
689 "yalign", 0.5,
690 NULL);
691 gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
692
696
699 gtk_widget_set_size_request(sw, -1, 200);
700
701 gtk_grid_attach(GTK_GRID(vgrid), sw, 0, 1, 1, 1);
702
703 /* Now populate the list */
704 if (pvictim) { /* You don't want to know what lag can do -- Syela */
705 const struct research *presearch = research_get(pplayer);
706 const struct research *vresearch = research_get(pvictim);
707 GtkTreeIter it;
708 GValue value = { 0, };
709
715 gtk_list_store_append(store, &it);
716
719 (presearch, i));
720 gtk_list_store_set_value(store, &it, 0, &value);
721 g_value_unset(&value);
722 gtk_list_store_set(store, &it, 1, i, -1);
723 }
725
728 gtk_list_store_append(store, &it);
729
731 {
732 struct astring str = ASTRING_INIT;
733 /* TRANS: %s is a unit name, e.g., Spy */
734 astr_set(&str, _("At %s's Discretion"),
737 astr_free(&str);
738 }
739 gtk_list_store_set_value(store, &it, 0, &value);
740 g_value_unset(&value);
741 gtk_list_store_set(store, &it, 1, A_UNSET, -1);
742 }
743 }
744
747
749 TRUE);
750
755
756 args->target_tech_id = 0;
757
759}
760
761/**********************************************************************/
764static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
765{
766 struct action_data *args = (struct action_data *)data;
767
768 if (response == GTK_RESPONSE_ACCEPT && args->target_building_id > -2) {
771 if (args->target_building_id == B_LAST) {
772 /* This is the untargeted version. */
774 args->actor_unit_id,
775 args->target_city_id,
776 args->target_building_id, "");
777 } else if (args->target_building_id == -1) {
778 /* This is the city production version. */
780 args->actor_unit_id,
781 args->target_city_id,
782 args->target_building_id, "");
783 } else {
784 /* This is the targeted version. */
786 args->actor_unit_id,
787 args->target_city_id,
788 args->target_building_id, "");
789 }
790 }
791 }
792
795 free(args);
796
797 /* The user have answered the follow up question. Move on. */
799}
800
801/**********************************************************************/
805{
806 struct action_data *args = (struct action_data *)data;
807
808 GtkTreeModel *model;
809 GtkTreeIter it;
810
811 if (gtk_tree_selection_get_selected(select, &model, &it)) {
812 gtk_tree_model_get(model, &it, 1, &(args->target_building_id), -1);
813
816 } else {
817 args->target_building_id = -2;
818
821 }
822}
823
824/**********************************************************************/
827static void create_improvements_list(struct player *pplayer,
828 struct city *pcity,
829 struct action_data *args)
830{
831 GtkWidget *sw, *frame, *label, *vgrid, *view;
832 GtkListStore *store;
835 GtkTreeIter it;
836 struct action *paction = action_by_number(args->act_id);
838
839 if (paction->result == ACTRES_STRIKE_BUILDING) {
840 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Strike Improvements"),
841 NULL, 0,
842 _("_Cancel"), GTK_RESPONSE_CANCEL,
843 _("_Strike"), GTK_RESPONSE_ACCEPT,
844 NULL);
845 } else {
846 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
847 NULL, 0,
848 _("_Cancel"), GTK_RESPONSE_CANCEL,
849 _("_Sabotage"), GTK_RESPONSE_ACCEPT,
850 NULL);
851 }
853
856
857 if (paction->result == ACTRES_STRIKE_BUILDING) {
858 frame = gtk_frame_new(_("Select Improvement to Strike"));
859 } else {
860 frame = gtk_frame_new(_("Select Improvement to Sabotage"));
861 }
863
869
871
875 g_object_unref(store);
877
880 "text", 0, NULL);
882
884 "use-underline", TRUE,
885 "mnemonic-widget", view,
886 "label", _("_Improvements:"),
887 "xalign", 0.0,
888 "yalign", 0.5,
889 NULL);
890 gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
891
895
899
900 gtk_grid_attach(GTK_GRID(vgrid), sw, 0, 1, 1, 1);
901
902 /* Now populate the list */
905 args->act_id)])) {
906 gtk_list_store_append(store, &it);
907 gtk_list_store_set(store, &it, 0, _("City Production"), 1, -1, -1);
908 }
909
910 city_built_iterate(pcity, pimprove) {
911 if (pimprove->sabotage > 0) {
912 gtk_list_store_append(store, &it);
913 gtk_list_store_set(store, &it,
915 1, improvement_number(pimprove),
916 -1);
917 }
919
922 struct astring str = ASTRING_INIT;
923
924 gtk_list_store_append(store, &it);
925
926 /* TRANS: %s is a unit name, e.g., Spy */
927 astr_set(&str, _("At %s's Discretion"),
929 gtk_list_store_set(store, &it, 0, astr_str(&str), 1, B_LAST, -1);
930
931 astr_free(&str);
932 }
933
936
938 TRUE);
939
944
945 args->target_building_id = -2;
946
948}
949
950/**********************************************************************/
954{
955 struct action_data *args = (struct action_data *)data;
956
958 struct player *pvictim = NULL;
959
960 if (pvcity) {
962 }
963
964/* It is concievable that pvcity will not be found, because something
965 has happened to the city during latency. Therefore we must initialize
966 pvictim to NULL and account for !pvictim in create_advances_list. -- Syela */
967
968 /* FIXME: Don't discard the second tech choice dialog. */
969 if (!spy_tech_shell) {
972 } else {
973 free(args);
974 }
975
976 /* Wait for the player's reply before moving on to the next unit that
977 * needs to know what action to take. */
979
981}
982
983/**********************************************************************/
992
993/**********************************************************************/
1002
1003/**********************************************************************/
1008 const struct action *paction)
1009{
1010 /* FIXME: Don't discard the second target choice dialog. */
1011 if (!spy_sabotage_shell) {
1013 act_data(paction->id,
1014 actor->id, pcity->id, 0, 0,
1015 0, 0, 0, 0));
1017 }
1018}
1019
1020/**********************************************************************/
1023static void incite_response(GtkWidget *w, gint response, gpointer data)
1024{
1025 struct action_data *args = (struct action_data *)data;
1026
1027 if (response == GTK_RESPONSE_YES) {
1029 args->target_city_id, 0, "");
1030 }
1031
1033 free(args);
1034
1035 /* The user have answered the follow up question. Move on. */
1037}
1038
1039/**********************************************************************/
1042void popup_incite_dialog(struct unit *actor, struct city *pcity, int cost,
1043 const struct action *paction)
1044{
1046 char buf[1024];
1047
1048 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
1049 "Treasury contains %d gold.",
1050 client_player()->economic.gold),
1051 client_player()->economic.gold);
1052
1056 _("You can't incite a revolt in %s."),
1058 gtk_window_set_title(GTK_WINDOW(shell), _("City can't be incited!"));
1060 } else if (cost <= client_player()->economic.gold) {
1063 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1064 PL_("Incite a revolt for %d gold?\n%s",
1065 "Incite a revolt for %d gold?\n%s", cost), cost, buf);
1066 gtk_window_set_title(GTK_WINDOW(shell), _("Incite a Revolt!"));
1068 } else {
1070 0,
1072 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1073 PL_("Inciting a revolt costs %d gold.\n%s",
1074 "Inciting a revolt costs %d gold.\n%s", cost), cost, buf);
1075 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
1077 }
1079
1081 act_data(paction->id, actor->id,
1082 pcity->id, 0, 0,
1083 0, 0, 0, 0));
1084}
1085
1086/**********************************************************************/
1090{
1091 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
1092
1093 if (arg == GTK_RESPONSE_YES) {
1095
1096 if (actor != NULL) {
1098 "target"));
1100 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
1101
1102 if (tgt_unit == NULL) {
1103 /* Make the action dialog pop up again. */
1105 actor->id,
1106 /* Let the server choose the target
1107 * unit. */
1109 tgt_tile->index,
1112 } else {
1114 actor->id,
1115 tgt_id,
1116 tgt_tile->index,
1119 }
1120 }
1121 } else {
1122 /* Dialog canceled. This ends the action selection process. */
1124 }
1125
1127}
1128
1129/**********************************************************************/
1133{
1134 struct action_data *args = act_sel_dialog_data;
1135
1136 struct unit *punit;
1137 struct unit *tunit;
1138 struct tile *ptile;
1139
1141 && (ptile = index_to_tile(&(wld.map), args->target_tile_id))
1142 && (tunit = game_unit_by_number(args->target_unit_id))) {
1143 select_tgt_unit(punit, ptile, ptile->units, tunit,
1144 _("Target unit selection"),
1145 _("Looking for target unit:"),
1146 _("Units at tile:"),
1147 _("Select"),
1149 }
1150
1154 free(args);
1155}
1156
1157/**********************************************************************/
1161{
1162 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
1163
1164 if (arg == GTK_RESPONSE_YES) {
1166
1167 if (actor != NULL) {
1169 "target"));
1171 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
1172
1173 if (tgt_extra == NULL) {
1174 /* Make the action dialog pop up again. */
1176 actor->id,
1178 tgt_tile->index,
1179 /* Let the server choose the target
1180 * extra. */
1183 } else {
1185 actor->id,
1187 tgt_tile->index,
1188 tgt_id,
1190 }
1191 }
1192 } else {
1193 /* Dialog canceled. This ends the action selection process. */
1195 }
1196
1198}
1199
1200/**********************************************************************/
1204{
1205 struct action_data *args = act_sel_dialog_data;
1206
1207 struct unit *act_unit;
1208 struct extra_type *tgt_extra;
1209 struct tile *tgt_tile;
1210
1212 && (tgt_tile = index_to_tile(&(wld.map), args->target_tile_id))
1215
1216 /* Start with the extras at the tile */
1218
1220 if (BV_ISSET(potential_targets, extra_number(pextra))) {
1221 /* This extra is at the tile. Can anything be done to it? */
1223 pextra)) {
1225 }
1226 } else {
1227 /* This extra isn't at the tile yet. Can it be created? */
1229 pextra)) {
1231 }
1232 }
1234
1236 /* TRANS: GTK action selection dialog extra target
1237 * selection dialog title. */
1238 _("Target extra selection"),
1239 /* TRANS: GTK action selection dialog extra target
1240 * selection dialog actor unit label. */
1241 _("Looking for target extra:"),
1242 /* TRANS: GTK action selection dialog extra target
1243 * selection dialog extra list label. */
1244 _("Extra targets:"),
1245 _("Select"),
1247 }
1248
1252 free(args);
1253}
1254
1255/**********************************************************************/
1259{
1260 struct action_data *args = act_sel_dialog_data;
1261
1262 struct unit *punit;
1263
1264 if ((punit = game_unit_by_number(args->actor_unit_id))) {
1266 }
1267}
1268
1269/**********************************************************************/
1273{
1274 struct action_data *args = act_sel_dialog_data;
1275
1276 key_unit_wait();
1277
1278 /* The dialog was destroyed when key_unit_wait() resulted in
1279 * action_selection_close() being called. */
1280
1281 free(args);
1282}
1283
1284/**********************************************************************/
1292
1293/**********************************************************************/
1301
1302/**********************************************************************/
1310
1311/* Mapping from an action to the function to call when its button is
1312 * pushed. */
1314 /* Unit acting against a city target. */
1325
1326 /* Unit acting against a unit target. */
1328
1329 /* Unit acting against all units at a tile. */
1331
1332 /* Unit acting against a tile. */
1334
1335 /* Unit acting with no target except itself. */
1336 /* No special callback functions needed for any self targeted actions. */
1337};
1338
1339/**********************************************************************/
1344 const struct act_prob *act_probs,
1345 const char *custom,
1347{
1348 const gchar *label;
1349 const gchar *tooltip;
1350 GCallback cb;
1351
1352 if (af_map[act_id] == NULL) {
1353 /* No special call back function needed for this action. */
1355 } else {
1356 /* Special action specific callback function specified. */
1357 cb = af_map[act_id];
1358 }
1359
1360 /* Don't show disabled actions. */
1362 return;
1363 }
1364
1365 label = action_prepare_ui_name(act_id, "_",
1367 custom);
1368
1370 act_probs[act_id]);
1371
1374 FALSE, tooltip);
1375}
1376
1377/**********************************************************************/
1382 const struct act_prob *act_probs,
1383 const char *custom,
1385{
1386 const gchar *label;
1387 const gchar *tooltip;
1388
1389 /* An action that just became impossible has its button disabled.
1390 * An action that became possible again must be re-enabled. */
1394
1395 /* The probability may have changed. */
1396 label = action_prepare_ui_name(act_id, "_",
1398
1400 act_probs[act_id]);
1401
1404 label);
1407 tooltip);
1408}
1409
1410/**********************************************************************/
1415 struct city *target_city,
1416 struct unit *target_unit,
1417 struct tile *target_tile,
1418 struct extra_type *target_extra,
1419 const struct act_prob *act_probs)
1420{
1421 GtkWidget *shl;
1422 struct astring title = ASTRING_INIT, text = ASTRING_INIT;
1423 struct city *actor_homecity;
1424
1425 int button_id;
1426
1428 act_data(ACTION_ANY, /* Not decided yet */
1429 actor_unit->id,
1433 /* No target_building or target_tech supplied. (Dec 2019) */
1434 B_LAST, A_UNSET, -1,
1436
1437 /* Could be caused by the server failing to reply to a request for more
1438 * information or a bug in the client code. */
1440 "Diplomat queue problem. Is another diplomat window open?");
1441
1442 /* No extra input is required as no action has been chosen yet. */
1444
1445 /* No buttons are added yet. */
1446 for (button_id = 0; button_id < BUTTON_COUNT; button_id++) {
1448 }
1449
1451
1455 target_city->id :
1458 target_unit->id :
1471 EXTRA_NONE;
1472
1473 astr_set(&title,
1474 /* TRANS: %s is a unit name, e.g., Spy */
1475 _("Choose Your %s's Strategy"),
1477
1478 if (target_city && actor_homecity) {
1479 astr_set(&text,
1480 _("Your %s from %s reaches the city of %s.\nWhat now?"),
1484 } else if (target_city) {
1485 astr_set(&text,
1486 _("Your %s has arrived at %s.\nWhat is your command?"),
1489 } else if (target_unit != nullptr) {
1491
1492 if (owner != nullptr) {
1493 astr_set(&text,
1494 /* TRANS: Your Spy is ready to act against Roman Freight. */
1495 _("Your %s is ready to act against %s %s."),
1499 } else {
1500 /* Flagless unit */
1501 astr_set(&text,
1502 /* TRANS: Your Spy is ready to act against Freight. */
1503 _("Your %s is ready to act against %s."),
1506 }
1507 } else {
1509 "No target specified.");
1510 astr_set(&text,
1511 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
1512 _("Your %s is waiting for your command."),
1514 }
1515
1517 astr_str(&text));
1518
1519 /* Unit acting against a city */
1520
1521 action_iterate(act) {
1526 act_probs[act],
1527 actor_unit,
1528 target_city),
1529 act);
1530 }
1532
1533 /* Unit acting against another unit */
1534
1535 action_iterate(act) {
1540 act_probs[act],
1541 actor_unit,
1542 target_city),
1543 act);
1544 }
1546
1547 /* Unit acting against all units at a tile */
1548
1549 action_iterate(act) {
1554 act_probs[act],
1555 actor_unit,
1556 target_city),
1557 act);
1558 }
1560
1561 /* Unit acting against a tile */
1562
1563 action_iterate(act) {
1568 act_probs[act],
1569 actor_unit,
1570 target_city),
1571 act);
1572 }
1574
1575 /* Unit acting against a tile's extras */
1576
1577 action_iterate(act) {
1582 act_probs[act],
1583 actor_unit,
1584 target_city),
1585 act);
1586 }
1588
1589 /* Unit acting against itself. */
1590
1591 action_iterate(act) {
1596 act_probs[act],
1597 actor_unit,
1598 target_city),
1599 act);
1600 }
1602
1603 if (target_unit != NULL
1604 && unit_list_size(target_tile->units) > 1) {
1607 choice_dialog_add(shl, _("Change unit target"),
1610 }
1611
1612 if (target_extra != NULL) {
1615 choice_dialog_add(shl, _("Change extra target"),
1618 }
1619
1622 choice_dialog_add(shl, _("Show Location"),
1625 TRUE, NULL);
1626
1629 choice_dialog_add(shl, _("_Wait"),
1632 TRUE, NULL);
1633
1636 choice_dialog_add(shl, _("_Cancel"),
1639 FALSE, NULL);
1640
1642
1644
1646 g_signal_connect(shl, "destroy",
1648 g_signal_connect(shl, "close-request",
1651
1652 /* Give follow up questions access to action probabilities. */
1654 action_iterate(act) {
1657
1658 astr_free(&title);
1659 astr_free(&text);
1660}
1661
1662/**********************************************************************/
1668{
1669 if (act_sel_dialog == NULL) {
1670 return IDENTITY_NUMBER_ZERO;
1671 }
1672 return actor_unit_id;
1673}
1674
1675/**********************************************************************/
1682{
1683 if (act_sel_dialog == NULL) {
1684 return IDENTITY_NUMBER_ZERO;
1685 }
1686 return target_ids[ATK_CITY];
1687}
1688
1689/**********************************************************************/
1696{
1697 if (act_sel_dialog == NULL) {
1698 return IDENTITY_NUMBER_ZERO;
1699 }
1700
1701 return target_ids[ATK_UNIT];
1702}
1703
1704/**********************************************************************/
1711{
1712 if (act_sel_dialog == NULL) {
1713 return TILE_INDEX_NONE;
1714 }
1715
1716 return target_ids[ATK_TILE];
1717}
1718
1719/**********************************************************************/
1726{
1727 if (act_sel_dialog == NULL) {
1728 return EXTRA_NONE;
1729 }
1730
1731 return target_extra_id;
1732}
1733
1734/**********************************************************************/
1738 struct city *target_city,
1739 struct unit *target_unit,
1740 struct tile *target_tile,
1741 struct extra_type *target_extra,
1742 const struct act_prob *act_probs)
1743{
1744 if (act_sel_dialog == NULL) {
1746 "The action selection dialog should have been open");
1747 return;
1748 }
1749
1752 "The action selection dialog is for another actor unit.");
1753 return;
1754 }
1755
1756 /* A new target may have appeared. */
1757 if (target_city) {
1759 }
1760 if (target_unit) {
1762 }
1763 if (target_tile) {
1765 }
1766 /* No target_building or target_tech supplied. (Dec 2019) */
1767 if (target_extra) {
1769 }
1770
1771 action_iterate(act) {
1772 const char *custom;
1773
1774 if (action_id_get_actor_kind(act) != AAK_UNIT) {
1775 /* Not relevant. */
1776 continue;
1777 }
1778
1780 act_probs[act],
1781 actor_unit,
1782 target_city);
1783
1784 if (BUTTON_NOT_THERE == action_button_map[act]) {
1785 /* Add the button (unless its probability is 0). */
1787 } else {
1788 /* Update the existing button. */
1790 }
1792
1793 /* DO NOT change the action_button_map[] for any button to reflect its
1794 * new position. A button keeps its choice dialog internal name when its
1795 * position changes. A button's id number is therefore based on when
1796 * it was added, not on its current position. */
1797
1799 /* Move the wait button below the recently added button. */
1802 }
1803
1805 /* Move the cancel button below the recently added button. */
1808 }
1809
1811}
1812
1813/**********************************************************************/
1817{
1818 if (act_sel_dialog != NULL) {
1821 }
1822}
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)
void choice_dialog_destroy(GtkWidget *dlg)
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