1 /*
2 Copyright (C) 2009-2021 Parallel Realities
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19 
20 #include "../headers.h"
21 
22 #include "../audio/audio.h"
23 #include "../audio/music.h"
24 #include "../game.h"
25 #include "../graphics/graphics.h"
26 #include "../hud.h"
27 #include "../init.h"
28 #include "../system/error.h"
29 #include "../system/load_save.h"
30 #include "about_menu.h"
31 #include "io_menu.h"
32 #include "medals_menu.h"
33 #include "ok_menu.h"
34 #include "options_menu.h"
35 #include "stats_menu.h"
36 #include "widget.h"
37 #include "yes_no_menu.h"
38 
39 extern Input input, menuInput;
40 extern Game game;
41 
42 static Menu menu;
43 
44 static void loadMenuLayout(void);
45 static void showOptionsMenu(void);
46 static void doMenu(void);
47 static void showIOMenu(void);
48 static void doNewGame(void);
49 static void doTutorial(void);
50 static void doQuit(void);
51 static void showMainMenu(void);
52 static void showAboutMenu(void);
53 static void showStatsMenu(void);
54 static void showMedalsMenu(void);
55 static void quitToTitle(void);
56 static void continueGame(void);
57 static void restartCheckpoint(void);
58 
drawMainMenu()59 void drawMainMenu()
60 {
61 	int i;
62 
63 	drawImage(menu.background, menu.x, menu.y, FALSE, 196);
64 
65 	for (i=0;i<menu.widgetCount;i++)
66 	{
67 		drawWidget(menu.widgets[i], &menu, menu.index == i);
68 	}
69 }
70 
doMenu()71 static void doMenu()
72 {
73 	Widget *w;
74 	int left, right, up, down, attack, xAxisMoved, yAxisMoved;
75 
76 	left = FALSE;
77 	right = FALSE;
78 	up = FALSE;
79 	down = FALSE;
80 	attack = FALSE;
81 
82 	if (menuInput.left == TRUE)
83 	{
84 		left = TRUE;
85 	}
86 
87 	else if (menuInput.right == TRUE)
88 	{
89 		right = TRUE;
90 	}
91 
92 	else if (menuInput.up == TRUE)
93 	{
94 		up = TRUE;
95 	}
96 
97 	else if (menuInput.down == TRUE)
98 	{
99 		down = TRUE;
100 	}
101 
102 	else if (menuInput.attack == TRUE)
103 	{
104 		attack = TRUE;
105 	}
106 
107 	else if (input.left == TRUE)
108 	{
109 		left = TRUE;
110 	}
111 
112 	else if (input.right == TRUE)
113 	{
114 		right = TRUE;
115 	}
116 
117 	else if (input.up == TRUE)
118 	{
119 		up = TRUE;
120 	}
121 
122 	else if (input.down == TRUE)
123 	{
124 		down = TRUE;
125 	}
126 
127 	else if (input.attack == TRUE)
128 	{
129 		attack = TRUE;
130 	}
131 
132 	if (down == TRUE)
133 	{
134 		do
135 		{
136 			menu.index++;
137 
138 			if (menu.index >= menu.widgetCount)
139 			{
140 				menu.index = 0;
141 			}
142 		}
143 
144 		while (menu.widgets[menu.index]->disabled == TRUE || menu.widgets[menu.index]->hidden == TRUE);
145 
146 		playSound("sound/common/click");
147 	}
148 
149 	else if (up == TRUE)
150 	{
151 		do
152 		{
153 			menu.index--;
154 
155 			if (menu.index < 0)
156 			{
157 				menu.index = menu.widgetCount - 1;
158 			}
159 		}
160 
161 		while (menu.widgets[menu.index]->disabled == TRUE || menu.widgets[menu.index]->hidden == TRUE);
162 
163 		playSound("sound/common/click");
164 	}
165 
166 	else if (attack == TRUE)
167 	{
168 		w = menu.widgets[menu.index];
169 
170 		if (w->clickAction != NULL)
171 		{
172 			playSound("sound/common/click");
173 
174 			w->clickAction();
175 		}
176 	}
177 
178 	else if (left == TRUE)
179 	{
180 		w = menu.widgets[menu.index];
181 
182 		if (w->rightAction != NULL)
183 		{
184 			playSound("sound/common/click");
185 
186 			w->rightAction();
187 		}
188 	}
189 
190 	else if (right == TRUE)
191 	{
192 		w = menu.widgets[menu.index];
193 
194 		if (w->leftAction != NULL)
195 		{
196 			playSound("sound/common/click");
197 
198 			w->leftAction();
199 		}
200 	}
201 
202 	xAxisMoved = input.xAxisMoved;
203 	yAxisMoved = input.yAxisMoved;
204 
205 	memset(&menuInput, 0, sizeof(Input));
206 	memset(&input, 0, sizeof(Input));
207 
208 	input.xAxisMoved = xAxisMoved;
209 	input.yAxisMoved = yAxisMoved;
210 }
211 
loadMenuLayout()212 static void loadMenuLayout()
213 {
214 	int i, x, y, w, maxWidth;
215 
216 	y = x = -1;
217 
218 	menu.widgetCount = 10;
219 
220 	menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount);
221 
222 	if (menu.widgets == NULL)
223 	{
224 		showErrorAndExit("Ran out of memory when creating Main Menu");
225 	}
226 
227 	menu.widgets[0] = createWidget(_("New Game"), NULL, NULL, NULL, &doNewGame, x, y, TRUE, 255, 255, 255);
228 
229 	menu.widgets[1] = createWidget(_("Continue"), NULL, NULL, NULL, &continueGame, x, y, TRUE, 255, 255, 255);
230 
231 	menu.widgets[1]->disabled = game.canContinue == TRUE ? FALSE : TRUE;
232 
233 	menu.widgets[2] = createWidget(_("Restart Checkpoint"), NULL, NULL, NULL, &restartCheckpoint, x, y, TRUE, 255, 255, 255);
234 
235 	menu.widgets[2]->disabled = game.canContinue == TRUE ? FALSE : TRUE;
236 
237 	menu.widgets[3] = createWidget(_("Tutorial"), NULL, NULL, NULL, &doTutorial, x, y, TRUE, 255, 255, 255);
238 
239 	menu.widgets[4] = createWidget(_("Load Game"), NULL, NULL, NULL, &showIOMenu, x, y, TRUE, 255, 255, 255);
240 
241 	menu.widgets[5] = createWidget(_("Options"), NULL, NULL, NULL, &showOptionsMenu, x, y, TRUE, 255, 255, 255);
242 
243 	menu.widgets[6] = createWidget(_("Statistics"), NULL, NULL, NULL, &showStatsMenu, x, y, TRUE, 255, 255, 255);
244 
245 	menu.widgets[7] = createWidget(_("Medals"), NULL, NULL, NULL, &showMedalsMenu, x, y, TRUE, 255, 255, 255);
246 
247 	menu.widgets[8] = createWidget(_("About"), NULL, NULL, NULL, &showAboutMenu, x, y, TRUE, 255, 255, 255);
248 
249 	menu.widgets[9] = createWidget(_("Quit"), NULL, NULL, NULL, &doQuit, x, y, TRUE, 255, 255, 255);
250 
251 	y = BUTTON_PADDING + BORDER_PADDING;
252 
253 	w = 0;
254 
255 	maxWidth = 0;
256 
257 	for (i=0;i<menu.widgetCount;i++)
258 	{
259 		if (menu.widgets[i]->label != NULL && menu.widgets[i]->normalState->w > maxWidth)
260 		{
261 			maxWidth = menu.widgets[i]->normalState->w;
262 		}
263 	}
264 
265 	for (i=0;i<menu.widgetCount;i++)
266 	{
267 		menu.widgets[i]->y = y;
268 
269 		if (menu.widgets[i]->x != -1)
270 		{
271 			menu.widgets[i]->x = BUTTON_PADDING + BORDER_PADDING;
272 		}
273 
274 		if (menu.widgets[i]->label != NULL)
275 		{
276 			menu.widgets[i]->label->y = y;
277 
278 			menu.widgets[i]->label->x = menu.widgets[i]->x + maxWidth + 10;
279 
280 			if (menu.widgets[i]->label->x + menu.widgets[i]->label->text->w > w)
281 			{
282 				w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w;
283 			}
284 		}
285 
286 		else
287 		{
288 			if (menu.widgets[i]->x + menu.widgets[i]->selectedState->w > w)
289 			{
290 				w = menu.widgets[i]->x + menu.widgets[i]->selectedState->w;
291 			}
292 		}
293 
294 		if (i != 1)
295 		{
296 			y += menu.widgets[i]->selectedState->h + BUTTON_PADDING;
297 		}
298 	}
299 
300 	menu.w = w + BUTTON_PADDING;
301 	menu.h = y - BORDER_PADDING;
302 
303 	menu.background = addBorder(createSurface(menu.w, menu.h, FALSE), 255, 255, 255, 0, 0, 0);
304 
305 	menu.x = (SCREEN_WIDTH - menu.background->w) / 2;
306 	menu.y = (SCREEN_HEIGHT - menu.background->h) / 2;
307 }
308 
freeMainMenu()309 void freeMainMenu()
310 {
311 	int i;
312 
313 	if (menu.widgets != NULL)
314 	{
315 		for (i=0;i<menu.widgetCount;i++)
316 		{
317 			freeWidget(menu.widgets[i]);
318 		}
319 
320 		free(menu.widgets);
321 
322 		menu.widgets = NULL;
323 	}
324 
325 	if (menu.background != NULL)
326 	{
327 		destroyTexture(menu.background);
328 
329 		menu.background = NULL;
330 	}
331 }
332 
initMainMenu()333 Menu *initMainMenu()
334 {
335 	menu.action = &doMenu;
336 
337 	if (menu.widgets == NULL)
338 	{
339 		loadMenuLayout();
340 	}
341 
342 	menu.widgets[1]->disabled = game.canContinue == TRUE ? FALSE : TRUE;
343 
344 	menu.widgets[1]->hidden = game.previousStatus == IN_TITLE ? FALSE : TRUE;
345 
346 	menu.widgets[2]->disabled = game.canContinue == TRUE ? FALSE : TRUE;
347 
348 	menu.widgets[2]->hidden = game.previousStatus == IN_GAME ? FALSE : TRUE;
349 
350 	menu.widgets[6]->disabled = game.previousStatus == IN_GAME ? FALSE : TRUE;
351 
352 	menu.returnAction = NULL;
353 
354 	return &menu;
355 }
356 
showOptionsMenu()357 static void showOptionsMenu()
358 {
359 	game.menu = initOptionsMenu();
360 
361 	game.drawMenu = &drawOptionsMenu;
362 }
363 
showAboutMenu()364 static void showAboutMenu()
365 {
366 	game.menu = initAboutMenu();
367 
368 	game.drawMenu = &drawAboutMenu;
369 }
370 
showStatsMenu()371 static void showStatsMenu()
372 {
373 	game.menu = initStatsMenu();
374 
375 	game.drawMenu = &drawStatsMenu;
376 }
377 
showIOMenu()378 static void showIOMenu()
379 {
380 	game.menu = initIOMenu(FALSE);
381 
382 	game.drawMenu = &drawIOMenu;
383 }
384 
showMedalsMenu()385 static void showMedalsMenu()
386 {
387 	game.menu = initMedalsMenu();
388 
389 	game.drawMenu = &drawMedalsMenu;
390 }
391 
doNewGame()392 static void doNewGame()
393 {
394 	if (game.previousStatus == IN_TITLE)
395 	{
396 		newGame();
397 	}
398 
399 	else
400 	{
401 		game.menu = initYesNoMenu(_("Start a new game?"), &newGame, &showMainMenu);
402 
403 		game.drawMenu = &drawYesNoMenu;
404 	}
405 }
406 
doTutorial()407 static void doTutorial()
408 {
409 	if (game.previousStatus == IN_TITLE)
410 	{
411 		tutorial();
412 	}
413 
414 	else
415 	{
416 		game.menu = initYesNoMenu(_("Play the tutorial?"), &tutorial, &showMainMenu);
417 
418 		game.drawMenu = &drawYesNoMenu;
419 	}
420 }
421 
doQuit()422 static void doQuit()
423 {
424 	if (game.previousStatus == IN_TITLE)
425 	{
426 		quitGame();
427 	}
428 
429 	else
430 	{
431 		game.menu = initYesNoMenu(_("Exit the game?"), &quitToTitle, &showMainMenu);
432 
433 		game.drawMenu = &drawYesNoMenu;
434 	}
435 }
436 
continueGame()437 static void continueGame()
438 {
439 	if (loadGame(getMostRecentSave()) == TRUE)
440 	{
441 		menu.index = 0;
442 
443 		menu.returnAction = NULL;
444 
445 		freeMessageQueue();
446 
447 		setInfoBoxMessage(60, 255, 255, 255, _("Game Loaded"));
448 
449 		game.paused = FALSE;
450 	}
451 
452 	else
453 	{
454 		game.menu = initOKMenu(_("Failed to load game"), &showIOMenu);
455 
456 		game.drawMenu = &drawOKMenu;
457 	}
458 }
459 
restartCheckpoint()460 static void restartCheckpoint()
461 {
462 	getContinuePoint();
463 }
464 
quitToTitle()465 static void quitToTitle()
466 {
467 	menu.index = 0;
468 
469 	pauseGame();
470 
471 	setTransition(TRANSITION_OUT, &titleScreen);
472 
473 	fadeOutMusic(500);
474 }
475 
showMainMenu()476 static void showMainMenu()
477 {
478 	game.menu = initMainMenu();
479 
480 	game.drawMenu = &drawMainMenu;
481 }
482