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 "../draw.h"
25 #include "../graphics/graphics.h"
26 #include "../init.h"
27 #include "../system/error.h"
28 #include "label.h"
29 #include "options_menu.h"
30 #include "widget.h"
31 
32 extern Input input, menuInput;
33 extern Game game;
34 extern Control control;
35 
36 static Menu menu;
37 
38 static void loadMenuLayout(void);
39 static void showOptionsMenu(void);
40 static void doMenu(void);
41 static char *getVolumePercent(int);
42 static void toggleSound(void);
43 static void changeVolume(int *, Widget *, int);
44 static void lowerSFXVolume(void);
45 static void raiseSFXVolume(void);
46 static void lowerMusicVolume(void);
47 static void raiseMusicVolume(void);
48 static void toggleQuality(void);
49 static char *getQuality(void);
50 
drawSoundMenu()51 void drawSoundMenu()
52 {
53 	int i;
54 
55 	drawImage(menu.background, menu.x, menu.y, FALSE, 196);
56 
57 	for (i=0;i<menu.widgetCount;i++)
58 	{
59 		drawWidget(menu.widgets[i], &menu, menu.index == i);
60 	}
61 }
62 
doMenu()63 static void doMenu()
64 {
65 	Widget *w;
66 	int left, right, up, down, attack, xAxisMoved, yAxisMoved;
67 
68 	left = FALSE;
69 	right = FALSE;
70 	up = FALSE;
71 	down = FALSE;
72 	attack = FALSE;
73 
74 	if (menuInput.left == TRUE)
75 	{
76 		left = TRUE;
77 	}
78 
79 	else if (menuInput.right == TRUE)
80 	{
81 		right = TRUE;
82 	}
83 
84 	else if (menuInput.up == TRUE)
85 	{
86 		up = TRUE;
87 	}
88 
89 	else if (menuInput.down == TRUE)
90 	{
91 		down = TRUE;
92 	}
93 
94 	else if (menuInput.attack == TRUE)
95 	{
96 		attack = TRUE;
97 	}
98 
99 	else if (input.left == TRUE)
100 	{
101 		left = TRUE;
102 	}
103 
104 	else if (input.right == TRUE)
105 	{
106 		right = TRUE;
107 	}
108 
109 	else if (input.up == TRUE)
110 	{
111 		up = TRUE;
112 	}
113 
114 	else if (input.down == TRUE)
115 	{
116 		down = TRUE;
117 	}
118 
119 	else if (input.attack == TRUE)
120 	{
121 		attack = TRUE;
122 	}
123 
124 	if (down == TRUE)
125 	{
126 		menu.index++;
127 
128 		if (menu.index == menu.widgetCount)
129 		{
130 			menu.index = 0;
131 		}
132 
133 		playSound("sound/common/click");
134 	}
135 
136 	else if (up == TRUE)
137 	{
138 		menu.index--;
139 
140 		if (menu.index < 0)
141 		{
142 			menu.index = menu.widgetCount - 1;
143 		}
144 
145 		playSound("sound/common/click");
146 	}
147 
148 	else if (attack == TRUE)
149 	{
150 		w = menu.widgets[menu.index];
151 
152 		if (w->clickAction != NULL)
153 		{
154 			w->clickAction();
155 		}
156 
157 		playSound("sound/common/click");
158 	}
159 
160 	else if (left == TRUE)
161 	{
162 		w = menu.widgets[menu.index];
163 
164 		if (w->leftAction != NULL)
165 		{
166 			w->leftAction();
167 		}
168 
169 		playSound("sound/common/click");
170 	}
171 
172 	else if (right == TRUE)
173 	{
174 		w = menu.widgets[menu.index];
175 
176 		if (w->rightAction != NULL)
177 		{
178 			w->rightAction();
179 		}
180 
181 		playSound("sound/common/click");
182 	}
183 
184 	xAxisMoved = input.xAxisMoved;
185 	yAxisMoved = input.yAxisMoved;
186 
187 	memset(&menuInput, 0, sizeof(Input));
188 	memset(&input, 0, sizeof(Input));
189 
190 	input.xAxisMoved = xAxisMoved;
191 	input.yAxisMoved = yAxisMoved;
192 }
193 
loadMenuLayout()194 static void loadMenuLayout()
195 {
196 	char *text;
197 	int x, y, w, maxWidth, i;
198 
199 	menu.widgetCount = 5;
200 
201 	menu.widgets = malloc(sizeof(Widget *) * menu.widgetCount);
202 
203 	if (menu.widgets == NULL)
204 	{
205 		showErrorAndExit("Ran out of memory when creating Control Menu");
206 	}
207 
208 	x = y = 0;
209 
210 	menu.widgets[0] = createWidget(_("Sound"), &control.button[CONTROL_UP], &toggleSound, &toggleSound, &toggleSound, x, y, TRUE, 255, 255, 255);
211 
212 	menu.widgets[0]->label = createLabel(game.audio == TRUE || game.audioDisabled == TRUE ? _("Yes") : _("No"), menu.widgets[0]->x + menu.widgets[0]->normalState->w + 10, y);
213 
214 	menu.widgets[1] = createWidget(_("SFX Volume"), &game.sfxDefaultVolume, &lowerSFXVolume, &raiseSFXVolume, NULL, x, y, TRUE, 255, 255, 255);
215 
216 	text = getVolumePercent(game.sfxDefaultVolume);
217 
218 	menu.widgets[1]->label = createLabel(_(text), menu.widgets[1]->x + menu.widgets[1]->normalState->w + 10, y);
219 
220 	free(text);
221 
222 	menu.widgets[2] = createWidget(_("Music Volume"), &game.musicDefaultVolume, &lowerMusicVolume, &raiseMusicVolume, NULL, x, y, TRUE, 255, 255, 255);
223 
224 	text = getVolumePercent(game.musicDefaultVolume);
225 
226 	menu.widgets[2]->label = createLabel(_(text), menu.widgets[2]->x + menu.widgets[2]->normalState->w + 10, y);
227 
228 	free(text);
229 
230 	menu.widgets[3] = createWidget(_("Audio Quality"), &game.audioQuality, &toggleQuality, &toggleQuality, &toggleQuality, x, y, TRUE, 255, 255, 255);
231 
232 	text = getQuality();
233 
234 	menu.widgets[3]->label = createLabel(text, menu.widgets[3]->x + menu.widgets[3]->normalState->w + 10, y);
235 
236 	free(text);
237 
238 	menu.widgets[4] = createWidget(_("Back"), NULL, NULL, NULL, &showOptionsMenu, -1, y, TRUE, 255, 255, 255);
239 
240 	y = BUTTON_PADDING + BORDER_PADDING;
241 
242 	maxWidth = w = 0;
243 
244 	for (i=0;i<menu.widgetCount;i++)
245 	{
246 		if (menu.widgets[i]->label != NULL && menu.widgets[i]->normalState->w > maxWidth)
247 		{
248 			maxWidth = menu.widgets[i]->normalState->w;
249 		}
250 	}
251 
252 	for (i=0;i<menu.widgetCount;i++)
253 	{
254 		menu.widgets[i]->y = y;
255 
256 		if (menu.widgets[i]->x != -1)
257 		{
258 			menu.widgets[i]->x = BUTTON_PADDING + BORDER_PADDING;
259 		}
260 
261 		if (menu.widgets[i]->label != NULL)
262 		{
263 			menu.widgets[i]->label->y = y;
264 
265 			menu.widgets[i]->label->x = menu.widgets[i]->x + maxWidth + 10;
266 
267 			if (menu.widgets[i]->label->x + menu.widgets[i]->label->text->w > w)
268 			{
269 				w = menu.widgets[i]->label->x + menu.widgets[i]->label->text->w;
270 			}
271 		}
272 
273 		else
274 		{
275 			if (menu.widgets[i]->x + menu.widgets[i]->selectedState->w > w)
276 			{
277 				w = menu.widgets[i]->x + menu.widgets[i]->selectedState->w;
278 			}
279 		}
280 
281 		y += menu.widgets[i]->selectedState->h + BUTTON_PADDING;
282 	}
283 
284 	menu.w = w + BUTTON_PADDING;
285 	menu.h = y - BORDER_PADDING;
286 
287 	menu.background = addBorder(createSurface(menu.w, menu.h, FALSE), 255, 255, 255, 0, 0, 0);
288 
289 	menu.x = (SCREEN_WIDTH - menu.background->w) / 2;
290 	menu.y = (SCREEN_HEIGHT - menu.background->h) / 2;
291 }
292 
initSoundMenu()293 Menu *initSoundMenu()
294 {
295 	menu.action = &doMenu;
296 
297 	if (menu.widgets == NULL)
298 	{
299 		loadMenuLayout();
300 	}
301 
302 	menu.returnAction = &showOptionsMenu;
303 
304 	return &menu;
305 }
306 
freeSoundMenu()307 void freeSoundMenu()
308 {
309 	int i;
310 
311 	if (menu.widgets != NULL)
312 	{
313 		for (i=0;i<menu.widgetCount;i++)
314 		{
315 			freeWidget(menu.widgets[i]);
316 		}
317 
318 		free(menu.widgets);
319 
320 		menu.widgets = NULL;
321 	}
322 
323 	if (menu.background != NULL)
324 	{
325 		destroyTexture(menu.background);
326 
327 		menu.background = NULL;
328 	}
329 }
330 
toggleSound()331 static void toggleSound()
332 {
333 	Widget *w = menu.widgets[menu.index];
334 
335 	game.audio = game.audio == TRUE ? FALSE : TRUE;
336 
337 	if (game.audio == FALSE)
338 	{
339 		game.audioDisabled = FALSE;
340 
341 		freeMusic();
342 
343 		Mix_CloseAudio();
344 	}
345 
346 	else
347 	{
348 		if (initAudio() == TRUE)
349 		{
350 			playLoadedMusic();
351 		}
352 
353 		else
354 		{
355 			game.audio = FALSE;
356 		}
357 	}
358 
359 	updateLabelText(w->label, game.audio == TRUE ? _("Yes") : _("No"));
360 }
361 
lowerSFXVolume()362 static void lowerSFXVolume()
363 {
364 	Widget *w = menu.widgets[menu.index];
365 
366 	changeVolume(&game.sfxDefaultVolume, w, -1);
367 }
368 
raiseSFXVolume()369 static void raiseSFXVolume()
370 {
371 	Widget *w = menu.widgets[menu.index];
372 
373 	changeVolume(&game.sfxDefaultVolume, w, 1);
374 }
375 
lowerMusicVolume()376 static void lowerMusicVolume()
377 {
378 	Widget *w = menu.widgets[menu.index];
379 
380 	changeVolume(&game.musicDefaultVolume, w, -1);
381 
382 	updateMusicVolume();
383 }
384 
raiseMusicVolume()385 static void raiseMusicVolume()
386 {
387 	Widget *w = menu.widgets[menu.index];
388 
389 	changeVolume(&game.musicDefaultVolume, w, 1);
390 
391 	updateMusicVolume();
392 }
393 
toggleQuality()394 static void toggleQuality()
395 {
396 	char *text;
397 	Widget *w = menu.widgets[menu.index];
398 
399 	game.audioQuality = game.audioQuality == 22050 ? 44100 : 22050;
400 
401 	changeSoundQuality();
402 
403 	text = getQuality();
404 
405 	updateLabelText(w->label, text);
406 
407 	free(text);
408 }
409 
changeVolume(int * maxVolume,Widget * w,int adjustment)410 static void changeVolume(int *maxVolume, Widget *w, int adjustment)
411 {
412 	char *text;
413 
414 	*maxVolume += adjustment;
415 
416 	if (*maxVolume < 0)
417 	{
418 		*maxVolume = 0;
419 	}
420 
421 	else if (*maxVolume > 10)
422 	{
423 		*maxVolume = 10;
424 	}
425 
426 	text = getVolumePercent(*maxVolume);
427 
428 	updateLabelText(w->label, text);
429 
430 	free(text);
431 }
432 
getVolumePercent(int volume)433 static char *getVolumePercent(int volume)
434 {
435 	char *text;
436 
437 	text = malloc(3);
438 
439 	if (text == NULL)
440 	{
441 		showErrorAndExit("Failed to allocate a whole 3 bytes for a Volume label");
442 	}
443 
444 	SNPRINTF(text, 3, "%d", volume);
445 
446 	return text;
447 }
448 
showOptionsMenu()449 static void showOptionsMenu()
450 {
451 	game.menu = initOptionsMenu();
452 
453 	game.drawMenu = &drawOptionsMenu;
454 }
455 
getQuality()456 static char *getQuality()
457 {
458 	char *text = malloc(10);
459 
460 	if (text == NULL)
461 	{
462 		showErrorAndExit("Failed to allocate a whole 10 bytes for a Quality label");
463 	}
464 
465 	SNPRINTF(text, 10, "%d", game.audioQuality);
466 
467 	return text;
468 }
469