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-5.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#define FC_TYPE_ACTION_ROW (fc_action_row_get_type())
98
100
108
113
115
116/**********************************************************************/
120{
122
123 free(row->name);
124 row->name = nullptr;
125
127}
128
129/**********************************************************************/
132static void
139
140/**********************************************************************/
143static void
145{
146 self->name = nullptr;
147}
148
149/**********************************************************************/
153{
154 FcActionRow *result;
155
156 result = g_object_new(FC_TYPE_ACTION_ROW, nullptr);
157
158 return result;
159}
160
161/**********************************************************************/
166 int actor_id,
167 int target_city_id,
168 int target_unit_id,
169 int target_tile_id,
171 int target_tech_id,
173 int tgt_extra_id)
174{
175 struct action_data *data = fc_malloc(sizeof(*data));
176
177 data->act_id = act_id;
178 data->actor_unit_id = actor_id;
186
187 return data;
188}
189
190/**********************************************************************/
195{
197 /* The client isn't waiting for information for any unanswered follow
198 * up questions. */
199
200 struct unit *actor_unit;
201
203 /* The action selection dialog wasn't closed because the actor unit
204 * was lost. */
205
206 /* The probabilities didn't just disappear, right? */
209
211 }
212
214 /* The action selection dialog was closed but only so it can be
215 * redrawn with fresh data. */
216
218 } else {
219 /* The action selection process is over, at least for now. */
221 }
222
223 if (did_not_decide) {
224 /* The action selection dialog was closed but the player didn't
225 * decide what the unit should do. */
226
227 /* Reset so the next action selection dialog does the right thing. */
229 } else {
230 /* An action, or no action at all, was selected. */
233 }
234 }
235}
236
237/**********************************************************************/
242{
243 /* Stop waiting. Move on to the next queued unit. */
246}
247
248/**********************************************************************/
255{
256 /* Stop assuming the answer to a follow up question will arrive. */
258}
259
260/**********************************************************************/
265{
266 /* Don't add an action mapping here unless the non targeted version is
267 * selectable in the targeted version's target selection dialog. */
268 switch ((enum gen_action)tgt_action_id) {
277 default:
278 /* No non targeted version found. */
279 return ACTION_NONE;
280 }
281}
282
283/**********************************************************************/
288{
289 /* Don't add an action mapping here unless the non targeted version is
290 * selectable in the targeted version's target selection dialog. */
291 switch ((enum gen_action)tgt_action_id) {
298 default:
299 /* No non targeted version found. */
300 return ACTION_NONE;
301 }
302}
303
304/**********************************************************************/
309{
310 int actor_id, target_id, sub_target;
311 struct action *paction;
312
313 struct action_data *args = act_sel_dialog_data;
314
315 bool failed = FALSE;
316
317 /* Data */
318 args->act_id = GPOINTER_TO_INT(data);
320
321 /* Actor */
323 actor_id = args->actor_unit_id;
324 if (NULL == game_unit_by_number(actor_id)) {
325 /* Probably dead. */
326 failed = TRUE;
327 }
328
329 /* Target */
330 target_id = IDENTITY_NUMBER_ZERO;
332 case ATK_CITY:
333 target_id = args->target_city_id;
334 if (NULL == game_city_by_number(target_id)) {
335 /* Probably destroyed. */
336 failed = TRUE;
337 }
338 break;
339 case ATK_UNIT:
340 target_id = args->target_unit_id;
341 if (NULL == game_unit_by_number(target_id)) {
342 /* Probably dead. */
343 failed = TRUE;
344 }
345 break;
346 case ATK_STACK:
347 case ATK_TILE:
348 case ATK_EXTRAS:
349 target_id = args->target_tile_id;
350 if (NULL == index_to_tile(&(wld.map), target_id)) {
351 /* TODO: Should this be possible at all? If not: add assertion. */
352 failed = TRUE;
353 }
354 break;
355 case ATK_SELF:
356 target_id = IDENTITY_NUMBER_ZERO;
357 break;
358 case ATK_COUNT:
360 failed = TRUE;
361 }
362
363 /* Sub target. */
364 sub_target = NO_TARGET;
365 if (paction->target_complexity != ACT_TGT_COMPL_SIMPLE) {
367 case ASTK_BUILDING:
368 sub_target = args->target_building_id;
369 if (NULL == improvement_by_number(sub_target)) {
370 /* Did the ruleset change? */
371 failed = TRUE;
372 }
373 break;
374 case ASTK_TECH:
375 sub_target = args->target_tech_id;
376 if (NULL == valid_advance_by_number(sub_target)) {
377 /* Did the ruleset change? */
378 failed = TRUE;
379 }
380 break;
381 case ASTK_EXTRA:
383 /* TODO: Validate if the extra is there? */
384 sub_target = args->target_extra_id;
385 if (NULL == extra_by_number(sub_target)) {
386 /* Did the ruleset change? */
387 failed = TRUE;
388 }
389 break;
390 case ASTK_SPECIALIST:
391 sub_target = args->target_specialist_id;
392 if (nullptr == specialist_by_number(sub_target)) {
393 /* Did the ruleset change? */
394 failed = TRUE;
395 }
396 break;
397 case ASTK_NONE:
398 case ASTK_COUNT:
399 /* Shouldn't happen. */
401 failed = TRUE;
402 break;
403 }
404 }
405
406 /* Send request. */
407 if (!failed) {
408 request_do_action(paction->id, actor_id, target_id, sub_target, "");
409 }
410
411 /* Clean up. */
413 /* No follow up questions. */
415 FC_FREE(args);
416}
417
418/**********************************************************************/
423{
424 int actor_id, target_id;
425 struct action *paction;
426
427 struct action_data *args = act_sel_dialog_data;
428
429 bool failed = FALSE;
430
431 /* Data */
432 args->act_id = GPOINTER_TO_INT(data);
434
435 /* Actor */
437 actor_id = args->actor_unit_id;
438 if (NULL == game_unit_by_number(actor_id)) {
439 /* Probably dead. */
440 failed = TRUE;
441 }
442
443 /* Target */
444 target_id = IDENTITY_NUMBER_ZERO;
446 case ATK_CITY:
447 target_id = args->target_city_id;
448 if (NULL == game_city_by_number(target_id)) {
449 /* Probably destroyed. */
450 failed = TRUE;
451 }
452 break;
453 case ATK_UNIT:
454 target_id = args->target_unit_id;
455 if (NULL == game_unit_by_number(target_id)) {
456 /* Probably dead. */
457 failed = TRUE;
458 }
459 break;
460 case ATK_STACK:
461 case ATK_TILE:
462 case ATK_EXTRAS:
463 target_id = args->target_tile_id;
464 if (NULL == index_to_tile(&(wld.map), target_id)) {
465 /* TODO: Should this be possible at all? If not: add assertion. */
466 failed = TRUE;
467 }
468 break;
469 case ATK_SELF:
470 target_id = IDENTITY_NUMBER_ZERO;
471 break;
472 case ATK_COUNT:
474 failed = TRUE;
475 }
476
477 /* Send request. */
478 if (!failed) {
479 request_action_details(paction->id, actor_id, target_id);
480 }
481
482 /* Wait for the server's reply before moving on to the next unit that
483 * needs to know what action to take. */
485
486 /* Clean up. */
488 /* No client side follow up questions. */
490 FC_FREE(args);
491}
492
493/**********************************************************************/
506
507/**********************************************************************/
511{
512 struct unit *punit;
513 struct action_data *args = act_sel_dialog_data;
514
517 struct unit_list *as_list;
518
523 }
524
526 free(args);
527}
528
529/**********************************************************************/
532static void bribe_unit_response(GtkWidget *w, gint response, gpointer data)
533{
534 struct action_data *args = (struct action_data *)data;
535
536 if (response == GTK_RESPONSE_YES) {
538 args->target_unit_id, 0, "");
539 }
540
542 free(args);
543
544 /* The user have answered the follow up question. Move on. */
546}
547
548/**********************************************************************/
551static void bribe_stack_response(GtkWidget *w, gint response, gpointer data)
552{
553 struct action_data *args = (struct action_data *)data;
554
555 if (response == GTK_RESPONSE_YES) {
557 args->target_tile_id, 0, "");
558 }
559
561 free(args);
562
563 /* The user have answered the follow up question. Move on. */
565}
566
567/**********************************************************************/
570void popup_bribe_unit_dialog(struct unit *actor, struct unit *punit, int cost,
571 const struct action *paction)
572{
574 char buf[1024];
575
576 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
577 "Treasury contains %d gold.",
578 client_player()->economic.gold),
579 client_player()->economic.gold);
580
581 if (cost <= client_player()->economic.gold) {
584 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
585 PL_("Bribe unit for %d gold?\n%s",
586 "Bribe unit for %d gold?\n%s", cost), cost, buf);
587 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Unit"));
589 } else {
592 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
593 PL_("Bribing the unit costs %d gold.\n%s",
594 "Bribing the unit costs %d gold.\n%s", cost), cost, buf);
595 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
597 }
599
601 act_data(paction->id, actor->id,
602 0, punit->id, 0,
603 0, 0, 0, 0));
604}
605
606/**********************************************************************/
609void popup_bribe_stack_dialog(struct unit *actor, struct tile *ptile, int cost,
610 const struct action *paction)
611{
613 char buf[1024];
614
615 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
616 "Treasury contains %d gold.",
617 client_player()->economic.gold),
618 client_player()->economic.gold);
619
620 if (cost <= client_player()->economic.gold) {
623 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
624 PL_("Bribe unit stack for %d gold?\n%s",
625 "Bribe unit stack for %d gold?\n%s", cost), cost, buf);
626 gtk_window_set_title(GTK_WINDOW(shell), _("Bribe Enemy Stack"));
628 } else {
631 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
632 PL_("Bribing units costs %d gold.\n%s",
633 "Bribing units costs %d gold.\n%s", cost), cost, buf);
634 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
636 }
638
640 act_data(paction->id, actor->id,
641 0, 0, ptile->index,
642 0, 0, 0, 0));
643}
644
645/**********************************************************************/
648static void spy_advances_response(GtkWidget *w, gint response,
649 gpointer data)
650{
651 struct action_data *args = (struct action_data *)data;
652
653 if (response == GTK_RESPONSE_ACCEPT && args->target_tech_id > 0) {
656 if (args->target_tech_id == A_UNSET) {
657 /* This is the untargeted version. */
659 args->actor_unit_id, args->target_city_id,
660 args->target_tech_id, "");
661 } else {
662 /* This is the targeted version. */
664 args->actor_unit_id, args->target_city_id,
665 args->target_tech_id, "");
666 }
667 }
668 }
669
672 free(data);
673
674 /* The user have answered the follow up question. Move on. */
676}
677
678/**********************************************************************/
702
703/**********************************************************************/
717
718/**********************************************************************/
727
728/**********************************************************************/
731static void create_advances_list(struct player *pplayer,
732 struct player *pvictim,
733 struct action_data *args)
734{
735 GtkWidget *frame, *label, *vgrid;
736 GListStore *store;
740 GtkSingleSelection *selection;
741
743
744 spy_tech_shell = gtk_dialog_new_with_buttons(_("Steal Technology"),
745 NULL, 0,
746 _("_Cancel"), GTK_RESPONSE_CANCEL,
747 _("_Steal"), GTK_RESPONSE_ACCEPT,
748 NULL);
750
753
754 frame = gtk_frame_new(_("Select Advance to Steal"));
756
762
764
765 selection = gtk_single_selection_new(G_LIST_MODEL(store));
767
770 nullptr);
772 nullptr);
773
776
778 "use-underline", TRUE,
779 "mnemonic-widget", list,
780 "label", _("_Advances:"),
781 "xalign", 0.0,
782 "yalign", 0.5,
783 NULL);
784 gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
785
786 gtk_grid_attach(GTK_GRID(vgrid), list, 0, 1, 1, 1);
787
788 /* Now populate the list */
789 if (pvictim) { /* You don't want to know what lag can do -- Syela */
790 const struct research *presearch = research_get(pplayer);
791 const struct research *vresearch = research_get(pvictim);
792 GValue value = { 0, };
793
800
802 row->id = i;
803
804 g_list_store_append(store, row);
806 }
808
812
813 {
814 struct astring str = ASTRING_INIT;
815
816 /* TRANS: %s is a unit name, e.g., Spy */
817 astr_set(&str, _("At %s's Discretion"),
820
821 row->name = fc_strdup(astr_str(&str));
822
823 astr_free(&str);
824 }
825
826 row->id = A_UNSET;
827
828 g_list_store_append(store, row);
830 }
831 }
832
835
837 TRUE);
838
839 g_signal_connect(selection, "selection-changed",
843
844 args->target_tech_id = 0;
845}
846
847/**********************************************************************/
850static void spy_improvements_response(GtkWidget *w, gint response, gpointer data)
851{
852 struct action_data *args = (struct action_data *)data;
853
854 if (response == GTK_RESPONSE_ACCEPT && args->target_building_id > -2) {
857 if (args->target_building_id == B_LAST) {
858 /* This is the untargeted version. */
860 args->actor_unit_id,
861 args->target_city_id,
862 args->target_building_id, "");
863 } else if (args->target_building_id == -1) {
864 /* This is the city production version. */
866 args->actor_unit_id,
867 args->target_city_id,
868 args->target_building_id, "");
869 } else {
870 /* This is the targeted version. */
872 args->actor_unit_id,
873 args->target_city_id,
874 args->target_building_id, "");
875 }
876 }
877 }
878
881 free(args);
882
883 /* The user have answered the follow up question. Move on. */
885}
886
887/**********************************************************************/
911
912/**********************************************************************/
915static void create_improvements_list(struct player *pplayer,
916 struct city *pcity,
917 struct action_data *args)
918{
919 GtkWidget *frame, *label, *vgrid;
920 GListStore *store;
924 GtkSingleSelection *selection;
925 struct action *paction = action_by_number(args->act_id);
927
928 if (paction->result == ACTRES_STRIKE_BUILDING) {
929 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Strike Improvements"),
930 NULL, 0,
931 _("_Cancel"), GTK_RESPONSE_CANCEL,
932 _("_Strike"), GTK_RESPONSE_ACCEPT,
933 NULL);
934 } else {
935 spy_sabotage_shell = gtk_dialog_new_with_buttons(_("Sabotage Improvements"),
936 NULL, 0,
937 _("_Cancel"), GTK_RESPONSE_CANCEL,
938 _("_Sabotage"), GTK_RESPONSE_ACCEPT,
939 NULL);
940 }
942
945
946 if (paction->result == ACTRES_STRIKE_BUILDING) {
947 frame = gtk_frame_new(_("Select Improvement to Strike"));
948 } else {
949 frame = gtk_frame_new(_("Select Improvement to Sabotage"));
950 }
952
958
960
961 selection = gtk_single_selection_new(G_LIST_MODEL(store));
963
966 nullptr);
968 nullptr);
969
970 column = gtk_column_view_column_new(_("Improvement"), factory);
972
974 "use-underline", TRUE,
975 "mnemonic-widget", list,
976 "label", _("_Improvements:"),
977 "xalign", 0.0,
978 "yalign", 0.5,
979 NULL);
980 gtk_grid_attach(GTK_GRID(vgrid), label, 0, 0, 1, 1);
981 gtk_grid_attach(GTK_GRID(vgrid), list, 0, 1, 1, 1);
982
983 /* Now populate the list */
986 args->act_id)])) {
988
989 row->name = fc_strdup(_("City Production"));
990 row->id = -1;
991
992 g_list_store_append(store, row);
994 }
995
996 city_built_iterate(pcity, pimprove) {
997 if (pimprove->sabotage > 0) {
999
1001 row->id = improvement_number(pimprove);
1002
1003 g_list_store_append(store, row);
1005 }
1007
1010 struct astring str = ASTRING_INIT;
1012
1013 /* TRANS: %s is a unit name, e.g., Spy */
1014 astr_set(&str, _("At %s's Discretion"),
1016
1017 row->name = fc_strdup(astr_str(&str));
1018 row->id = B_LAST;
1019
1020 g_list_store_append(store, row);
1022
1023 astr_free(&str);
1024 }
1025
1028
1030 TRUE);
1031
1032 g_signal_connect(selection, "selection-changed",
1036
1037 args->target_building_id = -2;
1038}
1039
1040/**********************************************************************/
1044{
1045 struct action_data *args = (struct action_data *)data;
1046
1048 struct player *pvictim = NULL;
1049
1050 if (pvcity) {
1052 }
1053
1054/* It is concievable that pvcity will not be found, because something
1055 has happened to the city during latency. Therefore we must initialize
1056 pvictim to NULL and account for !pvictim in create_advances_list. -- Syela */
1057
1058 /* FIXME: Don't discard the second tech choice dialog. */
1059 if (!spy_tech_shell) {
1062 } else {
1063 free(args);
1064 }
1065
1066 /* Wait for the player's reply before moving on to the next unit that
1067 * needs to know what action to take. */
1069
1071}
1072
1073/**********************************************************************/
1082
1083/**********************************************************************/
1092
1093/**********************************************************************/
1098 const struct action *paction)
1099{
1100 /* FIXME: Don't discard the second target choice dialog. */
1101 if (!spy_sabotage_shell) {
1103 act_data(paction->id,
1104 actor->id, pcity->id, 0, 0,
1105 0, 0, 0, 0));
1107 }
1108}
1109
1110/**********************************************************************/
1113static void incite_response(GtkWidget *w, gint response, gpointer data)
1114{
1115 struct action_data *args = (struct action_data *)data;
1116
1117 if (response == GTK_RESPONSE_YES) {
1119 args->target_city_id, 0, "");
1120 }
1121
1123 free(args);
1124
1125 /* The user have answered the follow up question. Move on. */
1127}
1128
1129/**********************************************************************/
1132void popup_incite_dialog(struct unit *actor, struct city *pcity, int cost,
1133 const struct action *paction)
1134{
1136 char buf[1024];
1137
1138 fc_snprintf(buf, ARRAY_SIZE(buf), PL_("Treasury contains %d gold.",
1139 "Treasury contains %d gold.",
1140 client_player()->economic.gold),
1141 client_player()->economic.gold);
1142
1146 _("You can't incite a revolt in %s."),
1148 gtk_window_set_title(GTK_WINDOW(shell), _("City can't be incited!"));
1150 } else if (cost <= client_player()->economic.gold) {
1153 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1154 PL_("Incite a revolt for %d gold?\n%s",
1155 "Incite a revolt for %d gold?\n%s", cost), cost, buf);
1156 gtk_window_set_title(GTK_WINDOW(shell), _("Incite a Revolt!"));
1158 } else {
1160 0,
1162 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1163 PL_("Inciting a revolt costs %d gold.\n%s",
1164 "Inciting a revolt costs %d gold.\n%s", cost), cost, buf);
1165 gtk_window_set_title(GTK_WINDOW(shell), _("Traitors Demand Too Much!"));
1167 }
1169
1171 act_data(paction->id, actor->id,
1172 pcity->id, 0, 0,
1173 0, 0, 0, 0));
1174}
1175
1176/**********************************************************************/
1180{
1181 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
1182
1183 if (arg == GTK_RESPONSE_YES) {
1185
1186 if (actor != NULL) {
1188 "target"));
1190 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
1191
1192 if (tgt_unit == NULL) {
1193 /* Make the action dialog pop up again. */
1195 actor->id,
1196 /* Let the server choose the target
1197 * unit. */
1199 tgt_tile->index,
1202 } else {
1204 actor->id,
1205 tgt_id,
1206 tgt_tile->index,
1209 }
1210 }
1211 } else {
1212 /* Dialog canceled. This ends the action selection process. */
1214 }
1215
1217}
1218
1219/**********************************************************************/
1223{
1224 struct action_data *args = act_sel_dialog_data;
1225
1226 struct unit *punit;
1227 struct unit *tunit;
1228 struct tile *ptile;
1229
1231 && (ptile = index_to_tile(&(wld.map), args->target_tile_id))
1232 && (tunit = game_unit_by_number(args->target_unit_id))) {
1233 select_tgt_unit(punit, ptile, ptile->units, tunit,
1234 _("Target unit selection"),
1235 _("Looking for target unit:"),
1236 _("Units at tile:"),
1237 _("Select"),
1239 }
1240
1244 free(args);
1245}
1246
1247/**********************************************************************/
1251{
1252 int au_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(dlg), "actor"));
1253
1254 if (arg == GTK_RESPONSE_YES) {
1256
1257 if (actor != NULL) {
1259 "target"));
1261 struct tile *tgt_tile = g_object_get_data(G_OBJECT(dlg), "tile");
1262
1263 if (tgt_extra == NULL) {
1264 /* Make the action dialog pop up again. */
1266 actor->id,
1268 tgt_tile->index,
1269 /* Let the server choose the target
1270 * extra. */
1273 } else {
1275 actor->id,
1277 tgt_tile->index,
1278 tgt_id,
1280 }
1281 }
1282 } else {
1283 /* Dialog canceled. This ends the action selection process. */
1285 }
1286
1288}
1289
1290/**********************************************************************/
1294{
1295 struct action_data *args = act_sel_dialog_data;
1296
1297 struct unit *act_unit;
1298 struct extra_type *tgt_extra;
1299 struct tile *tgt_tile;
1300
1302 && (tgt_tile = index_to_tile(&(wld.map), args->target_tile_id))
1305
1306 /* Start with the extras at the tile */
1308
1310 if (BV_ISSET(potential_targets, extra_number(pextra))) {
1311 /* This extra is at the tile. Can anything be done to it? */
1313 pextra)) {
1315 }
1316 } else {
1317 /* This extra isn't at the tile yet. Can it be created? */
1319 pextra)) {
1321 }
1322 }
1324
1326 /* TRANS: GTK action selection dialog extra target
1327 * selection dialog title. */
1328 _("Target extra selection"),
1329 /* TRANS: GTK action selection dialog extra target
1330 * selection dialog actor unit label. */
1331 _("Looking for target extra:"),
1332 /* TRANS: GTK action selection dialog extra target
1333 * selection dialog extra list label. */
1334 _("Extra targets:"),
1335 _("Select"),
1337 }
1338
1342 free(args);
1343}
1344
1345/**********************************************************************/
1349{
1350 struct action_data *args = act_sel_dialog_data;
1351
1352 struct unit *punit;
1353
1354 if ((punit = game_unit_by_number(args->actor_unit_id))) {
1356 }
1357}
1358
1359/**********************************************************************/
1363{
1364 struct action_data *args = act_sel_dialog_data;
1365
1366 key_unit_wait();
1367
1368 /* The dialog was destroyed when key_unit_wait() resulted in
1369 * action_selection_close() being called. */
1370
1371 free(args);
1372}
1373
1374/**********************************************************************/
1382
1383/**********************************************************************/
1391
1392/**********************************************************************/
1400
1401/* Mapping from an action to the function to call when its button is
1402 * pushed. */
1404 /* Unit acting against a city target. */
1415
1416 /* Unit acting against a unit target. */
1418
1419 /* Unit acting against all units at a tile. */
1421
1422 /* Unit acting against a tile. */
1424
1425 /* Unit acting with no target except itself. */
1426 /* No special callback functions needed for any self targeted actions. */
1427};
1428
1429/**********************************************************************/
1434 const struct act_prob *act_probs,
1435 const char *custom,
1437{
1438 const gchar *label;
1439 const gchar *tooltip;
1440 GCallback cb;
1441
1442 if (af_map[act_id] == NULL) {
1443 /* No special call back function needed for this action. */
1445 } else {
1446 /* Special action specific callback function specified. */
1447 cb = af_map[act_id];
1448 }
1449
1450 /* Don't show disabled actions. */
1452 return;
1453 }
1454
1455 label = action_prepare_ui_name(act_id, "_",
1457 custom);
1458
1460 act_probs[act_id]);
1461
1464 FALSE, tooltip);
1465}
1466
1467/**********************************************************************/
1472 const struct act_prob *act_probs,
1473 const char *custom,
1475{
1476 const gchar *label;
1477 const gchar *tooltip;
1478
1479 /* An action that just became impossible has its button disabled.
1480 * An action that became possible again must be re-enabled. */
1484
1485 /* The probability may have changed. */
1486 label = action_prepare_ui_name(act_id, "_",
1488
1490 act_probs[act_id]);
1491
1494 label);
1497 tooltip);
1498}
1499
1500/**********************************************************************/
1505 struct city *target_city,
1506 struct unit *target_unit,
1507 struct tile *target_tile,
1508 struct extra_type *target_extra,
1509 const struct act_prob *act_probs)
1510{
1511 GtkWidget *shl;
1512 struct astring title = ASTRING_INIT, text = ASTRING_INIT;
1513 struct city *actor_homecity;
1514
1515 int button_id;
1516
1518 act_data(ACTION_ANY, /* Not decided yet */
1519 actor_unit->id,
1523 /* No target_building or target_tech supplied. (Dec 2019) */
1524 B_LAST, A_UNSET, -1,
1526
1527 /* Could be caused by the server failing to reply to a request for more
1528 * information or a bug in the client code. */
1530 "Diplomat queue problem. Is another diplomat window open?");
1531
1532 /* No extra input is required as no action has been chosen yet. */
1534
1535 /* No buttons are added yet. */
1536 for (button_id = 0; button_id < BUTTON_COUNT; button_id++) {
1538 }
1539
1541
1545 target_city->id :
1548 target_unit->id :
1561 EXTRA_NONE;
1562
1563 astr_set(&title,
1564 /* TRANS: %s is a unit name, e.g., Spy */
1565 _("Choose Your %s's Strategy"),
1567
1568 if (target_city && actor_homecity) {
1569 astr_set(&text,
1570 _("Your %s from %s reaches the city of %s.\nWhat now?"),
1574 } else if (target_city) {
1575 astr_set(&text,
1576 _("Your %s has arrived at %s.\nWhat is your command?"),
1579 } else if (target_unit != nullptr) {
1581
1582 if (owner != nullptr) {
1583 astr_set(&text,
1584 /* TRANS: Your Spy is ready to act against Roman Freight. */
1585 _("Your %s is ready to act against %s %s."),
1589 } else {
1590 /* Flagless unit */
1591 astr_set(&text,
1592 /* TRANS: Your Spy is ready to act against Freight. */
1593 _("Your %s is ready to act against %s."),
1596 }
1597 } else {
1599 "No target specified.");
1600 astr_set(&text,
1601 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
1602 _("Your %s is waiting for your command."),
1604 }
1605
1607 astr_str(&text));
1608
1609 /* Unit acting against a city */
1610
1611 action_iterate(act) {
1616 act_probs[act],
1617 actor_unit,
1618 target_city),
1619 act);
1620 }
1622
1623 /* Unit acting against another unit */
1624
1625 action_iterate(act) {
1630 act_probs[act],
1631 actor_unit,
1632 target_city),
1633 act);
1634 }
1636
1637 /* Unit acting against all units at a tile */
1638
1639 action_iterate(act) {
1644 act_probs[act],
1645 actor_unit,
1646 target_city),
1647 act);
1648 }
1650
1651 /* Unit acting against a tile */
1652
1653 action_iterate(act) {
1658 act_probs[act],
1659 actor_unit,
1660 target_city),
1661 act);
1662 }
1664
1665 /* Unit acting against a tile's extras */
1666
1667 action_iterate(act) {
1672 act_probs[act],
1673 actor_unit,
1674 target_city),
1675 act);
1676 }
1678
1679 /* Unit acting against itself. */
1680
1681 action_iterate(act) {
1686 act_probs[act],
1687 actor_unit,
1688 target_city),
1689 act);
1690 }
1692
1693 if (target_unit != NULL
1694 && unit_list_size(target_tile->units) > 1) {
1697 choice_dialog_add(shl, _("Change unit target"),
1700 }
1701
1702 if (target_extra != NULL) {
1705 choice_dialog_add(shl, _("Change extra target"),
1708 }
1709
1712 choice_dialog_add(shl, _("Show Location"),
1715 TRUE, NULL);
1716
1719 choice_dialog_add(shl, _("_Wait"),
1722 TRUE, NULL);
1723
1726 choice_dialog_add(shl, _("_Cancel"),
1729 FALSE, NULL);
1730
1732
1734
1736 g_signal_connect(shl, "destroy",
1738 g_signal_connect(shl, "close-request",
1741
1742 /* Give follow up questions access to action probabilities. */
1744 action_iterate(act) {
1747
1748 astr_free(&title);
1749 astr_free(&text);
1750}
1751
1752/**********************************************************************/
1758{
1759 if (act_sel_dialog == NULL) {
1760 return IDENTITY_NUMBER_ZERO;
1761 }
1762 return actor_unit_id;
1763}
1764
1765/**********************************************************************/
1772{
1773 if (act_sel_dialog == NULL) {
1774 return IDENTITY_NUMBER_ZERO;
1775 }
1776 return target_ids[ATK_CITY];
1777}
1778
1779/**********************************************************************/
1786{
1787 if (act_sel_dialog == NULL) {
1788 return IDENTITY_NUMBER_ZERO;
1789 }
1790
1791 return target_ids[ATK_UNIT];
1792}
1793
1794/**********************************************************************/
1801{
1802 if (act_sel_dialog == NULL) {
1803 return TILE_INDEX_NONE;
1804 }
1805
1806 return target_ids[ATK_TILE];
1807}
1808
1809/**********************************************************************/
1816{
1817 if (act_sel_dialog == NULL) {
1818 return EXTRA_NONE;
1819 }
1820
1821 return target_extra_id;
1822}
1823
1824/**********************************************************************/
1828 struct city *target_city,
1829 struct unit *target_unit,
1830 struct tile *target_tile,
1831 struct extra_type *target_extra,
1832 const struct act_prob *act_probs)
1833{
1834 if (act_sel_dialog == NULL) {
1836 "The action selection dialog should have been open");
1837 return;
1838 }
1839
1842 "The action selection dialog is for another actor unit.");
1843 return;
1844 }
1845
1846 /* A new target may have appeared. */
1847 if (target_city) {
1849 }
1850 if (target_unit) {
1852 }
1853 if (target_tile) {
1855 }
1856 /* No target_building or target_tech supplied. (Dec 2019) */
1857 if (target_extra) {
1859 }
1860
1861 action_iterate(act) {
1862 const char *custom;
1863
1864 if (action_id_get_actor_kind(act) != AAK_UNIT) {
1865 /* Not relevant. */
1866 continue;
1867 }
1868
1870 act_probs[act],
1871 actor_unit,
1872 target_city);
1873
1874 if (BUTTON_NOT_THERE == action_button_map[act]) {
1875 /* Add the button (unless its probability is 0). */
1877 } else {
1878 /* Update the existing button. */
1880 }
1882
1883 /* DO NOT change the action_button_map[] for any button to reflect its
1884 * new position. A button keeps its choice dialog internal name when its
1885 * position changes. A button's id number is therefore based on when
1886 * it was added, not on its current position. */
1887
1889 /* Move the wait button below the recently added button. */
1892 }
1893
1895 /* Move the cancel button below the recently added button. */
1898 }
1899
1901}
1902
1903/**********************************************************************/
1907{
1908 if (act_sel_dialog != NULL) {
1911 }
1912}
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
static struct ai_type * self
Definition classicai.c:47
struct civclient client
#define client_player()
void client_unit_init_act_prob_cache(struct unit *punit)
Definition climisc.c:1264
static struct fc_sockaddr_list * list
Definition clinet.c:102
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 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)
static void fc_action_row_class_init(FcActionRowClass *klass)
static void fc_action_row_init(FcActionRow *self)
static void fc_action_row_finalize(GObject *gobject)
#define FC_TYPE_ACTION_ROW
static void action_factory_bind(GtkSignalListItemFactory *self, GtkListItem *list_item, gpointer user_data)
static FcActionRow * fc_action_row_new(void)
static void action_factory_setup(GtkSignalListItemFactory *self, GtkListItem *list_item, gpointer user_data)
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_strdup(str)
Definition mem.h:43
#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
GObjectClass parent_class
GObject parent_instance
int target_building_id
int target_specialist_id
action_id act_id
char name[MAX_LEN_NAME]
Definition ai.h:51
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