1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
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)
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 ***********************************************************************/
15 #include <fc_config.h>
20 #include <QHeaderView>
22 #include <QMessageBox>
23 #include <QRadioButton>
25 #include <QTableWidgetItem>
35 #include "government.h"
36 #include "improvement.h"
51 #include "hudwidget.h"
52 #include "qtg_cxxside.h"
55 /* Locations for non action enabler controlled buttons. */
56 #define BUTTON_MOVE ACTION_COUNT
57 #define BUTTON_WAIT BUTTON_MOVE + 1
58 #define BUTTON_CANCEL BUTTON_MOVE + 2
59 #define BUTTON_COUNT BUTTON_MOVE + 3
61 extern void popdown_all_spaceships_dialogs();
62 extern void popdown_players_report();
63 extern void popdown_economy_report();
64 extern void popdown_units_report();
65 extern void popdown_science_report();
66 extern void popdown_city_report();
67 extern void popdown_endgame_report();
69 static void act_sel_keep_moving(QVariant data1
, QVariant data2
);
70 static void diplomat_incite(QVariant data1
, QVariant data2
);
71 static void spy_request_sabotage_list(QVariant data1
, QVariant data2
);
72 static void spy_sabotage(QVariant data1
, QVariant data2
);
73 static void spy_steal(QVariant data1
, QVariant data2
);
74 static void spy_steal_something(QVariant data1
, QVariant data2
);
75 static void diplomat_steal(QVariant data1
, QVariant data2
);
76 static void spy_poison(QVariant data1
, QVariant data2
);
77 static void spy_steal_gold(QVariant data1
, QVariant data2
);
78 static void diplomat_embassy(QVariant data1
, QVariant data2
);
79 static void spy_sabotage_unit(QVariant data1
, QVariant data2
);
80 static void diplomat_investigate(QVariant data1
, QVariant data2
);
81 static void diplomat_sabotage(QVariant data1
, QVariant data2
);
82 static void diplomat_bribe(QVariant data1
, QVariant data2
);
83 static void caravan_marketplace(QVariant data1
, QVariant data2
);
84 static void caravan_establish_trade(QVariant data1
, QVariant data2
);
85 static void caravan_help_build(QVariant data1
, QVariant data2
);
86 static void keep_moving(QVariant data1
, QVariant data2
);
87 static void pillage_something(QVariant data1
, QVariant data2
);
88 static void action_entry(choice_dialog
*cd
,
90 const struct act_prob
*act_probs
,
92 QVariant data1
, QVariant data2
);
95 static bool is_showing_pillage_dialog
= false;
96 static races_dialog
* race_dialog
;
97 static bool is_race_dialog_open
= false;
99 /* Information used in action selection follow up questions. Can't be
100 * stored in the action selection dialog since it is closed before the
101 * follow up question is asked. */
102 static bool is_more_user_input_needed
= FALSE
;
104 /* Don't remove a unit's action decision want or move on to the next actor
105 unit that wants a decision in the current unit selection. */
106 static bool did_not_decide
= false;
108 qdef_act
* qdef_act::m_instance
= 0;
110 /**********************************************************************
111 Initialize a mapping between an action and the function to call if
112 the action's button is pushed.
113 **********************************************************************/
114 static const QHash
<enum gen_action
, pfcn_void
> af_map_init(void)
116 QHash
<enum gen_action
, pfcn_void
> action_function
;
118 /* Unit acting against a city target. */
119 action_function
[ACTION_ESTABLISH_EMBASSY
] = diplomat_embassy
;
120 action_function
[ACTION_SPY_INVESTIGATE_CITY
] = diplomat_investigate
;
121 action_function
[ACTION_SPY_POISON
] = spy_poison
;
122 action_function
[ACTION_SPY_STEAL_GOLD
] = spy_steal_gold
;
123 action_function
[ACTION_SPY_SABOTAGE_CITY
] = diplomat_sabotage
;
124 action_function
[ACTION_SPY_TARGETED_SABOTAGE_CITY
] =
125 spy_request_sabotage_list
;
126 action_function
[ACTION_SPY_STEAL_TECH
] = diplomat_steal
;
127 action_function
[ACTION_SPY_TARGETED_STEAL_TECH
] = spy_steal
;
128 action_function
[ACTION_SPY_INCITE_CITY
] = diplomat_incite
;
129 action_function
[ACTION_TRADE_ROUTE
] = caravan_establish_trade
;
130 action_function
[ACTION_MARKETPLACE
] = caravan_marketplace
;
131 action_function
[ACTION_HELP_WONDER
] = caravan_help_build
;
133 /* Unit acting against a unit target. */
134 action_function
[ACTION_SPY_BRIBE_UNIT
] = diplomat_bribe
;
135 action_function
[ACTION_SPY_SABOTAGE_UNIT
] = spy_sabotage_unit
;
137 return action_function
;
140 /* Mapping from an action to the function to call when its button is
142 static const QHash
<enum gen_action
, pfcn_void
> af_map
= af_map_init();
144 /***************************************************************************
145 Constructor for selecting nations
146 ***************************************************************************/
147 races_dialog::races_dialog(struct player
*pplayer
,
148 QWidget
*parent
) : QDialog(parent
)
151 QGridLayout
*qgroupbox_layout
;
153 QTableWidgetItem
*item
;
160 setAttribute(Qt::WA_DeleteOnClose
);
161 is_race_dialog_open
= true;
162 main_layout
= new QGridLayout
;
163 selected_nation_tabs
= new QTableWidget
;
164 nation_tabs
= new QTableWidget();
165 styles
= new QTableWidget
;
166 ok_button
= new QPushButton
;
167 qnation_set
= new QComboBox
;
168 ns_label
= new QLabel
;
171 selected_nation
= -1;
174 setWindowTitle(_("Select Nation"));
175 selected_nation_tabs
->setRowCount(0);
176 selected_nation_tabs
->setColumnCount(1);
177 selected_nation_tabs
->setSelectionMode(QAbstractItemView::SingleSelection
);
178 selected_nation_tabs
->verticalHeader()->setVisible(false);
179 selected_nation_tabs
->horizontalHeader()->setVisible(false);
180 selected_nation_tabs
->setProperty("showGrid", "true");
181 selected_nation_tabs
->setEditTriggers(QAbstractItemView::NoEditTriggers
);
182 selected_nation_tabs
->setShowGrid(false);
183 selected_nation_tabs
->setAlternatingRowColors(true);
185 nation_tabs
->setRowCount(0);
186 nation_tabs
->setColumnCount(1);
187 nation_tabs
->setSelectionMode(QAbstractItemView::SingleSelection
);
188 nation_tabs
->verticalHeader()->setVisible(false);
189 nation_tabs
->horizontalHeader()->setVisible(false);
190 nation_tabs
->setProperty("showGrid", "true");
191 nation_tabs
->setEditTriggers(QAbstractItemView::NoEditTriggers
);
192 nation_tabs
->setShowGrid(false);
193 ns_label
->setText(_("Nation Set:"));
194 styles
->setRowCount(0);
195 styles
->setColumnCount(2);
196 styles
->setSelectionMode(QAbstractItemView::SingleSelection
);
197 styles
->verticalHeader()->setVisible(false);
198 styles
->horizontalHeader()->setVisible(false);
199 styles
->setProperty("showGrid", "false");
200 styles
->setProperty("selectionBehavior", "SelectRows");
201 styles
->setEditTriggers(QAbstractItemView::NoEditTriggers
);
202 styles
->setShowGrid(false);
204 qgroupbox_layout
= new QGridLayout
;
205 no_name
= new QGroupBox(parent
);
206 leader_name
= new QComboBox(no_name
);
207 is_male
= new QRadioButton(no_name
);
208 is_female
= new QRadioButton(no_name
);
210 leader_name
->setEditable(true);
211 qgroupbox_layout
->addWidget(leader_name
, 1, 0, 1, 2);
212 qgroupbox_layout
->addWidget(is_male
, 2, 1);
213 qgroupbox_layout
->addWidget(is_female
, 2, 0);
214 is_female
->setText(_("Female"));
215 is_male
->setText(_("Male"));
216 no_name
->setLayout(qgroupbox_layout
);
218 description
= new QTextEdit
;
219 description
->setReadOnly(true);
220 description
->setText(_("Choose nation"));
221 no_name
->setTitle(_("Your leader name"));
224 * Fill styles, no need to update them later
227 styles_iterate(pstyle
) {
228 i
= basic_city_style_for_style(pstyle
);
231 item
= new QTableWidgetItem
;
232 styles
->insertRow(i
);
233 pix
= get_sample_city_sprite(tileset
, i
)->pm
;
234 item
->setData(Qt::DecorationRole
, *pix
);
235 item
->setData(Qt::UserRole
, style_number(pstyle
));
236 size
.setWidth(pix
->width());
237 size
.setHeight(pix
->height());
238 item
->setSizeHint(size
);
239 styles
->setItem(i
, 0, item
);
240 item
= new QTableWidgetItem
;
241 item
->setText(style_name_translation(pstyle
));
242 styles
->setItem(i
, 1, item
);
244 } styles_iterate_end
;
246 header
= styles
->horizontalHeader();
247 header
->setSectionResizeMode(QHeaderView::Stretch
);
248 header
->resizeSections(QHeaderView::ResizeToContents
);
249 header
= styles
->verticalHeader();
250 header
->resizeSections(QHeaderView::ResizeToContents
);
251 nation_sets_iterate(pset
) {
252 qnation_set
->addItem(nation_set_name_translation(pset
),
253 nation_set_rule_name(pset
));
254 } nation_sets_iterate_end
;
255 /* create nation sets */
258 connect(styles
->selectionModel(),
259 SIGNAL(selectionChanged(const QItemSelection
&,
260 const QItemSelection
&)),
261 SLOT(style_selected(const QItemSelection
&,
262 const QItemSelection
&)));
263 connect(selected_nation_tabs
->selectionModel(),
264 SIGNAL(selectionChanged(const QItemSelection
&,
265 const QItemSelection
&)),
266 SLOT(nation_selected(const QItemSelection
&,
267 const QItemSelection
&)));
268 connect(leader_name
, SIGNAL(currentIndexChanged(int)),
269 SLOT(leader_selected(int)));
270 connect(leader_name
->lineEdit(), SIGNAL(returnPressed()),
272 connect(qnation_set
, SIGNAL(currentIndexChanged(int)),
273 SLOT(nationset_changed(int)));
274 connect(nation_tabs
->selectionModel(),
275 SIGNAL(selectionChanged(const QItemSelection
&,
276 const QItemSelection
&)),
277 SLOT(group_selected(const QItemSelection
&,
278 const QItemSelection
&)));
280 ok_button
= new QPushButton
;
281 ok_button
->setText(_("Cancel"));
282 connect(ok_button
, SIGNAL(pressed()), SLOT(cancel_pressed()));
283 main_layout
->addWidget(ok_button
, 8, 2, 1, 1);
284 random_button
= new QPushButton
;
285 random_button
->setText(_("Random"));
286 connect(random_button
, SIGNAL(pressed()), SLOT(random_pressed()));
287 main_layout
->addWidget(random_button
, 8, 0, 1, 1);
288 ok_button
= new QPushButton
;
289 ok_button
->setText(_("Ok"));
290 connect(ok_button
, SIGNAL(pressed()), SLOT(ok_pressed()));
291 main_layout
->addWidget(ok_button
, 8, 3, 1, 1);
292 main_layout
->addWidget(no_name
, 0, 3, 2, 1);
293 if (nation_set_count() > 1) {
294 main_layout
->addWidget(ns_label
, 0, 0, 1, 1);
295 main_layout
->addWidget(qnation_set
, 0, 1, 1, 1);
296 main_layout
->addWidget(nation_tabs
, 1, 0, 5, 2);
298 main_layout
->addWidget(nation_tabs
, 0, 0, 6, 2);
300 main_layout
->addWidget(styles
, 2, 3, 4, 1);
301 main_layout
->addWidget(description
, 6, 0, 2, 4);
302 main_layout
->addWidget(selected_nation_tabs
, 0, 2, 6, 1);
304 setLayout(main_layout
);
307 if (C_S_RUNNING
== client_state()) {
308 title
= _("Edit Nation");
309 } else if (NULL
!= pplayer
&& pplayer
== client
.conn
.playing
) {
310 title
= _("What Nation Will You Be?");
312 title
= _("Pick Nation");
315 update_nationset_combo();
316 setWindowTitle(title
);
319 /***************************************************************************
320 Destructor for races dialog
321 ***************************************************************************/
322 races_dialog::~races_dialog()
324 ::is_race_dialog_open
= false;
327 /***************************************************************************
328 Sets first index to call update of nation list
329 ***************************************************************************/
330 void races_dialog::refresh()
332 struct nation_group
*group
;
333 QTableWidgetItem
*item
;
338 nation_tabs
->clearContents();
339 nation_tabs
->setRowCount(0);
340 nation_tabs
->insertRow(0);
341 item
= new QTableWidgetItem
;
342 item
->setText(_("All nations"));
343 item
->setData(Qt::UserRole
, -99);
344 nation_tabs
->setItem(0, 0, item
);
346 for (i
= 1; i
< nation_group_count() + 1; i
++) {
347 group
= nation_group_by_number(i
- 1);
348 if (is_nation_group_hidden(group
)) {
352 /* checking if group is empty */
353 nations_iterate(pnation
) {
354 if (!is_nation_playable(pnation
)
355 || !is_nation_pickable(pnation
)
356 || !nation_is_in_group(pnation
, group
)) {
360 } nations_iterate_end
;
364 nation_tabs
->insertRow(i
);
365 item
= new QTableWidgetItem
;
366 item
->setData(Qt::UserRole
, i
- 1);
367 item
->setText(nation_group_name_translation(group
));
368 nation_tabs
->setItem(i
, 0, item
);
370 header
= nation_tabs
->horizontalHeader();
371 header
->resizeSections(QHeaderView::Stretch
);
372 header
= nation_tabs
->verticalHeader();
373 header
->resizeSections(QHeaderView::ResizeToContents
);
377 /***************************************************************************
378 Updates nation_set combo ( usually called from option change )
379 ***************************************************************************/
380 void races_dialog::update_nationset_combo()
383 struct nation_set
*s
;
385 popt
= optset_option_by_name(server_optset
, "nationset");
387 s
= nation_set_by_setting_value(option_str_get(popt
));
388 qnation_set
->setCurrentIndex(nation_set_index(s
));
389 qnation_set
->setToolTip(nation_set_description(s
));
393 /***************************************************************************
394 Selected group of nation
395 ***************************************************************************/
396 void races_dialog::group_selected(const QItemSelection
&sl
,
397 const QItemSelection
&ds
)
399 QModelIndexList indexes
= sl
.indexes();
402 if (indexes
.isEmpty()) {
405 index
= indexes
.at(0);
406 set_index(index
.row());
410 /***************************************************************************
411 Sets new nations' group by current current selection,
412 index is used only when there is no current selection.
413 ***************************************************************************/
414 void races_dialog::set_index(int index
)
416 QTableWidgetItem
*item
;
419 struct nation_group
*group
;
423 selected_nation_tabs
->clearContents();
424 selected_nation_tabs
->setRowCount(0);
427 i
= nation_tabs
->currentRow();
429 item
= nation_tabs
->item(i
, 0);
430 index
= item
->data(Qt::UserRole
).toInt();
433 group
= nation_group_by_number(index
);
435 nations_iterate(pnation
) {
436 if (!is_nation_playable(pnation
)
437 || !is_nation_pickable(pnation
)) {
440 if (!nation_is_in_group(pnation
, group
) && index
!= -99) {
443 item
= new QTableWidgetItem
;
444 selected_nation_tabs
->insertRow(i
);
445 s
= get_nation_flag_sprite(tileset
, pnation
);
446 if (pnation
->player
) {
448 f
.setStrikeOut(true);
452 item
->setData(Qt::DecorationRole
, *pix
);
453 item
->setData(Qt::UserRole
, nation_number(pnation
));
454 item
->setText(nation_adjective_translation(pnation
));
455 selected_nation_tabs
->setItem(i
, 0, item
);
456 } nations_iterate_end
;
458 selected_nation_tabs
->sortByColumn(0, Qt::AscendingOrder
);
459 header
= selected_nation_tabs
->horizontalHeader();
460 header
->resizeSections(QHeaderView::Stretch
);
461 header
= selected_nation_tabs
->verticalHeader();
462 header
->resizeSections(QHeaderView::ResizeToContents
);
465 /***************************************************************************
466 Sets selected nation and updates style and leaders selector
467 ***************************************************************************/
468 void races_dialog::nation_selected(const QItemSelection
&selected
,
469 const QItemSelection
&deselcted
)
474 QModelIndexList indexes
= selected
.indexes();
476 QTableWidgetItem
*item
;
479 if (indexes
.isEmpty()) {
483 index
= indexes
.at(0);
484 if (indexes
.isEmpty()){
487 qvar
= index
.data(Qt::UserRole
);
488 selected_nation
= qvar
.toInt();
490 helptext_nation(buf
, sizeof(buf
), nation_by_number(selected_nation
), NULL
);
491 description
->setText(buf
);
492 leader_name
->clear();
493 if (client
.conn
.playing
== tplayer
) {
494 leader_name
->addItem(client
.conn
.playing
->name
, true);
496 nation_leader_list_iterate(nation_leaders(nation_by_number
497 (selected_nation
)), pleader
) {
498 str
= QString::fromUtf8(nation_leader_name(pleader
));
499 leader_name
->addItem(str
, nation_leader_is_male(pleader
));
500 } nation_leader_list_iterate_end
;
503 * select style for nation
506 style
= style_number(style_of_nation(nation_by_number(selected_nation
)));
507 qvar
= qvar
.fromValue
<int>(style
);
508 item
= new QTableWidgetItem
;
510 for (ind
= 0; ind
< styles
->rowCount(); ind
++) {
511 item
= styles
->item(ind
, 0);
513 if (item
->data(Qt::UserRole
) == qvar
) {
514 styles
->selectRow(ind
);
519 /***************************************************************************
521 ***************************************************************************/
522 void races_dialog::style_selected(const QItemSelection
&selected
,
523 const QItemSelection
&deselcted
)
527 QModelIndexList indexes
= selected
.indexes();
529 if (indexes
.isEmpty()) {
533 index
= indexes
.at(0);
534 qvar
= index
.data(Qt::UserRole
);
535 selected_style
= qvar
.toInt();
538 /***************************************************************************
540 ***************************************************************************/
541 void races_dialog::leader_selected(int index
)
543 if (leader_name
->itemData(index
).toBool()) {
544 is_male
->setChecked(true);
545 is_female
->setChecked(false);
548 is_male
->setChecked(false);
549 is_female
->setChecked(true);
554 /***************************************************************************
555 Button accepting all selection has been pressed, closes dialog if
557 ***************************************************************************/
558 void races_dialog::ok_pressed()
561 if (selected_nation
== -1) {
565 if (selected_sex
== -1) {
566 output_window_append(ftc_client
, _("You must select your sex."));
570 if (selected_style
== -1) {
571 output_window_append(ftc_client
, _("You must select your style."));
575 if (leader_name
->currentText().length() == 0) {
576 output_window_append(ftc_client
, _("You must type a legal name."));
580 if (nation_by_number(selected_nation
)->player
!= NULL
) {
581 output_window_append(ftc_client
,
582 _("Nation has been chosen by other player"));
585 dsend_packet_nation_select_req(&client
.conn
, player_number(tplayer
),
586 selected_nation
, selected_sex
,
587 leader_name
->currentText().toUtf8().data(),
593 /***************************************************************************
594 Constructor for notify dialog
595 ***************************************************************************/
596 notify_dialog::notify_dialog(const char *caption
, const char *headline
,
597 const char *lines
, QWidget
*parent
)
603 setAttribute(Qt::WA_DeleteOnClose
);
604 setCursor(Qt::ArrowCursor
);
606 setFrameStyle(QFrame::Box
);
607 cw
= new close_widget(this);
610 qcaption
= QString(caption
);
611 qheadline
= QString(headline
);
612 qlines
= QString(lines
);
613 qlist
= qlines
.split("\n");
614 small_font
= *fc_font::instance()->get_font("gui_qt_font_notify_label");
619 gui()->mapview_wdg
->find_place(gui()->mapview_wdg
->width() - x
- 4, 4,
622 was_destroyed
= false;
626 /***************************************************************************
627 Starts new copy of notify dialog and closes current one
628 ***************************************************************************/
629 void notify_dialog::restart()
634 for (i
= 0; i
< qlist
.size(); ++i
) {
637 if (i
< qlist
.size() - 1) {
641 popup_notify_dialog(qcaption
.toLocal8Bit().data(),
642 qheadline
.toLocal8Bit().data(),
643 q
.toLocal8Bit().data());
648 /***************************************************************************
649 Calculates size of notify dialog
650 ***************************************************************************/
651 void notify_dialog::calc_size(int &x
, int &y
)
653 QFontMetrics
fm(small_font
);
655 QStringList str_list
;
658 str_list
<< qcaption
<< qheadline
;
660 for (i
= 0; i
< str_list
.count(); i
++) {
661 x
= qMax(x
, fm
.width(str_list
.at(i
)));
662 y
= y
+ 3 + fm
.height();
668 /***************************************************************************
669 Paint Event for notify dialog
670 ***************************************************************************/
671 void notify_dialog::paintEvent(QPaintEvent
* paint_event
)
673 QPainter
painter(this);
676 QFontMetrics
fm(small_font
);
680 pen
.setColor(palette().color(QPalette::Text
));
681 painter
.setFont(small_font
);
683 painter
.drawText(10, fm
.height() + 3, qcaption
);
684 painter
.drawText(10, 2 * fm
.height() + 6, qheadline
);
685 for (i
= 0; i
< qlist
.count(); i
++) {
686 painter
.drawText(10, 3 + (fm
.height() + 3) * (i
+ 3), qlist
[i
]);
691 /**************************************************************************
692 Called when mouse button was pressed, just to close on right click
693 **************************************************************************/
694 void notify_dialog::mousePressEvent(QMouseEvent
*event
)
696 cursor
= event
->globalPos() - geometry().topLeft();
697 if (event
->button() == Qt::RightButton
){
698 was_destroyed
= true;
703 /**************************************************************************
704 Called when mouse button was pressed and moving around
705 **************************************************************************/
706 void notify_dialog::mouseMoveEvent(QMouseEvent
*event
)
708 move(event
->globalPos() - cursor
);
709 setCursor(Qt::SizeAllCursor
);
712 /**************************************************************************
713 Called when mouse button unpressed. Restores cursor.
714 **************************************************************************/
715 void notify_dialog::mouseReleaseEvent(QMouseEvent
*event
)
717 setCursor(Qt::ArrowCursor
);
720 /***************************************************************************
721 Called when close button was pressed
722 ***************************************************************************/
723 void notify_dialog::update_menu()
725 was_destroyed
= true;
729 /***************************************************************************
730 Destructor for notify dialog, notice that somehow object is not destroyed
731 immediately, so it can be still visible for parent, check boolean
732 was_destroyed if u suspect it could not be destroyed yet
733 ***************************************************************************/
734 notify_dialog::~notify_dialog()
736 was_destroyed
= true;
740 /****************************************************************************
741 Default actions provider constructor
742 ****************************************************************************/
749 /****************************************************************************
750 Returns instance of qdef_act
751 ****************************************************************************/
752 qdef_act
*qdef_act::action()
755 m_instance
= new qdef_act
;
759 /****************************************************************************
760 Deletes qdef_act instance
761 ****************************************************************************/
762 void qdef_act::drop()
770 /****************************************************************************
771 Sets default action vs city
772 ****************************************************************************/
773 void qdef_act::vs_city_set(int i
)
778 /****************************************************************************
779 Sets default action vs unit
780 ****************************************************************************/
781 void qdef_act::vs_unit_set(int i
)
786 /****************************************************************************
787 Returns default action vs city
788 ****************************************************************************/
789 int qdef_act::vs_city_get()
794 /****************************************************************************
795 Returns default action vs unit
796 ****************************************************************************/
797 int qdef_act::vs_unit_get()
802 /***************************************************************************
803 Button canceling all selections has been pressed.
804 ***************************************************************************/
805 void races_dialog::cancel_pressed()
810 /***************************************************************************
812 ***************************************************************************/
813 void races_dialog::random_pressed()
815 dsend_packet_nation_select_req(&client
.conn
,player_number(tplayer
),-1,
820 /***************************************************************************
821 Notify goto dialog constructor
822 ***************************************************************************/
823 notify_goto::notify_goto(const char *headline
, const char *lines
,
824 const struct text_tag_list
*tags
, tile
*ptile
,
825 QWidget
*parent
): QMessageBox(parent
)
828 setAttribute(Qt::WA_DeleteOnClose
);
829 goto_but
= this->addButton(_("Goto Location"), QMessageBox::ActionRole
);
830 goto_but
->setIcon(fc_icons::instance()->get_icon("go-up"));
831 inspect_but
= this->addButton(_("Inspect City"), QMessageBox::ActionRole
);
832 inspect_but
->setIcon(fc_icons::instance()->get_icon("plus"));
834 close_but
= this->addButton(QMessageBox::Close
);
837 goto_but
->setVisible(false);
838 inspect_but
->setVisible(false);
840 struct city
*pcity
= tile_city(gtile
);
841 inspect_but
->setVisible(NULL
!= pcity
842 && city_owner(pcity
) == client
.conn
.playing
);
844 setWindowTitle(headline
);
846 qlines
.replace("\n", " ");
848 connect(goto_but
, SIGNAL(pressed()), SLOT(goto_tile()));
849 connect(inspect_but
, SIGNAL(pressed()), SLOT(inspect_city()));
850 connect(close_but
, SIGNAL(pressed()), SLOT(close()));
854 /***************************************************************************
855 Clicked goto tile in notify goto dialog
856 ***************************************************************************/
857 void notify_goto::goto_tile()
859 center_tile_mapcanvas(gtile
);
863 /***************************************************************************
864 Clicked inspect city in notify goto dialog
865 ***************************************************************************/
866 void notify_goto::inspect_city()
868 struct city
*pcity
= tile_city(gtile
);
870 qtg_real_city_dialog_popup(pcity
);
875 /***************************************************************************
876 User changed nation_set
877 ***************************************************************************/
878 void races_dialog::nationset_changed(int index
)
882 struct option
*poption
= optset_option_by_name(server_optset
, "nationset");
883 rule_name
= qnation_set
->currentData().toString();
884 rn
= rule_name
.toLocal8Bit().data();
885 if (nation_set_by_setting_value(option_str_get(poption
))
886 != nation_set_by_rule_name(rn
)) {
887 option_str_set(poption
, rn
);
891 /**************************************************************************
892 Popup a dialog to display information about an event that has a
893 specific location. The user should be given the option to goto that
895 **************************************************************************/
896 void popup_notify_goto_dialog(const char *headline
, const char *lines
,
897 const struct text_tag_list
*tags
,
900 notify_goto
*ask
= new notify_goto(headline
, lines
, tags
, ptile
,
905 /**************************************************************************
906 Popup a dialog to display connection message from server.
907 **************************************************************************/
908 void popup_connect_msg(const char *headline
, const char *message
)
910 QMessageBox
msg(gui()->central_wdg
);
912 msg
.setText(message
);
913 msg
.setStandardButtons(QMessageBox::Ok
);
914 msg
.setWindowTitle(headline
);
919 /**************************************************************************
920 Popup a generic dialog to display some generic information.
921 **************************************************************************/
922 void popup_notify_dialog(const char *caption
, const char *headline
,
925 notify_dialog
*nd
= new notify_dialog(caption
, headline
, lines
,
930 /**************************************************************************
931 Popup the nation selection dialog.
932 **************************************************************************/
933 void popup_races_dialog(struct player
*pplayer
)
935 if (!is_race_dialog_open
) {
936 race_dialog
= new races_dialog(pplayer
, gui()->central_wdg
);
937 is_race_dialog_open
= true;
940 race_dialog
->showNormal();
943 /**************************************************************************
944 Close the nation selection dialog. This should allow the user to
945 (at least) select a unit to activate.
946 **************************************************************************/
947 void popdown_races_dialog(void)
949 if (is_race_dialog_open
){
950 race_dialog
->close();
951 is_race_dialog_open
= false;
955 /**************************************************************************
956 Popup a dialog window to select units on a particular tile.
957 **************************************************************************/
958 void unit_select_dialog_popup(struct tile
*ptile
)
960 if(ptile
!= NULL
&& (unit_list_size(ptile
->units
) > 1
961 || (unit_list_size(ptile
->units
) == 1 && tile_city(ptile
)))) {
962 gui()->toggle_unit_sel_widget(ptile
);
966 /**************************************************************************
967 Update the dialog window to select units on a particular tile.
968 **************************************************************************/
969 void unit_select_dialog_update_real(void)
971 gui()->update_unit_sel();
974 /**************************************************************************
975 Updates nationset combobox
976 **************************************************************************/
977 void update_nationset_combo()
979 if (is_race_dialog_open
) {
980 race_dialog
->update_nationset_combo();
984 /**************************************************************************
985 The server has changed the set of selectable nations.
986 **************************************************************************/
987 void races_update_pickable(bool nationset_change
)
989 if (is_race_dialog_open
){
990 race_dialog
->refresh();
994 /**************************************************************************
995 In the nation selection dialog, make already-taken nations unavailable.
996 This information is contained in the packet_nations_used packet.
997 **************************************************************************/
998 void races_toggles_set_sensitive(void)
1000 if (is_race_dialog_open
) {
1001 race_dialog
->refresh();
1005 /**************************************************************************
1006 Popup a dialog asking if the player wants to start a revolution.
1007 **************************************************************************/
1008 void popup_revolution_dialog(struct government
*government
)
1010 hud_message_box
ask(gui()->central_wdg
);
1013 if (0 > client
.conn
.playing
->revolution_finishes
) {
1014 ask
.setStandardButtons(QMessageBox::Cancel
| QMessageBox::Ok
);
1015 ask
.setDefaultButton(QMessageBox::Cancel
);
1016 ask
.set_text_title(_("You say you wanna revolution?"),
1021 case QMessageBox::Cancel
:
1023 case QMessageBox::Ok
:
1024 revolution_response(government
);
1028 revolution_response(government
);
1032 /**************************************************************************
1033 Constructor for choice_dialog_button_data
1034 **************************************************************************/
1035 Choice_dialog_button::Choice_dialog_button(const QString title
,
1039 : QPushButton(title
)
1046 /**************************************************************************
1047 Get the function to call when the button is pressed.
1048 **************************************************************************/
1049 pfcn_void
Choice_dialog_button::getFunc()
1054 /**************************************************************************
1055 Get the first piece of data to feed the function when the button is
1057 **************************************************************************/
1058 QVariant
Choice_dialog_button::getData1()
1063 /**************************************************************************
1064 Get the second piece of data to feed the function when the button is
1066 **************************************************************************/
1067 QVariant
Choice_dialog_button::getData2()
1072 /**************************************************************************
1073 Sets the first piece of data
1074 **************************************************************************/
1075 void Choice_dialog_button::setData1(QVariant wariat
)
1080 /**************************************************************************
1081 Sets the second piece of data
1082 **************************************************************************/
1083 void Choice_dialog_button::setData2(QVariant wariat
)
1088 /***************************************************************************
1089 Constructor for choice_dialog
1090 ***************************************************************************/
1091 choice_dialog::choice_dialog(const QString title
, const QString text
,
1093 void (*run_on_close_in
)(int)): QWidget(parent
)
1095 QLabel
*l
= new QLabel(text
);
1097 setProperty("themed_choice", true);
1098 signal_mapper
= new QSignalMapper(this);
1099 layout
= new QVBoxLayout(this);
1100 run_on_close
= run_on_close_in
;
1102 layout
->addWidget(l
);
1103 setWindowFlags(Qt::Dialog
);
1104 setWindowTitle(title
);
1105 setAttribute(Qt::WA_DeleteOnClose
);
1106 gui()->set_diplo_dialog(this);
1108 unit_id
= IDENTITY_NUMBER_ZERO
;
1109 target_id
[ATK_CITY
] = IDENTITY_NUMBER_ZERO
;
1110 target_id
[ATK_UNIT
] = IDENTITY_NUMBER_ZERO
;
1112 targeted_unit
= nullptr;
1113 /* No buttons are added yet. */
1114 for (int i
= 0; i
< BUTTON_COUNT
; i
++) {
1115 action_button_map
<< NULL
;
1119 /***************************************************************************
1120 Destructor for choice dialog
1121 ***************************************************************************/
1122 choice_dialog::~choice_dialog()
1124 buttons_list
.clear();
1125 action_button_map
.clear();
1126 delete signal_mapper
;
1127 gui()->set_diplo_dialog(NULL
);
1130 run_on_close(unit_id
);
1131 run_on_close
= NULL
;
1135 /***************************************************************************
1136 Sets layout for choice dialog
1137 ***************************************************************************/
1138 void choice_dialog::set_layout()
1141 targeted_unit
= game_unit_by_number(target_id
[ATK_UNIT
]);
1143 if ((game_unit_by_number(unit_id
)) && targeted_unit
1144 && unit_list_size(targeted_unit
->tile
->units
) > 1) {
1146 QPushButton
*next
, *prev
;
1147 unit_skip
= new QHBoxLayout
;
1148 next
= new QPushButton();
1149 next
->setIcon(fc_icons::instance()->get_icon("city-right"));
1150 next
->setIconSize(QSize(32, 32));
1151 next
->setFixedSize(QSize(36, 36));
1152 prev
= new QPushButton();
1153 prev
->setIcon(fc_icons::instance()->get_icon("city-left"));
1154 prev
->setIconSize(QSize(32, 32));
1155 prev
->setFixedSize(QSize(36, 36));
1156 target_unit_button
= new QPushButton
;
1157 pix
= qtg_canvas_create(tileset_unit_width(tileset
),
1158 tileset_unit_height(tileset
));
1159 pix
->map_pixmap
.fill(Qt::transparent
);
1160 put_unit(targeted_unit
, pix
, 1.0, 0, 0);
1161 target_unit_button
->setIcon(QIcon(pix
->map_pixmap
));
1162 qtg_canvas_free(pix
);
1163 target_unit_button
->setIconSize(QSize(96, 96));
1164 target_unit_button
->setFixedSize(QSize(100, 100));
1165 unit_skip
->addStretch(100);
1166 unit_skip
->addWidget(prev
, Qt::AlignCenter
);
1167 unit_skip
->addWidget(target_unit_button
, Qt::AlignCenter
);
1168 unit_skip
->addWidget(next
, Qt::AlignCenter
);
1169 layout
->addLayout(unit_skip
);
1170 unit_skip
->addStretch(100);
1171 connect(prev
, SIGNAL(clicked()), SLOT(prev_unit()));
1172 connect(next
, SIGNAL(clicked()), SLOT(next_unit()));
1175 connect(signal_mapper
, SIGNAL(mapped(const int &)),
1176 this, SLOT(execute_action(const int &)));
1180 /***************************************************************************
1181 Adds new action for choice dialog
1182 ***************************************************************************/
1183 void choice_dialog::add_item(QString title
, pfcn_void func
, QVariant data1
,
1184 QVariant data2
, QString tool_tip
= "",
1185 const int button_id
= -1)
1187 Choice_dialog_button
*button
= new Choice_dialog_button(title
, func
,
1189 connect(button
, SIGNAL(clicked()), signal_mapper
, SLOT(map()));
1190 signal_mapper
->setMapping(button
, buttons_list
.count());
1191 buttons_list
.append(button
);
1193 if (!tool_tip
.isEmpty()) {
1194 button
->setToolTip(tool_tip
);
1197 if (0 <= button_id
) {
1198 /* The id is valid. */
1199 action_button_map
[button_id
] = button
;
1202 layout
->addWidget(button
);
1205 /***************************************************************************
1207 ***************************************************************************/
1208 void choice_dialog::show_me()
1212 p
= mapFromGlobal(QCursor::pos());
1213 p
.setY(p
.y()-this->height());
1214 p
.setX(p
.x()-this->width());
1219 /***************************************************************************
1220 Returns layout in choice dialog
1221 ***************************************************************************/
1222 QVBoxLayout
*choice_dialog::get_layout()
1227 /**************************************************************************
1228 Get the button with the given identity.
1229 **************************************************************************/
1230 Choice_dialog_button
*choice_dialog::get_identified_button(const int id
)
1233 fc_assert_msg(0 <= id
, "Invalid button ID.");
1237 return action_button_map
[id
];
1240 /***************************************************************************
1241 Try to pick up default unit action
1242 ***************************************************************************/
1243 bool try_default_unit_action(QVariant q1
, QVariant q2
)
1248 action
= qdef_act::action()->vs_unit_get();
1252 func
= af_map
[static_cast<gen_action
>(action
)];
1258 /***************************************************************************
1259 Try to pick up default city action
1260 ***************************************************************************/
1261 bool try_default_city_action(QVariant q1
, QVariant q2
)
1266 action
= qdef_act::action()->vs_city_get();
1270 func
= af_map
[static_cast<gen_action
>(action
)];
1275 /***************************************************************************
1277 ***************************************************************************/
1278 void choice_dialog::next_unit()
1281 struct unit
*new_target
= nullptr;
1282 bool break_next
= false;
1286 if (targeted_unit
== nullptr) {
1290 ptile
= targeted_unit
->tile
;
1292 unit_list_iterate(ptile
->units
, ptgt
) {
1297 if (break_next
== true) {
1301 if (ptgt
== targeted_unit
) {
1304 } unit_list_iterate_end
;
1305 targeted_unit
= new_target
;
1306 pix
= qtg_canvas_create(tileset_unit_width(tileset
),
1307 tileset_unit_height(tileset
));
1308 pix
->map_pixmap
.fill(Qt::transparent
);
1309 put_unit(targeted_unit
, pix
, 1.0, 0, 0);
1310 target_unit_button
->setIcon(QIcon(pix
->map_pixmap
));
1311 qtg_canvas_free(pix
);
1315 /***************************************************************************
1316 Focus previous target
1317 ***************************************************************************/
1318 void choice_dialog::prev_unit()
1321 struct unit
*new_target
= nullptr;
1323 if (targeted_unit
== nullptr) {
1327 ptile
= targeted_unit
->tile
;
1328 unit_list_iterate(ptile
->units
, ptgt
) {
1329 if ((ptgt
== targeted_unit
) && new_target
!= nullptr) {
1333 } unit_list_iterate_end
;
1334 targeted_unit
= new_target
;
1335 pix
= qtg_canvas_create(tileset_unit_width(tileset
),
1336 tileset_unit_height(tileset
));
1337 pix
->map_pixmap
.fill(Qt::transparent
);
1338 put_unit(targeted_unit
, pix
, 1.0, 0, 0);
1339 target_unit_button
->setIcon(QIcon(pix
->map_pixmap
));
1340 qtg_canvas_free(pix
);
1344 /***************************************************************************
1345 Update dialog for new target (targeted_unit)
1346 ***************************************************************************/
1347 void choice_dialog::update_dialog(const struct act_prob
*act_probs
)
1349 if (targeted_unit
== nullptr) {
1352 unit_skip
->setParent(nullptr);
1353 action_selection_refresh(game_unit_by_number(unit_id
), nullptr,
1354 targeted_unit
, targeted_unit
->tile
, act_probs
);
1355 layout
->addLayout(unit_skip
);
1358 /***************************************************************************
1359 Switches target unit
1360 ***************************************************************************/
1361 void choice_dialog::switch_target()
1363 if (targeted_unit
== nullptr) {
1366 unit_skip
->setParent(nullptr);
1367 dsend_packet_unit_get_actions(&client
.conn
,
1370 IDENTITY_NUMBER_ZERO
,
1371 targeted_unit
->tile
->index
,
1373 layout
->addLayout(unit_skip
);
1377 /***************************************************************************
1378 Run chosen action and close dialog
1379 ***************************************************************************/
1380 void choice_dialog::execute_action(const int action
)
1382 Choice_dialog_button
*button
= buttons_list
.at(action
);
1383 pfcn_void func
= button
->getFunc();
1385 func(button
->getData1(), button
->getData2());
1389 /**************************************************************************
1390 Put the button in the stack and temporarily remove it. When
1391 unstack_all_buttons() is called all buttons in the stack will be added
1392 to the end of the dialog.
1394 Can be used to place a button below existing buttons or below buttons
1395 added while it was in the stack.
1396 **************************************************************************/
1397 void choice_dialog::stack_button(Choice_dialog_button
*button
)
1399 /* Store the data in the stack. */
1400 last_buttons_stack
.append(button
);
1402 /* Temporary remove the button so it will end up below buttons added
1403 * before unstack_all_buttons() is called. */
1404 layout
->removeWidget(button
);
1406 /* The old mappings may not be valid after reinsertion. */
1407 signal_mapper
->removeMappings(button
);
1409 /* Synchronize the list with the layout. */
1410 buttons_list
.removeAll(button
);
1413 /**************************************************************************
1414 Put all the buttons in the stack back to the dialog. They will appear
1415 after any other buttons. See stack_button()
1416 **************************************************************************/
1417 void choice_dialog::unstack_all_buttons()
1419 while (!last_buttons_stack
.isEmpty()) {
1420 Choice_dialog_button
*button
= last_buttons_stack
.takeLast();
1422 /* Restore mapping. */
1423 signal_mapper
->setMapping(button
, buttons_list
.count());
1425 /* Reinsert the button below the other buttons. */
1426 buttons_list
.append(button
);
1427 layout
->addWidget(button
);
1431 /***************************************************************************
1432 Action enter market place for choice dialog
1433 ***************************************************************************/
1434 static void caravan_marketplace(QVariant data1
, QVariant data2
)
1436 int actor_unit_id
= data1
.toInt();
1437 int target_city_id
= data2
.toInt();
1439 if (NULL
!= game_unit_by_number(actor_unit_id
)
1440 && NULL
!= game_city_by_number(target_city_id
)) {
1441 request_do_action(ACTION_MARKETPLACE
, actor_unit_id
,
1446 /***************************************************************************
1447 Action establish trade for choice dialog
1448 ***************************************************************************/
1449 static void caravan_establish_trade(QVariant data1
, QVariant data2
)
1451 int actor_unit_id
= data1
.toInt();
1452 int target_city_id
= data2
.toInt();
1454 if (NULL
!= game_unit_by_number(actor_unit_id
)
1455 && NULL
!= game_city_by_number(target_city_id
)) {
1456 request_do_action(ACTION_TRADE_ROUTE
, actor_unit_id
,
1461 /***************************************************************************
1462 Action help build wonder for choice dialog
1463 ***************************************************************************/
1464 static void caravan_help_build(QVariant data1
, QVariant data2
)
1466 int caravan_id
= data1
.toInt();
1467 int caravan_target_id
= data2
.toInt();
1469 if (NULL
!= game_unit_by_number(caravan_id
)
1470 && NULL
!= game_city_by_number(caravan_target_id
)) {
1471 request_do_action(ACTION_HELP_WONDER
,
1472 caravan_id
, caravan_target_id
, 0);
1476 /***************************************************************************
1477 Delay selection of what action to take.
1478 ***************************************************************************/
1479 static void act_sel_wait(QVariant data1
, QVariant data2
)
1484 /***************************************************************************
1485 Empty action for choice dialog (just do nothing)
1486 ***************************************************************************/
1487 static void keep_moving(QVariant data1
, QVariant data2
)
1490 /***************************************************************************
1491 Starts revolution with targeted government as target or anarchy otherwise
1492 ***************************************************************************/
1493 void revolution_response(struct government
*government
)
1498 set_government_choice(government
);
1502 /**************************************************************************
1503 Move the queue of diplomats that need user input forward unless the
1504 current diplomat will need more input.
1505 **************************************************************************/
1506 static void diplomat_queue_handle_primary(int actor_unit_id
)
1508 if (!is_more_user_input_needed
) {
1509 /* The client isn't waiting for information for any unanswered follow
1512 struct unit
*actor_unit
;
1514 if ((actor_unit
= game_unit_by_number(actor_unit_id
))) {
1515 /* The action selection dialog wasn't closed because the actor unit
1518 /* The probabilities didn't just disappear, right? */
1519 fc_assert_action(actor_unit
->client
.act_prob_cache
,
1520 client_unit_init_act_prob_cache(actor_unit
));
1522 FC_FREE(actor_unit
->client
.act_prob_cache
);
1525 /* The action selection process is over, at least for now. */
1526 action_selection_no_longer_in_progress(actor_unit_id
);
1528 if (did_not_decide
) {
1529 /* The action selection dialog was closed but the player didn't
1530 * decide what the unit should do. */
1532 /* Reset so the next action selection dialog does the right thing. */
1533 did_not_decide
= false;
1535 /* An action, or no action at all, was selected. */
1536 action_decision_clear_want(actor_unit_id
);
1537 action_selection_next_in_focus(actor_unit_id
);
1542 /**************************************************************************
1543 Move the queue of diplomats that need user input forward since the
1544 current diplomat got the extra input that was required.
1545 **************************************************************************/
1546 static void diplomat_queue_handle_secondary(int actor_id
)
1548 /* Stop waiting. Move on to the next queued diplomat. */
1549 is_more_user_input_needed
= FALSE
;
1550 diplomat_queue_handle_primary(actor_id
);
1553 /**************************************************************************
1554 Returns a string with how many shields remains of the current production.
1555 This is useful as custom information on the help build wonder button.
1556 ***************************************************************************/
1557 static QString
city_prod_remaining(struct city
*target_city
)
1559 if (target_city
== nullptr
1560 || city_owner(target_city
) != client
.conn
.playing
) {
1561 /* Can't give remaining production for a foreign or non existing
1566 return QString(_("%1 remaining")).arg(
1567 impr_build_shield_cost(target_city
->production
.value
.building
)
1568 - target_city
->shield_stock
);
1571 /**************************************************************************
1572 Popup a dialog that allows the player to select what action a unit
1574 **************************************************************************/
1575 void popup_action_selection(struct unit
*actor_unit
,
1576 struct city
*target_city
,
1577 struct unit
*target_unit
,
1578 struct tile
*target_tile
,
1579 const struct act_prob
*act_probs
)
1581 struct astring title
= ASTRING_INIT
, text
= ASTRING_INIT
;
1586 struct city
*actor_homecity
;
1590 unit_act
= qdef_act::action()->vs_unit_get();
1591 city_act
= qdef_act::action()->vs_city_get();
1593 foreach (caras
, gui()->trade_gen
.lines
) {
1594 if (caras
.autocaravan
== actor_unit
) {
1596 if (nullptr != game_unit_by_number(actor_unit
->id
)
1597 && nullptr != game_city_by_number(target_city
->id
)) {
1598 request_do_action(ACTION_TRADE_ROUTE
, actor_unit
->id
,
1599 target_city
->id
, 0);
1600 client_unit_init_act_prob_cache(actor_unit
);
1601 diplomat_queue_handle_primary(actor_unit
->id
);
1602 i
= gui()->trade_gen
.lines
.indexOf(caras
);
1603 gui()->trade_gen
.lines
.takeAt(i
);
1609 && try_default_city_action(actor_unit
->id
, target_city
->id
)
1610 && action_prob_possible(act_probs
[static_cast<gen_action
>(unit_act
)])) {
1611 diplomat_queue_handle_primary(actor_unit
->id
);
1616 && try_default_unit_action(actor_unit
->id
, target_unit
->id
)
1617 && action_prob_possible(act_probs
[static_cast<gen_action
>(city_act
)])) {
1618 diplomat_queue_handle_primary(actor_unit
->id
);
1621 /* Could be caused by the server failing to reply to a request for more
1622 * information or a bug in the client code. */
1623 fc_assert_msg(!is_more_user_input_needed
,
1624 "Diplomat queue problem. Is another diplomat window open?");
1626 /* No extra input is required as no action has been chosen yet. */
1627 is_more_user_input_needed
= FALSE
;
1629 actor_homecity
= game_city_by_number(actor_unit
->homecity
);
1632 /* TRANS: %s is a unit name, e.g., Spy */
1633 _("Choose Your %s's Strategy"),
1634 unit_name_translation(actor_unit
));
1636 if (target_city
&& actor_homecity
) {
1638 _("Your %s from %s reaches the city of %s.\nWhat now?"),
1639 unit_name_translation(actor_unit
),
1640 city_name_get(actor_homecity
),
1641 city_name_get(target_city
));
1642 } else if (target_city
) {
1644 _("Your %s has arrived at %s.\nWhat is your command?"),
1645 unit_name_translation(actor_unit
),
1646 city_name_get(target_city
));
1647 } else if (target_unit
) {
1649 /* TRANS: Your Spy is ready to act against Roman Freight. */
1650 _("Your %s is ready to act against %s %s."),
1651 unit_name_translation(actor_unit
),
1652 nation_adjective_for_player(unit_owner(target_unit
)),
1653 unit_name_translation(target_unit
));
1655 fc_assert_msg(target_unit
|| target_city
,
1656 "No target unit or target city specified.");
1659 /* TRANS: %s is a unit name, e.g., Diplomat, Spy */
1660 _("Your %s is waiting for your command."),
1661 unit_name_translation(actor_unit
));
1664 cd
= gui()->get_diplo_dialog();
1665 if ((cd
!= nullptr) && cd
->targeted_unit
!= nullptr) {
1666 cd
->update_dialog(act_probs
);
1669 cd
= new choice_dialog(astr_str(&title
), astr_str(&text
),
1670 gui()->game_tab_widget
,
1671 diplomat_queue_handle_primary
);
1672 qv1
= actor_unit
->id
;
1674 cd
->unit_id
= actor_unit
->id
;
1677 cd
->target_id
[ATK_CITY
] = target_city
->id
;
1679 cd
->target_id
[ATK_CITY
] = IDENTITY_NUMBER_ZERO
;
1683 cd
->target_id
[ATK_UNIT
] = target_unit
->id
;
1685 cd
->target_id
[ATK_UNIT
] = IDENTITY_NUMBER_ZERO
;
1688 /* Unit acting against a city */
1690 /* Set the correct target for the following actions. */
1691 qv2
= cd
->target_id
[ATK_CITY
];
1693 action_iterate(act
) {
1694 if (action_id_get_actor_kind(act
) == AAK_UNIT
1695 && action_id_get_target_kind(act
) == ATK_CITY
) {
1697 (enum gen_action
)act
,
1699 act
== ACTION_HELP_WONDER
?
1700 city_prod_remaining(target_city
) : "",
1703 } action_iterate_end
;
1705 /* Unit acting against another unit */
1707 /* Set the correct target for the following actions. */
1708 qv2
= cd
->target_id
[ATK_UNIT
];
1710 action_iterate(act
) {
1711 if (action_id_get_actor_kind(act
) == AAK_UNIT
1712 && action_id_get_target_kind(act
) == ATK_UNIT
) {
1714 (enum gen_action
)act
,
1719 } action_iterate_end
;
1721 if (unit_can_move_to_tile(actor_unit
, target_tile
, FALSE
)
1722 || (is_military_unit(actor_unit
) || is_attack_unit(actor_unit
))
1723 || (can_unit_bombard(actor_unit
) && !is_ocean_tile(target_tile
))
1724 || (!target_city
&& unit_has_type_flag(actor_unit
, UTYF_CAPTURER
))) {
1725 qv2
= target_tile
->index
;
1727 func
= act_sel_keep_moving
;
1728 cd
->add_item(QString(_("Keep moving")), func
, qv1
, qv2
,
1732 func
= act_sel_wait
;
1733 cd
->add_item(QString(_("&Wait")), func
, qv1
, qv2
,
1737 cd
->add_item(QString(_("Do nothing")), func
, qv1
, qv2
,
1743 /* Give follow up questions access to action probabilities. */
1744 client_unit_init_act_prob_cache(actor_unit
);
1745 action_iterate(act
) {
1746 actor_unit
->client
.act_prob_cache
[act
] = act_probs
[act
];
1747 } action_iterate_end
;
1753 /**********************************************************************
1754 Show the user the action if it is enabled.
1755 **********************************************************************/
1756 static void action_entry(choice_dialog
*cd
,
1758 const struct act_prob
*act_probs
,
1760 QVariant data1
, QVariant data2
)
1765 if (act
== ACTION_SPY_SABOTAGE_CITY
1766 && action_prob_possible(
1767 act_probs
[ACTION_SPY_TARGETED_SABOTAGE_CITY
])) {
1768 /* The player can select Sabotage City from the target selection dialog
1769 * of Targeted Sabotage City. */
1773 if (act
== ACTION_SPY_STEAL_TECH
1774 && action_prob_possible(
1775 act_probs
[ACTION_SPY_TARGETED_STEAL_TECH
])) {
1776 /* The player can select Steal Tech from the target selection dialog of
1777 * Targeted Steal Tech. */
1781 /* Don't show disabled actions. */
1782 if (!action_prob_possible(act_probs
[act
])) {
1786 title
= QString(action_prepare_ui_name(act
, "&",
1789 custom
.toUtf8().data() :
1792 tool_tip
= QString(action_get_tool_tip(act
, act_probs
[act
]));
1794 cd
->add_item(title
, af_map
[act
], data1
, data2
, tool_tip
, act
);
1797 /**********************************************************************
1798 Update an existing button.
1799 **********************************************************************/
1800 static void action_entry_update(Choice_dialog_button
*button
,
1802 const struct act_prob
*act_probs
,
1804 QVariant data1
, QVariant data2
)
1809 /* An action that just became impossible has its button disabled.
1810 * An action that became possible again must be reenabled. */
1811 button
->setEnabled(action_prob_possible(act_probs
[act
]));
1812 button
->setData1(data1
);
1813 button
->setData2(data2
);
1814 /* The probability may have changed. */
1815 title
= QString(action_prepare_ui_name(act
, "&",
1818 custom
.toUtf8().data() :
1821 tool_tip
= QString(action_get_tool_tip(act
, act_probs
[act
]));
1823 button
->setText(title
);
1824 button
->setToolTip(tool_tip
);
1827 /***************************************************************************
1828 Action bribe unit for choice dialog
1829 ***************************************************************************/
1830 static void diplomat_bribe(QVariant data1
, QVariant data2
)
1832 int diplomat_id
= data1
.toInt();
1833 int diplomat_target_id
= data2
.toInt();
1835 if (NULL
!= game_unit_by_number(diplomat_id
)
1836 && NULL
!= game_unit_by_number(diplomat_target_id
)) {
1837 /* Wait for the server's reply before moving on to the next queued diplomat. */
1838 is_more_user_input_needed
= TRUE
;
1840 request_action_details(ACTION_SPY_BRIBE_UNIT
, diplomat_id
,
1841 diplomat_target_id
);
1845 /***************************************************************************
1846 Action sabotage unit for choice dialog
1847 ***************************************************************************/
1848 static void spy_sabotage_unit(QVariant data1
, QVariant data2
)
1850 int diplomat_id
= data1
.toInt();
1851 int diplomat_target_id
= data2
.toInt();
1853 request_do_action(ACTION_SPY_SABOTAGE_UNIT
, diplomat_id
,
1854 diplomat_target_id
, 0);
1857 /***************************************************************************
1858 Action steal tech with spy for choice dialog
1859 ***************************************************************************/
1860 static void spy_steal(QVariant data1
, QVariant data2
)
1865 int diplomat_id
= data1
.toInt();
1866 int diplomat_target_id
= data2
.toInt();
1867 struct unit
*actor_unit
= game_unit_by_number(diplomat_id
);
1868 struct city
*pvcity
= game_city_by_number(diplomat_target_id
);
1869 struct player
*pvictim
= NULL
;
1871 QList
<QVariant
> actor_and_target
;
1873 /* Wait for the player's reply before moving on to the next queued diplomat. */
1874 is_more_user_input_needed
= TRUE
;
1877 pvictim
= city_owner(pvcity
);
1879 cd
= gui()->get_diplo_dialog();
1883 struct astring stra
= ASTRING_INIT
;
1884 cd
= new choice_dialog(_("Steal"), _("Steal Technology"),
1885 gui()->game_tab_widget
,
1886 diplomat_queue_handle_secondary
);
1888 /* Put both actor and target city in qv1 since qv2 is taken */
1889 actor_and_target
.append(diplomat_id
);
1890 actor_and_target
.append(diplomat_target_id
);
1891 qv1
= QVariant::fromValue(actor_and_target
);
1893 struct player
*pplayer
= client
.conn
.playing
;
1895 const struct research
*presearch
= research_get(pplayer
);
1896 const struct research
*vresearch
= research_get(pvictim
);
1898 advance_index_iterate(A_FIRST
, i
) {
1899 if (research_invention_gettable(presearch
, i
,
1900 game
.info
.tech_steal_allow_holes
)
1901 && research_invention_state(vresearch
, i
) == TECH_KNOWN
1902 && research_invention_state(presearch
, i
) != TECH_KNOWN
) {
1903 func
= spy_steal_something
;
1904 str
= research_advance_name_translation(presearch
, i
);
1905 cd
->add_item(str
, func
, qv1
, i
);
1907 } advance_index_iterate_end
;
1909 if (action_prob_possible(
1910 actor_unit
->client
.act_prob_cache
[ACTION_SPY_STEAL_TECH
])) {
1911 astr_set(&stra
, _("At %s's Discretion"),
1912 unit_name_translation(actor_unit
));
1913 func
= spy_steal_something
;
1914 str
= astr_str(&stra
);
1915 cd
->add_item(str
, func
, qv1
, A_UNSET
);
1924 /***************************************************************************
1925 Action steal given tech for choice dialog
1926 ***************************************************************************/
1927 static void spy_steal_something(QVariant data1
, QVariant data2
)
1929 int diplomat_id
= data1
.toList().at(0).toInt();
1930 int diplomat_target_id
= data1
.toList().at(1).toInt();
1932 if (NULL
!= game_unit_by_number(diplomat_id
)
1933 && NULL
!= game_city_by_number(diplomat_target_id
)) {
1934 if (data2
.toInt() == A_UNSET
) {
1935 /* This is the untargeted version. */
1936 request_do_action(ACTION_SPY_STEAL_TECH
, diplomat_id
,
1937 diplomat_target_id
, data2
.toInt());
1939 /* This is the targeted version. */
1940 request_do_action(ACTION_SPY_TARGETED_STEAL_TECH
, diplomat_id
,
1941 diplomat_target_id
, data2
.toInt());
1946 /***************************************************************************
1947 Action request sabotage list for choice dialog
1948 ***************************************************************************/
1949 static void spy_request_sabotage_list(QVariant data1
, QVariant data2
)
1951 int diplomat_id
= data1
.toInt();
1952 int diplomat_target_id
= data2
.toInt();
1954 if (NULL
!= game_unit_by_number(diplomat_id
)
1955 && NULL
!= game_city_by_number(diplomat_target_id
)) {
1956 /* Wait for the server's reply before moving on to the next queued diplomat. */
1957 is_more_user_input_needed
= TRUE
;
1959 request_action_details(ACTION_SPY_TARGETED_SABOTAGE_CITY
, diplomat_id
,
1960 diplomat_target_id
);
1964 /***************************************************************************
1965 Action poison city for choice dialog
1966 ***************************************************************************/
1967 static void spy_poison(QVariant data1
, QVariant data2
)
1969 int diplomat_id
= data1
.toInt();
1970 int diplomat_target_id
= data2
.toInt();
1972 if (NULL
!= game_unit_by_number(diplomat_id
)
1973 && NULL
!= game_city_by_number(diplomat_target_id
)) {
1974 request_do_action(ACTION_SPY_POISON
,
1975 diplomat_id
, diplomat_target_id
, 0);
1979 /***************************************************************************
1980 Action steal gold for choice dialog
1981 ***************************************************************************/
1982 static void spy_steal_gold(QVariant data1
, QVariant data2
)
1984 int diplomat_id
= data1
.toInt();
1985 int diplomat_target_id
= data2
.toInt();
1987 if (NULL
!= game_unit_by_number(diplomat_id
)
1988 && NULL
!= game_city_by_number(diplomat_target_id
)) {
1989 request_do_action(ACTION_SPY_STEAL_GOLD
,
1990 diplomat_id
, diplomat_target_id
, 0);
1994 /***************************************************************************
1995 Action establish embassy for choice dialog
1996 ***************************************************************************/
1997 static void diplomat_embassy(QVariant data1
, QVariant data2
)
1999 int diplomat_id
= data1
.toInt();
2000 int diplomat_target_id
= data2
.toInt();
2002 if (NULL
!= game_unit_by_number(diplomat_id
)
2003 && NULL
!= game_city_by_number(diplomat_target_id
)) {
2004 request_do_action(ACTION_ESTABLISH_EMBASSY
, diplomat_id
,
2005 diplomat_target_id
, 0);
2009 /***************************************************************************
2010 Action investigate city for choice dialog
2011 ***************************************************************************/
2012 static void diplomat_investigate(QVariant data1
, QVariant data2
)
2014 int diplomat_id
= data1
.toInt();
2015 int diplomat_target_id
= data2
.toInt();
2017 if (NULL
!= game_city_by_number(diplomat_target_id
)
2018 && NULL
!= game_unit_by_number(diplomat_id
)) {
2019 request_do_action(ACTION_SPY_INVESTIGATE_CITY
, diplomat_id
,
2020 diplomat_target_id
, 0);
2024 /***************************************************************************
2025 Action sabotage for choice dialog
2026 ***************************************************************************/
2027 static void diplomat_sabotage(QVariant data1
, QVariant data2
)
2029 int diplomat_id
= data1
.toInt();
2030 int diplomat_target_id
= data2
.toInt();
2032 if (NULL
!= game_unit_by_number(diplomat_id
)
2033 && NULL
!= game_city_by_number(diplomat_target_id
)) {
2034 request_do_action(ACTION_SPY_SABOTAGE_CITY
, diplomat_id
,
2035 diplomat_target_id
, B_LAST
+ 1);
2039 /***************************************************************************
2040 Action steal with diplomat for choice dialog
2041 ***************************************************************************/
2042 static void diplomat_steal(QVariant data1
, QVariant data2
)
2044 int diplomat_id
= data1
.toInt();
2045 int diplomat_target_id
= data2
.toInt();
2047 if (NULL
!= game_unit_by_number(diplomat_id
)
2048 && NULL
!= game_city_by_number(diplomat_target_id
)) {
2049 request_do_action(ACTION_SPY_STEAL_TECH
, diplomat_id
,
2050 diplomat_target_id
, A_UNSET
);
2054 /***************************************************************************
2055 Action incite revolt for choice dialog
2056 ***************************************************************************/
2057 static void diplomat_incite(QVariant data1
, QVariant data2
)
2059 int diplomat_id
= data1
.toInt();
2060 int diplomat_target_id
= data2
.toInt();
2062 if (NULL
!= game_unit_by_number(diplomat_id
)
2063 && NULL
!= game_city_by_number(diplomat_target_id
)) {
2064 /* Wait for the server's reply before moving on to the next queued diplomat. */
2065 is_more_user_input_needed
= TRUE
;
2067 request_action_details(ACTION_SPY_INCITE_CITY
, diplomat_id
,
2068 diplomat_target_id
);
2072 /***************************************************************************
2073 Action keep moving with actor unit for choice dialog
2074 ***************************************************************************/
2075 static void act_sel_keep_moving(QVariant data1
, QVariant data2
)
2079 int diplomat_id
= data1
.toInt();
2080 int diplomat_target_id
= data2
.toInt();
2082 if ((punit
= game_unit_by_number(diplomat_id
))
2083 && (ptile
= index_to_tile(diplomat_target_id
))
2084 && !same_pos(unit_tile(punit
), ptile
)) {
2085 request_unit_non_action_move(punit
, ptile
);
2089 /**************************************************************************
2090 Popup a window asking a diplomatic unit if it wishes to incite the
2092 **************************************************************************/
2093 void popup_incite_dialog(struct unit
*actor
, struct city
*tcity
, int cost
)
2098 int diplomat_id
= actor
->id
;
2099 int diplomat_target_id
= tcity
->id
;
2101 /* Should be set before sending request to the server. */
2102 fc_assert(is_more_user_input_needed
);
2104 fc_snprintf(buf
, ARRAY_SIZE(buf
), PL_("Treasury contains %d gold.",
2105 "Treasury contains %d gold.",
2106 client_player()->economic
.gold
),
2107 client_player()->economic
.gold
);
2109 if (INCITE_IMPOSSIBLE_COST
== cost
) {
2110 hud_message_box
incite_impossible(gui()->central_wdg
);
2112 fc_snprintf(buf2
, ARRAY_SIZE(buf2
),
2113 _("You can't incite a revolt in %s."), city_name_get(tcity
));
2114 incite_impossible
.set_text_title(QString(buf2
), "!");
2115 incite_impossible
.setStandardButtons(QMessageBox::Ok
);
2116 incite_impossible
.exec();
2117 } else if (cost
<= client_player()->economic
.gold
) {
2118 hud_message_box
ask(gui()->central_wdg
);
2120 fc_snprintf(buf2
, ARRAY_SIZE(buf2
),
2121 PL_("Incite a revolt for %d gold?\n%s",
2122 "Incite a revolt for %d gold?\n%s", cost
), cost
, buf
);
2123 ask
.setStandardButtons(QMessageBox::Cancel
| QMessageBox::Ok
);
2124 ask
.setDefaultButton(QMessageBox::Cancel
);
2125 ask
.set_text_title(QString(buf2
), _("Incite a Revolt!"));
2128 case QMessageBox::Cancel
:
2130 case QMessageBox::Ok
:
2131 request_do_action(ACTION_SPY_INCITE_CITY
, diplomat_id
,
2132 diplomat_target_id
, 0);
2136 hud_message_box
too_much(gui()->central_wdg
);
2138 fc_snprintf(buf2
, ARRAY_SIZE(buf2
),
2139 PL_("Inciting a revolt costs %d gold.\n%s",
2140 "Inciting a revolt costs %d gold.\n%s", cost
), cost
,
2142 too_much
.set_text_title(QString(buf2
), "!");
2143 too_much
.setStandardButtons(QMessageBox::Ok
);
2147 diplomat_queue_handle_secondary(diplomat_id
);
2150 /**************************************************************************
2151 Popup a dialog asking a diplomatic unit if it wishes to bribe the
2153 **************************************************************************/
2154 void popup_bribe_dialog(struct unit
*actor
, struct unit
*tunit
, int cost
)
2156 hud_message_box
ask(gui()->central_wdg
);
2161 int diplomat_id
= actor
->id
;
2162 int diplomat_target_id
= tunit
->id
;
2164 /* Should be set before sending request to the server. */
2165 fc_assert(is_more_user_input_needed
);
2167 fc_snprintf(buf
, ARRAY_SIZE(buf
), PL_("Treasury contains %d gold.",
2168 "Treasury contains %d gold.",
2169 client_player()->economic
.gold
),
2170 client_player()->economic
.gold
);
2172 if (cost
<= client_player()->economic
.gold
) {
2173 fc_snprintf(buf2
, ARRAY_SIZE(buf2
), PL_("Bribe unit for %d gold?\n%s",
2174 "Bribe unit for %d gold?\n%s",
2176 ask
.set_text_title(QString(buf2
), QString(_("Bribe Enemy Unit")));
2177 ask
.setStandardButtons(QMessageBox::Cancel
| QMessageBox::Ok
);
2178 ask
.setDefaultButton(QMessageBox::Cancel
);
2181 case QMessageBox::Cancel
:
2183 case QMessageBox::Ok
:
2184 request_do_action(ACTION_SPY_BRIBE_UNIT
, diplomat_id
,
2185 diplomat_target_id
, 0);
2191 fc_snprintf(buf2
, ARRAY_SIZE(buf2
),
2192 PL_("Bribing the unit costs %d gold.\n%s",
2193 "Bribing the unit costs %d gold.\n%s", cost
), cost
, buf
);
2194 ask
.set_text_title(QString(buf2
), _("Traitors Demand Too Much!"));
2198 diplomat_queue_handle_secondary(diplomat_id
);
2201 /***************************************************************************
2202 Action pillage for choice dialog
2203 ***************************************************************************/
2204 static void pillage_something(QVariant data1
, QVariant data2
)
2209 struct extra_type
*target
;
2211 what
= data1
.toInt();
2212 punit_id
= data2
.toInt();
2213 punit
= game_unit_by_number(punit_id
);
2215 target
= extra_by_number(what
);
2216 request_new_unit_activity_targeted(punit
, ACTIVITY_PILLAGE
, target
);
2218 ::is_showing_pillage_dialog
= false;
2221 /***************************************************************************
2222 Action sabotage with spy for choice dialog
2223 ***************************************************************************/
2224 static void spy_sabotage(QVariant data1
, QVariant data2
)
2226 int diplomat_id
= data1
.toList().at(0).toInt();
2227 int diplomat_target_id
= data1
.toList().at(1).toInt();
2229 if (NULL
!= game_unit_by_number(diplomat_id
)
2230 && NULL
!= game_city_by_number(diplomat_target_id
)) {
2231 if (data2
.toInt() == B_LAST
) {
2232 /* This is the untargeted version. */
2233 request_do_action(ACTION_SPY_SABOTAGE_CITY
, diplomat_id
,
2234 diplomat_target_id
, data2
.toInt() + 1);
2236 /* This is the targeted version. */
2237 request_do_action(ACTION_SPY_TARGETED_SABOTAGE_CITY
, diplomat_id
,
2238 diplomat_target_id
, data2
.toInt() + 1);
2243 /**************************************************************************
2244 Popup a dialog asking a diplomatic unit if it wishes to sabotage the
2246 **************************************************************************/
2247 void popup_sabotage_dialog(struct unit
*actor
, struct city
*tcity
)
2252 int diplomat_id
= actor
->id
;
2253 int diplomat_target_id
= tcity
->id
;
2255 choice_dialog
*cd
= new choice_dialog(_("Sabotage"),
2256 _("Select Improvement to Sabotage"),
2257 gui()->game_tab_widget
,
2258 diplomat_queue_handle_secondary
);
2260 struct astring stra
= ASTRING_INIT
;
2261 QList
<QVariant
> actor_and_target
;
2263 /* Should be set before sending request to the server. */
2264 fc_assert(is_more_user_input_needed
);
2266 /* Put both actor and target city in qv1 since qv2 is taken */
2267 actor_and_target
.append(diplomat_id
);
2268 actor_and_target
.append(diplomat_target_id
);
2269 qv1
= QVariant::fromValue(actor_and_target
);
2271 func
= spy_sabotage
;
2272 cd
->add_item(QString(_("City Production")), func
, qv1
, -1);
2273 city_built_iterate(tcity
, pimprove
) {
2274 if (pimprove
->sabotage
> 0) {
2275 func
= spy_sabotage
;
2276 str
= city_improvement_name_translation(tcity
, pimprove
);
2278 cd
->add_item(str
, func
, qv1
, improvement_number(pimprove
));
2281 } city_built_iterate_end
;
2283 if (action_prob_possible(
2284 actor
->client
.act_prob_cache
[ACTION_SPY_SABOTAGE_CITY
])) {
2285 astr_set(&stra
, _("At %s's Discretion"),
2286 unit_name_translation(actor
));
2287 func
= spy_sabotage
;
2288 str
= astr_str(&stra
);
2289 cd
->add_item(str
, func
, qv1
, B_LAST
);
2297 /**************************************************************************
2298 Popup a dialog asking the unit which improvement they would like to
2300 **************************************************************************/
2301 void popup_pillage_dialog(struct unit
*punit
, bv_extras extras
)
2307 struct extra_type
*tgt
;
2309 if (is_showing_pillage_dialog
){
2312 cd
= new choice_dialog(_("What To Pillage"), _("Select what to pillage:"),
2313 gui()->game_tab_widget
);
2315 while ((tgt
= get_preferred_pillage(extras
))) {
2318 what
= extra_index(tgt
);
2319 BV_CLR(extras
, what
);
2321 func
= pillage_something
;
2322 str
= extra_name_translation(tgt
);
2324 cd
->add_item(str
, func
, qv1
, qv2
);
2330 /***************************************************************************
2331 Disband Message box contructor
2332 ***************************************************************************/
2333 disband_box::disband_box(struct unit_list
*punits
,
2334 QWidget
*parent
) : hud_message_box(parent
)
2339 setAttribute(Qt::WA_DeleteOnClose
);
2341 cpunits
= unit_list_new();
2342 unit_list_iterate(punits
, punit
) {
2343 unit_list_append(cpunits
, punit
);
2344 } unit_list_iterate_end
;
2346 str
= QString(PL_("Are you sure you want to disband that %1 unit?",
2347 "Are you sure you want to disband those %1 units?",
2348 unit_list_size(punits
))).arg(unit_list_size(punits
));
2349 pb
= addButton(_("Yes"), QMessageBox::AcceptRole
);
2350 addButton(_("No"), QMessageBox::RejectRole
);
2351 setDefaultButton(QMessageBox::Cancel
);
2352 set_text_title(str
, _("Disband units"));
2353 connect(pb
, SIGNAL(clicked()), this, SLOT(disband_clicked()));
2356 /***************************************************************************
2357 Clicked Yes in disband box
2358 ***************************************************************************/
2359 void disband_box::disband_clicked()
2361 unit_list_iterate(cpunits
, punit
) {
2362 if (!unit_has_type_flag(punit
, UTYF_UNDISBANDABLE
)) {
2363 request_unit_disband(punit
);
2365 } unit_list_iterate_end
;
2368 /***************************************************************************
2369 Destructor for disband box
2370 ***************************************************************************/
2371 disband_box::~disband_box()
2373 unit_list_destroy(cpunits
);
2376 /****************************************************************************
2377 Pops up a dialog to confirm disband of the unit(s).
2378 ****************************************************************************/
2379 void popup_disband_dialog(struct unit_list
*punits
)
2381 disband_box
*ask
= new disband_box(punits
, gui()->central_wdg
);
2385 /**************************************************************************
2386 Ruleset (modpack) has suggested loading certain tileset. Confirm from
2388 **************************************************************************/
2389 void popup_tileset_suggestion_dialog(void)
2391 hud_message_box
ask(gui()->central_wdg
);
2394 QPushButton
*ok_button
;
2396 title
= QString(_("Modpack suggests using %1 tileset."))
2397 .arg(game
.control
.preferred_tileset
);
2398 text
= QString("It might not work with other tilesets.\n"
2399 "You are currently using tileset %1.")
2400 .arg(tileset_basename(tileset
));
2401 ask
.addButton(_("Keep current tileset"), QMessageBox::ActionRole
);
2402 ok_button
= ask
.addButton(_("Load tileset"), QMessageBox::ActionRole
);
2403 ask
.set_text_title(text
, title
);
2405 if (ask
.clickedButton() == ok_button
) {
2406 tilespec_reread(game
.control
.preferred_tileset
, FALSE
);
2410 /****************************************************************
2411 Ruleset (modpack) has suggested loading certain soundset. Confirm from
2413 *****************************************************************/
2414 void popup_soundset_suggestion_dialog(void)
2416 hud_message_box
ask(gui()->central_wdg
);
2419 QPushButton
*ok_button
;
2421 title
= QString(_("Modpack suggests using %1 soundset."))
2422 .arg(game
.control
.preferred_soundset
);
2423 text
= QString("It might not work with other tilesets.\n"
2424 "You are currently using soundset %1.")
2425 .arg(sound_set_name
);
2426 ask
.addButton(_("Keep current soundset"), QMessageBox::ActionRole
);
2427 ok_button
= ask
.addButton(_("Load soundset"), QMessageBox::ActionRole
);
2428 ask
.set_text_title(text
, title
);
2430 if (ask
.clickedButton() == ok_button
) {
2431 audio_restart(game
.control
.preferred_soundset
, music_set_name
);
2435 /****************************************************************
2436 Ruleset (modpack) has suggested loading certain musicset. Confirm from
2438 *****************************************************************/
2439 void popup_musicset_suggestion_dialog(void)
2441 hud_message_box
ask(gui()->central_wdg
);
2444 QPushButton
*ok_button
;
2446 title
= QString(_("Modpack suggests using %1 musicset."))
2447 .arg(game
.control
.preferred_musicset
);
2448 text
= QString("It might not work with other tilesets.\n"
2449 "You are currently using musicset %1.")
2450 .arg(music_set_name
);
2451 ask
.addButton(_("Keep current musicset"), QMessageBox::ActionRole
);
2452 ok_button
= ask
.addButton(_("Load musicset"), QMessageBox::ActionRole
);
2453 ask
.set_text_title(text
, title
);
2455 if (ask
.clickedButton() == ok_button
) {
2456 audio_restart(sound_set_name
, game
.control
.preferred_musicset
);
2460 /**************************************************************************
2461 Tileset (modpack) has suggested loading certain theme. Confirm from
2463 **************************************************************************/
2464 bool popup_theme_suggestion_dialog(const char *theme_name
)
2470 /**************************************************************************
2471 Restarts all notify dialogs
2472 **************************************************************************/
2473 void restart_notify_dialogs()
2475 QList
<notify_dialog
*> nd_list
;
2478 nd_list
= gui()->mapview_wdg
->findChildren
<notify_dialog
*>();
2479 for (i
= 0; i
< nd_list
.count(); i
++) {
2480 nd_list
[i
]->restart();
2485 /**************************************************************************
2486 This function is called when the client disconnects or the game is
2487 over. It should close all dialog windows for that game.
2488 **************************************************************************/
2489 void popdown_all_game_dialogs(void)
2492 QList
<choice_dialog
*> cd_list
;
2493 QList
<notify_dialog
*> nd_list
;
2495 cd_list
= gui()->game_tab_widget
->findChildren
<choice_dialog
*>();
2496 for (i
= 0; i
< cd_list
.count(); i
++) {
2497 cd_list
[i
]->close();
2499 nd_list
= gui()->game_tab_widget
->findChildren
<notify_dialog
*>();
2500 for (i
= 0; i
< nd_list
.count(); i
++) {
2501 nd_list
[i
]->close();
2504 popdown_help_dialog();
2505 popdown_players_report();
2506 popdown_all_spaceships_dialogs();
2507 popdown_economy_report();
2508 popdown_units_report();
2509 popdown_science_report();
2510 popdown_city_report();
2511 popdown_endgame_report();
2512 gui()->popdown_unit_sel();
2515 /**************************************************************************
2516 Returns the id of the actor unit currently handled in action selection
2517 dialog when the action selection dialog is open.
2518 Returns IDENTITY_NUMBER_ZERO if no action selection dialog is open.
2519 **************************************************************************/
2520 int action_selection_actor_unit(void)
2522 choice_dialog
*cd
= gui()->get_diplo_dialog();
2527 return IDENTITY_NUMBER_ZERO
;
2531 /**************************************************************************
2532 Returns id of the target city of the actions currently handled in action
2533 selection dialog when the action selection dialog is open and it has a
2534 city target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
2535 is open or no city target is present in the action selection dialog.
2536 **************************************************************************/
2537 int action_selection_target_city(void)
2539 choice_dialog
*cd
= gui()->get_diplo_dialog();
2542 return cd
->target_id
[ATK_CITY
];
2544 return IDENTITY_NUMBER_ZERO
;
2548 /**************************************************************************
2549 Returns id of the target unit of the actions currently handled in action
2550 selection dialog when the action selection dialog is open and it has a
2551 unit target. Returns IDENTITY_NUMBER_ZERO if no action selection dialog
2552 is open or no unit target is present in the action selection dialog.
2553 **************************************************************************/
2554 int action_selection_target_unit(void)
2556 choice_dialog
*cd
= gui()->get_diplo_dialog();
2559 return cd
->target_id
[ATK_UNIT
];
2561 return IDENTITY_NUMBER_ZERO
;
2565 /**************************************************************************
2566 Updates the action selection dialog with new information.
2567 **************************************************************************/
2568 void action_selection_refresh(struct unit
*actor_unit
,
2569 struct city
*target_city
,
2570 struct unit
*target_unit
,
2571 struct tile
*target_tile
,
2572 const struct act_prob
*act_probs
)
2575 Choice_dialog_button
*keep_moving_button
;
2576 Choice_dialog_button
*wait_button
;
2579 asd
= gui()->get_diplo_dialog();
2581 fc_assert_msg(asd
!= NULL
,
2582 "The action selection dialog should have been open");
2586 if (actor_unit
->id
!= action_selection_actor_unit()) {
2587 fc_assert_msg(actor_unit
->id
== action_selection_actor_unit(),
2588 "The action selection dialog is for another actor unit.");
2591 /* Put the actor id in qv1. */
2592 qv1
= actor_unit
->id
;
2594 keep_moving_button
= asd
->get_identified_button(BUTTON_CANCEL
);
2595 if (keep_moving_button
!= NULL
) {
2596 /* Temporary remove the Keep moving button so it won't end up above
2597 * any added buttons. */
2598 asd
->stack_button(keep_moving_button
);
2601 wait_button
= asd
->get_identified_button(BUTTON_WAIT
);
2602 if (wait_button
!= NULL
) {
2603 /* Temporary remove the Wait button so it won't end up above
2604 * any added buttons. */
2605 asd
->stack_button(wait_button
);
2608 action_iterate(act
) {
2611 if (action_id_get_actor_kind(act
) != AAK_UNIT
) {
2616 if (action_prob_possible(act_probs
[act
])
2617 && act
== ACTION_HELP_WONDER
) {
2618 /* Add information about how far along the wonder is. */
2619 custom
= city_prod_remaining(target_city
);
2624 /* Put the target id in qv2. */
2625 switch (action_id_get_target_kind(act
)) {
2627 if (target_unit
!= NULL
) {
2628 qv2
= target_unit
->id
;
2630 fc_assert_msg(!action_prob_possible(act_probs
[act
])
2631 || target_unit
!= NULL
,
2632 "Action enabled against non existing unit!");
2634 qv2
= IDENTITY_NUMBER_ZERO
;
2638 if (target_city
!= NULL
) {
2639 qv2
= target_city
->id
;
2641 fc_assert_msg(!action_prob_possible(act_probs
[act
])
2642 || target_city
!= NULL
,
2643 "Action enabled against non existing city!");
2645 qv2
= IDENTITY_NUMBER_ZERO
;
2649 fc_assert_msg(ATK_COUNT
!= action_id_get_target_kind(act
),
2654 if (asd
->get_identified_button(act
)) {
2655 /* Update the existing button. */
2656 action_entry_update(asd
->get_identified_button(act
),
2657 (enum gen_action
)act
, act_probs
, custom
,
2660 /* Add the button (unless its probability is 0). */
2661 action_entry(asd
, (enum gen_action
)act
, act_probs
, custom
,
2664 } action_iterate_end
;
2666 if (keep_moving_button
!= NULL
|| wait_button
!= NULL
) {
2667 /* Reinsert the "Keep moving" button below any potential
2668 * buttons recently added. */
2669 asd
->unstack_all_buttons();
2673 /****************************************************************
2674 Closes the action selection dialog
2675 ****************************************************************/
2676 void action_selection_close(void)
2680 cd
= gui()->get_diplo_dialog();
2682 did_not_decide
= true;
2687 /****************************************************************
2688 Player has gained a new tech.
2689 *****************************************************************/
2690 void show_tech_gained_dialog(Tech_type_id tech
)
2694 /****************************************************************
2695 Show tileset error dialog.
2696 *****************************************************************/
2697 void show_tileset_error(const char *msg
)
2699 QMessageBox
ask(gui()->central_wdg
);
2702 fc_snprintf(buf
, sizeof(buf
),
2703 _("Tileset problem, it's probably incompatible with the"
2704 " ruleset:\n%s\nProgram will now exit."), msg
);
2706 ask
.setStandardButtons(QMessageBox::Ok
);
2707 ask
.setWindowTitle(_("Tileset error"));
2713 /****************************************************************
2714 Popup dialog for upgrade units
2715 *****************************************************************/
2716 void popup_upgrade_dialog(struct unit_list
*punits
)
2719 hud_message_box
ask(gui()->central_wdg
);
2723 if (!punits
|| unit_list_size(punits
) == 0) {
2726 if (!get_units_upgrade_info(buf
, sizeof(buf
), punits
)) {
2727 title
= _("Upgrade Unit!");
2728 ask
.setStandardButtons(QMessageBox::Ok
);
2730 title
= _("Upgrade Obsolete Units");
2731 ask
.setStandardButtons(QMessageBox::Cancel
| QMessageBox::Ok
);
2732 ask
.setDefaultButton(QMessageBox::Cancel
);
2734 ask
.set_text_title(QString(buf
), title
);
2738 case QMessageBox::Cancel
:
2741 case QMessageBox::Ok
:
2742 unit_list_iterate(punits
, punit
) {
2743 request_unit_upgrade(punit
);
2745 unit_list_iterate_end
;
2750 /****************************************************************
2751 Contructor for units_select
2752 *****************************************************************/
2753 units_select::units_select(tile
*ptile
, QWidget
*parent
)
2762 ufont
.setItalic(true);
2763 info_font
= *fc_font::instance()->get_font(fonts::notify_label
);
2767 p
= mapFromGlobal(QCursor::pos());
2768 cw
= new close_widget(this);
2769 setMouseTracking(true);
2770 final_p
.setX(p
.x());
2771 final_p
.setY(p
.y());
2772 if (p
.x() + width() > parentWidget()->width()) {
2773 final_p
.setX(parentWidget()->width() - width());
2775 if (p
.y() - height() < 0) {
2776 final_p
.setY(height());
2778 move(final_p
.x(), final_p
.y() - height());
2780 QTimer::singleShot(10, this, SLOT(update_img()));
2782 /****************************************************************
2783 Destructor for unit select
2784 *****************************************************************/
2785 units_select::~units_select()
2792 /****************************************************************
2793 Create pixmap of whole widget except borders (pix)
2794 *****************************************************************/
2795 void units_select::create_pixmap()
2800 QFontMetrics
fm(info_font
);
2803 QList
<QPixmap
*>pix_list
;
2811 struct canvas
*unit_pixmap
;
2820 if (unit_list
.count() > 0) {
2821 punit
= unit_list
.at(0);
2822 if (tileset_is_isometric(tileset
) == false) {
2823 item_size
.setWidth(tileset_unit_width(tileset
));
2824 item_size
.setHeight(tileset_unit_width(tileset
));
2826 item_size
.setWidth(tileset_unit_width(tileset
) * 0.7);
2827 item_size
.setHeight(tileset_unit_width(tileset
) * 0.7);
2830 if (h_pix
!= nullptr) {
2833 h_pix
= new QPixmap(item_size
.width(), item_size
.height());
2834 h_pix
->fill(palette().color(QPalette::HighlightedText
));
2835 if (unit_list
.size() < 5) {
2837 pix
= new QPixmap((unit_list
.size()) * item_size
.width(),
2838 item_size
.height());
2839 } else if (unit_list
.size() < 9) {
2841 pix
= new QPixmap(4 * item_size
.width(), 2 * item_size
.height());
2844 if (unit_list_size(utile
->units
) > unit_list
.size() - 1) {
2847 pix
= new QPixmap(4 * item_size
.width(), 3 * item_size
.height());
2849 pix
->fill(Qt::transparent
);
2850 foreach(punit
, unit_list
) {
2851 unit_pixmap
= qtg_canvas_create(tileset_unit_width(tileset
),
2852 tileset_unit_height(tileset
));
2853 unit_pixmap
->map_pixmap
.fill(Qt::transparent
);
2854 put_unit(punit
, unit_pixmap
, 1.0, 0, 0);
2855 img
= unit_pixmap
->map_pixmap
.toImage();
2856 crop
= zealous_crop_rect(img
);
2857 cropped_img
= img
.copy(crop
);
2858 if (tileset_is_isometric(tileset
) == false) {
2859 img
= cropped_img
.scaled(tileset_unit_width(tileset
),
2860 tileset_unit_width(tileset
),
2861 Qt::KeepAspectRatio
,
2862 Qt::SmoothTransformation
);
2864 img
= cropped_img
.scaled(tileset_unit_width(tileset
) * 0.7,
2865 tileset_unit_width(tileset
) * 0.7,
2866 Qt::KeepAspectRatio
,
2867 Qt::SmoothTransformation
);
2869 pixc
= QPixmap::fromImage(img
);
2870 pixp
= new QPixmap(pixc
);
2871 pix_list
.push_back(pixp
);
2872 qtg_canvas_free(unit_pixmap
);
2874 a
= qMin(item_size
.width() / 4, 12);
2875 x
= 0, y
= -item_size
.height(), i
= -1;
2877 ufont
.setPixelSize(a
);
2879 pen
.setColor(palette().color(QPalette::Text
));
2882 while (!pix_list
.isEmpty()) {
2883 tmp_pix
= pix_list
.takeFirst();
2887 y
= y
+ item_size
.height();
2889 punit
= unit_list
.at(i
);
2890 Q_ASSERT(punit
!= NULL
);
2891 rate
= unit_type_get(punit
)->move_rate
;
2892 f
= ((punit
->fuel
) - 1);
2893 if (i
== highligh_num
) {
2894 p
.drawPixmap(x
, y
, *h_pix
);
2895 p
.drawPixmap(x
, y
, *tmp_pix
);
2897 p
.drawPixmap(x
, y
, *tmp_pix
);
2899 str
= QString(move_points_text(punit
->moves_left
, false));
2900 if (utype_fuel(unit_type_get(punit
))) {
2901 str
= str
+ "(" + QString(move_points_text((rate
* f
)
2902 + punit
->moves_left
, false)) + ")";
2904 /* TRANS: MP = Movement points */
2905 str
= QString(_("MP:")) + str
;
2906 p
.drawText(x
, y
+ item_size
.height() - 4, str
);
2908 x
= x
+ item_size
.width();
2912 setFixedWidth(pix
->width() + 20);
2913 setFixedHeight(pix
->height() + 2 * (fm
.height() + 6));
2914 qDeleteAll(pix_list
.begin(), pix_list
.end());
2918 /****************************************************************
2919 Event for mouse moving around units_select
2920 *****************************************************************/
2921 void units_select::mouseMoveEvent(QMouseEvent
*event
)
2925 QFontMetrics
fm(info_font
);
2927 old_h
= highligh_num
;
2929 if (event
->x() > width() - 11
2930 || event
->y() > height() - fm
.height() - 5
2931 || event
->y() < fm
.height() + 3 || event
->x() < 11) {
2932 /** do nothing if mouse is on border, just skip next if */
2933 } else if (row_count
> 0) {
2934 a
= (event
->x() - 10) / item_size
.width();
2935 b
= (event
->y() - fm
.height() - 3) / item_size
.height();
2936 highligh_num
= b
* 4 + a
;
2938 if (old_h
!= highligh_num
) {
2944 /****************************************************************
2945 Mouse pressed event for units_select.
2946 Left Button - chooses units
2947 Right Button - closes widget
2948 *****************************************************************/
2949 void units_select::mousePressEvent(QMouseEvent
*event
)
2952 if (event
->button() == Qt::RightButton
) {
2953 was_destroyed
= true;
2957 if (event
->button() == Qt::LeftButton
&& highligh_num
!= -1) {
2959 if (highligh_num
>= unit_list
.count()) {
2962 punit
= unit_list
.at(highligh_num
);
2963 unit_focus_set(punit
);
2964 was_destroyed
= true;
2970 /****************************************************************
2971 Update image, because in constructor theme colors
2972 are uninitialized in QPainter
2973 *****************************************************************/
2974 void units_select::update_img()
2980 /****************************************************************
2981 Redirected paint event
2982 *****************************************************************/
2983 void units_select::paint(QPainter
*painter
, QPaintEvent
*event
)
2985 QFontMetrics
fm(info_font
);
2991 int point_size
= info_font
.pointSize();
2992 int pixel_size
= info_font
.pixelSize();
2994 if (point_size
< 0) {
2995 f_size
= &pixel_size
;
2997 f_size
= &point_size
;
2999 if (highligh_num
!= -1 && highligh_num
< unit_list
.count()) {
3000 punit
= unit_list
.at(highligh_num
);
3001 /* TRANS: HP - hit points */
3002 str2
= QString(_("%1 HP:%2/%3")).arg(QString(unit_activity_text(punit
)),
3003 QString::number(punit
->hp
),
3004 QString::number(unit_type_get(punit
)->hp
));
3006 str
= QString(PL_("%1 unit", "%1 units",
3007 unit_list_size(utile
->units
)))
3008 .arg(unit_list_size(utile
->units
));
3009 for (i
= *f_size
; i
> 4; i
--) {
3010 if (point_size
< 0) {
3011 info_font
.setPixelSize(i
);
3013 info_font
.setPointSize(i
);
3015 QFontMetrics
qfm(info_font
);
3016 if (10 + qfm
.width(str2
) < width()) {
3022 painter
->drawPixmap(10, h
+ 3, *pix
);
3023 pen
.setColor(palette().color(QPalette::Text
));
3024 painter
->setPen(pen
);
3025 painter
->setFont(info_font
);
3026 painter
->drawText(10, h
, str
);
3027 if (highligh_num
!= -1 && highligh_num
< unit_list
.count()) {
3028 painter
->drawText(10, height() - 5, str2
);
3031 if (point_size
< 0) {
3032 info_font
.setPixelSize(*f_size
);
3034 info_font
.setPointSize(*f_size
);
3036 cw
->put_to_corner();
3038 /****************************************************************
3039 Paint event, redirects to paint(...)
3040 *****************************************************************/
3041 void units_select::paintEvent(QPaintEvent
*event
)
3045 painter
.begin(this);
3046 paint(&painter
, event
);
3050 /****************************************************************
3051 Function from abstract fcwidget to update menu, its not needed
3052 cause widget is easy closable via right mouse click
3053 *****************************************************************/
3054 void units_select::update_menu()
3056 was_destroyed
= true;
3061 /****************************************************************
3062 Updates unit list on tile
3063 *****************************************************************/
3064 void units_select::update_units()
3067 struct unit_list
*punit_list
;
3069 if (utile
== NULL
) {
3070 struct unit
*punit
= head_of_units_in_focus();
3072 utile
= unit_tile(punit
);
3076 if (utile
!= nullptr) {
3077 punit_list
= utile
->units
;
3078 if (punit_list
!= nullptr) {
3079 unit_list_iterate(utile
->units
, punit
) {
3080 if (i
> show_line
* 4)
3081 unit_list
.push_back(punit
);
3083 } unit_list_iterate_end
;
3086 if (unit_list
.count() == 0) {
3091 /****************************************************************
3092 Close event for units_select, restores focus to map
3093 *****************************************************************/
3094 void units_select::closeEvent(QCloseEvent
* event
)
3096 gui()->mapview_wdg
->setFocus();
3097 QWidget::closeEvent(event
);
3100 /****************************************************************
3101 Mouse wheel event for units_select
3102 *****************************************************************/
3103 void units_select::wheelEvent(QWheelEvent
*event
)
3107 if (more
== false && utile
== NULL
) {
3110 nr
= qCeil(static_cast<qreal
>(unit_list_size(utile
->units
)) / 4) - 3;
3111 if (event
->delta() < 0) {
3113 show_line
= qMin(show_line
, nr
);
3116 show_line
= qMax(0, show_line
);
3124 /****************************************************************
3125 Keyboard handler for units_select
3126 *****************************************************************/
3127 void units_select::keyPressEvent(QKeyEvent
*event
)
3129 if (event
->key() == Qt::Key_Escape
) {
3130 was_destroyed
= true;
3134 QWidget::keyPressEvent(event
);
3138 /***************************************************************************
3139 Set current diplo dialog
3140 ***************************************************************************/
3141 void fc_client::set_diplo_dialog(choice_dialog
*widget
)
3143 opened_dialog
= widget
;
3146 /***************************************************************************
3147 Get current diplo dialog
3148 ***************************************************************************/
3149 choice_dialog
*fc_client::get_diplo_dialog()
3151 return opened_dialog
;
3154 /****************************************************************
3155 Give a warning when user is about to edit scenario with manually
3157 *****************************************************************/
3158 bool qtg_handmade_scenario_warning()
3160 /* Just tell the client common code to handle this. */
3164 /****************************************************************
3165 Unit wants to get into some transport on given tile.
3166 *****************************************************************/
3167 bool qtg_request_transport(struct unit
*pcargo
, struct tile
*ptile
)
3170 hud_unit_loader
*hul
;
3171 struct unit_list
*potential_transports
= unit_list_new();
3172 struct unit
*best_transport
= transporter_for_unit(pcargo
);
3174 unit_list_iterate(ptile
->units
, ptransport
) {
3175 if (can_unit_transport(ptransport
, pcargo
)
3176 && get_transporter_occupancy(ptransport
) < get_transporter_capacity(ptransport
)) {
3177 unit_list_append(potential_transports
, ptransport
);
3179 } unit_list_iterate_end
;
3181 tcount
= unit_list_size(potential_transports
);
3184 fc_assert(best_transport
== NULL
);
3185 unit_list_destroy(potential_transports
);
3187 return false; /* Unit was not handled here. */
3188 } else if (tcount
== 1) {
3189 /* There's exactly one potential transport - use it automatically */
3190 fc_assert(unit_list_get(potential_transports
, 0) == best_transport
);
3191 request_unit_load(pcargo
, unit_list_get(potential_transports
, 0), ptile
);
3193 unit_list_destroy(potential_transports
);
3198 hul
= new hud_unit_loader(pcargo
, ptile
);
3203 /***************************************************************************
3204 Popup detailed information about battle or save information for
3205 some kind of statistics
3206 ***************************************************************************/
3207 void qtg_popup_combat_info(int attacker_unit_id
, int defender_unit_id
,
3208 int attacker_hp
, int defender_hp
,
3209 bool make_winner_veteran
)