1 /***************************************************************************
2                           levels.c  -  description
3                              -------------------
4     begin                : Mon Aug 14 2000
5     copyright            : (C) 2000 by Michael Speck
6     email                : kulkanie@gmx.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include <math.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <dirent.h>
25 #include "levels.h"
26 #include "dynlist.h"
27 #include "game.h"
28 #include "file.h"
29 #include "sdl.h"
30 #include "timer.h"
31 #include "cfg.h"
32 
33 /* game struct -- game.c */
34 extern Game gm;
35 /* line counter -- file.c */
36 extern int f_ln;
37 /* Sdl -- sdl.c */
38 extern Sdl sdl;
39 /* profiles -- profile.c */
40 extern DLst prfs;
41 /* config -- cfg.c */
42 extern Cfg cfg;
43 
44 char **ls_lst = 0;
45 int  ls_n = 0;
46 DLst l_sts;
47 
48 /*
49     count and create a list with all loadable filenames found in SRC_DIR/levels
50 */
L_CrtLst()51 void L_CrtLst()
52 {
53     int     i;
54     char    d_nm[256];
55     char    path[256+64];
56     DIR     *dir = 0;
57     struct dirent  *e;
58     struct stat     s;
59 
60     ls_n = 0;
61 
62     // create directory string //
63     sprintf(d_nm, "%s/levels", SRC_DIR);
64 
65     // find and open directory //
66     if ((dir = opendir(d_nm)) == 0) {
67         fprintf(stderr, "ERROR: can't find directory '%s'\n", d_nm);
68         exit(1);
69     }
70 
71     printf("searching for level sets...\n");
72     // well, let's check the count the entries //
73     while ((e = readdir(dir)) != 0) {
74         sprintf(path, "%s/%s", d_nm, e->d_name);
75         stat(path, &s);
76         if (S_ISREG(s.st_mode)) {
77             (ls_n)++;
78             printf("'%s'\n", e->d_name);
79         }
80     }
81 
82     if (ls_n == 0) {
83         fprintf(stderr, "ERROR: '%s' seems to be empty\n", d_nm);
84         closedir(dir);
85         exit(1);
86     }
87     else
88         printf("...total of %i\n", ls_n);
89 
90     // now we'll create the list //
91     rewinddir(dir);
92     ls_lst = malloc(sizeof(char*) * (ls_n));
93     for (i = 0; i < ls_n; i++) {
94         do {
95             e = readdir(dir);
96             if (e == 0) continue;
97             sprintf(path, "%s/%s", d_nm, e->d_name);
98             stat(path, &s);
99         } while (!S_ISREG(s.st_mode));
100         ls_lst[i] = malloc(strlen(e->d_name) + 1);
101         strcpy(ls_lst[i], e->d_name);
102     }
103 
104     // close dir //
105     closedir(dir);
106 }
107 
108 /*
109     free list memory
110 */
L_DelLst()111 void L_DelLst()
112 {
113     int i;
114     if (!ls_lst) return;
115     for (i = 0; i < ls_n; i++)
116         free(ls_lst[i]);
117     free(ls_lst);
118 }
119 
120 /*
121     callback for dynlist l_sts to delete a level set
122 */
L_DelSt(void * p)123 void L_DelSt(void *p)
124 {
125     int i;
126     LSet *st = (LSet*)p;
127     if (st->ch) {
128         for (i = 0; i < st->c_num; i++)
129             free(st->ch[i].lvls);
130         free(st->ch);
131     }
132     free(p);
133 }
134 
135 /*
136     add an empty and invalid entry
137 */
L_AddInvSt(char * nm)138 void L_AddInvSt(char *nm)
139 {
140     LSet *st = malloc(sizeof(LSet));
141     st->c_num = 0;
142     st->ch = 0;
143     st->ok = 0;
144     strcpy(st->nm, nm);
145     DL_Add(&l_sts, st);
146 }
147 
148 /*
149     set marble, type and id of a map tile
150 */
L_StMpT(MapT * tl,int m,int t,int id)151 void L_StMpT(MapT *tl, int m, int t, int id)
152 {
153     tl->m = m;
154     tl->t = t;
155     tl->id = id;
156 }
157 
158 /*
159     parse and add a new lset from file f
160 */
L_LdSt(FILE * f)161 int L_LdSt(FILE *f)
162 {
163     int i, j, k, l;
164     char val[64];
165     char str[512];
166     LSet *st = malloc(sizeof(LSet));
167 
168     // info section //
169     F_GetE(f, str, F_SUB | F_VAL);
170     if (!F_CkE(str, F_SUB, "<info>", 0)) {
171         printf("ERROR: line %i: '<info>' expected\n", f_ln);
172         free(st);
173         return 0;
174     }
175     // levels per chapter //
176     F_GetE(f, str, F_VAL);
177     if (!F_CkE(str, F_VAL, "levels", val)) {
178         printf("ERROR: line %i: 'levels' expected\n", f_ln);
179         free(st);
180         return 0;
181     }
182     st->l_num = atoi(val);
183     // chapters //
184     F_GetE(f, str, F_VAL);
185     if (!F_CkE(str, F_VAL, "chapters", val)) {
186         printf("ERROR: line %i: 'chapters' expected\n", f_ln);
187         free(st);
188         return 0;
189     }
190     st->c_num = atoi(val);
191     // limit type //
192     F_GetE(f, str, F_VAL);
193     if (!F_CkE(str, F_VAL, "limit", val)) {
194         printf("ERROR: line %i: 'limit' expected\n", f_ln);
195         free(st);
196         return 0;
197     }
198     if ( !strncmp( "time", val, 4 ) )
199         st->limit_type = TIME;
200     else
201         st->limit_type = MOVES;
202     // info section //
203     F_GetE(f, str, F_SUB | F_VAL);
204     if (!F_CkE(str, F_SUB, "</info>", 0)) {
205         printf("ERROR: line %i: '</info>' expected\n", f_ln);
206         free(st);
207         return 0;
208     }
209 
210     // get memory
211     st->ch = malloc( sizeof(Chptr) * st->c_num );
212     for (i = 0; i < st->c_num; i++)
213         st->ch[i].lvls = malloc( sizeof(Lvl) * st->l_num );
214 
215     // chapters
216     for (i = 0; i < st->c_num; i++) {
217         // chapter start //
218         F_GetE(f, str, F_SUB | F_VAL);
219         if (!F_CkE(str, F_SUB, "<chapter>", 0)) {
220             printf("ERROR: line %i: '<chapter>' expected\n", f_ln);
221             goto failure;
222         }
223         // name //
224         F_GetE(f, str, F_VAL);
225         if (!F_CkE(str, F_VAL, "name", st->ch[i].nm)) {
226             printf("ERROR: line %i: 'name' expected\n", f_ln);
227             goto failure;
228         }
229         // author //
230         F_GetE(f, str, F_VAL);
231         if (!F_CkE(str, F_VAL, "author", st->ch[i].authr)) {
232             printf("ERROR: line %i: 'author' expected\n", f_ln);
233             goto failure;
234         }
235         // gset //
236         F_GetE(f, str, F_VAL);
237         if (!F_CkE(str, F_VAL, "gfx_set", st->ch[i].g_st)) {
238             printf("ERROR: line %i: 'gfx_set' expected\n", f_ln);
239             goto failure;
240         }
241         // open for play ? //
242         F_GetE(f, str, F_VAL);
243         if (!F_CkE(str, F_VAL, "open", val)) {
244             printf("ERROR: line %i: 'open' expected\n", f_ln);
245             goto failure;
246         }
247         st->ch[i].opn = atoi(val);
248 
249         // levels //
250         for (j = 0; j < st->l_num; j++) {
251             // level start //
252             F_GetE(f, str, F_SUB | F_VAL);
253             if (!F_CkE(str, F_SUB, "<level>", 0)) {
254                 printf("ERROR: line %i: '<level>' expected\n", f_ln);
255                 goto failure;
256             }
257             // time //
258             F_GetE(f, str, F_VAL);
259             if (!F_CkE(str, F_VAL, "limit", val)) {
260                 printf("ERROR: line %i: 'limit' expected\n", f_ln);
261                 goto failure;
262             }
263             st->ch[i].lvls[j].tm = atoi(val);
264             // map width //
265             F_GetE(f, str, F_VAL);
266             if (!F_CkE(str, F_VAL, "map_w", val)) {
267                 printf("ERROR: line %i: 'map_w' expected\n", f_ln);
268                 goto failure;
269             }
270             if ((st->ch[i].lvls[j].m_w = atoi(val)) > L_MAX_W || atoi(val) < L_MIN_W) {
271                 printf("ERROR: line %i: 'map_w' out of range (%i-%i): %i\n", f_ln, L_MIN_W, L_MAX_W, atoi(val));
272                 goto failure;
273             }
274             // map height //
275             F_GetE(f, str, F_VAL);
276             if (!F_CkE(str, F_VAL, "map_h", val)) {
277                 printf("ERROR: line %i: 'map_h' expected\n", f_ln);
278                 goto failure;
279             }
280             if ((st->ch[i].lvls[j].m_h = atoi(val)) > L_MAX_H || atoi(val) < L_MIN_H) {
281                 printf("ERROR: line %i: 'map_w' out of range (%i-%i): %i\n", f_ln, L_MIN_H, L_MAX_H, atoi(val));
282                 goto failure;
283             }
284             // figure width //
285             F_GetE(f, str, F_VAL);
286             if (!F_CkE(str, F_VAL, "fig_w", val)) {
287                 printf("ERROR: line %i: 'fig_w' expected\n", f_ln);
288                 goto failure;
289             }
290             st->ch[i].lvls[j].f_w = atoi(val);
291             if ((st->ch[i].lvls[j].f_w = atoi(val)) > F_MAX_W || atoi(val) < F_MIN_W) {
292                 printf("ERROR: line %i: 'fig_w' out of range (%i-%i): %i\n", f_ln, F_MIN_W, F_MAX_W, atoi(val));
293                 goto failure;
294             }
295             // figure height //
296             F_GetE(f, str, F_VAL);
297             if (!F_CkE(str, F_VAL, "fig_h", val)) {
298                 printf("ERROR: line %i: 'fig_h' expected\n", f_ln);
299                 goto failure;
300             }
301             if ((st->ch[i].lvls[j].f_h = atoi(val)) > F_MAX_H || atoi(val) < F_MIN_H) {
302                 printf("ERROR: line %i: 'fig_h' out of range (%i-%i): %i\n", f_ln, F_MIN_H, F_MAX_H, atoi(val));
303                 goto failure;
304             }
305 
306             // figure start //
307             F_GetE(f, str, F_SUB | F_VAL);
308             if (!F_CkE(str, F_SUB, "<figure>", 0)) {
309                 printf("ERROR: line %i: '<figure>' expected\n", f_ln);
310                 goto failure;
311             }
312             // figure //
313             for (k = 0; k < st->ch[i].lvls[j].f_h; k++) {
314                 F_GetE(f, str, F_VAL);
315                 for (l = 0; l < st->ch[i].lvls[j].f_w; l++) {
316                     if (str[l] >= '0' && str[l] <= '9')
317                         st->ch[i].lvls[j].fgr[l][k] = str[l] - 48;
318                     else
319                         if (str[l] != 32)
320                             printf("WARNING: line %i: bad figure marble '%c'\n", f_ln, str[l]);
321                         else
322                             st->ch[i].lvls[j].fgr[l][k] = -1;
323                 }
324             }
325             // figure end //
326             F_GetE(f, str, F_SUB | F_VAL);
327             if (!F_CkE(str, F_SUB, "</figure>", 0)) {
328                 printf("ERROR: line %i: '</figure>' expected\n", f_ln);
329                 goto failure;
330             }
331 
332             // map start //
333             F_GetE(f, str, F_SUB | F_VAL);
334             if (!F_CkE(str, F_SUB, "<map>", 0)) {
335                 printf("ERROR: line %i: '<map>' expected\n", f_ln);
336                 goto failure;
337             }
338             // map
339             for (k = 0; k < st->ch[i].lvls[j].m_h; k++) {
340                 memset(str, 0, 256);
341                 F_GetE(f, str, F_VAL);
342                 for (l = 0; l < st->ch[i].lvls[j].m_w; l++) {
343                     if (str[l] >= '0' && str[l] <= '9')
344                         L_StMpT(&st->ch[i].lvls[j].map[l][k], str[l] - 48, M_FLOOR, 0);
345                     else
346                         switch (str[l]) {
347                             case 'a':
348                             case 'b':
349                             case 'c':
350                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_WALL, str[l] - 97);
351                                 break;
352                             case ' ':
353                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_FLOOR, 0);
354                                 break;
355                             case 'u':
356                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_U, 0);
357                                 break;
358                             case 'd':
359                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_D, 0);
360                                 break;
361                             case 'r':
362                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_R, 0);
363                                 break;
364                             case 'l':
365                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_L, 0);
366                                 break;
367                             case 'U':
368                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_U_C, 0);
369                                 break;
370                             case 'D':
371                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_D_C, 0);
372                                 break;
373                             case 'R':
374                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_R_C, 0);
375                                 break;
376                             case 'L':
377                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_OW_L_C, 0);
378                                 break;
379                             case 'w':
380                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_TLP_0, 0);
381                                 break;
382                             case 'x':
383                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_TLP_1, 0);
384                                 break;
385                             case 'y':
386                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_TLP_2, 0);
387                                 break;
388                             case 'z':
389                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_TLP_3, 0);
390                                 break;
391                             case 'A':
392                             case 'B':
393                             case 'C':
394                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_CRUMBLE, str[l] - 65);
395                                 break;
396                             default:
397                                 L_StMpT(&st->ch[i].lvls[j].map[l][k], -1, M_EMPTY, 0);
398                         break;
399                         }
400                 }
401             }
402             // map end //
403             F_GetE(f, str, F_SUB | F_VAL);
404             if (!F_CkE(str, F_SUB, "</map>", 0)) {
405                 printf("ERROR: line %i: '</map>' expected\n", f_ln);
406                 goto failure;
407             }
408 
409             // level end //
410             F_GetE(f, str, F_SUB | F_VAL);
411             if (!F_CkE(str, F_SUB, "</level>", 0)) {
412                 printf("ERROR: line %i: '</level>' expected\n", f_ln);
413                 goto failure;
414             }
415         }
416 
417         // chapter end //
418         F_GetE(f, str, F_SUB);
419         if (!F_CkE(str, F_SUB, "</chapter>", 0)) {
420             printf("ERROR: line %i: '</chapter>' expected\n", f_ln);
421             goto failure;
422         }
423     }
424 
425     // return 1 in any case cuz 0 assumes that an empty set must be added
426     printf("ok\n");
427     DL_Add(&l_sts, st);
428     st->ok = 1;
429     return 1;
430 
431 failure:
432     DL_Add(&l_sts, st);
433 //    L_DelSt(st);
434     st->ok = 0;
435     return 1;
436 }
437 
438 /*
439     initialize level l
440 */
L_Ini(int c,int l)441 void L_Ini(int c, int l)
442 {
443     char *nm;
444     DL_E *e;
445     int gst_ok = 0;
446     int px, py, i, j, k;
447     Lvl *lp;
448     char str[64];
449     int off;
450     char *str_num[] = {"1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.", "10."};
451     float mv_mod;
452 
453     // show credit when new chapter
454     if ( gm.o_ch == -1 || gm.o_ch != c )
455         Cr_Ini();
456 
457     // set level & chapter  index
458     gm.o_ch = c;
459     gm.c_ch = c;
460     gm.c_l_id = l;
461     gm.l_done = 0;
462 
463     // set open flag
464     gm.c_s_inf->c_opn[gm.c_ch] = 1;
465 
466     // copy current level
467     if (gm.c_lvl) free(gm.c_lvl);
468     gm.c_lvl = malloc(sizeof(Lvl));
469     memcpy(gm.c_lvl, &gm.c_l_st->ch[gm.c_ch].lvls[gm.c_l_id], sizeof(Lvl));
470 
471     // load gfx set
472     nm = gm.c_l_st->ch[gm.c_ch].g_st;
473     e = gm.g_sts.hd.n;
474     while (e != &gm.g_sts.tl) {
475         if (!strncmp(nm, ((GSet*)e->d)->nm, strlen(nm)) && ((GSet*)e->d)->ok) {
476             gm.c_g_st = (GSet*)e->d;
477             gst_ok = 1;
478             break;
479         }
480         e = e->n;
481     }
482     if (!gst_ok) {
483         printf("WARNING: unknown or unuseable gfx set '%s';\nsearching for a good one...\n", nm);
484         // find first useable set
485         e = gm.g_sts.hd.n;
486         while (e != &gm.g_sts.tl) {
487             if (((GSet*)e->d)->ok) {
488                 gm.c_g_st = (GSet*)e->d;
489                 printf("'%s' used instead\n", gm.c_g_st->nm);
490                 gst_ok = 1;
491                 break;
492             }
493             e = e->n;
494         }
495         if (!gst_ok) {
496             printf("ERROR: no good gfx set found...\n");
497             exit(1);
498         }
499     }
500 
501     // set bkgd picture
502     if (gm.c_g_st->s_bkgd) {
503         for (j = 0; j < gm.scr_w - gm.brd_w; j += gm.c_g_st->s_bkgd->w)
504             for (k = 0; k < gm.scr_h; k += gm.c_g_st->s_bkgd->h) {
505                 D_DST(gm.s_bkgd, j, k, gm.c_g_st->s_bkgd->w, gm.c_g_st->s_bkgd->h);
506                 D_SRC(gm.c_g_st->s_bkgd, 0, 0);
507                 SS_Blt();
508             }
509         }
510     else {
511         D_DST(gm.s_bkgd, 0, 0, gm.scr_w - gm.brd_w, gm.scr_h);
512         SS_Fill(0x0);
513     }
514 
515     // add board
516     D_DST(gm.s_bkgd, gm.s_bkgd->w - gm.s_brd->w, 0, gm.s_brd->w, gm.s_brd->h);
517     D_SRC(gm.s_brd, 0, 0);
518     SS_Blt();
519 
520     // add static level gfx
521     lp = &gm.c_l_st->ch[gm.c_ch].lvls[gm.c_l_id];
522     gm.l_x = (gm.scr_w - gm.brd_w - lp->m_w * gm.t_w) / 2;
523     gm.l_y = (gm.scr_h - lp->m_h * gm.t_h) / 2;
524     for (i = 0; i < lp->m_w; i++)
525         for (j = 0; j < lp->m_h; j++)
526             L_DrwMpTl(i, j);
527 
528     // add marbles
529     for (i = 0; i < lp->m_w; i++)
530         for (j = 0; j < lp->m_h; j++)
531             if (lp->map[i][j].m != - 1) {
532                 D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
533                 D_SRC(gm.s_mrb, 0, lp->map[i][j].m * gm.t_h);
534                 SS_Blt();
535             }
536 
537     // add figure
538     px = gm.b_x + gm.f_x + (gm.f_fw - lp->f_w * gm.f_h) / 2;
539     py = gm.f_y + (gm.f_fh - lp->f_h * gm.f_h)/ 2;
540     for (i = 0; i < lp->f_w; i++)
541         for (j = 0; j < lp->f_h; j++)
542             if (lp->fgr[i][j] != -1) {
543                 D_DST(gm.s_bkgd, px + i * gm.f_w, py + j * gm.f_h, gm.f_w, gm.f_h);
544                 D_SRC(gm.s_fig, 0, lp->fgr[i][j] * gm.f_h);
545                 SS_Blt();
546             }
547 
548     // add player info
549     off = gm.f_sml->h + 2;
550     gm.f_sml->algn = TA_X_L | TA_Y_T;
551     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.i_x + gm.b_x, gm.i_y, "Player:", 0);
552     gm.f_sml->algn = TA_X_R | TA_Y_T;
553     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.scr_w - gm.i_x, gm.i_y, gm.c_prf->nm, 0);
554     gm.f_sml->algn = TA_X_L | TA_Y_T;
555     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.i_x + gm.b_x, gm.i_y + off, "Score:", 0);
556     gm.f_sml->algn = TA_X_R | TA_Y_T;
557     sprintf(str, "%i", gm.c_prf->scr);
558     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.scr_w - gm.i_x, gm.i_y + off, str, 0);
559     gm.f_sml->algn = TA_X_L | TA_Y_T;
560     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.i_x + gm.b_x, gm.i_y + off*2 + 5, "HighScore:", 0);
561     gm.f_sml->algn = TA_X_R | TA_Y_T;
562     sprintf(str, "%i", gm.hi_scr);
563     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.scr_w - gm.i_x, gm.i_y + off*2 + 5, str, 0);
564 
565     // add name of levelset above set info
566     gm.f_sml->algn = TA_X_C | TA_Y_T;
567     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.b_x + gm.brd_w / 2, gm.s_y + 5, gm.c_l_st->nm, 0);
568 
569     // compute position of first chapter
570     gm.c_x = 50; // changed
571     gm.c_y = gm.s_y + (gm.s_h - gm.c_l_st->c_num * L_SIZE) / 2;
572 
573     // add chapter numbers
574     gm.f_sml->algn = TA_X_L | TA_Y_T;
575     for (i = 0; i < gm.c_l_st->c_num; i++) {
576          SF_Wrt(gm.f_sml, gm.s_bkgd, gm.b_x + gm.c_x - 30, gm.c_y + i * L_SIZE, str_num[i], 0);
577     }
578 
579     // draw chapter lights
580     for (j = 0; j < gm.c_l_st->c_num; j++)
581         for (i = 0; i < gm.c_l_st->l_num; i++) {
582             D_DST(gm.s_bkgd, gm.b_x + gm.c_x + i * L_SIZE, gm.c_y + j * L_SIZE, L_SIZE, L_SIZE);
583             if (!gm.c_s_inf->c_opn[j]) {
584                 D_SRC(gm.s_lghts, L_RED * L_SIZE, 0);
585             }
586             else
587                 if ( gm.c_s_inf->cmp[j * gm.c_l_st->l_num + i] ) {
588                     D_SRC(gm.s_lghts, L_GREEN * L_SIZE, 0);
589                 }
590                 else {
591                     D_SRC(gm.s_lghts, L_ORANGE * L_SIZE, 0);
592                 }
593             SS_Blt();
594         }
595     // current level is white
596     D_DST(gm.s_bkgd, gm.b_x + gm.c_x + l * L_SIZE, gm.c_y + c * L_SIZE, L_SIZE, L_SIZE);
597     D_SRC(gm.s_lghts, L_WHITE * L_SIZE, 0);
598     SS_Blt();
599 
600     // initiate animations
601 
602     MA_Ini();
603 
604     // undim
605     D_FDST(sdl.scr);
606     D_FSRC(gm.s_bkgd);
607     SS_Blt();
608     if (cfg.dim)
609         SDL_UNDIM();
610     else
611         Sdl_FUpd();
612 
613     // reset timer
614     T_Rst();
615 
616     // reset marble and frame
617     gm.m_mv = 0;
618     gm.m_sel = 0;
619     gm.mf_a.p = 0;
620     gm.msf_a.p = 0;
621     gm.m_act = M_EMPTY;
622     gm.m_mx = gm.m_my = -1;
623 
624     if ( gm.c_l_st->limit_type == TIME ) {
625         /* set time from seconds to milliseconds if time used */
626         gm.c_lvl->tm *= 1000;
627         gm.c_lvl->tm+=1000;
628     }
629     else {
630         /* gm.c_lvl->tm containts the move limit. this is modified according
631            to the difficulty levels */
632         switch ( cfg.diff ) {
633             case DIFF_EASY:
634                 mv_mod = (int)ceil((float)gm.c_lvl->tm * 0.2 * ( 5 - gm.c_ch ) );
635                 gm.c_lvl->tm += mv_mod;
636                 if ( gm.c_lvl->tm % 2 ) gm.c_lvl->tm++;
637                 break;
638             case DIFF_NORMAL:
639                 mv_mod = (int)ceil((float)gm.c_lvl->tm * 0.1 * ( 5 - gm.c_ch ) );
640                 gm.c_lvl->tm += mv_mod;
641                 if ( gm.c_lvl->tm % 2 ) gm.c_lvl->tm++;
642                 break;
643             case DIFF_HARD:
644                 mv_mod = (int)ceil((float)gm.c_lvl->tm * 0.05 * ( 5 - gm.c_ch ) );
645                 gm.c_lvl->tm += mv_mod;
646                 if ( gm.c_lvl->tm % 2 ) gm.c_lvl->tm++;
647                 break;
648             case DIFF_BRAINSTORM:
649                 break;
650         }
651     }
652 
653     // init blink time //
654     gm.blink_time = 0;
655 
656     // cursor state
657     gm.c_stat = C_NONE;
658     SDL_SetCursor(gm.c_n);
659 
660     // reset shrapnells
661     DL_Clr(&gm.shr);
662 }
663 
664 /*
665     draw a map tile to gm.s_bkgd with x,y position in the map using current map
666 */
L_DrwMpTl(int i,int j)667 void L_DrwMpTl(int i, int j)
668 {
669     switch (gm.c_lvl->map[i][j].t) {
670         case M_WALL:
671             // add wall shadow on right side ? //
672             if ( i + 1 >= gm.c_lvl->m_w || gm.c_lvl->map[i + 1][j].t == M_EMPTY ) {
673 
674                 D_DST(gm.s_bkgd, gm.l_x + (i + 1) * gm.t_w, gm.l_y + j * gm.t_h, 1, gm.t_h + 1);
675                 SS_Fill(0x0);
676 
677             }
678             // add wall shadow on bottom ? //
679             if ( j + 1 >= gm.c_lvl->m_h || gm.c_lvl->map[i][j + 1].t == M_EMPTY ) {
680 
681                 D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + (j + 1) * gm.t_h, gm.t_w + 1, 1);
682                 SS_Fill(0x0);
683 
684             }
685             // add wall shadow on left side ? //
686             if ( (i == 0)
687 	       || ((i - 1 >= gm.c_lvl->m_w) || gm.c_lvl->map[i - 1][j].t == M_EMPTY )) {
688                 D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w - 1, gm.l_y + j * gm.t_h, 1, gm.t_h + 1);
689                 SS_Fill(0x0);
690 
691             }
692             // add wall shadow on top ? //
693 	    if ( (j == 0)
694 	       || ((j - 1 >= gm.c_lvl->m_h) || gm.c_lvl->map[i][j - 1].t == M_EMPTY )) {
695                 D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h - 1, gm.t_w + 1, 1);
696                 SS_Fill(0x0);
697 
698             }
699             D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
700             D_SRC(gm.c_g_st->s_wl, gm.c_lvl->map[i][j].id * gm.t_w, 0);
701             SS_Blt();
702             break;
703         case M_CRUMBLE:
704 
705             D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
706             D_SRC(gm.c_g_st->s_flr, 0, 0);
707             SS_Blt();
708 
709             D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
710             D_SRC(gm.c_g_st->s_crmbl, gm.c_lvl->map[i][j].id * gm.t_w, 0);
711             SS_Blt();
712 
713             gm.f_sml->algn = TA_X_R | TA_Y_B;
714             switch (gm.c_lvl->map[i][j].id) {
715                 case 0:
716                     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.l_x + (i + 1) * gm.t_w - 1, gm.l_y + (j + 1) * gm.t_h - 1, "1", 0);
717                 break;
718                 case 1:
719                     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.l_x + (i + 1) * gm.t_w - 1, gm.l_y + (j + 1) * gm.t_h - 1, "2", 0);
720                 break;
721                 case 2:
722                     SF_Wrt(gm.f_sml, gm.s_bkgd, gm.l_x + (i + 1) * gm.t_w - 1, gm.l_y + (j + 1) * gm.t_h - 1, "3", 0);
723                 break;
724             }
725 
726             break;
727         case M_EMPTY:
728             break;
729         default:
730             D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
731             D_SRC(gm.c_g_st->s_flr, 0, 0);
732             SS_Blt();
733             break;
734     }
735 
736     // static animations ? //
737     if (!cfg.ani) {
738         D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
739         switch (gm.c_lvl->map[i][j].t) {
740             case M_OW_U:
741             case M_OW_U_C:
742                 D_SRC(gm.c_g_st->s_u_arw, 0, 0);
743                 SS_Blt();
744                 break;
745             case M_OW_D:
746             case M_OW_D_C:
747                 D_SRC(gm.c_g_st->s_d_arw, 0, 0);
748                 SS_Blt();
749                 break;
750             case M_OW_L:
751             case M_OW_L_C:
752                 D_SRC(gm.c_g_st->s_l_arw, 0, 0);
753                 SS_Blt();
754                 break;
755             case M_OW_R:
756             case M_OW_R_C:
757                 D_SRC(gm.c_g_st->s_r_arw, 0, 0);
758                 SS_Blt();
759                 break;
760         }
761         D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
762         switch (gm.c_lvl->map[i][j].t) {
763             case M_OW_U_C:
764             case M_OW_D_C:
765                 D_SRC(gm.c_g_st->s_lr_bar, 0, 0);
766                 SS_Blt();
767                 break;
768             case M_OW_L_C:
769             case M_OW_R_C:
770                 D_SRC(gm.c_g_st->s_ud_bar, 0, 0);
771                 SS_Blt();
772                 break;
773         }
774 
775         D_DST(gm.s_bkgd, gm.l_x + i * gm.t_w, gm.l_y + j * gm.t_h, gm.t_w, gm.t_h);
776         switch (gm.c_lvl->map[i][j].t) {
777             case M_TLP_0:
778                 D_SRC(gm.c_g_st->s_tlp_0, 0, 0);
779                 SS_ABlt(gm.tlp_a);
780                 break;
781             case M_TLP_1:
782                 D_SRC(gm.c_g_st->s_tlp_1, 0, 0);
783                 SS_ABlt(gm.tlp_a);
784                 break;
785             case M_TLP_2:
786                 D_SRC(gm.c_g_st->s_tlp_2, 0, 0);
787                 SS_ABlt(gm.tlp_a);
788                 break;
789             case M_TLP_3:
790                 D_SRC(gm.c_g_st->s_tlp_3, 0, 0);
791                 SS_ABlt(gm.tlp_a);
792                 break;
793         }
794     }
795 }
796 
797 /*
798     proceed to next valid level
799 */
L_FndNxt()800 int L_FndNxt()
801 {
802     int i, j;
803 
804     // proceed to next level
805     gm.c_l_id++;
806     if (gm.c_l_id >= gm.c_l_st->l_num) {
807         gm.c_l_id = 0;
808         gm.c_ch++;
809         // check if this chapter can be entered or if this was the last chapter if not take first unsolved level found
810         if (gm.c_ch >= gm.c_l_st->c_num || !gm.c_l_st->ch[gm.c_ch].opn) {
811             for (i = 0; i < gm.c_ch; i++)
812                 for (j = 0; j < gm.c_l_st->l_num; j++)
813                     if (!gm.c_s_inf->cmp[i * gm.c_l_st->l_num + j]) {
814                         // not all levels completed jump back to first unsolved level
815                         gm.c_ch = i;
816                         gm.c_l_id = j;
817                         return 1;
818                     }
819             if (gm.c_ch >= gm.c_l_st->c_num)
820                 return 0;
821             else
822                 return 1;
823         }
824     }
825     else {
826         // check if all levels of this chapter has been solved
827         for (i = 0; i <= gm.c_ch; i++)
828             for (j = 0; j < gm.c_l_st->l_num; j++)
829                 if (!gm.c_s_inf->cmp[i * gm.c_l_st->l_num + j]) {
830                     return 1;
831                 }
832         // yes! open next chapter
833         if ( gm.c_ch < gm.c_l_st->c_num - 1 )
834             gm.c_s_inf->c_opn[gm.c_ch + 1] = 1;
835     }
836     return 1;
837 }
838