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 <stdio.h>
19 #include <stdlib.h>
20
21 #include <X11/Intrinsic.h>
22 #include <X11/StringDefs.h>
23 #include <X11/Xaw/Command.h>
24 #include <X11/Xaw/Form.h>
25 #include <X11/Xaw/Label.h>
26 #include <X11/Xaw/List.h>
27 #include <X11/Xaw/SimpleMenu.h>
28
29 /* utility */
30 #include "astring.h"
31 #include "fcintl.h"
32 #include "log.h"
33
34 /* common */
35 #include "actions.h"
36 #include "game.h"
37 #include "improvement.h"
38 #include "map.h"
39 #include "movement.h"
40 #include "research.h"
41 #include "tech.h"
42 #include "traderoutes.h"
43 #include "unitlist.h"
44
45 /* client */
46 #include "client_main.h"
47 #include "control.h"
48
49 /* client/gui-xaw */
50 #include "citydlg.h"
51 #include "dialogs.h"
52 #include "gui_main.h"
53 #include "gui_stuff.h"
54
55 /******************************************************************/
56 static Widget spy_tech_shell;
57 static Widget spy_advances_list, spy_advances_list_label;
58 static Widget spy_steal_command;
59
60 static int spy_tech_shell_is_modal;
61 static int advance_type[A_LAST+1];
62 static int steal_advance = 0;
63
64 /******************************************************************/
65 static Widget spy_sabotage_shell;
66 static Widget spy_improvements_list, spy_improvements_list_label;
67 static Widget spy_sabotage_command;
68
69 static int spy_sabotage_shell_is_modal;
70 static int improvement_type[B_LAST+1];
71 static int sabotage_improvement = 0;
72
73 static Widget diplomat_dialog;
74 int diplomat_id;
75 int diplomat_target_id[ATK_COUNT];
76
77 #define action_decision_taken(actor_id) \
78 action_selection_no_longer_in_progress(actor_id); \
79 action_decision_clear_want(actor_id); \
80 action_selection_next_in_focus(actor_id);
81
82 /**************************************************************************
83 User selected enter market place from caravan dialog
84 **************************************************************************/
caravan_marketplace_callback(Widget w,XtPointer client_data,XtPointer call_data)85 static void caravan_marketplace_callback(Widget w, XtPointer client_data,
86 XtPointer call_data)
87 {
88 destroy_message_dialog(w);
89 diplomat_dialog = NULL;
90
91 if (NULL != game_city_by_number(diplomat_target_id[ATK_CITY])
92 && NULL != game_unit_by_number(diplomat_id)) {
93 request_do_action(ACTION_MARKETPLACE, diplomat_id,
94 diplomat_target_id[ATK_CITY], 0);
95 }
96
97 action_decision_taken(diplomat_id);
98 }
99
100 /****************************************************************
101 User selected traderoute from caravan dialog
102 *****************************************************************/
caravan_establish_trade_callback(Widget w,XtPointer client_data,XtPointer call_data)103 static void caravan_establish_trade_callback(Widget w, XtPointer client_data,
104 XtPointer call_data)
105 {
106 destroy_message_dialog(w);
107 diplomat_dialog = NULL;
108
109 if (NULL != game_city_by_number(diplomat_target_id[ATK_CITY])
110 && NULL != game_unit_by_number(diplomat_id)) {
111 request_do_action(ACTION_TRADE_ROUTE, diplomat_id,
112 diplomat_target_id[ATK_CITY], 0);
113 }
114
115 action_decision_taken(diplomat_id);
116 }
117
118 /****************************************************************
119 ...
120 *****************************************************************/
caravan_help_build_wonder_callback(Widget w,XtPointer client_data,XtPointer call_data)121 static void caravan_help_build_wonder_callback(Widget w,
122 XtPointer client_data,
123 XtPointer call_data)
124 {
125 destroy_message_dialog(w);
126 diplomat_dialog = NULL;
127
128 if (NULL != game_city_by_number(diplomat_target_id[ATK_CITY])
129 && NULL != game_unit_by_number(diplomat_id)) {
130 request_do_action(ACTION_HELP_WONDER, diplomat_id,
131 diplomat_target_id[ATK_CITY], 0);
132 }
133
134 action_decision_taken(diplomat_id);
135 }
136
137 /****************************************************************
138 ...
139 *****************************************************************/
diplomat_bribe_yes_callback(Widget w,XtPointer client_data,XtPointer call_data)140 static void diplomat_bribe_yes_callback(Widget w, XtPointer client_data,
141 XtPointer call_data)
142 {
143 request_do_action(ACTION_SPY_BRIBE_UNIT, diplomat_id,
144 diplomat_target_id[ATK_UNIT], 0);
145
146 destroy_message_dialog(w);
147 }
148
149 /****************************************************************
150 ...
151 *****************************************************************/
diplomat_bribe_no_callback(Widget w,XtPointer client_data,XtPointer call_data)152 static void diplomat_bribe_no_callback(Widget w, XtPointer client_data,
153 XtPointer call_data)
154 {
155 destroy_message_dialog(w);
156 }
157
158 /**************************************************************************
159 Asks the server how much the bribe is
160 **************************************************************************/
diplomat_bribe_callback(Widget w,XtPointer client_data,XtPointer call_data)161 static void diplomat_bribe_callback(Widget w, XtPointer client_data,
162 XtPointer call_data)
163 {
164 destroy_message_dialog(w);
165 diplomat_dialog = NULL;
166
167 if (NULL != game_unit_by_number(diplomat_id)
168 && NULL != game_unit_by_number(diplomat_target_id[ATK_UNIT])) {
169 request_action_details(ACTION_SPY_BRIBE_UNIT, diplomat_id,
170 diplomat_target_id[ATK_UNIT]);
171 }
172 }
173
174 /**************************************************************************
175 Creates and popups the bribe dialog
176 **************************************************************************/
popup_bribe_dialog(struct unit * actor,struct unit * punit,int cost)177 void popup_bribe_dialog(struct unit *actor, struct unit *punit, int cost)
178 {
179 char tbuf[128], buf[128];
180
181 fc_snprintf(tbuf, ARRAY_SIZE(tbuf), PL_("Treasury contains %d gold.",
182 "Treasury contains %d gold.",
183 client_player()->economic.gold),
184 client_player()->economic.gold);
185
186 if (cost <= client_player()->economic.gold) {
187 fc_snprintf(buf, sizeof(buf),
188 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
189 PL_("Bribe unit for %d gold?\n%s",
190 "Bribe unit for %d gold?\n%s", cost), cost, tbuf);
191 popup_message_dialog(toplevel, "diplomatbribedialog", buf,
192 diplomat_bribe_yes_callback, 0, 0,
193 diplomat_bribe_no_callback, 0, 0,
194 NULL);
195 } else {
196 fc_snprintf(buf, sizeof(buf),
197 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
198 PL_("Bribing the unit costs %d gold.\n%s",
199 "Bribing the unit costs %d gold.\n%s", cost), cost, tbuf);
200 popup_message_dialog(toplevel, "diplomatnogolddialog", buf,
201 diplomat_bribe_no_callback, 0, 0,
202 NULL);
203 }
204 }
205
206 /****************************************************************
207 ...
208 *****************************************************************/
diplomat_sabotage_callback(Widget w,XtPointer client_data,XtPointer call_data)209 static void diplomat_sabotage_callback(Widget w, XtPointer client_data,
210 XtPointer call_data)
211 {
212 destroy_message_dialog(w);
213 diplomat_dialog = NULL;
214
215 if (NULL != game_unit_by_number(diplomat_id)
216 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
217 request_do_action(ACTION_SPY_SABOTAGE_CITY, diplomat_id,
218 diplomat_target_id[ATK_CITY], B_LAST + 1);
219 }
220
221 action_decision_taken(diplomat_id);
222 }
223
224 /****************************************************************
225 ...
226 *****************************************************************/
diplomat_embassy_callback(Widget w,XtPointer client_data,XtPointer call_data)227 static void diplomat_embassy_callback(Widget w, XtPointer client_data,
228 XtPointer call_data)
229 {
230 destroy_message_dialog(w);
231 diplomat_dialog = NULL;
232
233 if (NULL != game_unit_by_number(diplomat_id)
234 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
235 request_do_action(ACTION_ESTABLISH_EMBASSY, diplomat_id,
236 diplomat_target_id[ATK_CITY], 0);
237 }
238
239 action_decision_taken(diplomat_id);
240 }
241
242 /****************************************************************
243 ...
244 *****************************************************************/
diplomat_investigate_callback(Widget w,XtPointer client_data,XtPointer call_data)245 static void diplomat_investigate_callback(Widget w, XtPointer client_data,
246 XtPointer call_data)
247 {
248 destroy_message_dialog(w);
249 diplomat_dialog = NULL;
250
251 if (NULL != game_city_by_number(diplomat_target_id[ATK_CITY])
252 && NULL != game_unit_by_number(diplomat_id)) {
253 request_do_action(ACTION_SPY_INVESTIGATE_CITY, diplomat_id,
254 diplomat_target_id[ATK_CITY], 0);
255 }
256
257 action_decision_taken(diplomat_id);
258 }
259
260 /****************************************************************
261 ...
262 *****************************************************************/
spy_sabotage_unit_callback(Widget w,XtPointer client_data,XtPointer call_data)263 static void spy_sabotage_unit_callback(Widget w, XtPointer client_data,
264 XtPointer call_data)
265 {
266 request_do_action(ACTION_SPY_SABOTAGE_UNIT, diplomat_id,
267 diplomat_target_id[ATK_UNIT], 0);
268
269 destroy_message_dialog(w);
270 diplomat_dialog = NULL;
271 }
272
273 /****************************************************************
274 ...
275 *****************************************************************/
spy_poison_callback(Widget w,XtPointer client_data,XtPointer call_data)276 static void spy_poison_callback(Widget w, XtPointer client_data,
277 XtPointer call_data)
278 {
279 destroy_message_dialog(w);
280 diplomat_dialog = NULL;
281
282 if (NULL != game_unit_by_number(diplomat_id)
283 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
284 request_do_action(ACTION_SPY_POISON, diplomat_id,
285 diplomat_target_id[ATK_CITY], 0);
286 }
287
288 action_decision_taken(diplomat_id);
289 }
290
291 /********************************************************************
292 The player selected "Steal Gold"
293 ********************************************************************/
spy_steal_gold_callback(Widget w,XtPointer client_data,XtPointer call_data)294 static void spy_steal_gold_callback(Widget w, XtPointer client_data,
295 XtPointer call_data)
296 {
297 destroy_message_dialog(w);
298 diplomat_dialog = NULL;
299
300 if (NULL != game_unit_by_number(diplomat_id)
301 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
302 request_do_action(ACTION_SPY_STEAL_GOLD, diplomat_id,
303 diplomat_target_id[ATK_CITY], 0);
304 }
305
306 action_decision_taken(diplomat_id);
307 }
308
309 /****************************************************************
310 ...
311 *****************************************************************/
diplomat_steal_callback(Widget w,XtPointer client_data,XtPointer call_data)312 static void diplomat_steal_callback(Widget w, XtPointer client_data,
313 XtPointer call_data)
314 {
315 destroy_message_dialog(w);
316 diplomat_dialog = NULL;
317
318 if (NULL != game_unit_by_number(diplomat_id)
319 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
320 request_do_action(ACTION_SPY_STEAL_TECH, diplomat_id,
321 diplomat_target_id[ATK_CITY], A_UNSET);
322 }
323
324 action_decision_taken(diplomat_id);
325 }
326
327 /****************************************************************
328 ...
329 *****************************************************************/
spy_close_tech_callback(Widget w,XtPointer client_data,XtPointer call_data)330 static void spy_close_tech_callback(Widget w, XtPointer client_data,
331 XtPointer call_data)
332 {
333 if(spy_tech_shell_is_modal)
334 XtSetSensitive(main_form, TRUE);
335 XtDestroyWidget(spy_tech_shell);
336 spy_tech_shell=0;
337
338 action_decision_taken(diplomat_id);
339 }
340
341 /****************************************************************
342 ...
343 *****************************************************************/
spy_close_sabotage_callback(Widget w,XtPointer client_data,XtPointer call_data)344 static void spy_close_sabotage_callback(Widget w, XtPointer client_data,
345 XtPointer call_data)
346 {
347 if(spy_sabotage_shell_is_modal)
348 XtSetSensitive(main_form, TRUE);
349 XtDestroyWidget(spy_sabotage_shell);
350 spy_sabotage_shell=0;
351
352 action_decision_taken(diplomat_id);
353 }
354
355 /****************************************************************
356 ...
357 *****************************************************************/
spy_select_tech_callback(Widget w,XtPointer client_data,XtPointer call_data)358 static void spy_select_tech_callback(Widget w, XtPointer client_data,
359 XtPointer call_data)
360 {
361 XawListReturnStruct *ret;
362 ret=XawListShowCurrent(spy_advances_list);
363
364 if(ret->list_index!=XAW_LIST_NONE && advance_type[ret->list_index] != -1){
365 steal_advance = advance_type[ret->list_index];
366 XtSetSensitive(spy_steal_command, TRUE);
367 return;
368 }
369 XtSetSensitive(spy_steal_command, FALSE);
370 }
371
372 /****************************************************************
373 ...
374 *****************************************************************/
spy_select_improvement_callback(Widget w,XtPointer client_data,XtPointer call_data)375 static void spy_select_improvement_callback(Widget w, XtPointer client_data,
376 XtPointer call_data)
377 {
378 XawListReturnStruct *ret;
379 ret=XawListShowCurrent(spy_improvements_list);
380
381 if(ret->list_index!=XAW_LIST_NONE){
382 sabotage_improvement = improvement_type[ret->list_index];
383 XtSetSensitive(spy_sabotage_command, TRUE);
384 return;
385 }
386 XtSetSensitive(spy_sabotage_command, FALSE);
387 }
388
389 /****************************************************************
390 ...
391 *****************************************************************/
spy_steal_callback(Widget w,XtPointer client_data,XtPointer call_data)392 static void spy_steal_callback(Widget w, XtPointer client_data,
393 XtPointer call_data)
394 {
395 XtDestroyWidget(spy_tech_shell);
396 spy_tech_shell = 0l;
397
398 if(!steal_advance){
399 log_error("Bug in spy steal tech code");
400 action_decision_taken(diplomat_id);
401 return;
402 }
403
404 if (NULL != game_unit_by_number(diplomat_id)
405 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
406 if (steal_advance == A_UNSET) {
407 /* This is the untargeted version. */
408 /* FIXME: Don't give the user the untargeted option unless it is
409 * allowed. */
410 request_do_action(ACTION_SPY_STEAL_TECH, diplomat_id,
411 diplomat_target_id[ATK_CITY], steal_advance);
412 } else {
413 /* This is the targeted version. */
414 request_do_action(ACTION_SPY_TARGETED_STEAL_TECH, diplomat_id,
415 diplomat_target_id[ATK_CITY], steal_advance);
416 }
417 }
418
419 action_decision_taken(diplomat_id);
420 }
421
422 /****************************************************************
423 ...
424 *****************************************************************/
spy_sabotage_callback(Widget w,XtPointer client_data,XtPointer call_data)425 static void spy_sabotage_callback(Widget w, XtPointer client_data,
426 XtPointer call_data)
427 {
428 XtDestroyWidget(spy_sabotage_shell);
429 spy_sabotage_shell = 0l;
430
431 if (sabotage_improvement < -1) {
432 log_error("Bug in spy sabotage code");
433 action_decision_taken(diplomat_id);
434 return;
435 }
436
437 if (NULL != game_unit_by_number(diplomat_id)
438 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
439 if (sabotage_improvement == B_LAST) {
440 /* This is the untargeted version. */
441 request_do_action(ACTION_SPY_SABOTAGE_CITY, diplomat_id,
442 diplomat_target_id[ATK_CITY],
443 sabotage_improvement + 1);
444 } else {
445 /* This is the targeted version. */
446 request_do_action(ACTION_SPY_TARGETED_SABOTAGE_CITY, diplomat_id,
447 diplomat_target_id[ATK_CITY],
448 sabotage_improvement + 1);
449 }
450 }
451
452 action_decision_taken(diplomat_id);
453 }
454
455 /****************************************************************
456 ...
457 *****************************************************************/
create_advances_list(struct player * pplayer,struct player * pvictim,bool make_modal)458 static int create_advances_list(struct player *pplayer,
459 struct player *pvictim, bool make_modal)
460 {
461 Widget spy_tech_form;
462 Widget close_command;
463 Dimension width1, width2;
464 int j;
465
466 static const char *advances_can_steal[A_LAST+1];
467
468 struct unit *actor_unit = game_unit_by_number(diplomat_id);
469
470 spy_tech_shell =
471 I_T(XtVaCreatePopupShell("spystealtechpopup",
472 (make_modal ? transientShellWidgetClass :
473 topLevelShellWidgetClass),
474 toplevel, NULL));
475
476 spy_tech_form = XtVaCreateManagedWidget("spystealtechform",
477 formWidgetClass,
478 spy_tech_shell,
479 NULL);
480
481 spy_advances_list_label =
482 I_L(XtVaCreateManagedWidget("spystealtechlistlabel", labelWidgetClass,
483 spy_tech_form, NULL));
484
485 spy_advances_list = XtVaCreateManagedWidget("spystealtechlist",
486 listWidgetClass,
487 spy_tech_form,
488 NULL);
489
490 close_command =
491 I_L(XtVaCreateManagedWidget("spystealtechclosecommand", commandWidgetClass,
492 spy_tech_form, NULL));
493
494 spy_steal_command =
495 I_L(XtVaCreateManagedWidget("spystealtechcommand", commandWidgetClass,
496 spy_tech_form,
497 XtNsensitive, False,
498 NULL));
499
500
501 XtAddCallback(spy_advances_list, XtNcallback, spy_select_tech_callback, NULL);
502 XtAddCallback(close_command, XtNcallback, spy_close_tech_callback, NULL);
503 XtAddCallback(spy_steal_command, XtNcallback, spy_steal_callback, NULL);
504 XtRealizeWidget(spy_tech_shell);
505
506 /* Now populate the list */
507
508 j = 0;
509 advances_can_steal[j] = _("NONE");
510 advance_type[j] = -1;
511
512 if (pvictim) { /* you don't want to know what lag can do -- Syela */
513 const struct research *presearch = research_get(pplayer);
514 const struct research *vresearch = research_get(pvictim);
515
516 advance_index_iterate(A_FIRST, i) {
517 if (research_invention_state(vresearch, i) == TECH_KNOWN
518 && (research_invention_state(presearch, i) == TECH_UNKNOWN
519 || research_invention_state(presearch, i)
520 == TECH_PREREQS_KNOWN)) {
521 advances_can_steal[j] = advance_name_translation(advance_by_number(i));
522 advance_type[j++] = i;
523 }
524 }
525 {
526 static struct astring str = ASTRING_INIT;
527 /* TRANS: %s is a unit name, e.g., Spy */
528 astr_set(&str, _("At %s's Discretion"),
529 unit_name_translation(actor_unit));
530 advances_can_steal[j] = astr_str(&str);
531 advance_type[j++] = A_UNSET;
532 }
533 } advance_index_iterate_end;
534
535 if(j == 0) j++;
536 advances_can_steal[j] = NULL;
537
538 XtSetSensitive(spy_steal_command, FALSE);
539
540 XawListChange(spy_advances_list,
541 (CONST_FOR_XAW_LIST_CHANGE char **)advances_can_steal, 0, 0, 1);
542 XtVaGetValues(spy_advances_list, XtNwidth, &width1, NULL);
543 XtVaGetValues(spy_advances_list_label, XtNwidth, &width2, NULL);
544 XtVaSetValues(spy_advances_list, XtNwidth, MAX(width1,width2), NULL);
545 XtVaSetValues(spy_advances_list_label, XtNwidth, MAX(width1,width2), NULL);
546
547 return j;
548 }
549
550 /****************************************************************
551 ...
552 *****************************************************************/
create_improvements_list(struct player * pplayer,struct city * pcity,bool make_modal)553 static int create_improvements_list(struct player *pplayer,
554 struct city *pcity, bool make_modal)
555 {
556 Widget spy_sabotage_form;
557 Widget close_command;
558 Dimension width1, width2;
559 int j;
560
561 static const char *improvements_can_sabotage[B_LAST+1];
562
563 struct unit *actor_unit = game_unit_by_number(diplomat_id);
564
565 spy_sabotage_shell =
566 I_T(XtVaCreatePopupShell("spysabotageimprovementspopup",
567 (make_modal ? transientShellWidgetClass :
568 topLevelShellWidgetClass),
569 toplevel, NULL));
570
571 spy_sabotage_form = XtVaCreateManagedWidget("spysabotageimprovementsform",
572 formWidgetClass,
573 spy_sabotage_shell,
574 NULL);
575
576 spy_improvements_list_label =
577 I_L(XtVaCreateManagedWidget("spysabotageimprovementslistlabel",
578 labelWidgetClass,
579 spy_sabotage_form,
580 NULL));
581
582 spy_improvements_list = XtVaCreateManagedWidget("spysabotageimprovementslist",
583 listWidgetClass,
584 spy_sabotage_form,
585 NULL);
586
587 close_command =
588 I_L(XtVaCreateManagedWidget("spysabotageimprovementsclosecommand",
589 commandWidgetClass,
590 spy_sabotage_form,
591 NULL));
592
593 spy_sabotage_command =
594 I_L(XtVaCreateManagedWidget("spysabotageimprovementscommand",
595 commandWidgetClass,
596 spy_sabotage_form,
597 XtNsensitive, False,
598 NULL));
599
600
601 XtAddCallback(spy_improvements_list, XtNcallback, spy_select_improvement_callback, NULL);
602 XtAddCallback(close_command, XtNcallback, spy_close_sabotage_callback, NULL);
603 XtAddCallback(spy_sabotage_command, XtNcallback, spy_sabotage_callback, NULL);
604 XtRealizeWidget(spy_sabotage_shell);
605
606 /* Now populate the list */
607
608 j = 0;
609 improvements_can_sabotage[j] = _("City Production");
610 improvement_type[j++] = -1;
611
612 city_built_iterate(pcity, pimprove) {
613 if (pimprove->sabotage > 0) {
614 improvements_can_sabotage[j] = city_improvement_name_translation(pcity, pimprove);
615 improvement_type[j++] = improvement_number(pimprove);
616 }
617 } city_built_iterate_end;
618
619 if(j > 1) {
620 static struct astring str = ASTRING_INIT;
621 /* TRANS: %s is a unit name, e.g., Spy */
622 astr_set(&str, _("At %s's Discretion"),
623 unit_name_translation(actor_unit));
624 improvements_can_sabotage[j] = astr_str(&str);
625 improvement_type[j++] = B_LAST;
626 } else {
627 improvement_type[0] = B_LAST; /* fake "discretion", since must be production */
628 }
629
630 improvements_can_sabotage[j] = NULL;
631
632 XtSetSensitive(spy_sabotage_command, FALSE);
633
634 XawListChange(spy_improvements_list,
635 (CONST_FOR_XAW_LIST_CHANGE char**) improvements_can_sabotage,
636 0, 0, 1);
637 XtVaGetValues(spy_improvements_list, XtNwidth, &width1, NULL);
638 XtVaGetValues(spy_improvements_list_label, XtNwidth, &width2, NULL);
639 XtVaSetValues(spy_improvements_list, XtNwidth, MAX(width1,width2), NULL);
640 XtVaSetValues(spy_improvements_list_label, XtNwidth, MAX(width1,width2), NULL);
641
642 return j;
643 }
644
645 /****************************************************************
646 ...
647 *****************************************************************/
spy_steal_popup(Widget w,XtPointer client_data,XtPointer call_data)648 static void spy_steal_popup(Widget w, XtPointer client_data,
649 XtPointer call_data)
650 {
651 struct city *pvcity = game_city_by_number(diplomat_target_id[ATK_CITY]);
652 struct player *pvictim = NULL;
653
654 if(pvcity)
655 pvictim = city_owner(pvcity);
656
657 /* it is concievable that pvcity will not be found, because something
658 has happened to the city during latency. Therefore we must initialize
659 pvictim to NULL and account for !pvictim in create_advances_list. -- Syela */
660
661 destroy_message_dialog(w);
662 diplomat_dialog = NULL;
663
664 if(!spy_tech_shell){
665 Position x, y;
666 Dimension width, height;
667 spy_tech_shell_is_modal=1;
668
669 create_advances_list(client.conn.playing, pvictim, spy_tech_shell_is_modal);
670
671 XtVaGetValues(toplevel, XtNwidth, &width, XtNheight, &height, NULL);
672
673 XtTranslateCoords(toplevel, (Position) width/10, (Position) height/10,
674 &x, &y);
675 XtVaSetValues(spy_tech_shell, XtNx, x, XtNy, y, NULL);
676
677 XtPopup(spy_tech_shell, XtGrabNone);
678 }
679 }
680
681 /**************************************************************************
682 Requests up-to-date list of improvements, the return of
683 which will trigger the popup_sabotage_dialog() function.
684 **************************************************************************/
spy_request_sabotage_list(Widget w,XtPointer client_data,XtPointer call_data)685 static void spy_request_sabotage_list(Widget w, XtPointer client_data,
686 XtPointer call_data)
687 {
688 destroy_message_dialog(w);
689 diplomat_dialog = NULL;
690
691 if (NULL != game_unit_by_number(diplomat_id)
692 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
693 request_action_details(ACTION_SPY_TARGETED_SABOTAGE_CITY, diplomat_id,
694 diplomat_target_id[ATK_CITY]);
695 }
696 }
697
698 /**************************************************************************
699 Pops-up the Spy sabotage dialog, upon return of list of
700 available improvements requested by the above function.
701 **************************************************************************/
popup_sabotage_dialog(struct unit * actor,struct city * pcity)702 void popup_sabotage_dialog(struct unit *actor, struct city *pcity)
703 {
704 if(!spy_sabotage_shell){
705 Position x, y;
706 Dimension width, height;
707 spy_sabotage_shell_is_modal=1;
708
709 create_improvements_list(client.conn.playing, pcity, spy_sabotage_shell_is_modal);
710
711 XtVaGetValues(toplevel, XtNwidth, &width, XtNheight, &height, NULL);
712
713 XtTranslateCoords(toplevel, (Position) width/10, (Position) height/10,
714 &x, &y);
715 XtVaSetValues(spy_sabotage_shell, XtNx, x, XtNy, y, NULL);
716
717 XtPopup(spy_sabotage_shell, XtGrabNone);
718 }
719 }
720
721 /****************************************************************
722 ...
723 *****************************************************************/
diplomat_incite_yes_callback(Widget w,XtPointer client_data,XtPointer call_data)724 static void diplomat_incite_yes_callback(Widget w, XtPointer client_data,
725 XtPointer call_data)
726 {
727 request_do_action(ACTION_SPY_INCITE_CITY, diplomat_id,
728 diplomat_target_id[ATK_CITY], 0);
729
730 destroy_message_dialog(w);
731
732 action_decision_taken(diplomat_id);
733 }
734
735 /****************************************************************
736 ...
737 *****************************************************************/
diplomat_incite_no_callback(Widget w,XtPointer client_data,XtPointer call_data)738 static void diplomat_incite_no_callback(Widget w, XtPointer client_data,
739 XtPointer call_data)
740 {
741 destroy_message_dialog(w);
742
743 action_decision_taken(diplomat_id);
744 }
745
746
747 /**************************************************************************
748 Asks the server how much the revolt is going to cost us
749 **************************************************************************/
diplomat_incite_callback(Widget w,XtPointer client_data,XtPointer call_data)750 static void diplomat_incite_callback(Widget w, XtPointer client_data,
751 XtPointer call_data)
752 {
753 destroy_message_dialog(w);
754 diplomat_dialog = NULL;
755
756 if (NULL != game_unit_by_number(diplomat_id)
757 && NULL != game_city_by_number(diplomat_target_id[ATK_CITY])) {
758 request_action_details(ACTION_SPY_INCITE_CITY, diplomat_id,
759 diplomat_target_id[ATK_CITY]);
760 }
761 }
762
763 /**************************************************************************
764 Popup the yes/no dialog for inciting, since we know the cost now
765 **************************************************************************/
popup_incite_dialog(struct unit * actor,struct city * pcity,int cost)766 void popup_incite_dialog(struct unit *actor, struct city *pcity, int cost)
767 {
768 char tbuf[128], buf[128];
769
770 fc_snprintf(tbuf, ARRAY_SIZE(tbuf), PL_("Treasury contains %d gold.",
771 "Treasury contains %d gold.",
772 client_player()->economic.gold),
773 client_player()->economic.gold);
774
775 if (INCITE_IMPOSSIBLE_COST == cost) {
776 fc_snprintf(buf, sizeof(buf), _("You can't incite a revolt in %s."),
777 city_name_get(pcity));
778 popup_message_dialog(toplevel, "diplomatnogolddialog", buf,
779 diplomat_incite_no_callback, 0, 0, NULL);
780 } else if (cost <= client_player()->economic.gold) {
781 fc_snprintf(buf, sizeof(buf),
782 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
783 PL_("Incite a revolt for %d gold?\n%s",
784 "Incite a revolt for %d gold?\n%s", cost), cost, tbuf);
785 diplomat_target_id[ATK_CITY] = pcity->id;
786 popup_message_dialog(toplevel, "diplomatrevoltdialog", buf,
787 diplomat_incite_yes_callback, 0, 0,
788 diplomat_incite_no_callback, 0, 0,
789 NULL);
790 } else {
791 fc_snprintf(buf, sizeof(buf),
792 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
793 PL_("Inciting a revolt costs %d gold.\n%s",
794 "Inciting a revolt costs %d gold.\n%s", cost), cost, tbuf);
795 popup_message_dialog(toplevel, "diplomatnogolddialog", buf,
796 diplomat_incite_no_callback, 0, 0,
797 NULL);
798 }
799 }
800
801
802 /**************************************************************************
803 Callback from action selection dialog for "keep moving".
804 (This should only occur when entering a tile that has an allied city or
805 an allied unit.)
806 **************************************************************************/
act_sel_keep_moving_callback(Widget w,XtPointer client_data,XtPointer call_data)807 static void act_sel_keep_moving_callback(Widget w,
808 XtPointer client_data,
809 XtPointer call_data)
810 {
811 struct unit *punit;
812 struct tile *ptile;
813
814 destroy_message_dialog(w);
815 diplomat_dialog = NULL;
816
817 if ((punit = game_unit_by_number(diplomat_id))
818 && (ptile = (struct tile *)client_data)
819 && !same_pos(unit_tile(punit), ptile)) {
820 request_unit_non_action_move(punit, ptile);
821 }
822 action_decision_taken(diplomat_id);
823 }
824
825 /****************************************************************
826 ...
827 *****************************************************************/
diplomat_cancel_callback(Widget w,XtPointer a,XtPointer b)828 static void diplomat_cancel_callback(Widget w, XtPointer a, XtPointer b)
829 {
830 destroy_message_dialog(w);
831 diplomat_dialog = NULL;
832
833 action_decision_taken(diplomat_id);
834 }
835
836 /*************************************************************************
837 Control the display of an action
838 **************************************************************************/
action_entry(Widget w,int act_id,const struct act_prob * act_probs)839 static void action_entry(Widget w, int act_id,
840 const struct act_prob *act_probs)
841 {
842 Arg arglist[1];
843
844 if (!action_prob_possible(act_probs[act_id])) {
845 XtSetSensitive(w, FALSE);
846 }
847
848 XtSetArg(arglist[0], "label",
849 action_prepare_ui_name(act_id, "",
850 act_probs[act_id], NULL));
851 XtSetValues(w, arglist, XtNumber(arglist));
852 }
853
854 /**************************************************************************
855 Popup a dialog that allows the player to select what action a unit
856 should take.
857 **************************************************************************/
popup_action_selection(struct unit * actor_unit,struct city * target_city,struct unit * target_unit,struct tile * target_tile,const struct act_prob * act_probs)858 void popup_action_selection(struct unit *actor_unit,
859 struct city *target_city,
860 struct unit *target_unit,
861 struct tile *target_tile,
862 const struct act_prob *act_probs)
863 {
864 struct astring text = ASTRING_INIT;
865
866 struct city *actor_homecity = game_city_by_number(actor_unit->homecity);
867
868 diplomat_id = actor_unit->id;
869
870 if (target_unit) {
871 diplomat_target_id[ATK_UNIT] = target_unit->id;
872 } else {
873 diplomat_target_id[ATK_UNIT] = IDENTITY_NUMBER_ZERO;
874 }
875
876 if (target_city) {
877 diplomat_target_id[ATK_CITY] = target_city->id;
878 } else {
879 diplomat_target_id[ATK_CITY] = IDENTITY_NUMBER_ZERO;
880 }
881
882 if (target_city && actor_homecity) {
883 astr_set(&text,
884 _("Your %s from %s reaches the city of %s.\nWhat now?"),
885 unit_name_translation(actor_unit),
886 city_name_get(actor_homecity),
887 city_name_get(target_city));
888 } else if (target_city) {
889 astr_set(&text,
890 _("Your %s has arrived at %s.\nWhat is your command?"),
891 unit_name_translation(actor_unit),
892 city_name_get(target_city));
893 } else {
894 astr_set(&text,
895 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
896 _("Your %s is waiting for your command."),
897 unit_name_translation(actor_unit));
898 }
899
900 diplomat_dialog =
901 popup_message_dialog(toplevel, "diplomatdialog", astr_str(&text),
902 diplomat_embassy_callback, 0, 1,
903 diplomat_investigate_callback, 0, 1,
904 spy_poison_callback, 0, 1,
905 diplomat_sabotage_callback, 0, 1,
906 spy_request_sabotage_list, 0, 1,
907 diplomat_steal_callback, 0, 1,
908 spy_steal_popup, 0, 1,
909 diplomat_incite_callback, 0, 1,
910 caravan_establish_trade_callback, 0, 0,
911 caravan_marketplace_callback, 0, 0,
912 caravan_help_build_wonder_callback, 0, 0,
913 diplomat_bribe_callback, 0, 0,
914 spy_sabotage_unit_callback, 0, 0,
915 spy_steal_gold_callback, 0, 0,
916 act_sel_keep_moving_callback, target_tile, 1,
917 diplomat_cancel_callback, 0, 0,
918 NULL);
919
920 action_entry(XtNameToWidget(diplomat_dialog, "*button0"),
921 ACTION_ESTABLISH_EMBASSY,
922 act_probs);
923
924 action_entry(XtNameToWidget(diplomat_dialog, "*button1"),
925 ACTION_SPY_INVESTIGATE_CITY,
926 act_probs);
927
928 action_entry(XtNameToWidget(diplomat_dialog, "*button2"),
929 ACTION_SPY_POISON,
930 act_probs);
931
932 action_entry(XtNameToWidget(diplomat_dialog, "*button3"),
933 ACTION_SPY_SABOTAGE_CITY,
934 act_probs);
935
936 action_entry(XtNameToWidget(diplomat_dialog, "*button4"),
937 ACTION_SPY_TARGETED_SABOTAGE_CITY,
938 act_probs);
939
940 action_entry(XtNameToWidget(diplomat_dialog, "*button5"),
941 ACTION_SPY_STEAL_TECH,
942 act_probs);
943
944 action_entry(XtNameToWidget(diplomat_dialog, "*button6"),
945 ACTION_SPY_TARGETED_STEAL_TECH,
946 act_probs);
947
948 action_entry(XtNameToWidget(diplomat_dialog, "*button7"),
949 ACTION_SPY_INCITE_CITY,
950 act_probs);
951
952 action_entry(XtNameToWidget(diplomat_dialog, "*button8"),
953 ACTION_TRADE_ROUTE,
954 act_probs);
955
956 action_entry(XtNameToWidget(diplomat_dialog, "*button9"),
957 ACTION_MARKETPLACE,
958 act_probs);
959
960 action_entry(XtNameToWidget(diplomat_dialog, "*button10"),
961 ACTION_HELP_WONDER,
962 act_probs);
963
964 action_entry(XtNameToWidget(diplomat_dialog, "*button11"),
965 ACTION_SPY_BRIBE_UNIT,
966 act_probs);
967
968 action_entry(XtNameToWidget(diplomat_dialog, "*button12"),
969 ACTION_SPY_SABOTAGE_UNIT,
970 act_probs);
971
972 action_entry(XtNameToWidget(diplomat_dialog, "*button13"),
973 ACTION_SPY_STEAL_GOLD,
974 act_probs);
975
976 if (!(unit_can_move_to_tile(actor_unit, target_tile, FALSE)
977 || (is_military_unit(actor_unit) || is_attack_unit(actor_unit))
978 || (can_unit_bombard(actor_unit) && !is_ocean_tile(target_tile))
979 || (!target_city && unit_has_type_flag(actor_unit,
980 UTYF_CAPTURER)))) {
981 XtSetSensitive(XtNameToWidget(diplomat_dialog, "*button14"), FALSE);
982 }
983
984 astr_free(&text);
985 }
986
987 /**************************************************************************
988 Returns the id of the actor unit currently handled in action selection
989 dialog when the action selection dialog is open.
990 Returns IDENTITY_NUMBER_ZERO if no action selection dialog is open.
991 **************************************************************************/
action_selection_actor_unit(void)992 int action_selection_actor_unit(void)
993 {
994 if (diplomat_dialog == NULL) {
995 return IDENTITY_NUMBER_ZERO;
996 }
997
998 return diplomat_id;
999 }
1000
1001 /**************************************************************************
1002 Returns id of the target city of the actions currently handled in action
1003 selection dialog when the action selection dialog is open and it has a
1004 city target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1005 is open or no city target is present in the action selection dialog.
1006 **************************************************************************/
action_selection_target_city(void)1007 int action_selection_target_city(void)
1008 {
1009 if (diplomat_dialog == NULL) {
1010 return IDENTITY_NUMBER_ZERO;
1011 }
1012
1013 return diplomat_target_id[ATK_CITY];
1014 }
1015
1016 /**************************************************************************
1017 Returns id of the target unit of the actions currently handled in action
1018 selection dialog when the action selection dialog is open and it has a
1019 unit target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1020 is open or no unit target is present in the action selection dialog.
1021 **************************************************************************/
action_selection_target_unit(void)1022 int action_selection_target_unit(void)
1023 {
1024 if (diplomat_dialog == NULL) {
1025 return IDENTITY_NUMBER_ZERO;
1026 }
1027
1028 return diplomat_target_id[ATK_UNIT];
1029 }
1030
1031 /**************************************************************************
1032 Updates the action selection dialog with new information.
1033 **************************************************************************/
action_selection_refresh(struct unit * actor_unit,struct city * target_city,struct unit * target_unit,struct tile * target_tile,const struct act_prob * act_probs)1034 void action_selection_refresh(struct unit *actor_unit,
1035 struct city *target_city,
1036 struct unit *target_unit,
1037 struct tile *target_tile,
1038 const struct act_prob *act_probs)
1039 {
1040 /* TODO: port me. */
1041 }
1042
1043 /**************************************************************************
1044 Closes the action selection dialog
1045 **************************************************************************/
action_selection_close(void)1046 void action_selection_close(void)
1047 {
1048 if (diplomat_dialog != NULL) {
1049 action_selection_no_longer_in_progress(diplomat_id);
1050
1051 XtDestroyWidget(diplomat_dialog);
1052 }
1053 }
1054
1055 /**************************************************************************
1056 Let the non shared client code know that the action selection process
1057 no longer is in progress for the specified unit.
1058
1059 This allows the client to clean up any client specific assumptions.
1060 **************************************************************************/
action_selection_no_longer_in_progress_gui_specific(int actor_id)1061 void action_selection_no_longer_in_progress_gui_specific(int actor_id)
1062 {
1063 /* Not needed here. */
1064 }
1065