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