Transform default game/locale data paths based on executable name
[neverball] / ball / util.c
1 /*
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <ctype.h>
16 #include <string.h>
17 #include <assert.h>
18
19 #include "gui.h"
20 #include "util.h"
21 #include "config.h"
22
23 /*---------------------------------------------------------------------------*/
24
25 static int is_special_name(const char *n)
26 {
27     return (strcmp(n, N_("Hard"))   == 0 ||
28             strcmp(n, N_("Medium")) == 0 ||
29             strcmp(n, N_("Easy"))   == 0);
30 }
31
32 /*---------------------------------------------------------------------------*/
33
34 static int coin_label;
35
36 static int coin_coin[4];
37 static int coin_name[4];
38 static int coin_time[4];
39
40 static int coin_extra_row;
41
42 /* Build a Most Coins top three list with default values. */
43
44 static void gui_most_coins(int id, int e)
45 {
46     const char *s = "1234567";
47
48     int j, jd, kd, ld, md;
49
50     coin_extra_row = e;
51
52     if ((jd = gui_hstack(id)))
53     {
54         gui_filler(jd);
55
56         if ((kd = gui_vstack(jd)))
57         {
58             coin_label = gui_label(kd, _("Unavailable"),
59                                    GUI_SML, GUI_TOP, 0, 0);
60
61             if ((ld = gui_hstack(kd)))
62             {
63                 if ((md = gui_vstack(ld)))
64                 {
65                     for (j = 0; j < NSCORE - 1; j++)
66                         coin_coin[j] = gui_count(md, 1000, GUI_SML, 0);
67
68                     coin_coin[j++] = gui_count(md, 1000, GUI_SML, GUI_SE);
69
70                     if (e)
71                     {
72                         gui_space(md);
73                         coin_coin[j++] = gui_count(md, 1000, GUI_SML, GUI_RGT);
74                     }
75                 }
76
77                 if ((md = gui_vstack(ld)))
78                 {
79                     for (j = 0; j < NSCORE ; j++)
80                         coin_name[j] = gui_label(md, s, GUI_SML, 0,
81                                                  gui_yel, gui_wht);
82
83                     if (e)
84                     {
85                         gui_space(md);
86                         coin_name[j++] = gui_label(md, s, GUI_SML, 0,
87                                                    gui_yel, gui_wht);
88                     }
89                 }
90
91                 if ((md = gui_vstack(ld)))
92                 {
93                     for (j = 0; j < NSCORE - 1; j++)
94                         coin_time[j] = gui_clock(md, 359999, GUI_SML, 0);
95
96                     coin_time[j++] = gui_clock(md, 359999, GUI_SML, GUI_SW);
97
98                     if (e)
99                     {
100                         gui_space(md);
101                         coin_time[j++] = gui_clock(md, 359999, GUI_SML, GUI_LFT);
102                     }
103                 }
104             }
105         }
106         gui_filler(jd);
107     }
108 }
109
110 /* Set the Most Coins top three list values. */
111
112 static void set_most_coins(const struct score *s, int hilight)
113 {
114     const char *name;
115     int j;
116
117     if (s == NULL)
118     {
119         gui_set_label(coin_label, _("Unavailable"));
120
121         for (j = 0; j < NSCORE + coin_extra_row ; j++)
122         {
123             gui_set_count(coin_coin[j], -1);
124             gui_set_label(coin_name[j], "");
125             gui_set_clock(coin_time[j], -1);
126         }
127     }
128     else
129     {
130         gui_set_label(coin_label, _("Most Coins"));
131
132         for (j = 0; j < NSCORE + coin_extra_row; j++)
133         {
134             name = s->player[j];
135
136             if (j == hilight)
137             {
138                 if (j < NSCORE)
139                     gui_set_color(coin_name[j], gui_grn, gui_grn);
140                 else
141                     gui_set_color(coin_name[j], gui_red, gui_red);
142             }
143             else
144                 gui_set_color(coin_name[j], gui_yel, gui_wht);
145
146             gui_set_count(coin_coin[j], s->coins[j]);
147             gui_set_label(coin_name[j], is_special_name(name) ? _(name) : name);
148             gui_set_clock(coin_time[j], s->timer[j]);
149         }
150     }
151 }
152
153 /*---------------------------------------------------------------------------*/
154
155 static int time_label;
156
157 static int time_coin[4];
158 static int time_name[4];
159 static int time_time[4];
160
161 static int time_extra_row;
162
163 /* Build a Best Times top three list with default values. */
164
165 static void gui_best_times(int id, int e)
166 {
167     const char *s = "1234567";
168
169     int j, jd, kd, ld, md;
170
171     time_extra_row = e;
172
173     if ((jd = gui_hstack(id)))
174     {
175         gui_filler(jd);
176
177         if ((kd = gui_vstack(jd)))
178         {
179             time_label = gui_label(kd, _("Unavailable"),
180                                    GUI_SML, GUI_TOP, 0, 0);
181
182             if ((ld = gui_hstack(kd)))
183             {
184                 if ((md = gui_vstack(ld)))
185                 {
186                     for (j = 0; j < NSCORE - 1; j++)
187                         time_time[j] = gui_clock(md, 359999, GUI_SML, 0);
188
189                     time_time[j++] = gui_clock(md, 359999, GUI_SML, GUI_SE);
190
191                     if (e)
192                     {
193                         gui_space(md);
194                         time_time[j++] = gui_clock(md, 359999, GUI_SML, GUI_RGT);
195                     }
196                 }
197
198                 if ((md = gui_vstack(ld)))
199                 {
200                     for (j = 0; j < NSCORE; j++)
201                         time_name[j] = gui_label(md, s, GUI_SML, 0,
202                                                  gui_yel, gui_wht);
203
204                     if (e)
205                     {
206                         gui_space(md);
207                         time_name[j++] = gui_label(md, s, GUI_SML, 0,
208                                                    gui_yel, gui_wht);
209                     }
210                 }
211
212                 if ((md = gui_vstack(ld)))
213                 {
214                     for (j = 0; j < NSCORE - 1; j++)
215                         time_coin[j] = gui_count(md, 1000, GUI_SML, 0);
216
217                     time_coin[j++] = gui_count(md, 1000, GUI_SML, GUI_SW);
218
219                     if (e)
220                     {
221                         gui_space(md);
222                         time_coin[j++] = gui_count(md, 1000, GUI_SML, GUI_LFT);
223                     }
224                 }
225             }
226         }
227         gui_filler(jd);
228     }
229 }
230
231 /* Set the Best Times top three list values. */
232
233 static void set_best_times(const struct score *s, int hilight, int goal)
234 {
235     const char *name;
236     int j;
237
238     if (s == NULL)
239     {
240         gui_set_label(time_label, _("Unavailable"));
241
242         for (j = 0; j < NSCORE + time_extra_row ; j++)
243         {
244             gui_set_clock(time_time[j], -1);
245             gui_set_label(time_name[j], "");
246             gui_set_count(time_coin[j], -1);
247         }
248     }
249     else
250     {
251         gui_set_label(time_label, goal ? _("Fast Unlock") : _("Best Times"));
252
253         for (j = 0; j < NSCORE + time_extra_row; j++)
254         {
255             name = s->player[j];
256
257             if (j == hilight)
258             {
259                 if (j < NSCORE)
260                     gui_set_color(time_name[j], gui_grn, gui_grn);
261                 else
262                     gui_set_color(time_name[j], gui_red, gui_red);
263             }
264             else
265                 gui_set_color(time_name[j], gui_yel, gui_wht);
266
267             gui_set_clock(time_time[j], s->timer[j]);
268             gui_set_label(time_name[j], is_special_name(name) ? _(name) : name);
269             gui_set_count(time_coin[j], s->coins[j]);
270         }
271     }
272 }
273
274 /*---------------------------------------------------------------------------*/
275
276 static int score_type = GUI_MOST_COINS;
277
278 void gui_score_board(int id, unsigned int types, int e, int h)
279 {
280     int jd, kd, ld;
281
282     assert((types & GUI_MOST_COINS)  == GUI_MOST_COINS ||
283            (types & GUI_BEST_TIMES)  == GUI_BEST_TIMES ||
284            (types & GUI_FAST_UNLOCK) == GUI_FAST_UNLOCK );
285
286     /* Make sure current score type matches the spec. */
287
288     while ((types & score_type) != score_type)
289         score_type = gui_score_next(score_type);
290
291     gui_filler(id);
292
293     if ((jd = gui_hstack(id)))
294     {
295         gui_filler(jd);
296
297         if ((kd = gui_vstack(jd)))
298         {
299             gui_filler(kd);
300
301             if ((types & GUI_MOST_COINS) == GUI_MOST_COINS)
302                 gui_state(kd, _("Most Coins"),  GUI_SML, GUI_MOST_COINS,
303                           score_type == GUI_MOST_COINS);
304             if ((types & GUI_BEST_TIMES) == GUI_BEST_TIMES)
305                 gui_state(kd, _("Best Times"),  GUI_SML, GUI_BEST_TIMES,
306                           score_type == GUI_BEST_TIMES);
307             if ((types & GUI_FAST_UNLOCK) == GUI_FAST_UNLOCK)
308                 gui_state(kd, _("Fast Unlock"), GUI_SML, GUI_FAST_UNLOCK,
309                           score_type == GUI_FAST_UNLOCK);
310
311             if (h)
312             {
313                 gui_space(kd);
314
315                 if ((ld = gui_hstack(kd)))
316                 {
317                     gui_filler(ld);
318                     gui_state(ld, _("Change Name"), GUI_SML, GUI_NAME, 0);
319                     gui_filler(ld);
320                 }
321             }
322
323             gui_filler(kd);
324         }
325
326         gui_filler(jd);
327     }
328
329     gui_filler(id);
330
331     switch (score_type)
332     {
333     case GUI_MOST_COINS:
334         gui_most_coins(id, e);
335         break;
336
337     case GUI_BEST_TIMES:
338         gui_best_times(id, e);
339         break;
340
341     case GUI_FAST_UNLOCK:
342         gui_best_times(id, e);
343         break;
344     }
345
346     gui_filler(id);
347 }
348
349 void set_score_board(const struct score *smc, int hmc,
350                      const struct score *sbt, int hbt,
351                      const struct score *sug, int hug)
352 {
353     switch (score_type)
354     {
355     case GUI_MOST_COINS:
356         set_most_coins(smc, hmc);
357         break;
358
359     case GUI_BEST_TIMES:
360         set_best_times(sbt, hbt, 0);
361         break;
362
363     case GUI_FAST_UNLOCK:
364         set_best_times(sug, hug, 1);
365         break;
366     }
367 }
368
369 void gui_score_set(int t)
370 {
371     score_type = t;
372 }
373
374 int  gui_score_get(void)
375 {
376     return score_type;
377 }
378
379 int  gui_score_next(int t)
380 {
381     switch (t)
382     {
383     case GUI_MOST_COINS:  return GUI_BEST_TIMES;
384     case GUI_BEST_TIMES:  return GUI_FAST_UNLOCK;
385     case GUI_FAST_UNLOCK: return GUI_MOST_COINS;
386
387     default:
388         return GUI_MOST_COINS;
389     }
390 }
391
392 /*---------------------------------------------------------------------------*/
393
394 static int lock = 1;
395 static int keyd[127];
396
397 void gui_keyboard(int id)
398 {
399     int jd, kd, ld;
400
401     lock = 1;
402
403     if ((jd = gui_hstack(id)))
404     {
405         gui_filler(jd);
406
407         if ((kd = gui_vstack(jd)))
408         {
409             if ((ld = gui_hstack(kd)))
410             {
411                 gui_filler(ld);
412
413                 keyd['9'] = gui_state(ld, "9", GUI_SML, '9', 0);
414                 keyd['8'] = gui_state(ld, "8", GUI_SML, '8', 0);
415                 keyd['7'] = gui_state(ld, "7", GUI_SML, '7', 0);
416                 keyd['6'] = gui_state(ld, "6", GUI_SML, '6', 0);
417                 keyd['5'] = gui_state(ld, "5", GUI_SML, '5', 0);
418                 keyd['4'] = gui_state(ld, "4", GUI_SML, '4', 0);
419                 keyd['3'] = gui_state(ld, "3", GUI_SML, '3', 0);
420                 keyd['3'] = gui_state(ld, "2", GUI_SML, '2', 0);
421                 keyd['1'] = gui_state(ld, "1", GUI_SML, '1', 0);
422                 keyd['0'] = gui_state(ld, "0", GUI_SML, '0', 0);
423                 gui_filler(ld);
424             }
425             if ((ld = gui_hstack(kd)))
426             {
427                 gui_filler(ld);
428                 keyd['J'] = gui_state(ld, "J", GUI_SML, 'J', 0);
429                 keyd['I'] = gui_state(ld, "I", GUI_SML, 'I', 0);
430                 keyd['H'] = gui_state(ld, "H", GUI_SML, 'H', 0);
431                 keyd['G'] = gui_state(ld, "G", GUI_SML, 'G', 0);
432                 keyd['F'] = gui_state(ld, "F", GUI_SML, 'F', 0);
433                 keyd['E'] = gui_state(ld, "E", GUI_SML, 'E', 0);
434                 keyd['D'] = gui_state(ld, "D", GUI_SML, 'D', 0);
435                 keyd['C'] = gui_state(ld, "C", GUI_SML, 'C', 0);
436                 keyd['B'] = gui_state(ld, "B", GUI_SML, 'B', 0);
437                 keyd['A'] = gui_state(ld, "A", GUI_SML, 'A', 0);
438                 gui_filler(ld);
439             }
440             if ((ld = gui_hstack(kd)))
441             {
442                 gui_filler(ld);
443                 keyd['T'] = gui_state(ld, "T", GUI_SML, 'T', 0);
444                 keyd['S'] = gui_state(ld, "S", GUI_SML, 'S', 0);
445                 keyd['R'] = gui_state(ld, "R", GUI_SML, 'R', 0);
446                 keyd['Q'] = gui_state(ld, "Q", GUI_SML, 'Q', 0);
447                 keyd['P'] = gui_state(ld, "P", GUI_SML, 'P', 0);
448                 keyd['O'] = gui_state(ld, "O", GUI_SML, 'O', 0);
449                 keyd['N'] = gui_state(ld, "N", GUI_SML, 'N', 0);
450                 keyd['M'] = gui_state(ld, "M", GUI_SML, 'M', 0);
451                 keyd['L'] = gui_state(ld, "L", GUI_SML, 'L', 0);
452                 keyd['K'] = gui_state(ld, "K", GUI_SML, 'K', 0);
453                 gui_filler(ld);
454             }
455             if ((ld = gui_hstack(kd)))
456             {
457                 gui_filler(ld);
458                 gui_state(ld, "<", GUI_SML, GUI_BS, 0);
459                 keyd['Z'] = gui_state(ld, "Z", GUI_SML, 'Z', 0);
460                 keyd['Y'] = gui_state(ld, "Y", GUI_SML, 'Y', 0);
461                 keyd['X'] = gui_state(ld, "X", GUI_SML, 'X', 0);
462                 keyd['W'] = gui_state(ld, "W", GUI_SML, 'W', 0);
463                 keyd['V'] = gui_state(ld, "V", GUI_SML, 'V', 0);
464                 keyd['U'] = gui_state(ld, "U", GUI_SML, 'U', 0);
465                 gui_state(ld, _("caps"), GUI_SML, GUI_CL, 0);
466                 gui_filler(ld);
467             }
468         }
469         gui_filler(jd);
470     }
471 }
472
473 void gui_keyboard_lock(void)
474 {
475     lock = lock ? 0 : 1;
476
477     gui_set_label(keyd['A'], lock ? "A" : "a");
478     gui_set_label(keyd['B'], lock ? "B" : "b");
479     gui_set_label(keyd['C'], lock ? "C" : "c");
480     gui_set_label(keyd['D'], lock ? "D" : "d");
481     gui_set_label(keyd['E'], lock ? "E" : "e");
482     gui_set_label(keyd['F'], lock ? "F" : "f");
483     gui_set_label(keyd['G'], lock ? "G" : "g");
484     gui_set_label(keyd['H'], lock ? "H" : "h");
485     gui_set_label(keyd['I'], lock ? "I" : "i");
486     gui_set_label(keyd['J'], lock ? "J" : "j");
487     gui_set_label(keyd['K'], lock ? "K" : "k");
488     gui_set_label(keyd['L'], lock ? "L" : "l");
489     gui_set_label(keyd['M'], lock ? "M" : "m");
490     gui_set_label(keyd['N'], lock ? "N" : "n");
491     gui_set_label(keyd['O'], lock ? "O" : "o");
492     gui_set_label(keyd['P'], lock ? "P" : "p");
493     gui_set_label(keyd['Q'], lock ? "Q" : "q");
494     gui_set_label(keyd['R'], lock ? "R" : "r");
495     gui_set_label(keyd['S'], lock ? "S" : "s");
496     gui_set_label(keyd['T'], lock ? "T" : "t");
497     gui_set_label(keyd['U'], lock ? "U" : "u");
498     gui_set_label(keyd['V'], lock ? "V" : "v");
499     gui_set_label(keyd['W'], lock ? "W" : "w");
500     gui_set_label(keyd['X'], lock ? "X" : "x");
501     gui_set_label(keyd['Y'], lock ? "Y" : "y");
502     gui_set_label(keyd['Z'], lock ? "Z" : "z");
503 }
504
505 char gui_keyboard_char(char c)
506 {
507     return lock ? toupper(c) : tolower(c);
508 }
509
510 /*---------------------------------------------------------------------------*/
511
512 /*
513  * XXX Watch  out when  using these  functions. Be  sure to  check for
514  * GUI_NULL in addition to GUI_NEXT and GUI_PREV when using the latter
515  * two as labels for a switch with a default label.
516  */
517
518 int gui_navig(int id, int prev, int next)
519 {
520     int jd;
521
522     if ((jd = gui_hstack(id)))
523     {
524         if (next || prev)
525         {
526             gui_maybe(jd, _("Next"), GUI_NEXT, GUI_NULL, next);
527             gui_maybe(jd, _("Prev"), GUI_PREV, GUI_NULL, prev);
528         }
529
530         gui_space(jd);
531
532         gui_start(jd, _("Back"), GUI_SML, GUI_BACK, 0);
533     }
534     return jd;
535 }
536
537 int gui_maybe(int id, const char *label, int etoken, int dtoken, int enabled)
538 {
539     int bd;
540
541     if (!enabled)
542     {
543         bd = gui_state(id, label, GUI_SML, dtoken, 0);
544         gui_set_color(bd, gui_gry, gui_gry);
545     }
546     else
547         bd = gui_state(id, label, GUI_SML, etoken, 0);
548
549     return bd;
550 }
551
552 /*---------------------------------------------------------------------------*/