1 #include "top_menu.h"
2
3 #include "building/construction.h"
4 #include "city/constants.h"
5 #include "city/finance.h"
6 #include "city/population.h"
7 #include "core/lang.h"
8 #include "game/file.h"
9 #include "game/settings.h"
10 #include "game/state.h"
11 #include "game/system.h"
12 #include "game/time.h"
13 #include "game/undo.h"
14 #include "graphics/graphics.h"
15 #include "graphics/image.h"
16 #include "graphics/lang_text.h"
17 #include "graphics/menu.h"
18 #include "graphics/screen.h"
19 #include "graphics/text.h"
20 #include "graphics/window.h"
21 #include "scenario/property.h"
22 #include "widget/city.h"
23 #include "window/advisors.h"
24 #include "window/city.h"
25 #include "window/config.h"
26 #include "window/file_dialog.h"
27 #include "window/hotkey_config.h"
28 #include "window/main_menu.h"
29 #include "window/message_dialog.h"
30 #include "window/mission_briefing.h"
31 #include "window/popup_dialog.h"
32
33 enum {
34 INFO_NONE = 0,
35 INFO_FUNDS = 1,
36 INFO_POPULATION = 2,
37 INFO_DATE = 3
38 };
39
40 static void menu_file_replay_map(int param);
41 static void menu_file_load_game(int param);
42 static void menu_file_save_game(int param);
43 static void menu_file_delete_game(int param);
44 static void menu_file_exit_to_main_menu(int param);
45 static void menu_file_exit_game(int param);
46
47 static void menu_options_general(int param);
48 static void menu_options_user_interface(int param);
49 static void menu_options_gameplay(int param);
50 static void menu_options_city_management(int param);
51 static void menu_options_hotkeys(int param);
52 static void menu_options_autosave(int param);
53
54 static void menu_help_help(int param);
55 static void menu_help_mouse_help(int param);
56 static void menu_help_warnings(int param);
57 static void menu_help_about(int param);
58
59 static void menu_advisors_go_to(int advisor);
60
61 static menu_item menu_file[] = {
62 {1, 2, menu_file_replay_map, 0},
63 {1, 3, menu_file_load_game, 0},
64 {1, 4, menu_file_save_game, 0},
65 {1, 6, menu_file_delete_game, 0},
66 {CUSTOM_TRANSLATION, TR_BUTTON_BACK_TO_MAIN_MENU, menu_file_exit_to_main_menu, 0},
67 {1, 5, menu_file_exit_game, 0},
68 };
69
70 static menu_item menu_options[] = {
71 {CUSTOM_TRANSLATION, TR_CONFIG_HEADER_GENERAL, menu_options_general, 0},
72 {CUSTOM_TRANSLATION, TR_CONFIG_HEADER_UI_CHANGES, menu_options_user_interface, 0},
73 {CUSTOM_TRANSLATION, TR_CONFIG_HEADER_GAMEPLAY_CHANGES, menu_options_gameplay, 0},
74 {CUSTOM_TRANSLATION, TR_CONFIG_HEADER_CITY_MANAGEMENT_CHANGES, menu_options_city_management, 0},
75 {CUSTOM_TRANSLATION, TR_BUTTON_CONFIGURE_HOTKEYS, menu_options_hotkeys, 0},
76 {19, 51, menu_options_autosave, 0}
77 };
78
79 static menu_item menu_help[] = {
80 {3, 1, menu_help_help, 0},
81 {3, 2, menu_help_mouse_help, 0},
82 {3, 5, menu_help_warnings, 0},
83 {3, 7, menu_help_about, 0},
84 };
85
86 static menu_item menu_advisors[] = {
87 {4, 1, menu_advisors_go_to, ADVISOR_LABOR},
88 {4, 2, menu_advisors_go_to, ADVISOR_MILITARY},
89 {4, 3, menu_advisors_go_to, ADVISOR_IMPERIAL},
90 {4, 4, menu_advisors_go_to, ADVISOR_RATINGS},
91 {4, 5, menu_advisors_go_to, ADVISOR_TRADE},
92 {4, 6, menu_advisors_go_to, ADVISOR_POPULATION},
93 {CUSTOM_TRANSLATION, TR_HEADER_HOUSING, menu_advisors_go_to, ADVISOR_HOUSING},
94 {4, 7, menu_advisors_go_to, ADVISOR_HEALTH},
95 {4, 8, menu_advisors_go_to, ADVISOR_EDUCATION},
96 {4, 9, menu_advisors_go_to, ADVISOR_ENTERTAINMENT},
97 {4, 10, menu_advisors_go_to, ADVISOR_RELIGION},
98 {4, 11, menu_advisors_go_to, ADVISOR_FINANCIAL},
99 {4, 12, menu_advisors_go_to, ADVISOR_CHIEF},
100 };
101
102 static menu_bar_item menu[] = {
103 {1, menu_file, 6},
104 {2, menu_options, 6},
105 {3, menu_help, 4},
106 {4, menu_advisors, 13},
107 };
108
109 static const int INDEX_OPTIONS = 1;
110 static const int INDEX_HELP = 2;
111
112 static struct {
113 int offset_funds;
114 int offset_population;
115 int offset_date;
116
117 int open_sub_menu;
118 int focus_menu_id;
119 int focus_sub_menu_id;
120 } data;
121
122 static struct {
123 int population;
124 int treasury;
125 int month;
126 } drawn;
127
clear_state(void)128 static void clear_state(void)
129 {
130 data.open_sub_menu = 0;
131 data.focus_menu_id = 0;
132 data.focus_sub_menu_id = 0;
133 }
134
set_text_for_autosave(void)135 static void set_text_for_autosave(void)
136 {
137 menu_update_text(&menu[INDEX_OPTIONS], 5, setting_monthly_autosave() ? 51 : 52);
138 }
139
set_text_for_tooltips(void)140 static void set_text_for_tooltips(void)
141 {
142 int new_text;
143 switch (setting_tooltips()) {
144 case TOOLTIPS_NONE:
145 new_text = 2;
146 break;
147 case TOOLTIPS_SOME:
148 new_text = 3;
149 break;
150 case TOOLTIPS_FULL:
151 new_text = 4;
152 break;
153 default:
154 return;
155 }
156 menu_update_text(&menu[INDEX_HELP], 1, new_text);
157 }
158
set_text_for_warnings(void)159 static void set_text_for_warnings(void)
160 {
161 menu_update_text(&menu[INDEX_HELP], 2, setting_warnings() ? 6 : 5);
162 }
163
init(void)164 static void init(void)
165 {
166 set_text_for_autosave();
167 set_text_for_tooltips();
168 set_text_for_warnings();
169 }
170
draw_background(void)171 static void draw_background(void)
172 {
173 window_city_draw_panels();
174 window_city_draw();
175 }
176
draw_foreground(void)177 static void draw_foreground(void)
178 {
179 if (data.open_sub_menu) {
180 menu_draw(&menu[data.open_sub_menu - 1], data.focus_sub_menu_id);
181 }
182 }
183
handle_input(const mouse * m,const hotkeys * h)184 static void handle_input(const mouse *m, const hotkeys *h)
185 {
186 widget_top_menu_handle_input(m, h);
187 }
188
top_menu_window_show(void)189 static void top_menu_window_show(void)
190 {
191 window_type window = {
192 WINDOW_TOP_MENU,
193 draw_background,
194 draw_foreground,
195 handle_input
196 };
197 init();
198 window_show(&window);
199 }
200
refresh_background(void)201 static void refresh_background(void)
202 {
203 int block_width = 24;
204 int image_base = image_group(GROUP_TOP_MENU);
205 int s_width = screen_width();
206 for (int i = 0; i * block_width < s_width; i++) {
207 image_draw(image_base + i % 8, i * block_width, 0);
208 }
209 // black panels for funds/pop/time
210 if (s_width < 800) {
211 image_draw(image_base + 14, 336, 0);
212 } else if (s_width < 1024) {
213 image_draw(image_base + 14, 336, 0);
214 image_draw(image_base + 14, 456, 0);
215 image_draw(image_base + 14, 648, 0);
216 } else {
217 image_draw(image_base + 14, 480, 0);
218 image_draw(image_base + 14, 624, 0);
219 image_draw(image_base + 14, 840, 0);
220 }
221 }
222
widget_top_menu_draw(int force)223 void widget_top_menu_draw(int force)
224 {
225 if (!force && drawn.treasury == city_finance_treasury() &&
226 drawn.population == city_population() &&
227 drawn.month == game_time_month()) {
228 return;
229 }
230
231 int s_width = screen_width();
232
233 refresh_background();
234 menu_bar_draw(menu, 4, s_width < 1024 ? 338 : 493);
235
236 color_t treasure_color = COLOR_WHITE;
237 int treasury = city_finance_treasury();
238 if (treasury < 0) {
239 treasure_color = COLOR_FONT_RED;
240 }
241 if (s_width < 800) {
242 data.offset_funds = 338;
243 data.offset_population = 453;
244 data.offset_date = 547;
245
246 int width = lang_text_draw_colored(6, 0, 350, 5, FONT_NORMAL_PLAIN, treasure_color);
247 text_draw_number(treasury, '@', " ", 346 + width, 5, FONT_NORMAL_PLAIN, treasure_color);
248
249 width = lang_text_draw(6, 1, 458, 5, FONT_NORMAL_GREEN);
250 text_draw_number(city_population(), '@', " ", 450 + width, 5, FONT_NORMAL_GREEN, 0);
251
252 lang_text_draw_month_year_max_width(game_time_month(), game_time_year(), 540, 5, 100, FONT_NORMAL_GREEN, 0);
253 } else if (s_width < 1024) {
254 data.offset_funds = 338;
255 data.offset_population = 458;
256 data.offset_date = 652;
257
258 int width = lang_text_draw_colored(6, 0, 350, 5, FONT_NORMAL_PLAIN, treasure_color);
259 text_draw_number(treasury, '@', " ", 346 + width, 5, FONT_NORMAL_PLAIN, treasure_color);
260
261 width = lang_text_draw_colored(6, 1, 470, 5, FONT_NORMAL_PLAIN, COLOR_WHITE);
262 text_draw_number(city_population(), '@', " ", 466 + width, 5, FONT_NORMAL_PLAIN, COLOR_WHITE);
263
264 lang_text_draw_month_year_max_width(game_time_month(), game_time_year(),
265 655, 5, 110, FONT_NORMAL_PLAIN, COLOR_FONT_YELLOW);
266 } else {
267 data.offset_funds = 493;
268 data.offset_population = 637;
269 data.offset_date = 852;
270
271 int width = lang_text_draw_colored(6, 0, 495, 5, FONT_NORMAL_PLAIN, treasure_color);
272 text_draw_number(treasury, '@', " ", 501 + width, 5, FONT_NORMAL_PLAIN, treasure_color);
273
274 width = lang_text_draw_colored(6, 1, 645, 5, FONT_NORMAL_PLAIN, COLOR_WHITE);
275 text_draw_number(city_population(), '@', " ", 651 + width, 5, FONT_NORMAL_PLAIN, COLOR_WHITE);
276
277 lang_text_draw_month_year_max_width(game_time_month(), game_time_year(),
278 850, 5, 110, FONT_NORMAL_PLAIN, COLOR_FONT_YELLOW);
279 }
280 drawn.treasury = treasury;
281 drawn.population = city_population();
282 drawn.month = game_time_month();
283 }
284
handle_input_submenu(const mouse * m,const hotkeys * h)285 static int handle_input_submenu(const mouse *m, const hotkeys *h)
286 {
287 if (m->right.went_up || h->escape_pressed) {
288 clear_state();
289 window_go_back();
290 return 1;
291 }
292 int menu_id = menu_bar_handle_mouse(m, menu, 4, &data.focus_menu_id);
293 if (menu_id && menu_id != data.open_sub_menu) {
294 window_request_refresh();
295 data.open_sub_menu = menu_id;
296 }
297 if (!menu_handle_mouse(m, &menu[data.open_sub_menu - 1], &data.focus_sub_menu_id)) {
298 if (m->left.went_up) {
299 clear_state();
300 window_go_back();
301 return 1;
302 }
303 }
304 return 0;
305 }
306
get_info_id(int mouse_x,int mouse_y)307 static int get_info_id(int mouse_x, int mouse_y)
308 {
309 if (mouse_y < 4 || mouse_y >= 18) {
310 return INFO_NONE;
311 }
312 if (mouse_x > data.offset_funds && mouse_x < data.offset_funds + 128) {
313 return INFO_FUNDS;
314 }
315 if (mouse_x > data.offset_population && mouse_x < data.offset_population + 128) {
316 return INFO_POPULATION;
317 }
318 if (mouse_x > data.offset_date && mouse_x < data.offset_date + 128) {
319 return INFO_DATE;
320 }
321 return INFO_NONE;
322 }
323
handle_right_click(int type)324 static int handle_right_click(int type)
325 {
326 if (type == INFO_NONE) {
327 return 0;
328 }
329 if (type == INFO_FUNDS) {
330 window_message_dialog_show(MESSAGE_DIALOG_TOP_FUNDS, window_city_draw_all);
331 } else if (type == INFO_POPULATION) {
332 window_message_dialog_show(MESSAGE_DIALOG_TOP_POPULATION, window_city_draw_all);
333 } else if (type == INFO_DATE) {
334 window_message_dialog_show(MESSAGE_DIALOG_TOP_DATE, window_city_draw_all);
335 }
336 return 1;
337 }
338
handle_mouse_menu(const mouse * m)339 static int handle_mouse_menu(const mouse *m)
340 {
341 int menu_id = menu_bar_handle_mouse(m, menu, 4, &data.focus_menu_id);
342 if (menu_id && m->left.went_up) {
343 data.open_sub_menu = menu_id;
344 top_menu_window_show();
345 return 1;
346 }
347 if (m->right.went_up) {
348 return handle_right_click(get_info_id(m->x, m->y));
349 }
350 return 0;
351 }
352
widget_top_menu_handle_input(const mouse * m,const hotkeys * h)353 int widget_top_menu_handle_input(const mouse *m, const hotkeys *h)
354 {
355 if (widget_city_has_input()) {
356 return 0;
357 }
358 if (data.open_sub_menu) {
359 return handle_input_submenu(m, h);
360 } else {
361 return handle_mouse_menu(m);
362 }
363 }
364
widget_top_menu_get_tooltip_text(tooltip_context * c)365 int widget_top_menu_get_tooltip_text(tooltip_context *c)
366 {
367 if (data.focus_menu_id) {
368 return 49 + data.focus_menu_id;
369 }
370 int button_id = get_info_id(c->mouse_x, c->mouse_y);
371 if (button_id) {
372 return 59 + button_id;
373 }
374 return 0;
375 }
376
replay_map_confirmed(int confirmed,int checked)377 static void replay_map_confirmed(int confirmed, int checked)
378 {
379 if (!confirmed) {
380 window_city_show();
381 return;
382 }
383 if (scenario_is_custom()) {
384 game_file_start_scenario_by_name(scenario_name());
385 window_city_show();
386 } else {
387 scenario_save_campaign_player_name();
388 window_mission_briefing_show();
389 }
390 }
391
menu_file_replay_map(int param)392 static void menu_file_replay_map(int param)
393 {
394 clear_state();
395 building_construction_clear_type();
396 window_popup_dialog_show_confirmation(lang_get_string(1, 2), 0, 0, replay_map_confirmed);
397 }
398
menu_file_load_game(int param)399 static void menu_file_load_game(int param)
400 {
401 clear_state();
402 building_construction_clear_type();
403 window_go_back();
404 window_file_dialog_show(FILE_TYPE_SAVED_GAME, FILE_DIALOG_LOAD);
405 }
406
menu_file_save_game(int param)407 static void menu_file_save_game(int param)
408 {
409 clear_state();
410 window_go_back();
411 window_file_dialog_show(FILE_TYPE_SAVED_GAME, FILE_DIALOG_SAVE);
412 }
413
menu_file_delete_game(int param)414 static void menu_file_delete_game(int param)
415 {
416 clear_state();
417 window_go_back();
418 window_file_dialog_show(FILE_TYPE_SAVED_GAME, FILE_DIALOG_DELETE);
419 }
420
menu_file_confirm_exit(int accepted,int checked)421 static void menu_file_confirm_exit(int accepted, int checked)
422 {
423 if (accepted) {
424 system_exit();
425 } else {
426 window_city_return();
427 }
428 }
429
main_menu_confirmed(int confirmed,int checked)430 static void main_menu_confirmed(int confirmed, int checked)
431 {
432 if (!confirmed) {
433 window_city_show();
434 return;
435 }
436 building_construction_clear_type();
437 game_undo_disable();
438 game_state_reset_overlay();
439 window_main_menu_show(1);
440 }
441
menu_file_exit_to_main_menu(int param)442 static void menu_file_exit_to_main_menu(int param)
443 {
444 clear_state();
445 window_popup_dialog_show_confirmation(translation_for(TR_BUTTON_BACK_TO_MAIN_MENU), 0, 0,
446 main_menu_confirmed);
447 }
448
menu_file_exit_game(int param)449 static void menu_file_exit_game(int param)
450 {
451 clear_state();
452 window_popup_dialog_show(POPUP_DIALOG_QUIT, menu_file_confirm_exit, 1);
453 }
454
menu_options_general(int param)455 static void menu_options_general(int param)
456 {
457 clear_state();
458 window_go_back();
459 window_config_show(CONFIG_PAGE_GENERAL, 0);
460 }
461
menu_options_user_interface(int param)462 static void menu_options_user_interface(int param)
463 {
464 clear_state();
465 window_go_back();
466 window_config_show(CONFIG_PAGE_UI_CHANGES, 0);
467 }
468
menu_options_gameplay(int param)469 static void menu_options_gameplay(int param)
470 {
471 clear_state();
472 window_go_back();
473 window_config_show(CONFIG_PAGE_GAMEPLAY_CHANGES, 0);
474 }
475
menu_options_city_management(int param)476 static void menu_options_city_management(int param)
477 {
478 clear_state();
479 window_go_back();
480 window_config_show(CONFIG_PAGE_CITY_MANAGEMENT_CHANGES, 0);
481 }
482
menu_options_hotkeys(int param)483 static void menu_options_hotkeys(int param)
484 {
485 clear_state();
486 window_go_back();
487 window_hotkey_config_show();
488 }
489
menu_options_autosave(int param)490 static void menu_options_autosave(int param)
491 {
492 setting_toggle_monthly_autosave();
493 set_text_for_autosave();
494 }
495
menu_help_help(int param)496 static void menu_help_help(int param)
497 {
498 clear_state();
499 window_go_back();
500 window_message_dialog_show(MESSAGE_DIALOG_HELP, window_city_draw_all);
501 }
502
menu_help_mouse_help(int param)503 static void menu_help_mouse_help(int param)
504 {
505 setting_cycle_tooltips();
506 set_text_for_tooltips();
507 }
508
menu_help_warnings(int param)509 static void menu_help_warnings(int param)
510 {
511 setting_toggle_warnings();
512 set_text_for_warnings();
513 }
514
menu_help_about(int param)515 static void menu_help_about(int param)
516 {
517 clear_state();
518 window_go_back();
519 window_message_dialog_show(MESSAGE_DIALOG_ABOUT, window_city_draw_all);
520 }
521
menu_advisors_go_to(int advisor)522 static void menu_advisors_go_to(int advisor)
523 {
524 clear_state();
525 window_go_back();
526 window_advisors_show_advisor(advisor);
527 }
528