1 /*****************************************************************************
2  * Copyright (c) 2014-2020 OpenRCT2 developers
3  *
4  * For a complete list of all authors, please refer to contributors.md
5  * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
6  *
7  * OpenRCT2 is licensed under the GNU General Public License version 3.
8  *****************************************************************************/
9 
10 #include <iterator>
11 #include <openrct2-ui/interface/Widget.h>
12 #include <openrct2-ui/windows/Window.h>
13 #include <openrct2/Context.h>
14 #include <openrct2/Game.h>
15 #include <openrct2/OpenRCT2.h>
16 #include <openrct2/audio/audio.h>
17 #include <openrct2/config/Config.h>
18 #include <openrct2/localisation/Localisation.h>
19 #include <openrct2/network/network.h>
20 #include <openrct2/scenario/Scenario.h>
21 #include <openrct2/windows/Intent.h>
22 
23 static constexpr const int32_t WH_SAVE = 54;
24 static constexpr const int32_t WW_SAVE = 260;
25 static constexpr const int32_t WH_QUIT = 38;
26 static constexpr const int32_t WW_QUIT = 177;
27 
28 // clang-format off
29 enum WINDOW_SAVE_PROMPT_WIDGET_IDX {
30     WIDX_BACKGROUND,
31     WIDX_TITLE,
32     WIDX_CLOSE,
33     WIDX_LABEL,
34     WIDX_SAVE,
35     WIDX_DONT_SAVE,
36     WIDX_CANCEL
37 };
38 
39 static rct_widget window_save_prompt_widgets[] = {
40     WINDOW_SHIM_WHITE(STR_NONE, WW_SAVE, WH_SAVE),
41     MakeWidget({  2, 19}, {256, 12}, WindowWidgetType::LabelCentred, WindowColour::Primary, STR_EMPTY                ), // question/label
42     MakeWidget({  8, 35}, { 78, 14}, WindowWidgetType::Button,        WindowColour::Primary, STR_SAVE_PROMPT_SAVE     ), // save
43     MakeWidget({ 91, 35}, { 78, 14}, WindowWidgetType::Button,        WindowColour::Primary, STR_SAVE_PROMPT_DONT_SAVE), // don't save
44     MakeWidget({174, 35}, { 78, 14}, WindowWidgetType::Button,        WindowColour::Primary, STR_SAVE_PROMPT_CANCEL   ), // cancel
45     WIDGETS_END,
46 };
47 
48 enum WINDOW_QUIT_PROMPT_WIDGET_IDX {
49     WQIDX_BACKGROUND,
50     WQIDX_TITLE,
51     WQIDX_CLOSE,
52     WQIDX_OK,
53     WQIDX_CANCEL
54 };
55 
56 static rct_widget window_quit_prompt_widgets[] = {
57     WINDOW_SHIM_WHITE(STR_QUIT_GAME_PROMPT_TITLE, WW_QUIT, WH_QUIT),
58     MakeWidget({ 8, 19}, {78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_OK    ), // ok
59     MakeWidget({91, 19}, {78, 14}, WindowWidgetType::Button, WindowColour::Primary, STR_CANCEL), // cancel
60     WIDGETS_END,
61 };
62 
63 static constexpr const rct_string_id window_save_prompt_labels[][2] = {
64     { STR_LOAD_GAME_PROMPT_TITLE,   STR_SAVE_BEFORE_LOADING },
65     { STR_QUIT_GAME_PROMPT_TITLE,   STR_SAVE_BEFORE_QUITTING },
66     { STR_QUIT_GAME_2_PROMPT_TITLE, STR_SAVE_BEFORE_QUITTING_2 },
67 };
68 
69 
70 static void window_save_prompt_close(rct_window *w);
71 static void window_save_prompt_mouseup(rct_window *w, rct_widgetindex widgetIndex);
72 static void window_save_prompt_paint(rct_window *w, rct_drawpixelinfo *dpi);
73 static void window_save_prompt_callback(int32_t result, const utf8 * path);
74 
75 static rct_window_event_list window_save_prompt_events([](auto& events)
__anon91dca2f80102(auto& events) 76 {
77     events.close = &window_save_prompt_close;
78     events.mouse_up = &window_save_prompt_mouseup;
79     events.paint = &window_save_prompt_paint;
80 });
81 // clang-format on
82 
83 /**
84  *
85  *  rct2: 0x0066DCBE
86  */
window_save_prompt_open()87 rct_window* window_save_prompt_open()
88 {
89     int32_t width, height;
90     rct_string_id stringId;
91     rct_window* window;
92     PromptMode prompt_mode;
93     rct_widget* widgets;
94     uint64_t enabled_widgets;
95 
96     prompt_mode = gSavePromptMode;
97     if (prompt_mode == PromptMode::Quit)
98         prompt_mode = PromptMode::SaveBeforeQuit;
99 
100     // do not show save prompt if we're in the title demo and click on load game
101     if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO)
102     {
103         game_load_or_quit_no_save_prompt();
104         return nullptr;
105     }
106 
107     if (!gConfigGeneral.confirmation_prompt)
108     {
109         /* game_load_or_quit_no_save_prompt() will exec requested task and close this window
110          * immediately again.
111          * TODO restructure these functions when we're sure game_load_or_quit_no_save_prompt()
112          * and game_load_or_quit() are not called by the original binary anymore.
113          */
114 
115         if (gScreenAge < 3840 && network_get_mode() == NETWORK_MODE_NONE)
116         {
117             game_load_or_quit_no_save_prompt();
118             return nullptr;
119         }
120     }
121 
122     // Check if window is already open
123     window = window_bring_to_front_by_class(WC_SAVE_PROMPT);
124     if (window != nullptr)
125     {
126         window_close(window);
127     }
128 
129     if (gScreenFlags & (SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))
130     {
131         widgets = window_quit_prompt_widgets;
132         enabled_widgets = (1 << WQIDX_CLOSE) | (1 << WQIDX_OK) | (1 << WQIDX_CANCEL);
133         width = WW_QUIT;
134         height = WH_QUIT;
135     }
136     else
137     {
138         widgets = window_save_prompt_widgets;
139         enabled_widgets = (1ULL << WIDX_CLOSE) | (1ULL << WIDX_SAVE) | (1ULL << WIDX_DONT_SAVE) | (1ULL << WIDX_CANCEL);
140         width = WW_SAVE;
141         height = WH_SAVE;
142     }
143 
144     if (EnumValue(prompt_mode) >= std::size(window_save_prompt_labels))
145     {
146         log_warning("Invalid save prompt mode %u", prompt_mode);
147         return nullptr;
148     }
149     window = WindowCreateCentred(width, height, &window_save_prompt_events, WC_SAVE_PROMPT, WF_TRANSPARENT | WF_STICK_TO_FRONT);
150 
151     window->widgets = widgets;
152     window->enabled_widgets = enabled_widgets;
153     WindowInitScrollWidgets(window);
154 
155     // Pause the game if not network play.
156     if (network_get_mode() == NETWORK_MODE_NONE)
157     {
158         gGamePaused |= GAME_PAUSED_MODAL;
159         OpenRCT2::Audio::StopAll();
160     }
161 
162     window_invalidate_by_class(WC_TOP_TOOLBAR);
163 
164     stringId = window_save_prompt_labels[EnumValue(prompt_mode)][0];
165     if (stringId == STR_LOAD_GAME_PROMPT_TITLE && gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
166         stringId = STR_LOAD_LANDSCAPE_PROMPT_TITLE;
167     if (stringId == STR_QUIT_GAME_PROMPT_TITLE && gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR)
168         stringId = STR_QUIT_SCENARIO_EDITOR;
169     window_save_prompt_widgets[WIDX_TITLE].text = stringId;
170     window_save_prompt_widgets[WIDX_LABEL].text = window_save_prompt_labels[EnumValue(prompt_mode)][1];
171 
172     return window;
173 }
174 
175 /**
176  *
177  *  rct2: 0x0066DF17
178  */
window_save_prompt_close(rct_window * w)179 static void window_save_prompt_close(rct_window* w)
180 {
181     // Unpause the game
182     if (network_get_mode() == NETWORK_MODE_NONE)
183     {
184         gGamePaused &= ~GAME_PAUSED_MODAL;
185         OpenRCT2::Audio::Resume();
186     }
187 
188     window_invalidate_by_class(WC_TOP_TOOLBAR);
189 }
190 
191 /**
192  *
193  *  rct2: 0x0066DDF2
194  */
window_save_prompt_mouseup(rct_window * w,rct_widgetindex widgetIndex)195 static void window_save_prompt_mouseup(rct_window* w, rct_widgetindex widgetIndex)
196 {
197     if (gScreenFlags & (SCREEN_FLAGS_TITLE_DEMO | SCREEN_FLAGS_TRACK_DESIGNER | SCREEN_FLAGS_TRACK_MANAGER))
198     {
199         switch (widgetIndex)
200         {
201             case WQIDX_OK:
202                 game_load_or_quit_no_save_prompt();
203                 break;
204             case WQIDX_CLOSE:
205             case WQIDX_CANCEL:
206                 window_close(w);
207                 break;
208         }
209         return;
210     }
211 
212     switch (widgetIndex)
213     {
214         case WIDX_SAVE:
215         {
216             Intent* intent;
217 
218             if (gScreenFlags & (SCREEN_FLAGS_EDITOR))
219             {
220                 intent = new Intent(WC_LOADSAVE);
221                 intent->putExtra(INTENT_EXTRA_LOADSAVE_TYPE, LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE);
222                 intent->putExtra(INTENT_EXTRA_PATH, gScenarioName);
223             }
224             else
225             {
226                 intent = static_cast<Intent*>(create_save_game_as_intent());
227             }
228             window_close(w);
229             intent->putExtra(INTENT_EXTRA_CALLBACK, reinterpret_cast<void*>(window_save_prompt_callback));
230             context_open_intent(intent);
231             delete intent;
232             break;
233         }
234         case WIDX_DONT_SAVE:
235             game_load_or_quit_no_save_prompt();
236             return;
237         case WIDX_CLOSE:
238         case WIDX_CANCEL:
239             window_close(w);
240             return;
241     }
242 }
243 
window_save_prompt_paint(rct_window * w,rct_drawpixelinfo * dpi)244 static void window_save_prompt_paint(rct_window* w, rct_drawpixelinfo* dpi)
245 {
246     WindowDrawWidgets(w, dpi);
247 }
248 
window_save_prompt_callback(int32_t result,const utf8 * path)249 static void window_save_prompt_callback(int32_t result, const utf8* path)
250 {
251     if (result == MODAL_RESULT_OK)
252     {
253         game_load_or_quit_no_save_prompt();
254     }
255 }
256