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