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