When mixer is not available, recommend SDL2_mixer instead of SDL1.2 mixer
[freeciv.git] / client / gui-sdl / action_dialog.c
blobd21fa649eb4aef3def789f6f70628a353188c855
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996-2006 - 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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 /* utility */
19 #include "astring.h"
20 #include "fcintl.h"
21 #include "log.h"
23 /* common */
24 #include "actions.h"
25 #include "game.h"
26 #include "movement.h"
27 #include "research.h"
28 #include "traderoutes.h"
29 #include "unitlist.h"
31 /* client */
32 #include "client_main.h"
33 #include "climisc.h"
34 #include "control.h"
36 /* client/gui-sdl */
37 #include "citydlg.h"
38 #include "colors.h"
39 #include "dialogs.h"
40 #include "graphics.h"
41 #include "gui_id.h"
42 #include "gui_tilespec.h"
43 #include "mapview.h"
44 #include "repodlgs.h"
45 #include "themespec.h"
46 #include "widget.h"
48 #include "dialogs_g.h"
50 typedef int (*act_func)(struct widget *);
52 struct diplomat_dialog {
53 int actor_unit_id;
54 int target_ids[ATK_COUNT];
55 struct ADVANCED_DLG *pdialog;
58 struct small_diplomat_dialog {
59 int actor_unit_id;
60 int target_id;
61 struct SMALL_DLG *pdialog;
64 extern bool is_unit_move_blocked;
66 void popdown_diplomat_dialog(void);
67 void popdown_incite_dialog(void);
68 void popdown_bribe_dialog(void);
70 static struct diplomat_dialog *pDiplomat_Dlg = NULL;
71 static bool is_more_user_input_needed = FALSE;
72 static bool did_not_decide = FALSE;
74 /**************************************************************************
75 The action selection is done.
76 **************************************************************************/
77 static void act_sel_done_primary(int actor_unit_id)
79 if (!is_more_user_input_needed) {
80 /* The client isn't waiting for information for any unanswered follow
81 * up questions. */
83 struct unit *actor_unit;
85 if ((actor_unit = game_unit_by_number(actor_unit_id))) {
86 /* The action selection dialog wasn't closed because the actor unit
87 * was lost. */
89 /* The probabilities didn't just disappear, right? */
90 fc_assert_action(actor_unit->client.act_prob_cache,
91 client_unit_init_act_prob_cache(actor_unit));
93 FC_FREE(actor_unit->client.act_prob_cache);
96 /* The action selection process is over, at least for now. */
97 action_selection_no_longer_in_progress(actor_unit_id);
99 if (did_not_decide) {
100 /* The action selection dialog was closed but the player didn't
101 * decide what the unit should do. */
103 /* Reset so the next action selection dialog does the right thing. */
104 did_not_decide = FALSE;
105 } else {
106 /* An action, or no action at all, was selected. */
107 action_decision_clear_want(actor_unit_id);
108 action_selection_next_in_focus(actor_unit_id);
113 /**************************************************************************
114 A follow up question about the selected action is done.
115 **************************************************************************/
116 static void act_sel_done_secondary(int actor_unit_id)
118 /* Stop blocking. */
119 is_more_user_input_needed = FALSE;
120 act_sel_done_primary(actor_unit_id);
123 /* ====================================================================== */
124 /* ============================ CARAVAN DIALOG ========================== */
125 /* ====================================================================== */
127 /****************************************************************
128 User selected that caravan should enter marketplace.
129 *****************************************************************/
130 static int caravan_marketplace_callback(struct widget *pWidget)
132 if (Main.event.button.button == SDL_BUTTON_LEFT) {
133 if (NULL != game_city_by_number(
134 pDiplomat_Dlg->target_ids[ATK_CITY])
135 && NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)) {
136 request_do_action(ACTION_MARKETPLACE,
137 pDiplomat_Dlg->actor_unit_id,
138 pDiplomat_Dlg->target_ids[ATK_CITY],
142 popdown_diplomat_dialog();
145 return -1;
148 /****************************************************************
149 User selected that caravan should establish traderoute.
150 *****************************************************************/
151 static int caravan_establish_trade_callback(struct widget *pWidget)
153 if (Main.event.button.button == SDL_BUTTON_LEFT) {
154 if (NULL != game_city_by_number(
155 pDiplomat_Dlg->target_ids[ATK_CITY])
156 && NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)) {
157 request_do_action(ACTION_TRADE_ROUTE,
158 pDiplomat_Dlg->actor_unit_id,
159 pDiplomat_Dlg->target_ids[ATK_CITY],
163 popdown_diplomat_dialog();
166 return -1;
169 /****************************************************************
170 User selected that caravan should help in wonder building.
171 *****************************************************************/
172 static int caravan_help_build_wonder_callback(struct widget *pWidget)
174 if (Main.event.button.button == SDL_BUTTON_LEFT) {
175 if (NULL != game_city_by_number(
176 pDiplomat_Dlg->target_ids[ATK_CITY])
177 && NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)) {
178 request_do_action(ACTION_HELP_WONDER,
179 pDiplomat_Dlg->actor_unit_id,
180 pDiplomat_Dlg->target_ids[ATK_CITY],
184 popdown_diplomat_dialog();
187 return -1;
190 /* ====================================================================== */
191 /* ============================ DIPLOMAT DIALOG ========================= */
192 /* ====================================================================== */
194 /****************************************************************
195 User interacted with diplomat dialog.
196 *****************************************************************/
197 static int diplomat_dlg_window_callback(struct widget *pWindow)
199 if (Main.event.button.button == SDL_BUTTON_LEFT) {
200 move_window_group(pDiplomat_Dlg->pdialog->pBeginWidgetList, pWindow);
202 return -1;
205 /****************************************************************
206 User clicked "Establish Embassy"
207 *****************************************************************/
208 static int diplomat_embassy_callback(struct widget *pWidget)
210 if (Main.event.button.button == SDL_BUTTON_LEFT) {
211 if (NULL != game_city_by_number(
212 pDiplomat_Dlg->target_ids[ATK_CITY])
213 && NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)) {
214 request_do_action(ACTION_ESTABLISH_EMBASSY,
215 pDiplomat_Dlg->actor_unit_id,
216 pDiplomat_Dlg->target_ids[ATK_CITY],
220 popdown_diplomat_dialog();
223 return -1;
226 /****************************************************************
227 User clicked "Investigate City"
228 *****************************************************************/
229 static int diplomat_investigate_callback(struct widget *pWidget)
231 if (Main.event.button.button == SDL_BUTTON_LEFT) {
232 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
233 && NULL != game_city_by_number(
234 pDiplomat_Dlg->target_ids[ATK_CITY])) {
235 request_do_action(ACTION_SPY_INVESTIGATE_CITY,
236 pDiplomat_Dlg->actor_unit_id,
237 pDiplomat_Dlg->target_ids[ATK_CITY],
241 /* FIXME: Wait for the city display in stead? */
242 popdown_diplomat_dialog();
245 return -1;
248 /****************************************************************
249 User clicked "Poison City"
250 *****************************************************************/
251 static int spy_poison_callback( struct widget *pWidget )
253 if (Main.event.button.button == SDL_BUTTON_LEFT) {
254 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
255 && NULL != game_city_by_number(
256 pDiplomat_Dlg->target_ids[ATK_CITY])) {
257 request_do_action(ACTION_SPY_POISON, pDiplomat_Dlg->actor_unit_id,
258 pDiplomat_Dlg->target_ids[ATK_CITY],
262 popdown_diplomat_dialog();
265 return -1;
268 /********************************************************************
269 User clicked "Steal Gold"
270 ********************************************************************/
271 static int spy_steal_gold_callback(struct widget *pWidget)
273 if (Main.event.button.button == SDL_BUTTON_LEFT) {
274 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
275 && NULL != game_city_by_number(
276 pDiplomat_Dlg->target_ids[ATK_CITY])) {
277 request_do_action(ACTION_SPY_STEAL_GOLD,
278 pDiplomat_Dlg->actor_unit_id,
279 pDiplomat_Dlg->target_ids[ATK_CITY],
283 popdown_diplomat_dialog();
286 return -1;
289 /****************************************************************
290 Requests up-to-date list of improvements, the return of
291 which will trigger the popup_sabotage_dialog() function.
292 *****************************************************************/
293 static int spy_sabotage_request(struct widget *pWidget)
295 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
296 && NULL != game_city_by_number(
297 pDiplomat_Dlg->target_ids[ATK_CITY])) {
298 request_action_details(ACTION_SPY_TARGETED_SABOTAGE_CITY,
299 pDiplomat_Dlg->actor_unit_id,
300 pDiplomat_Dlg->target_ids[ATK_CITY]);
301 is_more_user_input_needed = TRUE;
302 popdown_diplomat_dialog();
303 } else {
304 popdown_diplomat_dialog();
307 return -1;
310 /****************************************************************
311 User clicked "Sabotage City" for diplomat (not spy)
312 *****************************************************************/
313 static int diplomat_sabotage_callback(struct widget *pWidget)
315 if (Main.event.button.button == SDL_BUTTON_LEFT) {
316 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
317 && NULL != game_city_by_number(
318 pDiplomat_Dlg->target_ids[ATK_CITY])) {
319 request_do_action(ACTION_SPY_SABOTAGE_CITY,
320 pDiplomat_Dlg->actor_unit_id,
321 pDiplomat_Dlg->target_ids[ATK_CITY],
322 B_LAST + 1);
325 popdown_diplomat_dialog();
328 return -1;
331 /* --------------------------------------------------------- */
333 /****************************************************************
334 User interacted with spy's steal dialog window.
335 *****************************************************************/
336 static int spy_steal_dlg_window_callback(struct widget *pWindow)
338 if (Main.event.button.button == SDL_BUTTON_LEFT) {
339 move_window_group(pDiplomat_Dlg->pdialog->pBeginWidgetList, pWindow);
341 return -1;
344 /****************************************************************
345 Exit spy's steal or sabotage dialog.
346 *****************************************************************/
347 static int exit_spy_tgt_dlg_callback(struct widget *pWidget)
349 if (Main.event.button.button == SDL_BUTTON_LEFT) {
350 int actor_id = pDiplomat_Dlg->actor_unit_id;
352 fc_assert(is_more_user_input_needed);
353 popdown_diplomat_dialog();
354 act_sel_done_secondary(actor_id);
357 return -1;
360 /****************************************************************
361 User selected which tech spy steals.
362 *****************************************************************/
363 static int spy_steal_callback(struct widget *pWidget)
365 if (Main.event.button.button == SDL_BUTTON_LEFT) {
366 int steal_advance = MAX_ID - pWidget->ID;
367 int actor_id = pDiplomat_Dlg->actor_unit_id;
369 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
370 && NULL != game_city_by_number(
371 pDiplomat_Dlg->target_ids[ATK_CITY])) {
372 if (steal_advance == A_UNSET) {
373 /* This is the untargeted version. */
374 request_do_action(ACTION_SPY_STEAL_TECH,
375 pDiplomat_Dlg->actor_unit_id,
376 pDiplomat_Dlg->target_ids[ATK_CITY],
377 steal_advance);
378 } else {
379 /* This is the targeted version. */
380 request_do_action(ACTION_SPY_TARGETED_STEAL_TECH,
381 pDiplomat_Dlg->actor_unit_id,
382 pDiplomat_Dlg->target_ids[ATK_CITY],
383 steal_advance);
387 fc_assert(is_more_user_input_needed);
388 popdown_diplomat_dialog();
389 act_sel_done_secondary(actor_id);
392 return -1;
395 /**************************************************************************
396 Popup spy tech stealing dialog.
397 **************************************************************************/
398 static int spy_steal_popup(struct widget *pWidget)
400 const struct research *presearch, *vresearch;
401 struct city *pVcity = pWidget->data.city;
402 int id = MAX_ID - pWidget->ID;
403 struct player *pVictim = NULL;
404 struct CONTAINER *pCont;
405 struct widget *pBuf = NULL;
406 struct widget *pWindow;
407 SDL_String16 *pStr;
408 SDL_Surface *pSurf;
409 int max_col, max_row, col, count = 0;
410 int tech, idx;
411 SDL_Rect area;
413 struct unit *actor_unit = game_unit_by_number(id);
415 is_more_user_input_needed = TRUE;
416 popdown_diplomat_dialog();
418 if (pVcity)
420 pVictim = city_owner(pVcity);
423 fc_assert_ret_val_msg(!pDiplomat_Dlg, 1, "Diplomat dialog already open");
425 if (!pVictim) {
426 act_sel_done_secondary(id);
427 return 1;
430 count = 0;
431 presearch = research_get(client_player());
432 vresearch = research_get(pVictim);
433 advance_index_iterate(A_FIRST, i) {
434 if (research_invention_gettable(presearch, i,
435 game.info.tech_steal_allow_holes)
436 && TECH_KNOWN == research_invention_state(vresearch, i)
437 && TECH_KNOWN != research_invention_state(presearch, i)) {
438 count++;
440 } advance_index_iterate_end;
442 if(!count) {
443 /* if there is no known tech to steal then
444 send steal order at Spy's Discretion */
445 int target_id = pVcity->id;
447 request_do_action(ACTION_SPY_STEAL_TECH,
448 id, target_id, A_UNSET);
450 act_sel_done_secondary(id);
452 return -1;
455 pCont = fc_calloc(1, sizeof(struct CONTAINER));
456 pCont->id0 = pVcity->id;
457 pCont->id1 = id;/* spy id */
459 pDiplomat_Dlg = fc_calloc(1, sizeof(struct diplomat_dialog));
460 pDiplomat_Dlg->actor_unit_id = id;
461 pDiplomat_Dlg->target_ids[ATK_CITY] = pVcity->id;
462 pDiplomat_Dlg->pdialog = fc_calloc(1, sizeof(struct ADVANCED_DLG));
464 pStr = create_str16_from_char(_("Select Advance to Steal"), adj_font(12));
465 pStr->style |= TTF_STYLE_BOLD;
467 pWindow = create_window_skeleton(NULL, pStr, 0);
469 pWindow->action = spy_steal_dlg_window_callback;
470 set_wstate(pWindow , FC_WS_NORMAL);
472 add_to_gui_list(ID_DIPLOMAT_DLG_WINDOW, pWindow);
473 pDiplomat_Dlg->pdialog->pEndWidgetList = pWindow;
475 area = pWindow->area;
476 area.w = MAX(area.w, adj_size(8));
478 /* ------------------ */
479 /* exit button */
480 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
481 WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
482 pBuf->info_label = create_str16_from_char(_("Close Dialog (Esc)"),
483 adj_font(12));
484 area.w += pBuf->size.w + adj_size(10);
485 pBuf->action = exit_spy_tgt_dlg_callback;
486 set_wstate(pBuf, FC_WS_NORMAL);
487 pBuf->key = SDLK_ESCAPE;
489 add_to_gui_list(ID_TERRAIN_ADV_DLG_EXIT_BUTTON, pBuf);
490 /* ------------------------- */
492 if (action_prob_possible(
493 actor_unit->client.act_prob_cache[ACTION_SPY_STEAL_TECH])) {
494 /* count + at Spy's Discretion */
495 count++;
498 /* max col - 104 is steal tech widget width */
499 max_col = (Main.screen->w - (pWindow->size.w - pWindow->area.w) - adj_size(2)) / adj_size(104);
500 /* max row - 204 is steal tech widget height */
501 max_row = (Main.screen->h - (pWindow->size.h - pWindow->area.h)) / adj_size(204);
503 /* make space on screen for scrollbar */
504 if (max_col * max_row < count) {
505 max_col--;
508 if (count < max_col + 1) {
509 col = count;
510 } else {
511 if (count < max_col + adj_size(3)) {
512 col = max_col - adj_size(2);
513 } else {
514 if (count < max_col + adj_size(5)) {
515 col = max_col - 1;
516 } else {
517 col = max_col;
522 pStr = create_string16(NULL, 0, adj_font(10));
523 pStr->style |= (TTF_STYLE_BOLD | SF_CENTER);
525 count = 0;
526 advance_index_iterate(A_FIRST, i) {
527 if (research_invention_gettable(presearch, i,
528 game.info.tech_steal_allow_holes)
529 && TECH_KNOWN == research_invention_state(vresearch, i)
530 && TECH_KNOWN != research_invention_state(presearch, i)) {
531 count++;
533 copy_chars_to_string16(pStr, advance_name_translation(advance_by_number(i)));
534 pSurf = create_sellect_tech_icon(pStr, i, FULL_MODE);
535 pBuf = create_icon2(pSurf, pWindow->dst,
536 WF_FREE_THEME | WF_RESTORE_BACKGROUND);
538 set_wstate(pBuf, FC_WS_NORMAL);
539 pBuf->action = spy_steal_callback;
540 pBuf->data.cont = pCont;
542 add_to_gui_list(MAX_ID - i, pBuf);
544 if (count > (col * max_row)) {
545 set_wflag(pBuf, WF_HIDDEN);
548 } advance_index_iterate_end;
550 /* Get Spy tech to use for "At Spy's Discretion" -- this will have the
551 * side effect of displaying the unit's icon */
552 tech = advance_number(unit_type_get(actor_unit)->require_advance);
554 if (action_prob_possible(
555 actor_unit->client.act_prob_cache[ACTION_SPY_STEAL_TECH])) {
557 struct astring str = ASTRING_INIT;
559 /* TRANS: %s is a unit name, e.g., Spy */
560 astr_set(&str, _("At %s's Discretion"),
561 unit_name_translation(actor_unit));
562 copy_chars_to_string16(pStr, astr_str(&str));
563 astr_free(&str);
565 pSurf = create_sellect_tech_icon(pStr, tech, FULL_MODE);
567 pBuf = create_icon2(pSurf, pWindow->dst,
568 (WF_FREE_THEME | WF_RESTORE_BACKGROUND
569 | WF_FREE_DATA));
570 set_wstate(pBuf, FC_WS_NORMAL);
571 pBuf->action = spy_steal_callback;
572 pBuf->data.cont = pCont;
574 add_to_gui_list(MAX_ID - A_UNSET, pBuf);
575 count++;
578 /* --------------------------------------------------------- */
579 FREESTRING16(pStr);
580 pDiplomat_Dlg->pdialog->pBeginWidgetList = pBuf;
581 pDiplomat_Dlg->pdialog->pBeginActiveWidgetList = pDiplomat_Dlg->pdialog->pBeginWidgetList;
582 pDiplomat_Dlg->pdialog->pEndActiveWidgetList = pDiplomat_Dlg->pdialog->pEndWidgetList->prev->prev;
584 /* -------------------------------------------------------------- */
586 idx = 0;
587 if (count > col) {
588 count = (count + (col - 1)) / col;
589 if (count > max_row) {
590 pDiplomat_Dlg->pdialog->pActiveWidgetList = pDiplomat_Dlg->pdialog->pEndActiveWidgetList;
591 count = max_row;
592 idx = create_vertical_scrollbar(pDiplomat_Dlg->pdialog, col, count, TRUE, TRUE);
594 } else {
595 count = 1;
598 area.w = MAX(area.w, (col * pBuf->size.w + adj_size(2) + idx));
599 area.h = count * pBuf->size.h + adj_size(2);
601 /* alloca window theme and win background buffer */
602 pSurf = theme_get_background(theme, BACKGROUND_SPYSTEALDLG);
603 if (resize_window(pWindow, pSurf, NULL,
604 (pWindow->size.w - pWindow->area.w) + area.w,
605 (pWindow->size.h - pWindow->area.h) + area.h))
607 FREESURFACE(pSurf);
610 area = pWindow->area;
612 widget_set_position(pWindow,
613 (Main.screen->w - pWindow->size.w) / 2,
614 (Main.screen->h - pWindow->size.h) / 2);
616 /* exit button */
617 pBuf = pWindow->prev;
618 pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
619 pBuf->size.y = pWindow->size.y + adj_size(2);
621 setup_vertical_widgets_position(col, area.x + 1,
622 area.y, 0, 0,
623 pDiplomat_Dlg->pdialog->pBeginActiveWidgetList,
624 pDiplomat_Dlg->pdialog->pEndActiveWidgetList);
626 if(pDiplomat_Dlg->pdialog->pScroll) {
627 setup_vertical_scrollbar_area(pDiplomat_Dlg->pdialog->pScroll,
628 area.x + area.w, area.y,
629 area.h, TRUE);
632 redraw_group(pDiplomat_Dlg->pdialog->pBeginWidgetList, pWindow, FALSE);
633 widget_mark_dirty(pWindow);
635 return -1;
638 /****************************************************************
639 Technology stealing dialog, diplomat (not spy) version
640 *****************************************************************/
641 static int diplomat_steal_callback(struct widget *pWidget)
643 if (Main.event.button.button == SDL_BUTTON_LEFT) {
644 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
645 && NULL != game_city_by_number(
646 pDiplomat_Dlg->target_ids[ATK_CITY])) {
647 request_do_action(ACTION_SPY_STEAL_TECH,
648 pDiplomat_Dlg->actor_unit_id,
649 pDiplomat_Dlg->target_ids[ATK_CITY],
650 A_UNSET);
653 popdown_diplomat_dialog();
656 return -1;
659 /****************************************************************
660 ... Ask the server how much the revolt is going to cost us
661 *****************************************************************/
662 static int diplomat_incite_callback(struct widget *pWidget)
664 if (Main.event.button.button == SDL_BUTTON_LEFT) {
665 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
666 && NULL != game_city_by_number(
667 pDiplomat_Dlg->target_ids[ATK_CITY])) {
668 request_action_details(ACTION_SPY_INCITE_CITY,
669 pDiplomat_Dlg->actor_unit_id,
670 pDiplomat_Dlg->target_ids[ATK_CITY]);
671 is_more_user_input_needed = TRUE;
672 popdown_diplomat_dialog();
673 } else {
674 popdown_diplomat_dialog();
677 return -1;
680 /********************************************************************
681 Callback from action selection dialog for "keep moving".
682 (This should only occur when entering a tile with an allied city
683 or an allied unit.)
684 *********************************************************************/
685 static int act_sel_keep_moving_callback(struct widget *pWidget)
687 if (Main.event.button.button == SDL_BUTTON_LEFT) {
688 struct unit *punit;
690 if ((punit = game_unit_by_number(pDiplomat_Dlg->actor_unit_id))
691 && !same_pos(unit_tile(punit), pWidget->data.tile)) {
692 request_unit_non_action_move(punit, pWidget->data.tile);
695 popdown_diplomat_dialog();
697 return -1;
700 /********************************************************************
701 Delay selection of what action to take.
702 *********************************************************************/
703 static int act_sel_wait_callback(struct widget *pWidget)
705 if (Main.event.button.button == SDL_BUTTON_LEFT) {
706 key_unit_wait();
708 /* The dialog was popped down when key_unit_wait() resulted in
709 * action_selection_close() being called. */
712 return -1;
715 /****************************************************************
716 ... Ask the server how much the bribe is
717 *****************************************************************/
718 static int diplomat_bribe_callback(struct widget *pWidget)
720 if (Main.event.button.button == SDL_BUTTON_LEFT) {
721 if (NULL != game_unit_by_number(pDiplomat_Dlg->actor_unit_id)
722 && NULL !=
723 game_unit_by_number(pDiplomat_Dlg->target_ids[ATK_UNIT])) {
724 request_action_details(ACTION_SPY_BRIBE_UNIT,
725 pDiplomat_Dlg->actor_unit_id,
726 pDiplomat_Dlg->target_ids[ATK_UNIT]);
727 is_more_user_input_needed = TRUE;
728 popdown_diplomat_dialog();
729 } else {
730 popdown_diplomat_dialog();
733 return -1;
736 /****************************************************************
737 User clicked "Sabotage Unit"
738 *****************************************************************/
739 static int spy_sabotage_unit_callback(struct widget *pWidget)
741 if (Main.event.button.button == SDL_BUTTON_LEFT) {
742 int diplomat_id = MAX_ID - pWidget->ID;
743 int target_id = pWidget->data.unit->id;
745 popdown_diplomat_dialog();
746 request_do_action(ACTION_SPY_SABOTAGE_UNIT,
747 diplomat_id, target_id, 0);
750 return -1;
753 /****************************************************************
754 Close diplomat dialog.
755 *****************************************************************/
756 static int diplomat_close_callback(struct widget *pWidget)
758 if (Main.event.button.button == SDL_BUTTON_LEFT) {
759 popdown_diplomat_dialog();
762 return -1;
765 /**************************************************************************
766 Popdown a dialog giving a diplomatic unit some options when moving into
767 the target tile.
768 **************************************************************************/
769 void popdown_diplomat_dialog(void)
771 if (pDiplomat_Dlg) {
772 act_sel_done_primary(pDiplomat_Dlg->actor_unit_id);
774 is_unit_move_blocked = FALSE;
775 popdown_window_group_dialog(pDiplomat_Dlg->pdialog->pBeginWidgetList,
776 pDiplomat_Dlg->pdialog->pEndWidgetList);
777 FC_FREE(pDiplomat_Dlg->pdialog->pScroll);
778 FC_FREE(pDiplomat_Dlg->pdialog);
779 FC_FREE(pDiplomat_Dlg);
780 queue_flush();
784 /* Mapping from an action to the function to call when its button is
785 * pushed. */
786 static const act_func af_map[ACTION_COUNT] = {
787 /* Unit acting against a city target. */
788 [ACTION_ESTABLISH_EMBASSY] = diplomat_embassy_callback,
789 [ACTION_SPY_INVESTIGATE_CITY] = diplomat_investigate_callback,
790 [ACTION_SPY_POISON] = spy_poison_callback,
791 [ACTION_SPY_STEAL_GOLD] = spy_steal_gold_callback,
792 [ACTION_SPY_SABOTAGE_CITY] = diplomat_sabotage_callback,
793 [ACTION_SPY_TARGETED_SABOTAGE_CITY] = spy_sabotage_request,
794 [ACTION_SPY_STEAL_TECH] = diplomat_steal_callback,
795 [ACTION_SPY_TARGETED_STEAL_TECH] = spy_steal_popup,
796 [ACTION_SPY_INCITE_CITY] = diplomat_incite_callback,
797 [ACTION_TRADE_ROUTE] = caravan_establish_trade_callback,
798 [ACTION_MARKETPLACE] = caravan_marketplace_callback,
799 [ACTION_HELP_WONDER] = caravan_help_build_wonder_callback,
801 /* Unit acting against a unit target. */
802 [ACTION_SPY_BRIBE_UNIT] = diplomat_bribe_callback,
803 [ACTION_SPY_SABOTAGE_UNIT] = spy_sabotage_unit_callback
806 /**************************************************************************
807 Add an entry for an action in the action choice dialog.
808 **************************************************************************/
809 static void action_entry(const enum gen_action act,
810 const struct act_prob *act_probs,
811 const char *custom,
812 struct unit *act_unit,
813 struct city *tgt_city,
814 struct unit *tgt_unit,
815 struct widget *pWindow,
816 SDL_Rect *area)
818 struct widget *pBuf;
819 SDL_String16 *pStr;
820 const char *ui_name;
822 if (act == ACTION_SPY_SABOTAGE_CITY
823 && action_prob_possible(
824 act_probs[ACTION_SPY_TARGETED_SABOTAGE_CITY])) {
825 /* The player can select Sabotage City from the target selection dialog
826 * of Targeted Sabotage City. */
827 return;
830 if (act == ACTION_SPY_STEAL_TECH
831 && action_prob_possible(
832 act_probs[ACTION_SPY_TARGETED_STEAL_TECH])) {
833 /* The player can select Steal Tech from the target selection dialog of
834 * Targeted Steal Tech. */
835 return;
838 /* Don't show disabled actions */
839 if (!action_prob_possible(act_probs[act])) {
840 return;
843 ui_name = action_prepare_ui_name(act, "",
844 act_probs[act], custom);
846 create_active_iconlabel(pBuf, pWindow->dst, pStr,
847 ui_name, af_map[act]);
849 switch(action_id_get_target_kind(act)) {
850 case ATK_CITY:
851 pBuf->data.city = tgt_city;
852 break;
853 case ATK_UNIT:
854 pBuf->data.unit = tgt_unit;
855 break;
856 case ATK_COUNT:
857 fc_assert_msg(FALSE, "Unsupported target kind");
860 set_wstate(pBuf, FC_WS_NORMAL);
862 add_to_gui_list(MAX_ID - act_unit->id, pBuf);
864 area->w = MAX(area->w, pBuf->size.w);
865 area->h += pBuf->size.h;
868 /**************************************************************************
869 Return custom text for the specified action (given that the aciton is
870 possible).
871 **************************************************************************/
872 static const char *action_custom_text(const int action_id,
873 const struct act_prob prob,
874 const struct city *actor_homecity,
875 const struct city *target_city)
877 static struct astring custom = ASTRING_INIT;
879 if (!action_prob_possible(prob)) {
880 /* No info since impossible. */
881 return NULL;
884 switch (action_id) {
885 case ACTION_TRADE_ROUTE:
887 int revenue = get_caravan_enter_city_trade_bonus(actor_homecity,
888 target_city,
889 TRUE);
891 astr_set(&custom,
892 /* TRANS: Estimated one time bonus and recurring revenue for
893 * the Establish Trade _Route action. */
894 _("%d one time bonus + %d trade"),
895 revenue,
896 trade_between_cities(actor_homecity, target_city));
897 break;
899 case ACTION_MARKETPLACE:
901 int revenue = get_caravan_enter_city_trade_bonus(actor_homecity,
902 target_city,
903 FALSE);
905 astr_set(&custom,
906 /* TRANS: Estimated one time bonus for the Enter Marketplace
907 * action. */
908 _("%d one time bonus"), revenue);
909 break;
911 default:
912 /* No info to add. */
913 return NULL;
916 return astr_str(&custom);
919 /**************************************************************************
920 Popup a dialog that allows the player to select what action a unit
921 should take.
922 **************************************************************************/
923 void popup_action_selection(struct unit *actor_unit,
924 struct city *target_city,
925 struct unit *target_unit,
926 struct tile *target_tile,
927 const struct act_prob *act_probs)
929 struct widget *pWindow = NULL, *pBuf = NULL;
930 SDL_String16 *pStr;
931 SDL_Rect area;
932 struct city *actor_homecity;
934 fc_assert_ret_msg(!pDiplomat_Dlg, "Diplomat dialog already open");
936 /* Could be caused by the server failing to reply to a request for more
937 * information or a bug in the client code. */
938 fc_assert_msg(!is_more_user_input_needed,
939 "Diplomat queue problem. Is another diplomat window open?");
941 /* No extra input is required as no action has been chosen yet. */
942 is_more_user_input_needed = FALSE;
944 is_unit_move_blocked = TRUE;
946 actor_homecity = game_city_by_number(actor_unit->homecity);
948 pDiplomat_Dlg = fc_calloc(1, sizeof(struct diplomat_dialog));
949 pDiplomat_Dlg->actor_unit_id = actor_unit->id;
950 pDiplomat_Dlg->pdialog = fc_calloc(1, sizeof(struct ADVANCED_DLG));
952 /* window */
953 if (target_city) {
954 struct astring title = ASTRING_INIT;
955 /* TRANS: %s is a unit name, e.g., Spy */
956 astr_set(&title, _("Choose Your %s's Strategy"),
957 unit_name_translation(actor_unit));
958 pStr = create_str16_from_char(astr_str(&title), adj_font(12));
959 astr_free(&title);
960 } else {
961 pStr = create_str16_from_char(_("Subvert Enemy Unit"), adj_font(12));
964 pStr->style |= TTF_STYLE_BOLD;
966 pWindow = create_window_skeleton(NULL, pStr, 0);
968 pWindow->action = diplomat_dlg_window_callback;
969 set_wstate(pWindow, FC_WS_NORMAL);
971 add_to_gui_list(ID_CARAVAN_DLG_WINDOW, pWindow);
972 pDiplomat_Dlg->pdialog->pEndWidgetList = pWindow;
974 area = pWindow->area;
975 area.w = MAX(area.w, adj_size(8));
976 area.h = MAX(area.h, adj_size(2));
978 if (target_city) {
979 pDiplomat_Dlg->target_ids[ATK_CITY] = target_city->id;
980 } else {
981 pDiplomat_Dlg->target_ids[ATK_CITY] = IDENTITY_NUMBER_ZERO;
984 if (target_unit) {
985 pDiplomat_Dlg->target_ids[ATK_UNIT] = target_unit->id;
986 } else {
987 pDiplomat_Dlg->target_ids[ATK_UNIT] = IDENTITY_NUMBER_ZERO;
990 /* ---------- */
991 /* Unit acting against a city */
993 action_iterate(act) {
994 if (action_id_get_actor_kind(act) == AAK_UNIT
995 && action_id_get_target_kind(act) == ATK_CITY) {
996 action_entry(act, act_probs,
997 action_custom_text(act, act_probs[act],
998 actor_homecity, target_city),
999 actor_unit, target_city, NULL,
1000 pWindow, &area);
1002 } action_iterate_end;
1004 /* Unit acting against another unit */
1006 action_iterate(act) {
1007 if (action_id_get_actor_kind(act) == AAK_UNIT
1008 && action_id_get_target_kind(act) == ATK_UNIT) {
1009 action_entry(act, act_probs,
1010 NULL,
1011 actor_unit, NULL, target_unit,
1012 pWindow, &area);
1014 } action_iterate_end;
1016 /* ---------- */
1017 if (unit_can_move_to_tile(actor_unit, target_tile, FALSE)
1018 || (is_military_unit(actor_unit) || is_attack_unit(actor_unit))
1019 || (can_unit_bombard(actor_unit) && !is_ocean_tile(target_tile))
1020 || (!target_city && unit_has_type_flag(actor_unit, UTYF_CAPTURER))) {
1021 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1022 _("Keep moving"),
1023 act_sel_keep_moving_callback);
1025 pBuf->data.tile = target_tile;
1027 set_wstate(pBuf, FC_WS_NORMAL);
1029 add_to_gui_list(MAX_ID - actor_unit->id, pBuf);
1031 area.w = MAX(area.w, pBuf->size.w);
1032 area.h += pBuf->size.h;
1035 /* ---------- */
1036 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1037 _("Wait"), act_sel_wait_callback);
1039 pBuf->data.tile = target_tile;
1041 set_wstate(pBuf, FC_WS_NORMAL);
1043 add_to_gui_list(MAX_ID - actor_unit->id, pBuf);
1045 area.w = MAX(area.w, pBuf->size.w);
1046 area.h += pBuf->size.h;
1048 /* ---------- */
1049 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1050 _("Cancel"), diplomat_close_callback);
1052 set_wstate(pBuf , FC_WS_NORMAL);
1053 pBuf->key = SDLK_ESCAPE;
1055 add_to_gui_list(ID_LABEL , pBuf);
1057 area.w = MAX(area.w, pBuf->size.w);
1058 area.h += pBuf->size.h;
1059 /* ---------- */
1060 pDiplomat_Dlg->pdialog->pBeginWidgetList = pBuf;
1062 /* setup window size and start position */
1064 resize_window(pWindow, NULL, NULL,
1065 (pWindow->size.w - pWindow->area.w) + area.w,
1066 (pWindow->size.h - pWindow->area.h) + area.h);
1068 area = pWindow->area;
1070 auto_center_on_focus_unit();
1071 put_window_near_map_tile(pWindow, pWindow->size.w, pWindow->size.h,
1072 unit_tile(actor_unit));
1074 /* setup widget size and start position */
1076 pBuf = pWindow->prev;
1077 setup_vertical_widgets_position(1,
1078 area.x,
1079 area.y + 1, area.w, 0,
1080 pDiplomat_Dlg->pdialog->pBeginWidgetList, pBuf);
1082 /* --------------------- */
1083 /* redraw */
1084 redraw_group(pDiplomat_Dlg->pdialog->pBeginWidgetList, pWindow, 0);
1086 widget_flush(pWindow);
1088 /* Give follow up questions access to action probabilities. */
1089 client_unit_init_act_prob_cache(actor_unit);
1090 action_iterate(act) {
1091 actor_unit->client.act_prob_cache[act] = act_probs[act];
1092 } action_iterate_end;
1095 /**************************************************************************
1096 Returns the id of the actor unit currently handled in action selection
1097 dialog when the action selection dialog is open.
1098 Returns IDENTITY_NUMBER_ZERO if no action selection dialog is open.
1099 **************************************************************************/
1100 int action_selection_actor_unit(void)
1102 if (!pDiplomat_Dlg) {
1103 return IDENTITY_NUMBER_ZERO;
1106 return pDiplomat_Dlg->actor_unit_id;
1109 /**************************************************************************
1110 Returns id of the target city of the actions currently handled in action
1111 selection dialog when the action selection dialog is open and it has a
1112 city target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1113 is open or no city target is present in the action selection dialog.
1114 **************************************************************************/
1115 int action_selection_target_city(void)
1117 if (!pDiplomat_Dlg) {
1118 return IDENTITY_NUMBER_ZERO;
1121 return pDiplomat_Dlg->target_ids[ATK_CITY];
1124 /**************************************************************************
1125 Returns id of the target unit of the actions currently handled in action
1126 selection dialog when the action selection dialog is open and it has a
1127 unit target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
1128 is open or no unit target is present in the action selection dialog.
1129 **************************************************************************/
1130 int action_selection_target_unit(void)
1132 if (!pDiplomat_Dlg) {
1133 return IDENTITY_NUMBER_ZERO;
1136 return pDiplomat_Dlg->target_ids[ATK_UNIT];
1139 /**************************************************************************
1140 Updates the action selection dialog with new information.
1141 **************************************************************************/
1142 void action_selection_refresh(struct unit *actor_unit,
1143 struct city *target_city,
1144 struct unit *target_unit,
1145 struct tile *target_tile,
1146 const struct act_prob *act_probs)
1148 /* TODO: port me. */
1151 /****************************************************************
1152 Closes the action selection dialog
1153 ****************************************************************/
1154 void action_selection_close(void)
1156 did_not_decide = TRUE;
1157 popdown_diplomat_dialog();
1160 /* ====================================================================== */
1161 /* ============================ SABOTAGE DIALOG ========================= */
1162 /* ====================================================================== */
1164 /****************************************************************
1165 User selected what to sabotage.
1166 ****************************************************************/
1167 static int sabotage_impr_callback(struct widget *pWidget)
1169 if (Main.event.button.button == SDL_BUTTON_LEFT) {
1170 int sabotage_improvement = MAX_ID - pWidget->ID;
1171 int diplomat_target_id = pWidget->data.cont->id0;
1172 int diplomat_id = pWidget->data.cont->id1;
1174 fc_assert(is_more_user_input_needed);
1175 popdown_diplomat_dialog();
1177 if(sabotage_improvement == 1000)
1179 sabotage_improvement = -1;
1182 if (NULL != game_unit_by_number(diplomat_id)
1183 && NULL != game_city_by_number(diplomat_target_id)) {
1184 if (sabotage_improvement == B_LAST) {
1185 /* This is the untargeted version. */
1186 request_do_action(ACTION_SPY_SABOTAGE_CITY, diplomat_id,
1187 diplomat_target_id, sabotage_improvement + 1);
1188 } else {
1189 /* This is the targeted version. */
1190 request_do_action(ACTION_SPY_TARGETED_SABOTAGE_CITY, diplomat_id,
1191 diplomat_target_id, sabotage_improvement + 1);
1195 act_sel_done_secondary(diplomat_id);
1198 return -1;
1201 /*************************************************************************
1202 Pops-up the Spy sabotage dialog, upon return of list of
1203 available improvements requested by the above function.
1204 **************************************************************************/
1205 void popup_sabotage_dialog(struct unit *actor, struct city *pCity)
1207 struct widget *pWindow = NULL, *pBuf = NULL , *pLast = NULL;
1208 struct CONTAINER *pCont;
1209 SDL_String16 *pStr;
1210 SDL_Rect area, area2;
1211 int n, w = 0, h, imp_h = 0, y;
1213 fc_assert_ret_msg(!pDiplomat_Dlg, "Diplomat dialog already open");
1215 /* Should be set before sending request to the server. */
1216 fc_assert(is_more_user_input_needed);
1218 if (!actor) {
1219 act_sel_done_secondary(IDENTITY_NUMBER_ZERO);
1220 return;
1223 is_unit_move_blocked = TRUE;
1225 pDiplomat_Dlg = fc_calloc(1, sizeof(struct diplomat_dialog));
1226 pDiplomat_Dlg->actor_unit_id = actor->id;
1227 pDiplomat_Dlg->target_ids[ATK_CITY] = pCity->id;
1228 pDiplomat_Dlg->pdialog = fc_calloc(1, sizeof(struct ADVANCED_DLG));
1230 pCont = fc_calloc(1, sizeof(struct CONTAINER));
1231 pCont->id0 = pCity->id;
1232 pCont->id1 = actor->id; /* spy id */
1234 pStr = create_str16_from_char(_("Select Improvement to Sabotage") , adj_font(12));
1235 pStr->style |= TTF_STYLE_BOLD;
1237 pWindow = create_window_skeleton(NULL, pStr, 0);
1239 pWindow->action = diplomat_dlg_window_callback;
1240 set_wstate(pWindow, FC_WS_NORMAL);
1242 add_to_gui_list(ID_TERRAIN_ADV_DLG_WINDOW, pWindow);
1243 pDiplomat_Dlg->pdialog->pEndWidgetList = pWindow;
1245 area = pWindow->area;
1246 area.h = MAX(area.h, adj_size(2));
1248 /* ---------- */
1249 /* exit button */
1250 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
1251 WF_WIDGET_HAS_INFO_LABEL | WF_RESTORE_BACKGROUND);
1252 pBuf->info_label = create_str16_from_char(_("Close Dialog (Esc)"),
1253 adj_font(12));
1254 area.w += pBuf->size.w + adj_size(10);
1255 pBuf->action = exit_spy_tgt_dlg_callback;
1256 set_wstate(pBuf, FC_WS_NORMAL);
1257 pBuf->key = SDLK_ESCAPE;
1259 add_to_gui_list(ID_TERRAIN_ADV_DLG_EXIT_BUTTON, pBuf);
1260 /* ---------- */
1262 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1263 _("City Production"), sabotage_impr_callback);
1264 pBuf->data.cont = pCont;
1265 set_wstate(pBuf, FC_WS_NORMAL);
1266 set_wflag(pBuf, WF_FREE_DATA);
1267 add_to_gui_list(MAX_ID - 1000, pBuf);
1269 area.w = MAX(area.w, pBuf->size.w);
1270 area.h += pBuf->size.h;
1272 /* separator */
1273 pBuf = create_iconlabel(NULL, pWindow->dst, NULL, WF_FREE_THEME);
1275 add_to_gui_list(ID_SEPARATOR, pBuf);
1276 area.h += pBuf->next->size.h;
1278 pDiplomat_Dlg->pdialog->pEndActiveWidgetList = pBuf;
1280 /* ------------------ */
1281 n = 0;
1282 city_built_iterate(pCity, pImprove) {
1283 if (pImprove->sabotage > 0) {
1285 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1286 (char *) city_improvement_name_translation(pCity, pImprove),
1287 sabotage_impr_callback);
1288 pBuf->data.cont = pCont;
1289 set_wstate(pBuf , FC_WS_NORMAL);
1291 add_to_gui_list(MAX_ID - improvement_number(pImprove), pBuf);
1293 area.w = MAX(area.w , pBuf->size.w);
1294 imp_h += pBuf->size.h;
1296 if (n > 9) {
1297 set_wflag(pBuf, WF_HIDDEN);
1300 n++;
1301 /* ----------- */
1303 } city_built_iterate_end;
1305 pDiplomat_Dlg->pdialog->pBeginActiveWidgetList = pBuf;
1307 if (n > 0 && action_prob_possible(
1308 actor->client.act_prob_cache[ACTION_SPY_SABOTAGE_CITY])) {
1309 /* separator */
1310 pBuf = create_iconlabel(NULL, pWindow->dst, NULL, WF_FREE_THEME);
1312 add_to_gui_list(ID_SEPARATOR, pBuf);
1313 area.h += pBuf->next->size.h;
1314 /* ------------------ */
1317 if (action_prob_possible(
1318 actor->client.act_prob_cache[ACTION_SPY_SABOTAGE_CITY])) {
1319 struct astring str = ASTRING_INIT;
1321 /* TRANS: %s is a unit name, e.g., Spy */
1322 astr_set(&str, _("At %s's Discretion"), unit_name_translation(actor));
1323 create_active_iconlabel(pBuf, pWindow->dst, pStr, astr_str(&str),
1324 sabotage_impr_callback);
1325 astr_free(&str);
1327 pBuf->data.cont = pCont;
1328 set_wstate(pBuf, FC_WS_NORMAL);
1330 add_to_gui_list(MAX_ID - B_LAST, pBuf);
1332 area.w = MAX(area.w, pBuf->size.w);
1333 area.h += pBuf->size.h;
1336 /* ----------- */
1338 pLast = pBuf;
1339 pDiplomat_Dlg->pdialog->pBeginWidgetList = pLast;
1340 pDiplomat_Dlg->pdialog->pActiveWidgetList = pDiplomat_Dlg->pdialog->pEndActiveWidgetList;
1342 /* ---------- */
1343 if (n > 10)
1345 imp_h = 10 * pBuf->size.h;
1347 n = create_vertical_scrollbar(pDiplomat_Dlg->pdialog,
1348 1, 10, TRUE, TRUE);
1349 area.w += n;
1350 } else {
1351 n = 0;
1353 /* ---------- */
1356 area.h += imp_h;
1358 resize_window(pWindow, NULL, NULL,
1359 (pWindow->size.w - pWindow->area.w) + area.w,
1360 (pWindow->size.h - pWindow->area.h) + area.h);
1362 area = pWindow->area;
1364 auto_center_on_focus_unit();
1365 put_window_near_map_tile(pWindow, pWindow->size.w, pWindow->size.h,
1366 unit_tile(actor));
1368 w = area.w;
1370 /* exit button */
1371 pBuf = pWindow->prev;
1372 pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
1373 pBuf->size.y = pWindow->size.y + adj_size(2);
1375 /* Production sabotage */
1376 pBuf = pBuf->prev;
1378 pBuf->size.x = area.x;
1379 pBuf->size.y = y = area.y + 1;
1380 pBuf->size.w = w;
1381 h = pBuf->size.h;
1383 area2.x = adj_size(10);
1384 area2.h = adj_size(2);
1386 pBuf = pBuf->prev;
1387 while(pBuf)
1390 if (pBuf == pDiplomat_Dlg->pdialog->pEndActiveWidgetList) {
1391 w -= n;
1394 pBuf->size.w = w;
1395 pBuf->size.x = pBuf->next->size.x;
1396 pBuf->size.y = y = y + pBuf->next->size.h;
1398 if (pBuf->ID == ID_SEPARATOR)
1400 FREESURFACE(pBuf->theme);
1401 pBuf->size.h = h;
1402 pBuf->theme = create_surf(w, h, SDL_SWSURFACE);
1404 area2.y = pBuf->size.h / 2 - 1;
1405 area2.w = pBuf->size.w - adj_size(20);
1407 SDL_FillRect(pBuf->theme , &area2, map_rgba(pBuf->theme->format, *get_theme_color(COLOR_THEME_SABOTAGEDLG_SEPARATOR)));
1410 if (pBuf == pLast) {
1411 break;
1413 if (pBuf == pDiplomat_Dlg->pdialog->pBeginActiveWidgetList) {
1414 /* Reset to end of scrolling area */
1415 y = MIN(y, pDiplomat_Dlg->pdialog->pEndActiveWidgetList->size.y
1416 + 9 * pBuf->size.h);
1417 w += n;
1419 pBuf = pBuf->prev;
1422 if (pDiplomat_Dlg->pdialog->pScroll)
1424 setup_vertical_scrollbar_area(pDiplomat_Dlg->pdialog->pScroll,
1425 area.x + area.w,
1426 pDiplomat_Dlg->pdialog->pEndActiveWidgetList->size.y,
1427 pDiplomat_Dlg->pdialog->pBeginActiveWidgetList->prev->size.y
1428 - pDiplomat_Dlg->pdialog->pEndActiveWidgetList->size.y,
1429 TRUE);
1432 /* -------------------- */
1433 /* redraw */
1434 redraw_group(pDiplomat_Dlg->pdialog->pBeginWidgetList, pWindow, 0);
1436 widget_flush(pWindow);
1440 /* ====================================================================== */
1441 /* ============================== INCITE DIALOG ========================= */
1442 /* ====================================================================== */
1443 static struct small_diplomat_dialog *pIncite_Dlg = NULL;
1445 /****************************************************************
1446 User interacted with Incite Revolt dialog window.
1447 *****************************************************************/
1448 static int incite_dlg_window_callback(struct widget *pWindow)
1450 if (Main.event.button.button == SDL_BUTTON_LEFT) {
1451 move_window_group(pIncite_Dlg->pdialog->pBeginWidgetList, pWindow);
1453 return -1;
1456 /****************************************************************
1457 User confirmed incite
1458 *****************************************************************/
1459 static int diplomat_incite_yes_callback(struct widget *pWidget)
1461 if (Main.event.button.button == SDL_BUTTON_LEFT) {
1462 if (NULL != game_unit_by_number(pIncite_Dlg->actor_unit_id)
1463 && NULL != game_city_by_number(pIncite_Dlg->target_id)) {
1464 request_do_action(ACTION_SPY_INCITE_CITY, pIncite_Dlg->actor_unit_id,
1465 pIncite_Dlg->target_id, 0);
1468 popdown_incite_dialog();
1470 return -1;
1473 /****************************************************************
1474 Close incite dialog.
1475 *****************************************************************/
1476 static int exit_incite_dlg_callback(struct widget *pWidget)
1478 if (Main.event.button.button == SDL_BUTTON_LEFT) {
1479 popdown_incite_dialog();
1481 return -1;
1484 /**************************************************************************
1485 Popdown a window asking a diplomatic unit if it wishes to incite the
1486 given enemy city.
1487 **************************************************************************/
1488 void popdown_incite_dialog(void)
1490 if (pIncite_Dlg) {
1491 act_sel_done_secondary(pIncite_Dlg->actor_unit_id);
1493 is_unit_move_blocked = FALSE;
1494 popdown_window_group_dialog(pIncite_Dlg->pdialog->pBeginWidgetList,
1495 pIncite_Dlg->pdialog->pEndWidgetList);
1496 FC_FREE(pIncite_Dlg->pdialog);
1497 FC_FREE(pIncite_Dlg);
1498 flush_dirty();
1502 /**************************************************************************
1503 Popup a window asking a diplomatic unit if it wishes to incite the
1504 given enemy city.
1505 **************************************************************************/
1506 void popup_incite_dialog(struct unit *actor, struct city *pCity, int cost)
1508 struct widget *pWindow = NULL, *pBuf = NULL;
1509 SDL_String16 *pStr;
1510 char tBuf[255], cBuf[255];
1511 bool exit = FALSE;
1512 SDL_Rect area;
1514 if (pIncite_Dlg) {
1515 return;
1518 /* Should be set before sending request to the server. */
1519 fc_assert(is_more_user_input_needed);
1521 if (!actor || !unit_can_do_action(actor, ACTION_SPY_INCITE_CITY)) {
1522 act_sel_done_secondary(actor ? actor->id : IDENTITY_NUMBER_ZERO);
1523 return;
1526 is_unit_move_blocked = TRUE;
1528 pIncite_Dlg = fc_calloc(1, sizeof(struct small_diplomat_dialog));
1529 pIncite_Dlg->actor_unit_id = actor->id;
1530 pIncite_Dlg->target_id = pCity->id;
1531 pIncite_Dlg->pdialog = fc_calloc(1, sizeof(struct SMALL_DLG));
1533 fc_snprintf(tBuf, ARRAY_SIZE(tBuf), PL_("Treasury contains %d gold.",
1534 "Treasury contains %d gold.",
1535 client_player()->economic.gold),
1536 client_player()->economic.gold);
1538 /* window */
1539 pStr = create_str16_from_char(_("Incite a Revolt!"), adj_font(12));
1541 pStr->style |= TTF_STYLE_BOLD;
1543 pWindow = create_window_skeleton(NULL, pStr, 0);
1545 pWindow->action = incite_dlg_window_callback;
1546 set_wstate(pWindow, FC_WS_NORMAL);
1548 add_to_gui_list(ID_INCITE_DLG_WINDOW, pWindow);
1549 pIncite_Dlg->pdialog->pEndWidgetList = pWindow;
1551 area = pWindow->area;
1552 area.w =MAX(area.w, adj_size(8));
1553 area.h = MAX(area.h, adj_size(2));
1555 if (INCITE_IMPOSSIBLE_COST == cost) {
1557 /* exit button */
1558 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
1559 WF_WIDGET_HAS_INFO_LABEL
1560 | WF_RESTORE_BACKGROUND);
1561 pBuf->info_label = create_str16_from_char(_("Close Dialog (Esc)"),
1562 adj_font(12));
1563 area.w += pBuf->size.w + adj_size(10);
1564 pBuf->action = exit_incite_dlg_callback;
1565 set_wstate(pBuf, FC_WS_NORMAL);
1566 pBuf->key = SDLK_ESCAPE;
1568 add_to_gui_list(ID_INCITE_DLG_EXIT_BUTTON, pBuf);
1569 exit = TRUE;
1570 /* --------------- */
1572 fc_snprintf(cBuf, sizeof(cBuf), _("You can't incite a revolt in %s."),
1573 city_name_get(pCity));
1575 create_active_iconlabel(pBuf, pWindow->dst, pStr, cBuf, NULL);
1577 add_to_gui_list(ID_LABEL , pBuf);
1579 area.w = MAX(area.w , pBuf->size.w);
1580 area.h += pBuf->size.h;
1581 /*------------*/
1582 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1583 _("City can't be incited!"), NULL);
1585 add_to_gui_list(ID_LABEL , pBuf);
1587 area.w = MAX(area.w , pBuf->size.w);
1588 area.h += pBuf->size.h;
1590 } else if (cost <= client_player()->economic.gold) {
1591 fc_snprintf(cBuf, sizeof(cBuf),
1592 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1593 PL_("Incite a revolt for %d gold?\n%s",
1594 "Incite a revolt for %d gold?\n%s", cost), cost, tBuf);
1596 create_active_iconlabel(pBuf, pWindow->dst, pStr, cBuf, NULL);
1599 add_to_gui_list(ID_LABEL , pBuf);
1601 area.w = MAX(area.w, pBuf->size.w);
1602 area.h += pBuf->size.h;
1604 /*------------*/
1605 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1606 _("Yes") , diplomat_incite_yes_callback);
1608 pBuf->data.city = pCity;
1609 set_wstate(pBuf, FC_WS_NORMAL);
1611 add_to_gui_list(MAX_ID - actor->id, pBuf);
1613 area.w = MAX(area.w, pBuf->size.w);
1614 area.h += pBuf->size.h;
1615 /* ------- */
1616 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1617 _("No") , exit_incite_dlg_callback);
1619 set_wstate(pBuf, FC_WS_NORMAL);
1620 pBuf->key = SDLK_ESCAPE;
1622 add_to_gui_list(ID_LABEL, pBuf);
1624 area.w = MAX(area.w, pBuf->size.w);
1625 area.h += pBuf->size.h;
1627 } else {
1628 /* exit button */
1629 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
1630 WF_WIDGET_HAS_INFO_LABEL
1631 | WF_RESTORE_BACKGROUND);
1632 pBuf->info_label = create_str16_from_char(_("Close Dialog (Esc)"),
1633 adj_font(12));
1634 area.w += pBuf->size.w + adj_size(10);
1635 pBuf->action = exit_incite_dlg_callback;
1636 set_wstate(pBuf, FC_WS_NORMAL);
1637 pBuf->key = SDLK_ESCAPE;
1639 add_to_gui_list(ID_INCITE_DLG_EXIT_BUTTON, pBuf);
1640 exit = TRUE;
1641 /* --------------- */
1643 fc_snprintf(cBuf, sizeof(cBuf),
1644 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1645 PL_("Inciting a revolt costs %d gold.\n%s",
1646 "Inciting a revolt costs %d gold.\n%s", cost), cost, tBuf);
1648 create_active_iconlabel(pBuf, pWindow->dst, pStr, cBuf, NULL);
1651 add_to_gui_list(ID_LABEL, pBuf);
1653 area.w = MAX(area.w, pBuf->size.w);
1654 area.h += pBuf->size.h;
1656 /*------------*/
1657 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1658 _("Traitors Demand Too Much!"), NULL);
1660 add_to_gui_list(ID_LABEL , pBuf);
1662 area.w = MAX(area.w, pBuf->size.w);
1663 area.h += pBuf->size.h;
1665 pIncite_Dlg->pdialog->pBeginWidgetList = pBuf;
1667 /* setup window size and start position */
1669 resize_window(pWindow, NULL, NULL,
1670 (pWindow->size.w - pWindow->area.w) + area.w,
1671 (pWindow->size.h - pWindow->area.h) + area.h);
1673 area = pWindow->area;
1675 auto_center_on_focus_unit();
1676 put_window_near_map_tile(pWindow, pWindow->size.w, pWindow->size.h,
1677 pCity->tile);
1679 /* setup widget size and start position */
1680 pBuf = pWindow;
1682 if (exit)
1683 {/* exit button */
1684 pBuf = pBuf->prev;
1685 pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
1686 pBuf->size.y = pWindow->size.y + adj_size(2);
1689 pBuf = pBuf->prev;
1690 setup_vertical_widgets_position(1,
1691 area.x,
1692 area.y + 1, area.w, 0,
1693 pIncite_Dlg->pdialog->pBeginWidgetList, pBuf);
1695 /* --------------------- */
1696 /* redraw */
1697 redraw_group(pIncite_Dlg->pdialog->pBeginWidgetList, pWindow, 0);
1699 widget_flush(pWindow);
1703 /* ====================================================================== */
1704 /* ============================ BRIBE DIALOG ========================== */
1705 /* ====================================================================== */
1706 static struct small_diplomat_dialog *pBribe_Dlg = NULL;
1708 /**************************************************************************
1709 User interacted with bribe dialog window.
1710 **************************************************************************/
1711 static int bribe_dlg_window_callback(struct widget *pWindow)
1713 if (Main.event.button.button == SDL_BUTTON_LEFT) {
1714 move_window_group(pBribe_Dlg->pdialog->pBeginWidgetList, pWindow);
1716 return -1;
1719 /**************************************************************************
1720 User confirmed bribe.
1721 **************************************************************************/
1722 static int diplomat_bribe_yes_callback(struct widget *pWidget)
1724 if (Main.event.button.button == SDL_BUTTON_LEFT) {
1725 if (NULL != game_unit_by_number(pBribe_Dlg->actor_unit_id)
1726 && NULL != game_unit_by_number(pBribe_Dlg->target_id)) {
1727 request_do_action(ACTION_SPY_BRIBE_UNIT, pBribe_Dlg->actor_unit_id,
1728 pBribe_Dlg->target_id, 0);
1730 popdown_bribe_dialog();
1733 return -1;
1736 /**************************************************************************
1737 Close bribe dialog.
1738 **************************************************************************/
1739 static int exit_bribe_dlg_callback(struct widget *pWidget)
1741 if (Main.event.button.button == SDL_BUTTON_LEFT) {
1742 popdown_bribe_dialog();
1744 return -1;
1747 /**************************************************************************
1748 Popdown a dialog asking a diplomatic unit if it wishes to bribe the
1749 given enemy unit.
1750 **************************************************************************/
1751 void popdown_bribe_dialog(void)
1753 if (pBribe_Dlg) {
1754 act_sel_done_secondary(pBribe_Dlg->actor_unit_id);
1756 is_unit_move_blocked = FALSE;
1757 popdown_window_group_dialog(pBribe_Dlg->pdialog->pBeginWidgetList,
1758 pBribe_Dlg->pdialog->pEndWidgetList);
1759 FC_FREE(pBribe_Dlg->pdialog);
1760 FC_FREE(pBribe_Dlg);
1761 flush_dirty();
1765 /**************************************************************************
1766 Popup a dialog asking a diplomatic unit if it wishes to bribe the
1767 given enemy unit.
1768 **************************************************************************/
1769 void popup_bribe_dialog(struct unit *actor, struct unit *pUnit, int cost)
1771 struct widget *pWindow = NULL, *pBuf = NULL;
1772 SDL_String16 *pStr;
1773 char tBuf[255], cBuf[255];
1774 bool exit = FALSE;
1775 SDL_Rect area;
1777 if (pBribe_Dlg) {
1778 return;
1781 /* Should be set before sending request to the server. */
1782 fc_assert(is_more_user_input_needed);
1784 if (!actor || !unit_can_do_action(actor, ACTION_SPY_BRIBE_UNIT)) {
1785 act_sel_done_secondary(actor ? actor->id : IDENTITY_NUMBER_ZERO);
1786 return;
1789 is_unit_move_blocked = TRUE;
1791 pBribe_Dlg = fc_calloc(1, sizeof(struct small_diplomat_dialog));
1792 pBribe_Dlg->actor_unit_id = actor->id;
1793 pBribe_Dlg->target_id = pUnit->id;
1794 pBribe_Dlg->pdialog = fc_calloc(1, sizeof(struct SMALL_DLG));
1796 fc_snprintf(tBuf, ARRAY_SIZE(tBuf), PL_("Treasury contains %d gold.",
1797 "Treasury contains %d gold.",
1798 client_player()->economic.gold),
1799 client_player()->economic.gold);
1801 /* window */
1802 pStr = create_str16_from_char(_("Bribe Enemy Unit"), adj_font(12));
1804 pStr->style |= TTF_STYLE_BOLD;
1806 pWindow = create_window_skeleton(NULL, pStr, 0);
1808 pWindow->action = bribe_dlg_window_callback;
1809 set_wstate(pWindow, FC_WS_NORMAL);
1811 add_to_gui_list(ID_BRIBE_DLG_WINDOW, pWindow);
1812 pBribe_Dlg->pdialog->pEndWidgetList = pWindow;
1814 area = pWindow->area;
1815 area.w = MAX(area.w, adj_size(8));
1816 area.h = MAX(area.h, adj_size(2));
1818 if (cost <= client_player()->economic.gold) {
1819 fc_snprintf(cBuf, sizeof(cBuf),
1820 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1821 PL_("Bribe unit for %d gold?\n%s",
1822 "Bribe unit for %d gold?\n%s", cost), cost, tBuf);
1824 create_active_iconlabel(pBuf, pWindow->dst, pStr, cBuf, NULL);
1826 add_to_gui_list(ID_LABEL, pBuf);
1828 area.w = MAX(area.w, pBuf->size.w);
1829 area.h += pBuf->size.h;
1831 /*------------*/
1832 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1833 _("Yes"), diplomat_bribe_yes_callback);
1834 pBuf->data.unit = pUnit;
1835 set_wstate(pBuf, FC_WS_NORMAL);
1837 add_to_gui_list(MAX_ID - actor->id, pBuf);
1839 area.w = MAX(area.w, pBuf->size.w);
1840 area.h += pBuf->size.h;
1841 /* ------- */
1842 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1843 _("No") , exit_bribe_dlg_callback);
1845 set_wstate(pBuf , FC_WS_NORMAL);
1846 pBuf->key = SDLK_ESCAPE;
1848 add_to_gui_list(ID_LABEL, pBuf);
1850 area.w = MAX(area.w, pBuf->size.w);
1851 area.h += pBuf->size.h;
1853 } else {
1854 /* exit button */
1855 pBuf = create_themeicon(current_theme->Small_CANCEL_Icon, pWindow->dst,
1856 WF_WIDGET_HAS_INFO_LABEL
1857 | WF_RESTORE_BACKGROUND);
1858 pBuf->info_label = create_str16_from_char(_("Close Dialog (Esc)"),
1859 adj_font(12));
1860 area.w += pBuf->size.w + adj_size(10);
1861 pBuf->action = exit_bribe_dlg_callback;
1862 set_wstate(pBuf, FC_WS_NORMAL);
1863 pBuf->key = SDLK_ESCAPE;
1865 add_to_gui_list(ID_BRIBE_DLG_EXIT_BUTTON, pBuf);
1866 exit = TRUE;
1867 /* --------------- */
1869 fc_snprintf(cBuf, sizeof(cBuf),
1870 /* TRANS: %s is pre-pluralised "Treasury contains %d gold." */
1871 PL_("Bribing the unit costs %d gold.\n%s",
1872 "Bribing the unit costs %d gold.\n%s", cost), cost, tBuf);
1874 create_active_iconlabel(pBuf, pWindow->dst, pStr, cBuf, NULL);
1876 add_to_gui_list(ID_LABEL, pBuf);
1878 area.w = MAX(area.w, pBuf->size.w);
1879 area.h += pBuf->size.h;
1881 /*------------*/
1882 create_active_iconlabel(pBuf, pWindow->dst, pStr,
1883 _("Traitors Demand Too Much!"), NULL);
1885 add_to_gui_list(ID_LABEL, pBuf);
1887 area.w = MAX(area.w, pBuf->size.w);
1888 area.h += pBuf->size.h;
1890 pBribe_Dlg->pdialog->pBeginWidgetList = pBuf;
1892 /* setup window size and start position */
1894 resize_window(pWindow, NULL, NULL,
1895 (pWindow->size.w - pWindow->area.w) + area.w,
1896 (pWindow->size.h - pWindow->area.h) + area.h);
1898 area = pWindow->area;
1900 auto_center_on_focus_unit();
1901 put_window_near_map_tile(pWindow, pWindow->size.w, pWindow->size.h,
1902 unit_tile(actor));
1904 /* setup widget size and start position */
1905 pBuf = pWindow;
1907 if (exit)
1908 {/* exit button */
1909 pBuf = pBuf->prev;
1910 pBuf->size.x = area.x + area.w - pBuf->size.w - 1;
1911 pBuf->size.y = pWindow->size.y + adj_size(2);
1914 pBuf = pBuf->prev;
1915 setup_vertical_widgets_position(1,
1916 area.x,
1917 area.y + 1, area.w, 0,
1918 pBribe_Dlg->pdialog->pBeginWidgetList, pBuf);
1920 /* --------------------- */
1921 /* redraw */
1922 redraw_group(pBribe_Dlg->pdialog->pBeginWidgetList, pWindow, 0);
1924 widget_flush(pWindow);