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