1 /*
2 * Copyright 2009-2016 Peter Kosyh <p.kosyh at gmail.com>
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25 #include "externals.h"
26 #include "internals.h"
27
28
29 static int restart_needed = 0;
30 static int games_menu_from = 0;
31 static int themes_menu_page = 0;
32
33 static int cur_lang = 0;
34
35 int cur_menu = menu_main;
36 int top_menu = menu_main;
37
38 char *UNKNOWN_ERROR = NULL;
39 char *ERROR_MENU = NULL;
40 char *WARNING_MENU = NULL;
41 char *SAVE_SLOT_EMPTY = NULL;
42 char *SELECT_LOAD_MENU = NULL;
43 char *AUTOSAVE_SLOT = NULL;
44 char *BROKEN_SLOT = NULL;
45 char *SELECT_SAVE_MENU = NULL;
46 char *MAIN_MENU = NULL;
47 char *ABOUT_MENU = NULL;
48 char *BACK_MENU = NULL;
49 char *SETTINGS_SND_MENU = NULL;
50 char *SETTINGS_GFX_MENU = NULL;
51 char *SETTINGS_OTH_MENU = NULL;
52 char *CUSTOM_THEME_MENU = NULL;
53 char *OWN_THEME_MENU = NULL;
54 char *WAIT_MENU = NULL;
55 char *SELECT_GAME_MENU = NULL;
56 char *SELECT_THEME_MENU = NULL;
57 char *SAVED_MENU = NULL;
58 char *NOGAMES_MENU = NULL;
59 char *NOTHEMES_MENU = NULL;
60 char *BROWSE_MENU = NULL;
61 char *QUIT_MENU = NULL;
62 char *REMOVE_MENU = NULL;
63 char *ON = NULL;
64 char *OFF = NULL;
65
66 char *KBD_MODE_LINKS = NULL;
67 char *KBD_MODE_SMART = NULL;
68 char *KBD_MODE_SCROLL = NULL;
69 char *CANCEL_MENU = NULL;
70
71 char *FROM_THEME = NULL;
72
73 char *DISABLED_SAVE_MENU = NULL;
74
75 static char menu_buff[8192];
76
slot_name(const char * path)77 static char *slot_name(const char *path)
78 {
79 struct stat st;
80 char *l;
81 if (stat(path, &st))
82 return NULL;
83 l = lookup_tag(path, "Name", "--");
84 if (l) {
85 trunc_lines(l, 0);
86 if (!is_empty(l) && game_tag_valid(l)) {
87 int y;
88 char *m;
89 static char *months[] = {/* to work on every locale ;)*/
90 "Jan", "Feb",
91 "Mar", "Apr", "May",
92 "Jun", "Jul", "Aug",
93 "Sep", "Oct", "Nov",
94 "Dec",
95 };
96 struct tm *tm;
97 time_t t;
98
99 char *s = instead_fromgame(l);
100 free(l);
101 if (!s)
102 return s;
103 time(&t);
104 tm = localtime(&t);
105 y = tm->tm_year;
106 tm = localtime(&st.st_mtime);
107 l = malloc(strlen(s) + 64);
108 if (!l)
109 return s;
110 if (tm->tm_mon >=0 && tm->tm_mon < 12)
111 m = months[tm->tm_mon];
112 else
113 m = "?";
114 if (tm->tm_year == y)
115 snprintf(l, 64, "%02d %s %02d:%02d - ",
116 tm->tm_mday, m, tm->tm_hour, tm->tm_min);
117 else {
118 if (tm->tm_year < 1900)
119 tm->tm_year += 1900;
120 snprintf(l, 64, "%02d %s %02d:%02d %04d - ",
121 tm->tm_mday, m, tm->tm_hour, tm->tm_min, tm->tm_year);
122 }
123 strcat(l, s);
124 free(s);
125 return l;
126 }
127 free(l);
128 }
129 l = ctime(&st.st_mtime);
130 if (!l)
131 return NULL;
132 l[strcspn(l,"\n")] = 0;
133 return strdup(l);
134 }
135
load_menu(void)136 static void load_menu(void)
137 {
138 int i;
139 *menu_buff = 0;
140 /*
141 if (!game_saves_enabled()) {
142 strcat(menu_buff, DISABLED_SAVE_MENU);
143 strcat(menu_buff, CANCEL_MENU);
144 return;
145 } */
146 strcpy(menu_buff, SELECT_LOAD_MENU);
147 for (i = 0; i < MAX_SAVE_SLOTS; i ++) {
148 char tmp[PATH_MAX];
149 char *s = game_save_path(0, i);
150 if (!s || access(s, R_OK)) {
151 if (!i)
152 continue;
153 snprintf(tmp, sizeof(tmp), "<l>%d - %s\n</l>", i, SAVE_SLOT_EMPTY);
154 } else {
155 char *name;
156 if (!i)
157 name = strdup(AUTOSAVE_SLOT);
158 else
159 name = slot_name(s);
160 if (!name)
161 snprintf(tmp, sizeof(tmp), "<l>%d - %s</l>\n", i, BROKEN_SLOT);
162 else {
163 snprintf(tmp, sizeof(tmp), "<l>%d - <a:/load%d>%s</a></l>\n", i, i, name);
164 free(name);
165 }
166 }
167 strcat(menu_buff, tmp);
168 }
169 strcat(menu_buff,"\n");
170 strcat(menu_buff, CANCEL_MENU);
171 }
172
save_menu(void)173 static void save_menu(void)
174 {
175 int i;
176 *menu_buff = 0;
177 if (!game_saves_enabled()) {
178 strcat(menu_buff, DISABLED_SAVE_MENU);
179 strcat(menu_buff, CANCEL_MENU);
180 return;
181 }
182 strcpy(menu_buff, SELECT_SAVE_MENU);
183 for (i = 1; i < MAX_SAVE_SLOTS; i ++) {
184 char tmp[PATH_MAX];
185 char *s = game_save_path(0, i);
186 if (!s || access(s, R_OK))
187 snprintf(tmp, sizeof(tmp), "<l>%d - <a:/save%d>%s</a></l>\n", i, i, SAVE_SLOT_EMPTY);
188 else {
189 char *name;
190 if (!i)
191 name = strdup(AUTOSAVE_SLOT);
192 else
193 name = slot_name(s);
194 if (!name)
195 snprintf(tmp, sizeof(tmp), "<l>%d - <a:/save%d>%s</a></l>\n", i, i, BROKEN_SLOT);
196 else {
197 snprintf(tmp, sizeof(tmp), "<l>%d - <a:/save%d>%s</a></l>\n", i, i, name);
198 free(name);
199 }
200 }
201 strcat(menu_buff, tmp);
202 }
203 strcat(menu_buff,"\n");
204 strcat(menu_buff, CANCEL_MENU);
205 }
206
pages_menu(char * res,int nr,int max,const char * menu,const char * append)207 static int pages_menu(char *res, int nr, int max, const char *menu, const char *append)
208 {
209 static char buff[256];
210 int k = MENU_PER_PAGER;
211 int i = nr - MENU_PER_PAGER / 2;
212
213 if (i < 0)
214 i = 0;
215 else if (max - i < MENU_PER_PAGER)
216 i = max - MENU_PER_PAGER;
217 if (i < 0)
218 i = 0;
219 if (nr)
220 sprintf(buff, "<a:/%s prev><<</a> ", menu);
221 else
222 sprintf(buff, "<< ");
223 strcat(res, buff);
224 for (; i < max && k-- ; i ++) {
225 if (i != nr)
226 sprintf(buff, "<a:/%s %d>[%d]</a> ", menu, i, i + 1);
227 else
228 sprintf(buff, "[%d] ", i + 1);
229 strcat(res, buff);
230 }
231 if ((nr + 1) != max)
232 sprintf(buff, "<a:/%s next>>></a>", menu);
233 else
234 sprintf(buff, ">>");
235 strcat(res, buff);
236 strcat(res, append);
237 return 0;
238 }
239
games_menu(void)240 static void games_menu(void)
241 {
242 int i, n;
243 #ifdef _USE_BROWSE
244 int append_browse = 0;
245 #endif
246 char tmp[PATH_MAX];
247 #ifdef _USE_BROWSE
248 snprintf(tmp, sizeof(tmp), " <u><a:/browse>%s</a></u>\n", BROWSE_MENU);
249 #else
250 snprintf(tmp, sizeof(tmp), "\n");
251 #endif
252 strcpy(menu_buff, SELECT_GAME_MENU);
253 if ((games_nr - 1) / MENU_GAMES_MAX)
254 pages_menu(menu_buff, games_menu_from / MENU_GAMES_MAX, (games_nr - 1) / MENU_GAMES_MAX + 1, "games", tmp);
255 #ifdef _USE_BROWSE
256 else
257 append_browse = 1;
258 #endif
259 for (i = games_menu_from, n = 0; i < games_nr && n < MENU_GAMES_MAX; i ++) {
260
261 if (!games[i].name[0]) /* empty */
262 continue;
263 if (curgame_dir && !strcmp(games[i].dir, curgame_dir))
264 snprintf(tmp, sizeof(tmp), "<l><a:/resume><b>%s</b></a></l>", games[i].name);
265 else
266 snprintf(tmp, sizeof(tmp), "<l><a:%s>%s</a></l>", games[i].dir, games[i].name);
267 if (!strncmp(game_local_games_path(0), games[i].path, strlen(game_local_games_path(0))) &&
268 !access(games[i].path, W_OK)) {
269 snprintf(tmp + strlen(tmp), sizeof(tmp), " [<a:/remove_%d>X</a>]\n", i);
270 } else
271 strcat(tmp, "\n");
272
273 strcat(menu_buff, tmp);
274 n ++;
275 }
276 for(;n < MENU_GAMES_MAX && games_nr > MENU_GAMES_MAX; n++) /* align h */
277 strcat(menu_buff, "\n");
278 #ifdef _USE_BROWSE
279 if (append_browse) {
280 snprintf(tmp, sizeof(tmp), "<u><a:/browse>%s</a></u>\n", BROWSE_MENU);
281 strcat(menu_buff, tmp);
282 }
283 #endif
284 if (!games_nr) {
285 sprintf(menu_buff, NOGAMES_MENU, GAMES_PATH);
286 #ifdef _USE_BROWSE
287 strcat(menu_buff,"\n");
288 snprintf(tmp, sizeof(tmp), "<u><a:/browse>%s</a></u>\n", BROWSE_MENU);
289 strcat(menu_buff, tmp);
290 #endif
291 }
292 strcat(menu_buff,"\n");
293 strcat(menu_buff, BACK_MENU);
294 }
295
games_menu_maxw(void)296 int games_menu_maxw(void)
297 {
298 int i = 0;
299 int oldm = games_menu_from;
300 int maxw = 0;
301 for (i = 0; i < games_nr; i += MENU_GAMES_MAX) {
302 int w;
303 games_menu_from = i;
304 games_menu();
305 game_menu_box_wh(menu_buff, &w, NULL);
306 if (w > maxw)
307 maxw = w;
308 }
309 games_menu_from = oldm;
310 return maxw;
311 }
312
themes_menu(void)313 static void themes_menu(void)
314 {
315 int i, n, m;
316 int type;
317 int count = themes_max(&type);
318 int pages = 0;
319
320 if (count > 0)
321 pages = (count - 1) / MENU_THEMES_MAX + 1;
322
323 if (themes_menu_page >= pages)
324 themes_menu_page = 0;
325
326 strcpy(menu_buff, SELECT_THEME_MENU);
327
328 if (pages > 1)
329 pages_menu(menu_buff, themes_menu_page, pages, "themes", "\n");
330
331 for (i = 0, n = 0, m = 0; i < themes_nr && n < MENU_THEMES_MAX; i ++) {
332 char tmp[PATH_MAX];
333 if (!themes[i].name[0]) /* empty */
334 continue;
335 if (themes[i].type != type)
336 continue;
337 m ++;
338 if ((m - 1) / MENU_THEMES_MAX < themes_menu_page)
339 continue;
340 if (curtheme_dir[type] && !strcmp(themes[i].dir, curtheme_dir[type]))
341 snprintf(tmp, sizeof(tmp), "<l><a:/resume><b>%s</b></a></l>\n", themes[i].name);
342 else
343 snprintf(tmp, sizeof(tmp), "<l><a:%s>%s</a></l>\n", themes[i].dir, themes[i].name);
344 strcat(menu_buff, tmp);
345 n ++;
346 }
347
348 for(;n < MENU_THEMES_MAX && count > MENU_THEMES_MAX; n++) /* align h */
349 strcat(menu_buff, "\n");
350
351 if (!count)
352 sprintf(menu_buff, NOTHEMES_MENU, THEMES_PATH);
353 strcat(menu_buff, "\n");
354 strcat(menu_buff, BACK_MENU);
355 }
356
themes_menu_maxw(void)357 int themes_menu_maxw(void)
358 {
359 int i = 0;
360 int oldm = themes_menu_page;
361 int maxw = 0;
362 int pages = 0;
363 int count = themes_max(NULL);
364 if (count > 0)
365 pages = (count - 1) / MENU_THEMES_MAX + 1;
366 else
367 pages = 1;
368 for (i = 0; i < pages; i ++) {
369 int w;
370 themes_menu_page = i;
371 themes_menu();
372 game_menu_box_wh(menu_buff, &w, NULL);
373 if (w > maxw)
374 maxw = w;
375 }
376 themes_menu_page = oldm;
377 return maxw;
378 }
379
opt_get_mode(void)380 static char *opt_get_mode(void)
381 {
382 static char buff[128];
383 if (opt_mode[0] == -1 || opt_mode[1] == -1) {
384 snprintf(buff, sizeof(buff), "%s", FROM_THEME);
385 return buff;
386 }
387 snprintf(buff, sizeof(buff), "%dx%d", opt_mode[0], opt_mode[1]);
388 return buff;
389 }
390
391 static int gtr = 0;
392 static int menu_settings_num = 0;
393
menu_strip_tag(const char * a,const char * b)394 static void menu_strip_tag(const char *a, const char *b)
395 {
396 char *p, *ep;
397 size_t len;
398 p = strstr(menu_buff, a);
399 if (!p)
400 return;
401 ep = strstr(p, b);
402 if (!ep)
403 return;
404 /* ep += strcspn(ep, "\n\r");
405 ep += strspn(ep, "\n\r"); */
406 ep += strlen(b);
407 len = strlen(ep);
408 memmove(p, ep, len);
409 p[len] = 0;
410 }
411
menu_remove_tag(const char * a,const char * b)412 static void menu_remove_tag(const char *a, const char *b)
413 {
414 char *p, *ep;
415 size_t len;
416 p = strstr(menu_buff, a);
417 if (!p)
418 return;
419 ep = p + strlen(a);
420 len = strlen(ep);
421 memmove(p, ep, len);
422 p[len] = 0;
423
424 ep = strstr(p, b);
425 if (!ep)
426 return;
427 p = ep;
428 ep += strlen(b);
429 len = strlen(ep);
430
431 memmove(p, ep, len);
432 p[len] = 0;
433 }
434
game_menu_gen(void)435 char *game_menu_gen(void)
436 {
437 if (cur_menu == menu_main) {
438 strcpy(menu_buff, MAIN_MENU);
439 if (standalone_sw) {
440 int count = 0, n;
441 menu_strip_tag("<?:select>", "</?>");
442 count = themes_count(THEME_GLOBAL);
443 if (curgame_dir && opt_owntheme) {
444 if ((n = themes_count(THEME_GAME)) > 0)
445 count = n;
446 else if (game_own_theme)
447 count = 1;
448 }
449 if (count <= 1)
450 menu_strip_tag("<?:themes>", "</?>");
451 else
452 menu_remove_tag("<?:themes>", "</?>");
453 } else {
454 menu_remove_tag("<?:select>", "</?>");
455 menu_remove_tag("<?:themes>", "</?>");
456 }
457 } else if (cur_menu == menu_about || cur_menu == menu_about_instead) {
458 struct game *g;
459 if (cur_menu == menu_about && curgame_dir && (g = game_lookup(curgame_dir))) {
460 char version[32];
461 char author[64];
462 char info[192];
463 char instead[64];
464
465 if (g->version)
466 snprintf(version, sizeof(version), "%s", g->version);
467 else
468 strcpy(version, "1.0");
469
470 if (g->author)
471 snprintf(author, sizeof(author), "\n%s", g->author);
472 else
473 strcpy(author, "");
474
475 if (g->info)
476 snprintf(info, sizeof(info), "\n\n%s", g->info);
477 else
478 strcpy(info, "");
479
480 if (!standalone_sw)
481 snprintf(instead, sizeof(instead), "<a:/about-instead>INSTEAD</a> | ");
482 else
483 strcpy(instead, "");
484 author[sizeof(author) - 1] = 0;
485 version[sizeof(version) - 1] = 0;
486 info[sizeof(info) - 1] = 0;
487 snprintf(menu_buff, sizeof(menu_buff), "%s - %s%s%s\n\n%s%s",
488 g->name, version,
489 author, info,
490 instead, BACK_MENU);
491 } else {
492 snprintf(menu_buff, sizeof(menu_buff), ABOUT_MENU, VERSION);
493 }
494 } else if (cur_menu == menu_settings) {
495 char *just[JUST_MAX] = { FROM_THEME, OFF, ON };
496 char *kbd [KBD_MAX] = { KBD_MODE_SMART, KBD_MODE_LINKS, KBD_MODE_SCROLL };
497 int fsize = 100 + (10 * opt_fsize);
498 opt_kbd = (unsigned int)opt_kbd % KBD_MAX;
499 opt_justify = (unsigned int)opt_justify % JUST_MAX;
500 switch (menu_settings_num) {
501 case 0:
502 snprintf(menu_buff, sizeof(menu_buff), SETTINGS_GFX_MENU,
503 opt_get_mode(), opt_fs?ON:OFF, opt_hires?ON:OFF, fsize, just[opt_justify],
504 opt_hl?ON:OFF, opt_fading?ON:OFF, opt_owntheme?ON:OFF);
505 if (standalone_sw)
506 menu_strip_tag("<?:owntheme>", "</?>");
507 else
508 menu_remove_tag("<?:owntheme>", "</?>");
509 break;
510 case 1:
511 snprintf(menu_buff, sizeof(menu_buff), SETTINGS_SND_MENU,
512 snd_vol_to_pcn(snd_volume_mus(-1)), snd_hz(), opt_music?ON:OFF, opt_click?ON:OFF);
513 break;
514 case 2:
515 snprintf(menu_buff, sizeof(menu_buff), SETTINGS_OTH_MENU,
516 opt_motion?ON:OFF, opt_filter?ON:OFF, kbd[opt_kbd],
517 langs[cur_lang].name, (opt_autosave & 1)?ON:OFF);
518 break;
519 }
520 } else if (cur_menu == menu_askquit) {
521 strcpy(menu_buff, QUIT_MENU);
522 } else if (cur_menu == menu_saved) {
523 strcpy(menu_buff, SAVED_MENU);
524 } else if (cur_menu == menu_games) {
525 games_menu();
526 } else if (cur_menu == menu_themes) {
527 themes_menu();
528 } else if (cur_menu == menu_own_theme) {
529 strcpy(menu_buff, OWN_THEME_MENU);
530 } else if (cur_menu == menu_wait) {
531 strcpy(menu_buff, WAIT_MENU);
532 } else if (cur_menu == menu_custom_theme) {
533 strcpy(menu_buff, CUSTOM_THEME_MENU);
534 } else if (cur_menu == menu_load) {
535 load_menu();
536 } else if (cur_menu == menu_save) {
537 save_menu();
538 } else if (cur_menu == menu_error) {
539 snprintf(menu_buff, sizeof(menu_buff),
540 ERROR_MENU, instead_err()?instead_err():UNKNOWN_ERROR);
541 instead_err_msg(NULL);
542 } else if (cur_menu == menu_warning) {
543 snprintf(menu_buff, sizeof(menu_buff),
544 WARNING_MENU, instead_err()?instead_err():UNKNOWN_ERROR);
545 instead_err_msg(NULL);
546 } else if (cur_menu == menu_remove) {
547 const char *sname = games[gtr].path;
548 if (strlen(games[gtr].path) >= 48) {
549 sname = games[gtr].name;
550 }
551 snprintf(menu_buff, sizeof(menu_buff), REMOVE_MENU, sname);
552 }
553 return menu_buff;
554 }
555
game_menu_act(const char * a)556 int game_menu_act(const char *a)
557 {
558 static int old_vol = 0;
559
560 if (!strcmp(a, "/autosave")) {
561 opt_autosave = !(opt_autosave & 1);
562 game_menu_box(1, game_menu_gen());
563 } else if (!strcmp(a, "/kbd")) {
564 opt_kbd += 1;
565 if (opt_kbd == KBD_MAX)
566 opt_kbd = 0;
567 game_menu_box(1, game_menu_gen());
568 } else if (!strcmp(a, "/owntheme")) {
569 opt_owntheme = !opt_owntheme;
570 if (game_own_theme)
571 restart_needed = 1;
572 game_menu_box(1, game_menu_gen());
573 } else if (!strcmp(a, "/motion")) {
574 opt_motion ^= 1;
575 game_menu_box(1, game_menu_gen());
576 } else if (!strcmp(a, "/filter")) {
577 opt_filter ^= 1;
578 game_menu_box(1, game_menu_gen());
579 } else if (!strcmp(a, "/click")) {
580 opt_click ^= 1;
581 game_menu_box(1, game_menu_gen());
582 } else if (!strcmp(a, "/mode++")) {
583 if (gfx_next_mode(&opt_mode[0], &opt_mode[1]))
584 opt_mode[0] = opt_mode[1] = -1;
585 restart_needed = 1;
586 game_menu_box(1, game_menu_gen());
587 } else if (!strcmp(a, "/mode--")) {
588 if (gfx_prev_mode(&opt_mode[0], &opt_mode[1]))
589 opt_mode[0] = opt_mode[1] = -1;
590 restart_needed = 1;
591 game_menu_box(1, game_menu_gen());
592 } else if (!strcmp(a, "/just++")) {
593 restart_needed = 1;
594 opt_justify ++;
595 if (opt_justify >= JUST_MAX)
596 opt_justify = 0;
597 game_menu_box(1, game_menu_gen());
598 } else if (!strcmp(a, "/just--")) {
599 restart_needed = 1;
600 opt_justify --;
601 if (opt_justify < 0)
602 opt_justify = JUST_MAX - 1;
603 game_menu_box(1, game_menu_gen());
604 } else if (!strcmp(a, "/fs--")) {
605 opt_fsize --;
606 if (opt_fsize >= FONT_MIN_SZ) {
607 restart_needed = 1;
608 } else
609 opt_fsize ++;
610 game_menu_box(1, game_menu_gen());
611 } else if (!strcmp(a, "/fs++")) {
612 opt_fsize ++;
613 if (opt_fsize <= FONT_MAX_SZ) {
614 restart_needed = 1;
615 } else
616 opt_fsize --;
617 game_menu_box(1, game_menu_gen());
618 } else if (!strcmp(a, "/hl")) {
619 opt_hl ^= 1;
620 game_menu_box(1, game_menu_gen());
621 } else if (!strcmp(a, "/fading")) {
622 opt_fading ^= 1;
623 game_menu_box(1, game_menu_gen());
624 } else if (!strcmp(a, "/fs")) {
625 #if !defined(ANDROID) && !defined(IOS)
626 restart_needed = 1;
627 opt_fs ^= 1;
628 game_menu_box(1, game_menu_gen());
629 #endif
630 } else if (!strcmp(a, "/hires")) {
631 opt_hires ^= 1;
632 restart_needed = 1;
633 game_menu_box(1, game_menu_gen());
634 } else if (!strncmp(a, "/games ", 7)) {
635 if (!strcmp(a + 7, "prev")) {
636 games_menu_from -= MENU_GAMES_MAX;
637 if (games_menu_from < 0)
638 games_menu_from = 0;
639 } else if (!strcmp(a + 7, "next")) {
640 if (games_menu_from + MENU_GAMES_MAX < games_nr)
641 games_menu_from += MENU_GAMES_MAX;
642 } else {
643 int nr = atoi(a + 7);
644 games_menu_from = nr * MENU_GAMES_MAX;
645 }
646 game_menu_box(1, game_menu_gen());
647 } else if (!strncmp(a, "/themes ", 8)) {
648 if (!strcmp(a + 8, "prev")) {
649 themes_menu_page --;
650 if (themes_menu_page < 0)
651 themes_menu_page = 0;
652 } else if (!strcmp(a + 8, "next")) {
653 int count = themes_max(NULL); int pages = 0;
654 if (count > 0)
655 pages = (count - 1) / MENU_THEMES_MAX + 1;
656 if (themes_menu_page + 1 < pages)
657 themes_menu_page ++;
658 } else {
659 int nr = atoi(a + 8);
660 themes_menu_page = nr;
661 }
662 game_menu_box(1, game_menu_gen());
663 } else if (!strcmp(a, "/select")) {
664 game_menu(menu_games);
665 } else if (!strcmp(a, "/remove")) {
666 fprintf(stderr,"Removing '%s'\n", games[gtr].path);
667 if (curgame_dir && !strcmp(curgame_dir, games[gtr].dir)) {
668 game_done(0);
669 if (game_init(NULL)) {
670 game_error();
671 return 0;
672 }
673 }
674 games_remove(gtr);
675 if (games_menu_from >= games_nr)
676 games_menu_from -= MENU_GAMES_MAX;
677 if (games_menu_from < 0)
678 games_menu_from = 0;
679 game_menu(menu_games);
680 } else if (!strcmp(a, "/themes")) {
681 game_menu(menu_themes);
682 } else if (!strcmp(a, "/save_menu")) {
683 if (curgame_dir)
684 game_menu(menu_save);
685 } else if (!strncmp(a, "/save", 5)) {
686 if (!game_save(atoi(a + 5))) {
687 game_menu(menu_saved);
688 }
689 } else if (!strcmp(a, "/load_menu")) {
690 if (curgame_dir)
691 game_menu(menu_load);
692 } else if (!strncmp(a, "/load", 5)) {
693 int nr = atoi(a + 5);
694 if (!curgame_dir)
695 return 0;
696 game_menu_box(0, NULL);
697 if (!game_reset()) {
698 game_load(nr);
699 cur_menu = menu_main;
700 }
701 /* game_menu_box(0, NULL); */
702 } else if (!strcmp(a, "/new")) {
703 char *s;
704 if (!curgame_dir)
705 return 0;
706
707 /* remove autlosave */
708 s = game_save_path(0, 0);
709 if (s && !access(s, R_OK) && (opt_autosave & 1))
710 unlink (s);
711 game_menu_box(0, NULL);
712 if (!game_reset()) {
713 game_cmd("look", 0);
714 custom_theme_warn();
715 }
716 } else if (!strcmp(a,"/main")) {
717 if (top_menu != menu_main) {
718 cur_menu = menu_main;
719 game_menu_box(0, NULL);
720 } else
721 game_menu(menu_main);
722 if (restart_needed) {
723 game_restart();
724 restart_needed = 0;
725 }
726 } else if (!strcmp(a,"/ask_quit")) {
727 game_menu(menu_askquit);
728 } else if (!strncmp(a, "/remove_", 8)) {
729 gtr = atoi(a + 8);
730 game_menu(menu_remove);
731 } else if (!strcmp(a,"/about")) {
732 game_menu(menu_about);
733 } else if (!strcmp(a,"/about-instead")) {
734 game_menu(menu_about_instead);
735 } else if (!strcmp(a,"/mtoggle")) {
736 if (!old_vol) {
737 old_vol = snd_volume_mus(-1);
738 game_change_vol(0, 0);
739 } else {
740 game_change_vol(0, old_vol);
741 old_vol = 0;
742 }
743 game_menu_box(1, game_menu_gen());
744 } else if (!strcmp(a,"/music")) {
745 opt_music ^= 1;
746 if (!opt_music) {
747 game_stop_mus(0);
748 } else
749 game_music_player();
750 game_menu_box(1, game_menu_gen());
751 } else if (!strcmp(a,"/resume")) {
752 cur_menu = menu_main;
753 game_menu_box(0, NULL);
754 } else if (!strcmp(a, "/settings")) {
755 game_menu(menu_settings);
756 } else if (!strcmp(a, "/settings-gfx")) {
757 menu_settings_num = 0;
758 game_menu_box(1, game_menu_gen());
759 } else if (!strcmp(a, "/settings-snd")) {
760 menu_settings_num = 1;
761 game_menu_box(1, game_menu_gen());
762 } else if (!strcmp(a, "/settings-oth")) {
763 menu_settings_num = 2;
764 game_menu_box(1, game_menu_gen());
765 } else if (!strcmp(a, "/vol--")) {
766 game_change_vol(-10, 0);
767 game_menu_box(1, game_menu_gen());
768 } else if (!strcmp(a, "/vol++")) {
769 game_change_vol(+10, 0);
770 game_menu_box(1, game_menu_gen());
771 } else if (!strcmp(a, "/vol-")) {
772 game_change_vol(-1, 0);
773 game_menu_box(1, game_menu_gen());
774 } else if (!strcmp(a, "/vol+")) {
775 game_change_vol(+1, 0);
776 game_menu_box(1, game_menu_gen());
777 } else if (!strcmp(a, "/hz-")) {
778 int hz = snd_hz();
779 if (hz == 44100)
780 hz = 22050;
781 else if (hz == 22050)
782 hz = 11025;
783 else if (hz == 11025)
784 hz = 0;
785 else
786 hz = 22050;
787 game_change_hz(hz);
788 game_menu_box(1, game_menu_gen());
789 } else if (!strcmp(a, "/hz+")) {
790 int hz = snd_hz();
791 if (hz == 11025)
792 hz = 22050;
793 else if (hz == 22050)
794 hz = 44100;
795 else if (hz == 44100)
796 hz = 0;
797 else
798 hz = 22050;
799 game_change_hz(hz);
800 game_menu_box(1, game_menu_gen());
801 } else if (!strcmp(a, "/lang++")) {
802 do {
803 cur_lang ++;
804 if (cur_lang >= langs_nr)
805 cur_lang = 0;
806 } while (menu_lang_select(langs[cur_lang].file));
807 if (curgame_dir)
808 instead_set_lang(opt_lang);
809 themes_rename();
810 games_rename();
811 game_reset_name();
812 game_menu_box(1, game_menu_gen());
813 } else if (!strcmp(a, "/lang--")) {
814 do {
815 cur_lang --;
816 if (cur_lang < 0)
817 cur_lang = langs_nr - 1;
818 } while (menu_lang_select(langs[cur_lang].file));
819 if (curgame_dir)
820 instead_set_lang(opt_lang);
821 themes_rename();
822 games_rename();
823 game_reset_name();
824 game_menu_box(1, game_menu_gen());
825 } else if (!strcmp(a,"/quit")) {
826 return -1;
827 #ifdef _USE_BROWSE
828 } else if (!strcmp(a,"/browse")) {
829 game_from_disk();
830 return 0;
831 #endif
832 } else if (cur_menu == menu_games) {
833 char *p;
834 p = strdup(a);
835 if (p) {
836 game_done(0);
837 if (game_init(p)) {
838 game_error();
839 }
840 free(p);
841 }
842 } else if (cur_menu == menu_themes) {
843 char *p;
844 p = strdup(a);
845 if (p) {
846 char *og;
847 if (game_theme_select(p))
848 fprintf(stderr, "Can't select theme:%s:%s\n", p, strerror(errno));
849 og = curgame_dir;
850 game_save(-1);
851 game_done(0);
852 if (game_init(og)) {
853 game_error();
854 } else if (curgame_dir && game_own_theme && opt_owntheme && !curtheme_dir[THEME_GAME]) {
855 game_menu(menu_own_theme);
856 }
857 free(p);
858 }
859 }
860 return 0;
861 }
862
custom_theme_warn(void)863 void custom_theme_warn(void)
864 {
865 if (game_own_theme && !opt_owntheme && cur_menu != menu_warning) {
866 game_menu(menu_custom_theme);
867 }
868 }
869
870
871
872 struct lang *langs = NULL;
873 int langs_nr = 0;
874
875
lang_free(void)876 static void lang_free(void)
877 {
878 FREE(UNKNOWN_ERROR);
879 FREE(ERROR_MENU);
880 FREE(WARNING_MENU);
881 FREE(SAVE_SLOT_EMPTY);
882 FREE(SELECT_LOAD_MENU);
883 FREE(AUTOSAVE_SLOT);
884 FREE(BROKEN_SLOT);
885 FREE(SELECT_SAVE_MENU);
886 FREE(MAIN_MENU);
887 FREE(ABOUT_MENU);
888 FREE(BACK_MENU);
889 FREE(SETTINGS_SND_MENU);
890 FREE(SETTINGS_GFX_MENU);
891 FREE(SETTINGS_OTH_MENU);
892 FREE(CUSTOM_THEME_MENU);
893 FREE(OWN_THEME_MENU);
894 FREE(WAIT_MENU);
895 FREE(SELECT_GAME_MENU);
896 FREE(SELECT_THEME_MENU);
897 FREE(SAVED_MENU);
898 FREE(NOGAMES_MENU);
899 FREE(NOTHEMES_MENU);
900 FREE(QUIT_MENU);
901 FREE(REMOVE_MENU);
902 FREE(ON);
903 FREE(OFF);
904 FREE(KBD_MODE_LINKS);
905 FREE(KBD_MODE_SMART);
906 FREE(KBD_MODE_SCROLL);
907 FREE(CANCEL_MENU);
908 FREE(FROM_THEME);
909 FREE(DISABLED_SAVE_MENU);
910 FREE(BROWSE_MENU);
911 }
912
lang_ok(void)913 static int lang_ok(void)
914 {
915 if (UNKNOWN_ERROR && ERROR_MENU && WARNING_MENU && SAVE_SLOT_EMPTY &&
916 SELECT_LOAD_MENU && AUTOSAVE_SLOT && BROKEN_SLOT && SELECT_SAVE_MENU &&
917 MAIN_MENU && ABOUT_MENU && BACK_MENU && SETTINGS_SND_MENU && SETTINGS_GFX_MENU && SETTINGS_OTH_MENU &&
918 CUSTOM_THEME_MENU && OWN_THEME_MENU && SELECT_GAME_MENU && SELECT_THEME_MENU && WAIT_MENU &&
919 SAVED_MENU && NOGAMES_MENU && NOTHEMES_MENU && QUIT_MENU && REMOVE_MENU &&
920 ON && OFF && KBD_MODE_LINKS && KBD_MODE_SMART && KBD_MODE_SCROLL && CANCEL_MENU &&
921 FROM_THEME && DISABLED_SAVE_MENU && BROWSE_MENU)
922 return 0;
923 return -1;
924 }
925
926 struct parser lang_parser[] = {
927 { "UNKNOWN_ERROR", parse_esc_string, &UNKNOWN_ERROR, 0 },
928 { "ERROR_MENU", parse_esc_string, &ERROR_MENU, 0 },
929 { "WARNING_MENU", parse_esc_string, &WARNING_MENU, 0 },
930 { "SAVE_SLOT_EMPTY", parse_esc_string, &SAVE_SLOT_EMPTY, 0 },
931 { "SELECT_LOAD_MENU", parse_esc_string, &SELECT_LOAD_MENU, 0 },
932 { "AUTOSAVE_SLOT", parse_esc_string, &AUTOSAVE_SLOT, 0 },
933 { "BROKEN_SLOT", parse_esc_string, &BROKEN_SLOT, 0 },
934 { "SELECT_SAVE_MENU", parse_esc_string, &SELECT_SAVE_MENU, 0 },
935 { "MAIN_MENU", parse_esc_string, &MAIN_MENU, 0 },
936 { "ABOUT_MENU", parse_esc_string, &ABOUT_MENU, 0 },
937 { "BACK_MENU", parse_esc_string, &BACK_MENU, 0 },
938 { "SETTINGS_GFX_MENU", parse_esc_string, &SETTINGS_GFX_MENU, 0 },
939 { "SETTINGS_SND_MENU", parse_esc_string, &SETTINGS_SND_MENU, 0 },
940 { "SETTINGS_OTH_MENU", parse_esc_string, &SETTINGS_OTH_MENU, 0 },
941 { "CUSTOM_THEME_MENU", parse_esc_string, &CUSTOM_THEME_MENU, 0 },
942 { "OWN_THEME_MENU", parse_esc_string, &OWN_THEME_MENU, 0 },
943 { "WAIT_MENU", parse_esc_string, &WAIT_MENU, 0 },
944 { "SELECT_GAME_MENU", parse_esc_string, &SELECT_GAME_MENU, 0 },
945 { "SELECT_THEME_MENU", parse_esc_string, &SELECT_THEME_MENU, 0 },
946 { "SAVED_MENU", parse_esc_string, &SAVED_MENU, 0 },
947 { "NOGAMES_MENU", parse_esc_string, &NOGAMES_MENU, 0 },
948 { "NOTHEMES_MENU", parse_esc_string, &NOTHEMES_MENU, 0 },
949 { "QUIT_MENU", parse_esc_string, &QUIT_MENU, 0 },
950 { "REMOVE_MENU", parse_esc_string, &REMOVE_MENU, 0 },
951 { "ON", parse_esc_string, &ON, 0 },
952 { "OFF", parse_esc_string, &OFF, 0 },
953 { "KBD_MODE_LINKS", parse_esc_string, &KBD_MODE_LINKS, 0 },
954 { "KBD_MODE_SMART", parse_esc_string, &KBD_MODE_SMART, 0 },
955 { "KBD_MODE_SCROLL", parse_esc_string, &KBD_MODE_SCROLL, 0 },
956 { "CANCEL_MENU", parse_esc_string, &CANCEL_MENU, 0 },
957 { "FROM_THEME", parse_esc_string, &FROM_THEME, 0 },
958 { "DISABLED_SAVE_MENU", parse_esc_string, &DISABLED_SAVE_MENU, 0 },
959 { "BROWSE_MENU", parse_esc_string, &BROWSE_MENU, 0 },
960 { NULL, NULL, NULL, 0 },
961 };
962
lang_parse(const char * path)963 static int lang_parse(const char *path)
964 {
965 return parse_ini(path, lang_parser);
966 }
967
is_lang(const char * path,const char * n)968 static int is_lang(const char *path, const char *n)
969 {
970 char *p = getfilepath(path, n);
971 if (!p)
972 return 0;
973 if (access(p, F_OK))
974 return 0;
975 free(p);
976 if (!(p = strstr(n, ".ini")) && !(p = strstr(n, ".INI")))
977 return 0;
978 return 1;
979 }
980
lang_code(const char * str)981 static char *lang_code(const char *str)
982 {
983 char *p = strdup(str);
984 if (!p)
985 return NULL;
986 p[strcspn(p, ".")] = 0;
987 tolow(p);
988 return p;
989 }
990
991
lang_name(const char * path,const char * file)992 static char *lang_name(const char *path, const char *file)
993 {
994 char *l;
995 l = lookup_tag(path, "Name", ";");
996 if (l)
997 return l;
998 return lang_code(file);
999 }
1000
1001
cmp_lang(const void * p1,const void * p2)1002 static int cmp_lang(const void *p1, const void *p2)
1003 {
1004 const struct lang *l1 = (const struct lang*)p1;
1005 const struct lang *l2 = (const struct lang*)p2;
1006 return strcmp(l1->name, l2->name);
1007 }
1008
langs_sort()1009 static void langs_sort()
1010 {
1011 qsort(langs, langs_nr, sizeof(struct lang), cmp_lang);
1012 }
1013
menu_langs_lookup(const char * path)1014 int menu_langs_lookup(const char *path)
1015 {
1016 char *p;
1017 int n = 0, i = 0;
1018 DIR *d;
1019 struct dirent *de;
1020 struct lang *new_langs;
1021
1022 if (!path)
1023 return 0;
1024
1025 d = opendir(path);
1026 if (!d)
1027 return -1;
1028 while ((de = readdir(d))) {
1029 if (!is_lang(path, de->d_name))
1030 continue;
1031 n ++;
1032 }
1033 if (!n)
1034 goto out;
1035 closedir(d); d = opendir(path);
1036 if (!d)
1037 return -1;
1038 new_langs = realloc(langs, sizeof(struct lang) * (n + langs_nr));
1039 if (!new_langs) {
1040 closedir(d);
1041 return -1;
1042 }
1043 langs = new_langs;
1044
1045 while ((de = readdir(d)) && i < n) {
1046 if (!is_lang(path, de->d_name))
1047 continue;
1048 p = getfilepath(path, de->d_name);
1049 langs[langs_nr].path = p;
1050 langs[langs_nr].file = lang_code(de->d_name);
1051 langs[langs_nr].name = lang_name(p, de->d_name);
1052 langs_nr ++;
1053 i ++;
1054 }
1055 out:
1056 langs_sort();
1057 closedir(d);
1058 return 0;
1059 }
1060
menu_lang_select(const char * name)1061 int menu_lang_select(const char *name)
1062 {
1063 int i;
1064 char cwd[PATH_MAX];
1065 if (!name)
1066 return -1;
1067 getdir(cwd, sizeof(cwd));
1068 setdir(game_cwd);
1069 for (i = 0; i<langs_nr; i ++) {
1070 if (!strcmp(langs[i].file, name)) {
1071 lang_free();
1072 if (lang_parse(langs[i].path) || lang_ok()) {
1073 fprintf(stderr,"Error while loading language: %s\n", langs[i].file);
1074 setdir(cwd);
1075 return -1;
1076 }
1077 cur_lang = i;
1078 FREE(opt_lang); opt_lang = strdup(langs[i].file);
1079 setdir(cwd);
1080 return 0;
1081 }
1082 }
1083 setdir(cwd);
1084 return -1;
1085 }
1086