1 /***************************************************************************
2                           game.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 "game.h"
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "file.h"
23 #include "cfg.h"
24 #include "menu.h"
25 #include "timer.h"
26 
27 Game gm;
28 /* levelset names & levelsets -- levels.h */
29 extern char **ls_lst;
30 extern int  ls_n;
31 extern DLst l_sts;
32 /* line counter -- file.c */
33 extern int f_ln;
34 /* config -- cfg.c */
35 extern Cfg cfg;
36 /* Sdl -- sdl.c */
37 extern Sdl sdl;
38 /* profiles -- profile.c */
39 extern DLst prfs;
40 /* terminate game -- sdl.c */
41 extern int trm_gm;
42 
43 void modify_score( int *b_lvl, int *b_tm );
44 
45 /*
46     initialize game
47 */
G_Ini()48 void G_Ini()
49 {
50     FILE *f;
51     int i;
52     char str[256];
53     int ok = 0;
54     // cursors //
55     char data[32], mask[32];
56     char csr[6][256] = {
57         {
58             0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0,
59             0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0,
60             0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0,
61             0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0,
62             0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0,
63             0, 0, 0, 0, 2, 1, 2, 1, 1, 2, 1, 2, 0, 0, 0, 0,
64             0, 0, 0, 0, 2, 1, 2, 1, 1, 2, 1, 2, 0, 0, 0, 0,
65             0, 0, 0, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 0, 0, 0,
66             0, 0, 0, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 0, 0, 0,
67             0, 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0, 0,
68             0, 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0, 0,
69             0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0,
70             0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0,
71             2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
72             2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
73             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
74         },
75         {
76             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
77             2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
78             2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
79             0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0,
80             0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0,
81             0, 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0, 0,
82             0, 0, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2, 0, 0,
83             0, 0, 0, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 0, 0, 0,
84             0, 0, 0, 2, 1, 2, 1, 1, 1, 1, 2, 1, 2, 0, 0, 0,
85             0, 0, 0, 0, 2, 1, 2, 1, 1, 2, 1, 2, 0, 0, 0, 0,
86             0, 0, 0, 0, 2, 1, 2, 1, 1, 2, 1, 2, 0, 0, 0, 0,
87             0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0,
88             0, 0, 0, 0, 0, 2, 1, 2, 2, 1, 2, 0, 0, 0, 0, 0,
89             0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0,
90             0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0,
91             0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0,
92         },
93         {
94             2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95             2, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96             2, 1, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97             2, 1, 2, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0,
98             2, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0,
99             2, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 0,
100             2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 0,
101             2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2,
102             2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2,
103             2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 0,
104             2, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 0,
105             2, 1, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0,
106             2, 1, 2, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0,
107             2, 1, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108             2, 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
109             2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110         },
111         {
112             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
113             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2,
114             0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 1, 2,
115             0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1, 2,
116             0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2,
117             0, 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 2,
118             0, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2,
119             2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2,
120             2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2,
121             0, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2,
122             0, 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 1, 2,
123             0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 1, 2,
124             0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1, 2,
125             0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 1, 2,
126             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 2,
127             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
128         },
129         {
130             2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
131             2, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 2,
132             2, 1, 1, 1, 1, 2, 0, 0, 0, 0, 2, 1, 1, 1, 1, 2,
133             2, 1, 1, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 1, 1, 2,
134             2, 1, 1, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 1, 2, 0,
135             0, 2, 1, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 2, 0, 0,
136             0, 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0,
137             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
138             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
139             0, 0, 0, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0,
140             0, 0, 2, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 2, 0, 0,
141             0, 2, 1, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 1, 2, 0,
142             2, 1, 1, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 1, 1, 2,
143             2, 1, 1, 1, 1, 2, 0, 0, 0, 0, 2, 1, 1, 1, 1, 2,
144             2, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 2, 1, 1, 1, 2,
145             2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
146         },
147         {
148             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
149             2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
150             2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2,
151             0, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 2, 0,
152             0, 2, 1, 1, 2, 2, 2, 0, 0, 2, 2, 1, 1, 1, 2, 0,
153             0, 0, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 2, 0, 0,
154             0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0,
155             0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0,
156             0, 0, 0, 0, 2, 2, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0,
157             0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0,
158             0, 0, 2, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 2, 0, 0,
159             0, 2, 1, 2, 0, 2, 1, 1, 1, 1, 2, 0, 2, 1, 2, 0,
160             0, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 0,
161             2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2,
162             2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
163             2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
164         }
165     };
166 
167     // initialize dyn list l_sts
168     DL_Ini(&l_sts);
169     l_sts.flgs = DL_AUTODEL;
170     l_sts.cb = L_DelSt;
171     // load level sets
172     printf("loading levelsets...\n");
173     for (i = 0; i < ls_n; i++) {
174         printf("%s... ", ls_lst[i]);
175         sprintf(str, "%s/levels/%s", SRC_DIR, ls_lst[i]);
176         f = fopen(str, "r");
177         if (f != 0) {
178             f_ln = 1;
179             if (L_LdSt(f)) {
180                 ok = 1;
181                 strcpy(((LSet*)l_sts.tl.p->d)->nm, ls_lst[i]);
182             }
183             else
184                 L_AddInvSt(ls_lst[i]);
185             fclose(f);
186         }
187         else {
188             L_AddInvSt(ls_lst[i]);
189             printf("WARNING: levelset not found...\n");
190         }
191     }
192 
193     // found something ? //
194     if (!ok) {
195         printf("ERROR: no valid level set found; need at least one level set...\n");
196         exit(1);
197     }
198 
199     /* clear gm struct */
200     //memset( &gm, 0, sizeof( gm ) );
201 
202     // initialize gfx set
203     DL_Ini(&gm.g_sts);
204     gm.g_sts.flgs = DL_AUTODEL;
205     gm.g_sts.cb = G_DelGSt;
206     // load gfx sets
207     G_LdGSts();
208 
209     // load board
210     gm.s_brd = SS_Ld("gfx/board.bmp", SDL_SWSURFACE);
211     SDL_SetColorKey(gm.s_brd, 0, 0);
212     // load lights
213     gm.s_lghts = SS_Ld("gfx/lights.bmp", SDL_SWSURFACE);
214     // load marbles
215     gm.s_mrb = SS_Ld("gfx/marbles.bmp", SDL_SWSURFACE);
216     // load figure
217     gm.s_fig = SS_Ld("gfx/figure.bmp", SDL_SWSURFACE);
218     // load marble frame
219     gm.s_mf = SS_Ld("gfx/m_frame.bmp", SDL_SWSURFACE);
220     // load marble select frame
221     gm.s_msf = SS_Ld("gfx/m_sframe.bmp", SDL_SWSURFACE);
222     // background //
223     gm.s_bkgd = 0;
224 
225     // load fonts
226     gm.f_sml = SF_LdFxd("gfx/f_small.bmp", 32, 96, 8);
227     gm.f_wht = SF_LdFxd("gfx/f_white.bmp", 32, 96, 10);
228     gm.f_rd = SF_LdFxd("gfx/f_red.bmp", 32, 96, 10);
229 
230     // level
231     gm.c_lvl = 0;
232 
233     // marble
234     gm.m_v = 0.15;
235     gm.m_a.p = 0;
236     gm.m_a.f = 4;
237     gm.m_a.c = 0.016 + 0.008;
238     gm.m_a.w = gm.m_a.h = 32;
239     gm.m_act = M_EMPTY;
240     gm.m_o_x = gm.m_o_y = -1;
241     gm.m_warp = 0;
242 
243     // marble select frame
244     gm.msf_a.f = 4;
245     gm.msf_a.w = gm.msf_a.h = 40;
246     gm.msf_a.c = 0.02;
247     gm.msf_a.p = 0;
248 
249     // marble frame
250     gm.mf_a.f = 4;
251     gm.mf_a.w = gm.mf_a.h = 40;
252     gm.mf_a.c = 0.02;
253     gm.mf_a.p = 0;
254 
255     // layout
256     gm.b_x = 640 - 200;
257     gm.f_x = 35;
258     gm.f_y = 145;
259     gm.i_x = 20;
260     gm.i_y = 25;
261     gm.t_x = 40;
262     gm.t_y = 105;
263     gm.s_x = 15;
264     gm.s_y = 290;
265 
266     // geometry
267     gm.t_w = gm.t_h = 32;
268     gm.f_w = gm.f_h = 12;
269     gm.f_fw = gm.f_fh = 130;
270     gm.scr_w = 640;
271     gm.scr_h = 480;
272     gm.brd_w = 200;
273     gm.s_w = 170;
274     gm.s_h = 175;
275     gm.c_off = 12;
276 
277     // cursors
278     memset(data, 0, sizeof(data));
279     gm.c_u = gm.c_d = gm.c_l = gm.c_r = gm.c_s = gm.c_w = 0;
280     gm.c_n = SDL_GetCursor();
281     Cr_Ld(csr[0], data, mask);
282     gm.c_u = SDL_CreateCursor(data, mask, 16, 16, 8, 8);
283     Cr_Ld(csr[1], data, mask);
284     gm.c_d = SDL_CreateCursor(data, mask, 16, 16, 8, 8);
285     Cr_Ld(csr[2], data, mask);
286     gm.c_r = SDL_CreateCursor(data, mask, 16, 16, 8, 8);
287     Cr_Ld(csr[3], data, mask);
288     gm.c_l = SDL_CreateCursor(data, mask, 16, 16, 8, 8);
289     Cr_Ld(csr[4], data, mask);
290     gm.c_s = SDL_CreateCursor(data, mask, 16, 16, 8, 8);
291     Cr_Ld(csr[5], data, mask);
292     gm.c_w = SDL_CreateCursor(data, mask, 16, 16, 8, 8);
293 
294     // map animations
295     gm.m_ani = 0;
296 
297     // oneway animation info
298     gm.ma_ow_a.f = 4;
299     gm.ma_ow_a.c = 0.008;
300     gm.ma_ow_a.p = 0;
301     gm.ma_ow_a.w = gm.t_w;
302     gm.ma_ow_a.h = gm.t_h;
303 
304     // teleport information
305     gm.ma_tlp_a.f = 4;
306     gm.ma_tlp_a.c = 0.008;
307     gm.ma_tlp_a.p = 0;
308     gm.ma_tlp_a.w = gm.t_w;
309     gm.ma_tlp_a.h = gm.t_h;
310     gm.tlp_a = 32;
311 
312     // sounds
313 #ifdef SOUND
314     gm.wv_tlp = sound_chunk_load("teleport.wav");
315     gm.wv_sel = sound_chunk_load("select.wav");
316     gm.wv_stp = sound_chunk_load("stop.wav");
317     gm.wv_clk = sound_chunk_load("click.wav");
318     gm.wv_exp = sound_chunk_load("explode.wav");
319     gm.wv_alm = sound_chunk_load("alarm.wav");
320     gm.wv_arw = sound_chunk_load("arrow.wav");
321     gm.wv_scr = sound_chunk_load("score.wav");
322 #endif
323 
324     // shrapnells
325     DL_Ini(&gm.shr);
326     gm.shr.flgs = DL_AUTODEL;
327     gm.shr.cb = Shr_Del;
328     gm.shr_a_c = 0.1;
329 
330     // credits
331     gm.cr_a_c = 0.1;
332     gm.cr_tm = 3000;
333     gm.cr_y = 10;
334 
335     // shnapshot
336     gm.snap = 0;
337 }
338 
339 /*
340     terminate game
341 */
G_Trm()342 void G_Trm()
343 {
344     // release gfx
345     if (gm.s_brd) SDL_FreeSurface(gm.s_brd);
346     if (gm.s_lghts) SDL_FreeSurface(gm.s_lghts);
347     if (gm.s_mrb) SDL_FreeSurface(gm.s_mrb);
348     if (gm.s_fig) SDL_FreeSurface(gm.s_fig);
349     if (gm.s_mf) SDL_FreeSurface(gm.s_mf);
350     if (gm.s_msf) SDL_FreeSurface(gm.s_msf);
351     // release fonts
352     if (gm.f_sml) SF_Fr(gm.f_sml);
353     if (gm.f_wht) SF_Fr(gm.f_wht);
354     if (gm.f_rd) SF_Fr(gm.f_rd);
355     // release dynlists
356     DL_Clr(&gm.g_sts);
357     DL_Clr(&l_sts);
358     DL_Clr(&gm.shr);
359     // cursors //
360     if (gm.c_u) SDL_FreeCursor(gm.c_u);
361     if (gm.c_d) SDL_FreeCursor(gm.c_d);
362     if (gm.c_l) SDL_FreeCursor(gm.c_l);
363     if (gm.c_r) SDL_FreeCursor(gm.c_r);
364     if (gm.c_s) SDL_FreeCursor(gm.c_s);
365     if (gm.c_w) SDL_FreeCursor(gm.c_w);
366     // free map animations //
367     if (gm.m_ani)
368         free(gm.m_ani);
369     // sounds
370 #ifdef SOUND
371     if (gm.wv_tlp) sound_chunk_free(&gm.wv_tlp);
372     if (gm.wv_sel) sound_chunk_free(&gm.wv_sel);
373     if (gm.wv_stp) sound_chunk_free(&gm.wv_stp);
374     if (gm.wv_clk) sound_chunk_free(&gm.wv_clk);
375     if (gm.wv_exp) sound_chunk_free(&gm.wv_exp);
376     if (gm.wv_alm) sound_chunk_free(&gm.wv_alm);
377     if (gm.wv_arw) sound_chunk_free(&gm.wv_arw);
378     if (gm.wv_scr) sound_chunk_free(&gm.wv_scr);
379 #endif
380 }
381 
382 /*
383     open a new game
384 */
G_Opn()385 int G_Opn()
386 {
387     Prf     *p;
388     DL_E    *e;
389     int     flgs = SDL_SWSURFACE;
390 
391     // get current level set
392     gm.c_l_st = (LSet*)DL_Get(&l_sts, cfg.ls);
393 
394     // check if current level set is valid
395     if (!G_CkLSt()) {
396         // restore menu
397         MM_Shw(MM_RSZ);
398 
399         return 0;
400     }
401 
402     // current profile
403     gm.c_prf = (Prf*)DL_Get(&prfs, cfg.prf);
404 
405     // current set info
406     gm.c_s_inf = Prf_RegLS(gm.c_prf, gm.c_l_st);
407 
408     // dim & resize
409     if (cfg.dim)
410         SDL_DIM();
411     if (cfg.fscr)
412         flgs = flgs | SDL_FULLSCREEN;
413     Sdl_StVdMd(gm.scr_w, gm.scr_h, 16, flgs);
414 
415     // create background
416     gm.s_bkgd = SS_Crt(gm.scr_w, gm.scr_h, SDL_SWSURFACE);
417     SDL_SetColorKey(gm.s_bkgd, 0, 0);
418 
419     // get highest score
420     gm.hi_scr = 0;
421     e = prfs.hd.n;
422     while (e != &prfs.tl) {
423         p = (Prf*)e->d;
424         if (p->scr > gm.hi_scr)
425             gm.hi_scr = p->scr;
426         e = e->n;
427     }
428 
429     // clear old chapter
430     gm.o_ch = -1;
431 
432     // init first level
433     L_Ini(0, 0);
434 
435     return 1;
436 }
437 
438 /*
439     close game
440 */
G_Cls()441 void G_Cls()
442 {
443     // dim
444     if (!trm_gm && cfg.dim)
445         SDL_DIM();
446 
447     // free background
448     if (gm.s_bkgd) SDL_FreeSurface(gm.s_bkgd);
449 
450     // free level
451     free(gm.c_lvl);
452     gm.c_lvl = 0;
453 
454     // restore cursor
455     SDL_SetCursor(gm.c_n);
456 
457     // show menu
458     MM_Shw(MM_RSZ);
459 }
460 
461 /*
462     game's main loop
463 */
G_Run()464 void G_Run()
465 {
466     int leave = 0;
467     int restart = 0;
468     int ms;
469     SDL_Event ev;
470     SDL_Surface *buf;
471     int flgs;
472     int restore_pos;
473     int tm_rel = 0;
474     int ign_c_stat = 0;
475     int bonus_level, bonus_moves; /* bonus for level completion and remaining moves */
476 
477     while (!trm_gm) {
478         // clear input
479         while (SDL_PollEvent(&ev));
480         // main loop
481         while (!leave && !trm_gm && !gm.l_done && !restart) {
482             // don't consume all cpu time
483             SDL_Delay( 5 );
484 
485             restore_pos = 0; // do not restore old position
486             ign_c_stat = 0; // do not ignore cursor state
487             // get input
488             if (SDL_PollEvent(&ev)) {
489                 switch (ev.type) {
490                     case SDL_QUIT:
491                         trm_gm = 1;
492                         break;
493                     case SDL_KEYUP:
494                         switch (ev.key.keysym.sym) {
495                             case SDLK_TAB:
496                                 SnapShot();
497                                 break;
498                             case SDLK_ESCAPE:
499                                 if (G_CfmQut())
500                                     leave = 1;
501                                 break;
502                             case SDLK_p:
503                                 G_Ps();
504                                 break;
505                             case SDLK_r:
506                                 if (G_CfmRst())
507                                     restart = 1;
508                                 break;
509                             case SDLK_f:
510                                 buf = SS_Crt(gm.scr_w, gm.scr_h, SDL_SWSURFACE);
511                                 D_FDST(buf);
512                                 D_FSRC(sdl.scr);
513                                 SS_Blt();
514                                 cfg.fscr = !cfg.fscr;
515                                 flgs = SDL_SWSURFACE;
516                                 if (cfg.fscr)
517                                     flgs = flgs | SDL_FULLSCREEN;
518                                 Sdl_StVdMd(gm.scr_w, gm.scr_h, 16, flgs);
519                                 D_FDST(sdl.scr);
520                                 D_FSRC(buf);
521                                 SS_Blt();
522                                 Sdl_FUpd();
523                                 break;
524                             default:
525                                 /* if no marble is selected we don't have to check anything */
526                                 if ( !gm.m_sel )
527                                     break;
528                                 /* warp? */
529                                 if (gm.m_mv && (ev.key.keysym.sym == cfg.k_right || ev.key.keysym.sym == cfg.k_left || ev.key.keysym.sym == cfg.k_up || ev.key.keysym.sym == cfg.k_down)) {
530                                     gm.m_warp = 1;
531                                     break;
532                                 }
533                                 // undo key
534                                 if (ev.key.keysym.sym == cfg.k_undo) {
535                                     restore_pos = 1;
536 #ifdef SOUND
537                                     sound_play(gm.wv_clk);
538 #endif
539                                 }
540                                 // up key
541                                 if (ev.key.keysym.sym == cfg.k_up && (gm.m_vd & MD_U) && !gm.m_mv) {
542                                     ign_c_stat = 1;
543                                     gm.c_stat = C_U;
544                                     Mr_IniMv();
545 #ifdef SOUND
546                                     sound_play(gm.wv_clk);
547 #endif
548                                 }
549                                 // down key
550                                 if (ev.key.keysym.sym == cfg.k_down && (gm.m_vd & MD_D) && !gm.m_mv) {
551                                     ign_c_stat = 1;
552                                     gm.c_stat = C_D;
553                                     Mr_IniMv();
554 #ifdef SOUND
555                                     sound_play(gm.wv_clk);
556 #endif
557                                 }
558                                 // left key
559                                 if (ev.key.keysym.sym == cfg.k_left && (gm.m_vd & MD_L) && !gm.m_mv) {
560                                     ign_c_stat = 1;
561                                     gm.c_stat = C_L;
562                                     Mr_IniMv();
563 #ifdef SOUND
564                                     sound_play(gm.wv_clk);
565 #endif
566                                 }
567                                 // right key
568                                 if (ev.key.keysym.sym == cfg.k_right && (gm.m_vd & MD_R) && !gm.m_mv) {
569                                     ign_c_stat = 1;
570                                     gm.c_stat = C_R;
571                                     Mr_IniMv();
572 #ifdef SOUND
573                                     sound_play(gm.wv_clk);
574 #endif
575                                 }
576                                 break;
577                         }
578                         break;
579                     case SDL_MOUSEBUTTONDOWN:
580                         break;
581                     case SDL_MOUSEBUTTONUP:
582                         if ( ev.button.button == 1 && gm.m_mv &&
583                              ( gm.c_l_st->limit_type == MOVES ) ) {
584                             gm.m_warp = 1;
585                             break;
586                         }
587                         gm.bttn[ev.button.button] = 1;
588                         if (ev.button.button == 1) {
589                             if (gm.c_stat == C_SEL)
590                                 Mr_Sel(ev.button.x, ev.button.y);
591                             else
592                                 if (gm.m_sel && !gm.m_mv) {
593                                     // start movement of selected marble
594                                     Mr_IniMv();
595                                 }
596                         }
597                         else
598                             if (gm.m_sel && !gm.m_mv)
599                                 Mr_Rel(ev.button.x, ev.button.y);
600                         break;
601                     case SDL_MOUSEMOTION:
602                         if ( !ign_c_stat )
603                             Cr_Cng(ev.motion.x, ev.motion.y);
604                         gm.o_mx = ev.motion.x;
605                         gm.o_my = ev.motion.y;
606                         break;
607                     default:
608                         break;
609                 }
610             }
611 
612             // hide
613             if (!leave && !restart) {
614                 Mr_Hd();
615                 MF_Hd();
616                 Tm_Hd();
617                 Inf_Hd();
618                 Shr_Hd();
619                 Cr_Hd();
620             }
621 
622             // update
623             ms = T_Gt();
624             MA_Upd(ms);
625             if (restore_pos)
626                 Mr_ResPos();
627             if ( !Mr_Upd(ms) )
628                 restart = 1;
629             MF_Upd(ms);
630             Shr_Upd(ms);
631             Cr_Upd(ms);
632             if (!Tm_Upd(ms))
633                 restart = 1;
634             if (Inf_Upd() && G_CfmWrp()) {
635                 gm.c_ch = gm.w_c;
636                 gm.c_l_id = gm.w_l;
637                 restart = 1;
638             }
639 
640             // show
641             if (!leave && !restart)
642                 MA_Shw();
643             if (!leave && !restart) {
644                 Mr_Shw();
645             }
646             if (!leave && !restart && !gm.l_done) {
647                 MF_Shw();
648                 Tm_Shw();
649                 Inf_Shw();
650                 Shr_Shw();
651                 Cr_Shw();
652 
653                 // refresh
654                 Sdl_UpdR();
655             }
656             else
657                 sdl.rnum = 0; // reset redraw regions
658 
659             // reset buttonstate
660             memset(gm.bttn, 0, sizeof(gm.bttn));
661         }
662 
663         // leave ?
664         if (leave)
665             break;
666 
667         // init next level
668         if (gm.l_done || restart) {
669 
670             if (gm.l_done) {
671 
672                 // figure animation
673                 FA_Run();
674                 // bonus summary
675                 if ( !gm.c_s_inf->cmp[gm.c_ch * gm.c_s_inf->l_num + gm.c_l_id] ) {
676 
677                     /* level wasn't completed until now so gain score for it */
678                     bonus_level = LB_COMPLETED;
679                     bonus_moves = gm.c_lvl->tm * LB_PER_MOVE;
680                     modify_score( &bonus_level, &bonus_moves );
681                     BS_Run( bonus_level, bonus_moves );
682                     tm_rel = ( 1000 * gm.c_lvl->tm ) / gm.c_l_st->ch[gm.c_ch].lvls[gm.c_l_id].tm;
683                     Prf_Upd(gm.c_prf, gm.c_s_inf, gm.c_ch * gm.c_l_st->l_num + gm.c_l_id, tm_rel, bonus_level + bonus_moves );
684 
685                 }
686 
687             }
688 
689             if (cfg.dim)
690                 SDL_DIM();
691             if (!restart)
692                 if (!L_FndNxt()) // game finished ?
693                     break;
694             L_Ini(gm.c_ch, gm.c_l_id);
695             restart = 0;
696         }
697     }
698     // save profiles
699     Prf_Sv();
700 }
701 
702 /*
703     load all gfx sets
704 */
G_LdGSts()705 void G_LdGSts()
706 {
707     char    d_nm[256];
708     char    path[256+64];
709     DIR     *dir = 0;
710     struct dirent  *e;
711     struct stat     s;
712     GSet    *g_st;
713 
714     printf("loading graphics sets...\n");
715 
716     // create directory string //
717     sprintf(d_nm, "%s/gfx", SRC_DIR);
718 
719     // find and open directory //
720     if ((dir = opendir(d_nm)) == 0) {
721         fprintf(stderr, "ERROR: can't find directory '%s'\n", d_nm);
722         exit(1);
723     }
724 
725     // well, let's check for directories //
726     while ((e = readdir(dir)) != 0) {
727         sprintf(path, "%s/%s", d_nm, e->d_name);
728         stat(path, &s);
729         if (S_ISDIR(s.st_mode) && e->d_name[0] != '.') {
730             printf("'%s'... \n", e->d_name);
731             // load gfx //
732             g_st = (GSet*)malloc(sizeof(GSet));
733             memset(g_st, 0, sizeof(GSet));
734             strcpy(g_st->nm, e->d_name);
735             g_st->ok = 1;
736 
737             sprintf(path, "gfx/%s/%s", e->d_name, "background.bmp");
738             g_st->s_bkgd = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL);
739             SDL_SetColorKey(g_st->s_bkgd, 0, 0);
740 
741             sprintf(path, "gfx/%s/%s", e->d_name, "wall.bmp");
742             if ((g_st->s_wl = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
743                 g_st->ok = 0;
744 
745             sprintf(path, "gfx/%s/%s", e->d_name, "floor.bmp");
746             if ((g_st->s_flr = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
747                 g_st->ok = 0;
748 
749             sprintf(path, "gfx/%s/%s", e->d_name, "arrow_r.bmp");
750             if ((g_st->s_r_arw = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
751                 g_st->ok = 0;
752 
753             sprintf(path, "gfx/%s/%s", e->d_name, "arrow_l.bmp");
754             if ((g_st->s_l_arw = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
755                 g_st->ok = 0;
756 
757             sprintf(path, "gfx/%s/%s", e->d_name, "arrow_u.bmp");
758             if ((g_st->s_u_arw = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
759                 g_st->ok = 0;
760 
761             sprintf(path, "gfx/%s/%s", e->d_name, "arrow_d.bmp");
762             if ((g_st->s_d_arw = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
763                 g_st->ok = 0;
764 
765             sprintf(path, "gfx/%s/%s", e->d_name, "barrier_lr.bmp");
766             if ((g_st->s_lr_bar = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
767                 g_st->ok = 0;
768 
769             sprintf(path, "gfx/%s/%s", e->d_name, "barrier_ud.bmp");
770             if ((g_st->s_ud_bar = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
771                 g_st->ok = 0;
772 
773             sprintf(path, "gfx/%s/%s", e->d_name, "teleport0.bmp");
774             if ((g_st->s_tlp_0 = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
775                 g_st->ok = 0;
776 
777             sprintf(path, "gfx/%s/%s", e->d_name, "teleport1.bmp");
778             if ((g_st->s_tlp_1 = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
779                 g_st->ok = 0;
780 
781             sprintf(path, "gfx/%s/%s", e->d_name, "teleport2.bmp");
782             if ((g_st->s_tlp_2 = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
783                 g_st->ok = 0;
784 
785             sprintf(path, "gfx/%s/%s", e->d_name, "teleport3.bmp");
786             if ((g_st->s_tlp_3 = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
787                 g_st->ok = 0;
788 
789             sprintf(path, "gfx/%s/%s", e->d_name, "wall_crumble.bmp");
790             if ((g_st->s_crmbl = SS_Ld(path, SDL_SWSURFACE | SDL_NONFATAL)) == 0)
791                 g_st->ok = 0;
792 
793             if (g_st->ok) {
794                 printf("ok\n");
795                 // opaque
796                 SDL_SetColorKey(g_st->s_flr, 0, 0);
797                 SDL_SetColorKey(g_st->s_wl, 0, 0);
798             }
799             DL_Add(&gm.g_sts, g_st);
800         }
801     }
802     closedir(dir);
803 }
804 
805 
806 /*
807     delete a gset
808 */
G_DelGSt(void * p)809 void G_DelGSt(void *p)
810 {
811     GSet *st = (GSet*)p;
812     if (st->s_bkgd) SDL_FreeSurface(st->s_bkgd);
813     if (st->s_wl) SDL_FreeSurface(st->s_wl);
814     if (st->s_flr) SDL_FreeSurface(st->s_flr);
815     if (st->s_u_arw) SDL_FreeSurface(st->s_u_arw);
816     if (st->s_d_arw) SDL_FreeSurface(st->s_d_arw);
817     if (st->s_r_arw) SDL_FreeSurface(st->s_r_arw);
818     if (st->s_l_arw) SDL_FreeSurface(st->s_l_arw);
819     if (st->s_lr_bar) SDL_FreeSurface(st->s_lr_bar);
820     if (st->s_ud_bar) SDL_FreeSurface(st->s_ud_bar);
821     if (st->s_tlp_0) SDL_FreeSurface(st->s_tlp_0);
822     if (st->s_tlp_1) SDL_FreeSurface(st->s_tlp_1);
823     if (st->s_tlp_2) SDL_FreeSurface(st->s_tlp_2);
824     if (st->s_tlp_3) SDL_FreeSurface(st->s_tlp_3);
825     if (st->s_crmbl) SDL_FreeSurface(st->s_crmbl);
826     free(st);
827 }
828 
829 /*
830     pause game
831 */
G_Ps()832 void G_Ps()
833 {
834     SFnt *ft = gm.f_sml;
835     SDL_Surface *buf;
836     char str[256];
837     SDL_Event e;
838     int leave = 0;
839     int flgs;
840     int mx = gm.o_mx, my = gm.o_my;
841 
842     // save screen //
843     buf = SS_Crt(gm.scr_w, gm.scr_h, SDL_SWSURFACE);
844     SDL_SetColorKey(buf, 0, 0);
845     D_FDST(buf);
846     D_FSRC(sdl.scr);
847     SS_Blt();
848 
849     // cursor
850     SDL_SetCursor(gm.c_n);
851 
852     // fill with black
853     D_FDST(sdl.scr);
854     SS_Fill(0x0);
855 
856     // write info
857     ft->algn = TA_X_C | TA_Y_C;
858     sprintf(str, "Game paused");
859     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, gm.scr_h / 2, str, 0);
860 
861     Sdl_FUpd();
862 
863     // wait for 'p'
864     while (!leave) {
865         SDL_WaitEvent(&e);
866         switch (e.type) {
867             case SDL_QUIT:
868                 trm_gm = 1;
869                 leave = 1;
870                 break;
871             case SDL_KEYUP:
872                 if (e.key.keysym.sym == SDLK_p)
873                     leave = 1;
874                 if (e.key.keysym.sym == SDLK_f) {
875                     cfg.fscr = !cfg.fscr;
876                     flgs = SDL_SWSURFACE;
877                     if (cfg.fscr)
878                         flgs = flgs | SDL_FULLSCREEN;
879                     Sdl_StVdMd(gm.scr_w, gm.scr_h, 16, flgs);
880                     D_FDST(sdl.scr);
881                     SS_Fill(0x0);
882                     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, gm.scr_h / 2, str, 0);
883                     Sdl_FUpd();
884                 }
885                 break;
886             case SDL_MOUSEMOTION:
887                 mx = e.motion.x;
888                 my = e.motion.y;
889                 break;
890         }
891     }
892 
893     // restore screen
894     D_FDST(sdl.scr);
895     D_FSRC(buf);
896     SS_Blt();
897     Sdl_FUpd();
898     SDL_FreeSurface(buf);
899 
900     // cursor
901     Cr_Cng(mx, my);
902 
903     //reset time //
904     T_Rst();
905 }
906 
907 /*
908     check if the figure has been completed
909 */
G_CkFgr()910 void G_CkFgr()
911 {
912     int i, j, k, l;
913     Lvl *lvl = gm.c_lvl;
914 
915     for (i = 0; i < lvl->m_w - lvl->f_w; i++)
916         for (j = 0; j < lvl->m_h - lvl->f_h; j++) {
917             gm.l_done = 1;
918             for (k = 0; k < lvl->f_w; k++) {
919                 for (l = 0; l < lvl->f_h; l++) {
920                     if (lvl->fgr[k][l] != -1)
921                         if (lvl->map[i + k][j + l].m != lvl->fgr[k][l]) {
922                             gm.l_done = 0;
923                             break;
924                         }
925                 }
926                 if (!gm.l_done)
927                     break;
928             }
929             if (gm.l_done)
930                 return;
931         }
932 }
933 
934 /*
935     confirm warp
936 */
G_CfmWrp()937 int G_CfmWrp()
938 {
939     SFnt *ft = gm.f_sml;
940     SDL_Surface *buf;
941     SDL_Event e;
942     char str[256];
943     int leave = 0, ret = 0;
944     int mx = gm.o_mx, my = gm.o_my;
945 
946     // save screen //
947     buf = SS_Crt(gm.scr_w, gm.scr_h, SDL_SWSURFACE);
948     SDL_SetColorKey(buf, 0, 0);
949     D_FDST(buf);
950     D_FSRC(sdl.scr);
951     SS_Blt();
952 
953     // cursor
954     SDL_SetCursor(gm.c_n);
955 
956     // fill with black
957     D_FDST(sdl.scr);
958     SS_Fill(0x0);
959 
960     // write info
961     ft->algn = TA_X_C | TA_Y_T;
962     sprintf(str, "Your current position is level %i of chapter %i.", gm.c_l_id + 1, gm.c_ch + 1);
963     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, 200, str, 0);
964     sprintf(str, "Do you really want to enter level %i of chapter %i?", gm.w_l + 1, gm.w_c + 1);
965     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, 200 + 15, str, 0);
966     sprintf(str, "(All changes in the current level will be lost!)");
967     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, 200 + 30, str, 0);
968     sprintf(str, "(press y/n)");
969     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, 200 + 50, str, 0);
970 
971     Sdl_FUpd();
972 
973 #ifdef SOUND
974     sound_play(gm.wv_clk);
975 #endif
976     while (!leave) {
977         SDL_WaitEvent(&e);
978         switch (e.type) {
979             case SDL_QUIT:
980                 trm_gm = leave = 1;
981                 break;
982             case SDL_KEYUP:
983                 switch (e.key.keysym.sym) {
984                     case SDLK_y:
985                         ret = 1;
986                         leave = 1;
987                         break;
988                     case SDLK_n:
989                         ret = 0;
990                         leave = 1;
991                         break;
992                     default:
993                         break;
994                 }
995                 break;
996             case SDL_MOUSEBUTTONUP:
997                 switch (e.button.button) {
998                     case 1:
999                         ret = 1;
1000                         leave = 1;
1001                         break;
1002                     default:
1003                         ret = 0;
1004                         leave = 1;
1005                         break;
1006                 }
1007                 break;
1008             case SDL_MOUSEMOTION:
1009                 mx = e.motion.x;
1010                 my = e.motion.y;
1011                 break;
1012         }
1013     }
1014 #ifdef SOUND
1015     sound_play(gm.wv_clk);
1016 #endif
1017 
1018     // restore screen
1019     if (cfg.dim)
1020         SDL_DIM();
1021     if (!ret) {
1022         D_FDST(sdl.scr);
1023         D_FSRC(buf);
1024         SS_Blt();
1025         if (cfg.dim)
1026             SDL_UNDIM();
1027         else
1028             Sdl_FUpd();
1029 
1030         // cursor
1031         Cr_Cng(mx, my);
1032 
1033     }
1034     SDL_FreeSurface(buf);
1035 
1036     // reset time //
1037     T_Rst();
1038 
1039     return ret;
1040 }
1041 
1042 /*
1043     confirm quit
1044 */
G_CfmQut()1045 int G_CfmQut()
1046 {
1047     SFnt *ft = gm.f_sml;
1048     SDL_Surface *buf;
1049     SDL_Event e;
1050     char str[256];
1051     int leave = 0, ret = 0;
1052     int mx = gm.o_mx, my = gm.o_my;
1053 
1054     // save screen //
1055     buf = SS_Crt(gm.scr_w, gm.scr_h, SDL_SWSURFACE);
1056     SDL_SetColorKey(buf, 0, 0);
1057     D_FDST(buf);
1058     D_FSRC(sdl.scr);
1059     SS_Blt();
1060 
1061     // cursor
1062     SDL_SetCursor(gm.c_n);
1063 
1064     // fill with black
1065     D_FDST(sdl.scr);
1066     SS_Fill(0x0);
1067 
1068     // write info
1069     ft->algn = TA_X_C | TA_Y_C;
1070     sprintf(str, "Do you really want to quit? (y/n)");
1071     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, gm.scr_h / 2, str, 0);
1072 
1073     Sdl_FUpd();
1074 
1075 #ifdef SOUND
1076     sound_play(gm.wv_clk);
1077 #endif
1078     while (!leave) {
1079         SDL_WaitEvent(&e);
1080         switch (e.type) {
1081             case SDL_QUIT:
1082                 trm_gm = leave = 1;
1083                 break;
1084             case SDL_KEYUP:
1085                 switch (e.key.keysym.sym) {
1086                     case SDLK_ESCAPE:
1087                     case SDLK_y:
1088                         ret = 1;
1089                         leave = 1;
1090                         break;
1091                     case SDLK_n:
1092                         ret = 0;
1093                         leave = 1;
1094                         break;
1095                     default:
1096                         break;
1097                 }
1098                 break;
1099             case SDL_MOUSEBUTTONUP:
1100                 switch (e.button.button) {
1101                     case 1:
1102                         ret = 1;
1103                         leave = 1;
1104                         break;
1105                     default:
1106                         ret = 0;
1107                         leave = 1;
1108                         break;
1109                 }
1110                 break;
1111         }
1112     }
1113 #ifdef SOUND
1114     sound_play(gm.wv_clk);
1115 #endif
1116 
1117     // restore screen
1118     if (!ret) {
1119         if (cfg.dim)
1120             SDL_DIM();
1121         D_FDST(sdl.scr);
1122         D_FSRC(buf);
1123         SS_Blt();
1124         if (cfg.dim)
1125             SDL_UNDIM();
1126         else
1127             Sdl_FUpd();
1128 
1129         // cursor
1130         Cr_Cng(mx, my);
1131 
1132     }
1133     SDL_FreeSurface(buf);
1134 
1135     // reset time //
1136     T_Rst();
1137 
1138     return ret;
1139 }
1140 
1141 /*
1142     confirm quit
1143 */
G_CfmRst()1144 int G_CfmRst()
1145 {
1146     SFnt *ft = gm.f_sml;
1147     SDL_Surface *buf;
1148     SDL_Event e;
1149     char str[256];
1150     int leave = 0, ret = 0;
1151     int mx = gm.o_mx, my = gm.o_my;
1152 
1153     // save screen //
1154     buf = SS_Crt(gm.scr_w, gm.scr_h, SDL_SWSURFACE);
1155     SDL_SetColorKey(buf, 0, 0);
1156     D_FDST(buf);
1157     D_FSRC(sdl.scr);
1158     SS_Blt();
1159 
1160     // cursor
1161     SDL_SetCursor(gm.c_n);
1162 
1163     // fill with black
1164     D_FDST(sdl.scr);
1165     SS_Fill(0x0);
1166 
1167     // write info
1168     ft->algn = TA_X_C | TA_Y_C;
1169     sprintf(str, "Do you really want to restart? (y/n)");
1170     SF_Wrt(ft, sdl.scr, gm.scr_w / 2, gm.scr_h / 2, str, 0);
1171 
1172     Sdl_FUpd();
1173 
1174 #ifdef SOUND
1175     sound_play(gm.wv_clk);
1176 #endif
1177     while (!leave) {
1178         SDL_WaitEvent(&e);
1179         switch (e.type) {
1180             case SDL_QUIT:
1181                 trm_gm = leave = 1;
1182                 break;
1183             case SDL_KEYUP:
1184                 switch (e.key.keysym.sym) {
1185                     case SDLK_r:
1186                     case SDLK_y:
1187                         ret = 1;
1188                         leave = 1;
1189                         break;
1190                     case SDLK_n:
1191                         ret = 0;
1192                         leave = 1;
1193                         break;
1194                     default:
1195                         break;
1196                 }
1197                 break;
1198             case SDL_MOUSEBUTTONUP:
1199                 switch (e.button.button) {
1200                     case 1:
1201                         ret = 1;
1202                         leave = 1;
1203                         break;
1204                     default:
1205                         ret = 0;
1206                         leave = 1;
1207                         break;
1208                 }
1209                 break;
1210         }
1211     }
1212 #ifdef SOUND
1213     sound_play(gm.wv_clk);
1214 #endif
1215 
1216     // restore screen
1217     if (cfg.dim)
1218         SDL_DIM();
1219     if (!ret) {
1220         D_FDST(sdl.scr);
1221         D_FSRC(buf);
1222         SS_Blt();
1223         if (cfg.dim)
1224             SDL_UNDIM();
1225         else
1226             Sdl_FUpd();
1227 
1228         // cursor
1229         Cr_Cng(mx, my);
1230 
1231     }
1232     SDL_FreeSurface(buf);
1233 
1234     // reset time //
1235     T_Rst();
1236 
1237     return ret;
1238 }
1239 
1240 /*
1241     check if level set can be played and ask for confirmation if it got errors
1242 */
G_CkLSt()1243 int G_CkLSt()
1244 {
1245     char str[256];
1246     SFnt *ft = gm.f_sml;
1247     SDL_Event e;
1248 
1249     if (gm.c_l_st->ch == 0) {
1250         D_FDST(sdl.scr);
1251         SS_Fill(0x0);
1252         sprintf(str, "This level set cannot be played.\n");
1253         ft->algn = TA_X_C | TA_Y_C;
1254         SF_Wrt(ft, sdl.scr, sdl.scr->w / 2, sdl.scr->h / 2, str, 0);
1255         Sdl_FUpd();
1256         Sdl_WtFrClk();
1257         return 0;
1258     }
1259     if (!gm.c_l_st->ok) {
1260         D_FDST(sdl.scr);
1261         SS_Fill(0x0);
1262         sprintf(str, "This level set has errors. Play anyway? (y/n)\n");
1263         ft->algn = TA_X_C | TA_Y_C;
1264         SF_Wrt(ft, sdl.scr, sdl.scr->w / 2, sdl.scr->h / 2, str, 0);
1265         Sdl_FUpd();
1266         while (1) {
1267             if (SDL_WaitEvent(&e))
1268                 switch (e.type) {
1269                     case SDL_KEYUP:
1270                         switch (e.key.keysym.sym) {
1271                             case SDLK_ESCAPE:
1272                             case SDLK_n:
1273                                 return 0;
1274                             case SDLK_y:
1275                                 return 1;
1276                             default:
1277                                 break;
1278                         }
1279                     case SDL_MOUSEBUTTONUP:
1280                         switch (e.button.button) {
1281                             case 1:
1282                                 return 1;
1283                             default:
1284                                 return 0;
1285                                 break;
1286                         }
1287                         break;
1288                 }
1289         }
1290     }
1291     return 1;
1292 }
1293 
1294 // marble //
1295 /*
1296     hide current marble
1297 */
Mr_Hd()1298 void Mr_Hd()
1299 {
1300     if (!gm.m_sel) return;
1301     D_DST(sdl.scr, (int)gm.m_x, (int)gm.m_y, gm.t_w, gm.t_h);
1302     D_SRC(gm.s_bkgd, (int)gm.m_x, (int)gm.m_y);
1303     SS_Blt();
1304     Sdl_AddR((int)gm.m_x, (int)gm.m_y, gm.t_w, gm.t_h);
1305 }
1306 
1307 /*
1308     show current marble
1309 */
Mr_Shw()1310 void Mr_Shw()
1311 {
1312     if (!gm.m_sel) return;
1313     D_DST(sdl.scr, (int)gm.m_x, (int)gm.m_y, gm.t_w, gm.t_h);
1314     D_SRC(gm.s_mrb, (int)gm.m_a.p * gm.m_a.w, gm.m_id * gm.t_h);
1315     SS_Blt();
1316     Sdl_AddR((int)gm.m_x, (int)gm.m_y, gm.t_w, gm.t_h);
1317 }
1318 
1319 /*
1320     update current marble
1321     return 0 if times out( moves )
1322 */
Mr_Upd(int ms)1323 int Mr_Upd(int ms)
1324 {
1325     float c; // change
1326     int stp = 0; // marble stopped ?
1327 
1328     if (!gm.m_sel || !gm.m_mv) return 1;
1329 
1330     // marble animation (frame)
1331     switch (gm.m_d) {
1332         case 1:
1333         case 2:
1334             gm.m_a.p += gm.m_a.c * ms;
1335             if (gm.m_a.p >= gm.m_a.f)
1336                 gm.m_a.p = 0;
1337             break;
1338         case 0:
1339         case 3:
1340             gm.m_a.p -= gm.m_a.c * ms;
1341             if (gm.m_a.p <= 0)
1342                 gm.m_a.p = gm.m_a.f;
1343             break;
1344     }
1345 
1346     c = ms * gm.m_v;
1347     switch (gm.m_d) {
1348         case 0:
1349             gm.m_y -= c;
1350             if (gm.m_y <= gm.m_ty) {
1351                 Mr_Stp();
1352                 stp = 1;
1353             }
1354             break;
1355         case 1:
1356             gm.m_x += c;
1357             if (gm.m_x >= gm.m_tx) {
1358                 Mr_Stp();
1359                 stp = 1;
1360             }
1361             break;
1362         case 2:
1363             gm.m_y += c;
1364             if (gm.m_y >= gm.m_ty) {
1365                 Mr_Stp();
1366                 stp = 1;
1367             }
1368             break;
1369         case 3:
1370             gm.m_x -= c;
1371             if (gm.m_x <= gm.m_tx) {
1372                 Mr_Stp();
1373                 stp = 1;
1374             }
1375             break;
1376     }
1377 
1378     // warp???
1379     if ( gm.m_warp ) {
1380         gm.m_x = gm.m_tx; gm.m_y = gm.m_ty;
1381         Mr_Stp();
1382         stp = 1;
1383         gm.m_warp = 0;
1384     }
1385 
1386     // check time if move limit //
1387     if ( stp && gm.c_l_st->limit_type == MOVES &&
1388          gm.m_act != M_TLP_0 && gm.m_act != M_TLP_1 &&
1389          gm.m_act != M_TLP_2 && gm.m_act != M_TLP_3) {
1390 
1391         gm.c_lvl->tm--;
1392         if ( gm.c_lvl->tm <= 0 && !gm.l_done /* completion with last move is okay */ )
1393             return 0;
1394 
1395     }
1396 
1397     // stopped and awaiting action ?
1398     if (stp && gm.m_act != M_EMPTY)
1399         Mr_Act();
1400     else
1401         if (stp) {
1402 #ifdef SOUND
1403             sound_play(gm.wv_stp);
1404 #endif
1405         }
1406 
1407     return 1;
1408 }
1409 
1410 /*
1411     select a marble
1412 */
Mr_Sel(int x,int y)1413 void Mr_Sel(int x, int y)
1414 {
1415     int mx, my;
1416 
1417     mx = (x - gm.l_x) / gm.t_w;
1418     my = (y - gm.l_y) / gm.t_h;
1419 
1420     if (gm.m_sel) {
1421         gm.mf_a.p = gm.msf_a.p = 0;
1422         Mr_Ins();
1423     }
1424 
1425     // set selected
1426     gm.m_sel = 1;
1427     // get map position
1428     gm.m_mx = mx;
1429     gm.m_my = my;
1430     // check valid moving directions
1431     Mr_CkVDir(mx, my);
1432     // delete marble from background
1433     L_DrwMpTl(mx, my);
1434     // get position in screen
1435     gm.m_x = mx * gm.t_w + gm.l_x;
1436     gm.m_y = my * gm.t_h + gm.l_y;
1437     // get id //
1438     gm.m_id = gm.c_lvl->map[mx][my].m;
1439     // delete marble from map
1440     gm.c_lvl->map[mx][my].m = -1;
1441     // save old position
1442     gm.m_o_x = (int)gm.m_x;
1443     gm.m_o_y = (int)gm.m_y;
1444     gm.m_o_move_count = gm.c_lvl->tm;
1445 
1446 #ifdef SOUND
1447     sound_play(gm.wv_sel);
1448 #endif
1449 }
1450 
1451 /*
1452     release a marble
1453 */
Mr_Rel(int x,int y)1454 void Mr_Rel(int x, int y)
1455 {
1456     Mr_Ins();
1457     gm.m_sel = 0;
1458     SDL_SetCursor(gm.c_n);
1459     gm.m_o_x = gm.m_o_y = -1;
1460 }
1461 
1462 /*
1463     initialize movement
1464 */
Mr_IniMv()1465 void Mr_IniMv()
1466 {
1467     int x_a = 0, y_a = 0, tx, ty;
1468     int t_fnd = 0;
1469 
1470     // direction
1471     gm.m_d = gm.c_stat -2;
1472     if (gm.m_d < 0 || gm.m_d > 4)
1473         return;
1474 
1475     // direction verified; activate movement
1476     gm.m_mv = 1;
1477 
1478     // store position if no action
1479     if ( gm.m_act == M_EMPTY ) {
1480         gm.m_o_x = (int)gm.m_x;
1481         gm.m_o_y = (int)gm.m_y;
1482         gm.m_o_move_count = gm.c_lvl->tm;
1483     }
1484 
1485     // clear previous action
1486     gm.m_act = M_EMPTY;
1487 
1488     // compute target position
1489     switch (gm.m_d) {
1490         case 0: y_a = -1; break;
1491         case 1: x_a = 1; break;
1492         case 2: y_a = 1; break;
1493         case 3: x_a = -1; break;
1494     }
1495     tx = gm.m_mx + x_a; ty = gm.m_my + y_a;
1496     while ( // target already found
1497             !t_fnd &&
1498             // wall
1499             gm.c_lvl->map[tx][ty].t != M_WALL &&
1500             // crumbling wall
1501             gm.c_lvl->map[tx][ty].t != M_CRUMBLE &&
1502             // marble
1503             gm.c_lvl->map[tx][ty].m == -1 &&
1504             // up
1505             !((gm.c_lvl->map[tx][ty].t == M_OW_D || gm.c_lvl->map[tx][ty].t == M_OW_D_C || gm.c_lvl->map[tx][ty].t == M_OW_L_C || gm.c_lvl->map[tx][ty].t == M_OW_R_C) && y_a == -1) &&
1506             // down
1507             !((gm.c_lvl->map[tx][ty].t == M_OW_U || gm.c_lvl->map[tx][ty].t == M_OW_U_C || gm.c_lvl->map[tx][ty].t == M_OW_L_C || gm.c_lvl->map[tx][ty].t == M_OW_R_C) && y_a == 1) &&
1508             // right
1509             !((gm.c_lvl->map[tx][ty].t == M_OW_L || gm.c_lvl->map[tx][ty].t == M_OW_L_C || gm.c_lvl->map[tx][ty].t == M_OW_U_C || gm.c_lvl->map[tx][ty].t == M_OW_D_C) && x_a == 1) &&
1510             // left
1511             !((gm.c_lvl->map[tx][ty].t == M_OW_R || gm.c_lvl->map[tx][ty].t == M_OW_R_C || gm.c_lvl->map[tx][ty].t == M_OW_U_C || gm.c_lvl->map[tx][ty].t == M_OW_D_C) && x_a == -1)
1512            ) {
1513 
1514         // check action
1515         switch (gm.c_lvl->map[tx][ty].t) {
1516             case M_TLP_0:
1517             case M_TLP_1:
1518             case M_TLP_2:
1519             case M_TLP_3:
1520                 t_fnd = 1;
1521                 gm.m_act = gm.c_lvl->map[tx][ty].t;
1522                 break;
1523             case M_OW_U:
1524                 if (y_a != -1) {
1525                     gm.m_act = M_OW_U;
1526                     t_fnd = 1;
1527                 }
1528                 break;
1529             case M_OW_D:
1530                 if (y_a != 1) {
1531                     gm.m_act = M_OW_D;
1532                     t_fnd = 1;
1533                 }
1534                 break;
1535             case M_OW_L:
1536                 if (x_a != -1) {
1537                     gm.m_act = M_OW_L;
1538                     t_fnd = 1;
1539                 }
1540                 break;
1541             case M_OW_R:
1542                 if (x_a != 1) {
1543                     gm.m_act = M_OW_R;
1544                     t_fnd = 1;
1545                 }
1546                 break;
1547         }
1548         tx += x_a;
1549         ty += y_a;
1550     }
1551 
1552     // crumbling wall
1553     if (gm.c_lvl->map[tx][ty].t == M_CRUMBLE)
1554         gm.m_act = M_CRUMBLE;
1555 
1556     tx -= x_a;
1557     ty -= y_a;
1558 
1559     gm.m_tx = tx * gm.t_w + gm.l_x;
1560     gm.m_ty = ty * gm.t_h + gm.l_y;
1561 
1562     // wait cursor
1563     SDL_SetCursor(gm.c_w);
1564 }
1565 
1566 /*
1567     stop a marble
1568 */
Mr_Stp()1569 void Mr_Stp()
1570 {
1571     int mx, my;
1572 
1573     // position in screen
1574     gm.m_x = gm.m_tx;
1575     gm.m_y = gm.m_ty;
1576 
1577     mx = (gm.m_x - gm.l_x) / gm.t_w;
1578     my = (gm.m_y - gm.l_y) / gm.t_h;
1579 
1580     // position in map
1581     gm.m_mx = mx;
1582     gm.m_my = my;
1583 
1584     // check valid moving directions
1585     Mr_CkVDir(mx, my);
1586 
1587     gm.m_mv = 0;
1588     gm.m_a.p = 0;
1589 
1590     // check cursor //
1591     Cr_Cng(gm.o_mx, gm.o_my);
1592 
1593     // if no action check if the figure is completed
1594     if (gm.m_act == M_EMPTY || gm.m_act == M_CRUMBLE) {
1595 
1596         gm.c_lvl->map[mx][my].m = gm.m_id;
1597         G_CkFgr();
1598         gm.c_lvl->map[mx][my].m = -1;
1599     }
1600 }
1601 
1602 /*
1603     insert a marble into map
1604 */
Mr_Ins()1605 void Mr_Ins()
1606 {
1607     int mx, my, x, y;
1608 
1609     mx = (gm.m_x - gm.l_x) / gm.t_w;
1610     my = (gm.m_y - gm.l_y) / gm.t_h;
1611     x = mx * gm.t_w + gm.l_x;
1612     y = my * gm.t_h + gm.l_y;
1613 
1614     //hide frame
1615     MF_Hd();
1616     // draw to background
1617     D_DST(gm.s_bkgd, x, y, gm.t_w, gm.t_h);
1618     D_SRC(gm.s_mrb, 0, gm.m_id * gm.t_h);
1619     SS_Blt();
1620     // to screen
1621     D_DST(sdl.scr, x, y, gm.t_w, gm.t_h);
1622     D_SRC(gm.s_mrb, 0, gm.m_id * gm.t_h);
1623     SS_Blt();
1624     // and to map
1625     gm.c_lvl->map[mx][my].m = gm.m_id;
1626 }
1627 
1628 /*
1629     check valid directions
1630 */
Mr_CkVDir(int mx,int my)1631 void Mr_CkVDir(int mx, int my)
1632 {
1633     gm.m_vd = 0;
1634     if ( gm.c_lvl->map[mx][my].t != M_OW_D_C && gm.c_lvl->map[mx][my].t != M_OW_U_C && gm.c_lvl->map[mx - 1][my].t != M_WALL && gm.c_lvl->map[mx - 1][my].t != M_CRUMBLE && gm.c_lvl->map[mx - 1][my].m == -1 && gm.c_lvl->map[mx - 1][my].t != M_OW_R && gm.c_lvl->map[mx - 1][my].t != M_OW_R_C && gm.c_lvl->map[mx - 1][my].t != M_OW_U_C && gm.c_lvl->map[mx - 1][my].t != M_OW_D_C)
1635         gm.m_vd = gm.m_vd | MD_L;
1636     if ( gm.c_lvl->map[mx][my].t != M_OW_D_C && gm.c_lvl->map[mx][my].t != M_OW_U_C && gm.c_lvl->map[mx + 1][my].t != M_WALL && gm.c_lvl->map[mx + 1][my].t != M_CRUMBLE && gm.c_lvl->map[mx + 1][my].m == -1 && gm.c_lvl->map[mx + 1][my].t != M_OW_L && gm.c_lvl->map[mx + 1][my].t != M_OW_L_C && gm.c_lvl->map[mx + 1][my].t != M_OW_U_C && gm.c_lvl->map[mx + 1][my].t != M_OW_D_C)
1637         gm.m_vd = gm.m_vd | MD_R;
1638     if ( gm.c_lvl->map[mx][my].t != M_OW_L_C && gm.c_lvl->map[mx][my].t != M_OW_R_C && gm.c_lvl->map[mx][my - 1].t != M_WALL && gm.c_lvl->map[mx][my - 1].t != M_CRUMBLE && gm.c_lvl->map[mx][my - 1].m == -1 && gm.c_lvl->map[mx][my - 1].t != M_OW_D && gm.c_lvl->map[mx][my - 1].t != M_OW_D_C && gm.c_lvl->map[mx][my - 1].t != M_OW_L_C && gm.c_lvl->map[mx][my - 1].t != M_OW_R_C)
1639         gm.m_vd = gm.m_vd | MD_U;
1640     if ( gm.c_lvl->map[mx][my].t != M_OW_L_C && gm.c_lvl->map[mx][my].t != M_OW_R_C && gm.c_lvl->map[mx][my + 1].t != M_WALL && gm.c_lvl->map[mx][my + 1].t != M_CRUMBLE && gm.c_lvl->map[mx][my + 1].m == -1 && gm.c_lvl->map[mx][my + 1].t != M_OW_U && gm.c_lvl->map[mx][my + 1].t != M_OW_U_C && gm.c_lvl->map[mx][my + 1].t != M_OW_L_C && gm.c_lvl->map[mx][my + 1].t != M_OW_R_C)
1641         gm.m_vd = gm.m_vd | MD_D;
1642 }
1643 
1644 /*
1645     handle actions!
1646 */
Mr_Act()1647 void Mr_Act()
1648 {
1649     int x_a = 0, y_a = 0, ow = 0, mx = gm.m_mx, my = gm.m_my, tx, ty;
1650     int i, j;
1651 
1652     // crumbling wall ?
1653     if (gm.m_act == M_CRUMBLE) {
1654         tx = mx + (gm.m_d == 1 ? 1 : gm.m_d == 3 ? -1 : 0);
1655         ty = my + (gm.m_d == 0 ? -1 : gm.m_d == 2 ? 1 : 0);
1656         if (gm.c_lvl->map[tx][ty].t == M_CRUMBLE) {
1657 #ifdef SOUND
1658                 sound_play(gm.wv_stp);
1659 #endif
1660             if (gm.c_lvl->map[tx][ty].id > 0)
1661                 gm.c_lvl->map[tx][ty].id--;
1662             else {
1663                 Wl_Exp(gm.l_x + tx * gm.t_w, gm.l_y + ty * gm.t_h, gm.m_d);
1664                 gm.c_lvl->map[tx][ty].t = M_FLOOR;
1665                 // check moving direction
1666                 Mr_CkVDir(gm.m_mx, gm.m_my);
1667                 Cr_Cng(gm.o_mx, gm.o_my);
1668                 // reset restore position
1669                 gm.m_o_x = gm.m_tx;
1670                 gm.m_o_y = gm.m_ty;
1671                 gm.m_o_move_count = gm.c_lvl->tm;
1672 #ifdef SOUND
1673                 sound_play(gm.wv_exp);
1674 #endif
1675             }
1676             // draw to background
1677             L_DrwMpTl(tx, ty);
1678             // draw to screen
1679             D_DST(sdl.scr, gm.l_x + tx * gm.t_w, gm.l_y + ty * gm.t_h, gm.t_w, gm.t_h);
1680             D_SRC(gm.s_bkgd, gm.l_x + tx * gm.t_w, gm.l_y + ty * gm.t_h);
1681             SS_Blt();
1682             // add refresh rect
1683             Sdl_AddR(gm.l_x + tx * gm.t_w, gm.l_y + ty * gm.t_h, gm.t_w, gm.t_h);
1684         }
1685         // no action
1686 //        gm.m_act = M_EMPTY;
1687         return;
1688     }
1689 
1690     // oneway ?
1691     switch (gm.m_act) {
1692         case M_OW_U:
1693             y_a = -1;
1694             ow = 1;
1695             gm.c_stat = C_U;
1696             break;
1697         case M_OW_D:
1698             y_a = 1;
1699             ow = 1;
1700             gm.c_stat = C_D;
1701             break;
1702         case M_OW_R:
1703             x_a = 1;
1704             ow = 1;
1705             gm.c_stat = C_R;
1706             break;
1707         case M_OW_L:
1708             x_a = -1;
1709             ow = 1;
1710             gm.c_stat = C_L;
1711             break;
1712     }
1713     if (ow) {
1714 /*        mx += x_a; my += y_a;
1715         while (gm.c_lvl->map[mx][my].m != -1) {
1716             mx += x_a;
1717             my += y_a;
1718         }
1719         mx -= x_a; my -= y_a;
1720         if (mx != gm.m_mx || my != gm.m_my) {
1721             Mr_Ins();
1722             Mr_Sel(gm.l_x + mx * gm.t_w, gm.l_y + my * gm.t_h);
1723         }*/
1724 #ifdef SOUND
1725         sound_play(gm.wv_arw);
1726 #endif
1727         Mr_IniMv();
1728         return;
1729     }
1730 
1731     // teleport ?
1732     if (gm.m_act >= M_TLP_0 && gm.m_act <= M_TLP_3) {
1733         for (i = 0; i < gm.c_lvl->m_w; i++) {
1734             for (j = 0; j < gm.c_lvl->m_h; j++)
1735                 if (gm.c_lvl->map[i][j].t == gm.m_act && (i != gm.m_mx || j != gm.m_my)) {
1736                     // only warp if destination is empty //
1737                     if (gm.c_lvl->map[i][j].m == -1) {
1738                         gm.m_mx = i;
1739                         gm.m_my = j;
1740                         gm.m_x = gm.m_mx * gm.t_w + gm.l_x;
1741                         gm.m_y = gm.m_my * gm.t_h + gm.l_y;
1742 #ifdef SOUND
1743                         sound_play(gm.wv_tlp);
1744 #endif
1745                     }
1746                     gm.c_stat = gm.m_d + 2; // restore c_stat for movement initialization
1747                     // initate movement
1748                     Mr_IniMv();
1749 
1750 /*                    // check if the figure is completed
1751                     gm.c_lvl->map[gm.m_mx][gm.m_my].m = gm.m_id;
1752                     G_CkFgr();
1753                     gm.c_lvl->map[gm.m_mx][gm.m_my].m = -1;*/
1754 
1755                     return;
1756                 }
1757         }
1758     }
1759 
1760 //    gm.m_act = M_EMPTY;
1761 }
1762 
1763 /*
1764     restore old position
1765 */
Mr_ResPos()1766 void Mr_ResPos()
1767 {
1768     if ( !gm.m_sel || gm.m_o_x == -1 ) return;
1769 
1770     gm.m_act = M_EMPTY;
1771     gm.m_tx = gm.m_o_x;
1772     gm.m_ty = gm.m_o_y;
1773     if ( gm.c_l_st->limit_type == MOVES )
1774         gm.c_lvl->tm = gm.m_o_move_count;
1775     Mr_Stp();
1776 }
1777 
1778 // timer //
1779 /*
1780     hide time
1781 */
Tm_Hd()1782 void Tm_Hd()
1783 {
1784     int w = gm.brd_w - gm.t_x * 2;
1785     int h = gm.f_wht->h;
1786 
1787     D_DST(sdl.scr, gm.t_x + gm.b_x, gm.t_y, w, h);
1788     D_SRC(gm.s_bkgd, gm.t_x + gm.b_x, gm.t_y);
1789     SS_Blt();
1790     Sdl_AddR(gm.t_x + gm.b_x, gm.t_y, w, h);
1791 }
1792 
1793 /*
1794     show time
1795 */
Tm_Shw()1796 void Tm_Shw()
1797 {
1798     SFnt *ft;
1799     char str_tm[16];
1800     char str_sec[4];
1801     int tm;
1802 
1803     // adjust time //
1804     if ( gm.c_l_st->limit_type == TIME )
1805         tm = gm.c_lvl->tm / 1000;
1806     else
1807         tm = gm.c_lvl->tm;
1808 
1809     // select font
1810     ft = gm.f_wht;
1811     if ( gm.c_l_st->limit_type == TIME && tm <= 30 )
1812         ft = gm.f_rd;
1813     else
1814         if ( gm.c_l_st->limit_type == MOVES && tm <= 10 )
1815             ft = gm.f_rd;
1816 
1817     // draw "time"
1818     ft->algn = TA_X_L | TA_Y_T;
1819     if ( gm.c_l_st->limit_type == TIME )
1820         SF_Wrt(ft, sdl.scr, gm.t_x + gm.b_x, gm.t_y, "Time:", 0);
1821     else
1822         SF_Wrt(ft, sdl.scr, gm.t_x + gm.b_x, gm.t_y, "Moves:", 0);
1823 
1824     // compute and draw time str
1825     if ( gm.c_l_st->limit_type == TIME ) {
1826 
1827         sprintf(str_tm, "%i:", tm / 60);
1828         sprintf(str_sec, "%i", tm % 60);
1829         if (strlen(str_sec) < 2)
1830             strcat(str_tm, "0");
1831         strcat(str_tm, str_sec);
1832 
1833     }
1834     else
1835         sprintf( str_tm, "%i", tm );
1836 
1837     ft->algn = TA_X_R | TA_Y_T;
1838     SF_Wrt(ft, sdl.scr, gm.scr_w - gm.t_x, gm.t_y, str_tm, 0);
1839 
1840     Sdl_AddR(gm.t_x + gm.b_x, gm.t_y, gm.b_x - gm.t_x*2, ft->h);
1841 }
1842 
1843 /*
1844     update time
1845     return 0 if time out
1846 */
Tm_Upd(int ms)1847 int Tm_Upd(int ms)
1848 {
1849 #ifdef SOUND
1850     int old_sec = gm.c_lvl->tm / 1000;
1851 #endif
1852 
1853     gm.blink_time += ms;
1854 
1855     // if limit_type is MOVES, time is ignored //
1856     if ( gm.c_l_st->limit_type == MOVES ) return 1;
1857 
1858     gm.c_lvl->tm -= ms;
1859 
1860     // new second ?
1861 #ifdef SOUND
1862     if ( old_sec != gm.c_lvl->tm / 1000 && old_sec <= 30 )
1863         sound_play(gm.wv_alm);
1864 #endif
1865 
1866     if (gm.c_lvl->tm < 0) {
1867         gm.c_lvl->tm = 0;
1868         return 0;
1869     }
1870     return 1;
1871 }
1872 
1873 // level info //
1874 /*
1875     hide level info
1876 */
Inf_Hd()1877 void Inf_Hd()
1878 {
1879     D_DST(sdl.scr, gm.b_x + gm.s_x, gm.s_y + gm.s_h - 20, gm.s_w, 20);
1880     D_SRC(gm.s_bkgd, gm.b_x + gm.s_x, gm.s_y + gm.s_h - 20);
1881     SS_Blt();
1882     Sdl_AddR(gm.b_x + gm.s_x, gm.s_y + gm.s_h - 20, gm.s_w, 20);
1883 }
1884 
1885 /*
1886     update level info
1887 */
Inf_Upd()1888 int Inf_Upd()
1889 {
1890     int x, y;
1891 
1892     x = (gm.o_mx - gm.c_x - gm.b_x) / L_SIZE;
1893     y = (gm.o_my - gm.c_y) / L_SIZE;
1894 
1895     if (gm.o_mx < gm.c_x + gm.b_x || gm.o_my < gm.c_y  || x >= gm.c_l_st->l_num || y >= gm.c_l_st->c_num) {
1896         sprintf(gm.inf_str, "Tier %i, Puzzle %i", gm.c_ch + 1, gm.c_l_id + 1);
1897         return 0;
1898     }
1899     if (!gm.c_s_inf->cmp[y * gm.c_s_inf->l_num + x] && !gm.c_s_inf->c_opn[y]) {
1900         sprintf(gm.inf_str, "Access Denied");
1901         return 0;
1902     }
1903     sprintf(gm.inf_str, "Tier %i, Puzzle %i", y + 1, x + 1);
1904     if (gm.bttn[1]) {
1905         gm.w_c = y;
1906         gm.w_l = x;
1907         return 1;
1908     }
1909     return 0;
1910 }
1911 
1912 /*
1913     show level info
1914 */
Inf_Shw()1915 void Inf_Shw()
1916 {
1917     gm.f_sml->algn = TA_X_C | TA_Y_B;
1918     SF_Wrt(gm.f_sml, sdl.scr, gm.b_x + gm.brd_w / 2, gm.s_y + gm.s_h - 5, gm.inf_str, 0);
1919 }
1920 
1921 // cursor
1922 /*
1923     load cursor
1924 */
Cr_Ld(char * src,char * d,char * m)1925 void Cr_Ld(char *src, char *d, char*m)
1926 {
1927     int w=16, h = 16;
1928     int i, j, k;
1929     char b_d, b_m;
1930     int p;
1931 
1932     k = 0;
1933     for (j = 0; j < w * h; j += 8, k++) {
1934         p = 1;
1935         b_d = b_m = 0;
1936         // create byte
1937         for (i = 7; i >= 0; i--) {
1938             switch (src[j + i]) {
1939                 case 2:
1940                     b_d += p;
1941                 case 1:
1942                     b_m += p;
1943                     break;
1944             }
1945             p *= 2;
1946         }
1947         // add to mask
1948         d[k] = b_d;
1949         m[k] = b_m;
1950     }
1951 }
1952 
1953 /*
1954     change cursors appearing
1955 */
Cr_Cng(int x,int y)1956 void Cr_Cng(int x, int y)
1957 {
1958     int mx, my, cx, cy;
1959 
1960     if (gm.m_mv) {
1961         if (x > gm.scr_w - gm.brd_w)
1962             SDL_SetCursor(gm.c_n);
1963         else
1964             SDL_SetCursor(gm.c_w);
1965         return;
1966     }
1967 
1968     mx = (x - gm.l_x) / gm.t_w;
1969     my = (y - gm.l_y) / gm.t_h;
1970 
1971     if ( mx >= 0 && my >= 0 && mx < gm.c_lvl->m_w && my < gm.c_lvl->m_h
1972      && (gm.c_lvl->map[mx][my].m != - 1 || (gm.m_mx == mx && gm.m_my == my))) {
1973         // on marble
1974         SDL_SetCursor(gm.c_s);
1975         gm.c_stat = C_SEL;
1976     }
1977     else
1978         if (!gm.m_sel || x > gm.scr_w - gm.brd_w) {
1979             // nothing selected
1980             SDL_SetCursor(gm.c_n);
1981             gm.c_stat = C_NONE;
1982         }
1983         else {
1984             // up, left, right, down
1985             cx = x - (gm.m_mx * gm.t_w + gm.l_x + gm.t_w / 2);
1986             cy = y - (gm.m_my * gm.t_h + gm.l_y + gm.t_h / 2);
1987             if (abs(cx) > abs(cy)) {
1988                 if (cx > 0) {
1989                     if (gm.m_vd & MD_R) {
1990                         SDL_SetCursor(gm.c_r);
1991                         gm.c_stat = C_R;
1992                     }
1993                     else {
1994                        SDL_SetCursor(gm.c_n);
1995                        gm.c_stat = C_NONE;
1996                     }
1997                 }
1998                 else {
1999                     if (gm.m_vd & MD_L) {
2000                         SDL_SetCursor(gm.c_l);
2001                         gm.c_stat = C_L;
2002                     }
2003                     else {
2004                         SDL_SetCursor(gm.c_n);
2005                         gm.c_stat = C_NONE;
2006                     }
2007                 }
2008             }
2009             else {
2010                 if (cy > 0) {
2011                     if (gm.m_vd & MD_D) {
2012                         SDL_SetCursor(gm.c_d);
2013                         gm.c_stat = C_D;
2014                     }
2015                     else {
2016                         SDL_SetCursor(gm.c_n);
2017                         gm.c_stat = C_NONE;
2018                     }
2019                 }
2020                 else {
2021                     if (gm.m_vd & MD_U) {
2022                         SDL_SetCursor(gm.c_u);
2023                         gm.c_stat = C_U;
2024                     }
2025                     else {
2026                         SDL_SetCursor(gm.c_n);
2027                         gm.c_stat = C_NONE;
2028                     }
2029                 }
2030             }
2031         }
2032 }
2033 
2034 // frame //
2035 /*
2036     hide marble frame
2037 */
MF_Hd()2038 void MF_Hd()
2039 {
2040     int x, y, w, h;
2041 
2042     if (!gm.m_sel) return;
2043 
2044     // get size
2045     if (gm.msf_a.p == gm.msf_a.f) {
2046         w = gm.mf_a.w;
2047         h = gm.mf_a.h;
2048     }
2049     else {
2050         w = gm.msf_a.w;
2051         h = gm.msf_a.h;
2052     }
2053 
2054     // get position
2055     x = gm.m_x + (gm.t_w - w) / 2;
2056     y = gm.m_y + (gm.t_h - h) / 2;
2057 
2058     // hide
2059     D_DST(sdl.scr, x, y, w, h);
2060     D_SRC(gm.s_bkgd, x, y);
2061     SS_Blt();
2062     Sdl_AddR(x - 1, y - 1, w + 1, h + 1);
2063 }
2064 
2065 /*
2066     update marble frame
2067 */
MF_Upd(int ms)2068 void MF_Upd(int ms)
2069 {
2070     if (!gm.m_sel) {
2071         gm.mf_a.p = gm.msf_a.p = 0;
2072         return;
2073     }
2074     if (gm.msf_a.p != gm.msf_a.f) {
2075         // still select animation
2076         gm.msf_a.p += gm.msf_a.c * ms;
2077         if (gm.msf_a.p >= gm.msf_a.f)
2078             gm.msf_a.p = gm.msf_a.f;
2079     }
2080     else {
2081         gm.mf_a.p += gm.mf_a.c * ms;
2082         if (gm.mf_a.p >= gm.mf_a.f)
2083             gm.mf_a.p = 0;
2084     }
2085 }
2086 
2087 /*
2088     show marble frame
2089 */
MF_Shw()2090 void MF_Shw()
2091 {
2092     int x, y;
2093     AInf *a;
2094     SDL_Surface *s;
2095 
2096     if (!gm.m_sel) return;
2097 
2098     // get animation info
2099     if (gm.msf_a.p == gm.msf_a.f) {
2100         a = &gm.mf_a;
2101         s = gm.s_mf;
2102     }
2103     else {
2104         a = &gm.msf_a;
2105         s = gm.s_msf;
2106     }
2107 
2108     // get position
2109     x = gm.m_x + (gm.t_w - a->w) / 2;
2110     y = gm.m_y + (gm.t_h - a->h) / 2;
2111 
2112     // show
2113     D_DST(sdl.scr, x, y, a->w, a->h);
2114     D_SRC(s, (int)a->p * a->w, 0);
2115     SS_Blt();
2116     Sdl_AddR(x, y, a->w, a->h);
2117 }
2118 
2119 // map animations //
2120 /*
2121     get position and type of all animations
2122 */
MA_Ini()2123 void MA_Ini()
2124 {
2125     int i, j;
2126 
2127     // free and reallocate m_ani
2128     if (gm.m_ani)
2129         free(gm.m_ani);
2130     gm.m_ani = (MAni*)malloc(sizeof(MAni) * gm.c_lvl->m_w * gm.c_lvl->m_h);
2131     gm.ma_num = 0;
2132 
2133     // parse level map
2134     for (i = 0; i < gm.c_lvl->m_w; i++)
2135         for (j = 0; j < gm.c_lvl->m_h; j++)
2136             switch (gm.c_lvl->map[i][j].t) {
2137                 case M_OW_U:
2138                 case M_OW_D:
2139                 case M_OW_L:
2140                 case M_OW_R:
2141                 case M_OW_U_C:
2142                 case M_OW_D_C:
2143                 case M_OW_L_C:
2144                 case M_OW_R_C:
2145                     gm.m_ani[gm.ma_num].x = i;
2146                     gm.m_ani[gm.ma_num].y = j;
2147                     gm.m_ani[gm.ma_num].t = gm.c_lvl->map[i][j].t;
2148                     gm.m_ani[gm.ma_num].a = &gm.ma_ow_a;
2149                     gm.ma_num++;
2150                     break;
2151                 case M_TLP_0:
2152                 case M_TLP_1:
2153                 case M_TLP_2:
2154                 case M_TLP_3:
2155                     gm.m_ani[gm.ma_num].x = i;
2156                     gm.m_ani[gm.ma_num].y = j;
2157                     gm.m_ani[gm.ma_num].t = gm.c_lvl->map[i][j].t;
2158                     gm.m_ani[gm.ma_num].a = &gm.ma_tlp_a;
2159                     gm.ma_num++;
2160                     break;
2161                 default:
2162                     break;
2163             }
2164 }
2165 
MA_Upd(int ms)2166 void MA_Upd(int ms)
2167 {
2168     if (!cfg.ani) return;
2169 
2170     gm.ma_ow_a.p += (float)ms * gm.ma_ow_a.c;
2171     if (gm.ma_ow_a.p >= gm.ma_ow_a.f)
2172         gm.ma_ow_a.p = 0;
2173 
2174     gm.ma_tlp_a.p += (float)ms * gm.ma_tlp_a.c;
2175     if (gm.ma_tlp_a.p >= gm.ma_tlp_a.f)
2176         gm.ma_tlp_a.p = 0;
2177 }
2178 
2179 /*
2180     show map animations
2181 */
MA_Shw()2182 void MA_Shw()
2183 {
2184     int i;
2185     int x, y;
2186 
2187     if (!cfg.ani) return;
2188 
2189     for (i = 0; i < gm.ma_num; i++) {
2190         // get position in screen
2191         x = gm.l_x + gm.m_ani[i].x * gm.t_w;
2192         y = gm.l_y + gm.m_ani[i].y * gm.t_h;
2193 
2194         // draw empty floor
2195         D_DST(sdl.scr, x, y, gm.t_w, gm.t_h);
2196         D_SRC(gm.c_g_st->s_flr, 0, 0);
2197         SS_Blt();
2198 
2199         // oneway
2200         D_DST(sdl.scr, x, y, gm.t_w, gm.t_h);
2201         switch (gm.m_ani[i].t) {
2202             case M_OW_R:
2203             case M_OW_R_C:
2204                 D_SRC(gm.c_g_st->s_r_arw, (int)gm.m_ani[i].a->p * gm.t_w, 0);
2205                 SS_Blt();
2206                 break;
2207             case M_OW_L:
2208             case M_OW_L_C:
2209                 D_SRC(gm.c_g_st->s_l_arw, (int)gm.m_ani[i].a->p * gm.t_w, 0);
2210                 SS_Blt();
2211                 break;
2212             case M_OW_U:
2213             case M_OW_U_C:
2214                 D_SRC(gm.c_g_st->s_u_arw, 0, (int)gm.m_ani[i].a->p * gm.t_h);
2215                 SS_Blt();
2216                 break;
2217             case M_OW_D:
2218             case M_OW_D_C:
2219                 D_SRC(gm.c_g_st->s_d_arw, 0, (int)gm.m_ani[i].a->p * gm.t_h);
2220                 SS_Blt();
2221                 break;
2222         }
2223         D_DST(sdl.scr, x, y, gm.t_w, gm.t_h);
2224         switch (gm.m_ani[i].t) {
2225             case M_OW_U_C:
2226             case M_OW_D_C:
2227                 D_SRC(gm.c_g_st->s_lr_bar, 0, 0);
2228                 SS_Blt();
2229                 break;
2230             case M_OW_L_C:
2231             case M_OW_R_C:
2232                 D_SRC(gm.c_g_st->s_ud_bar, 0, 0);
2233                 SS_Blt();
2234                 break;
2235         }
2236 
2237         // teleport
2238         D_DST(sdl.scr, x, y, gm.t_w, gm.t_h);
2239         switch (gm.m_ani[i].t) {
2240             case M_TLP_0:
2241                 D_SRC(gm.c_g_st->s_tlp_0, (int)gm.m_ani[i].a->p * gm.t_w, 0);
2242                 SS_ABlt(gm.tlp_a);
2243                 break;
2244             case M_TLP_1:
2245                 D_SRC(gm.c_g_st->s_tlp_1, (int)gm.m_ani[i].a->p * gm.t_w, 0);
2246                 SS_ABlt(gm.tlp_a);
2247                 break;
2248             case M_TLP_2:
2249                 D_SRC(gm.c_g_st->s_tlp_2, (int)gm.m_ani[i].a->p * gm.t_w, 0);
2250                 SS_ABlt(gm.tlp_a);
2251                 break;
2252             case M_TLP_3:
2253                 D_SRC(gm.c_g_st->s_tlp_3, (int)gm.m_ani[i].a->p * gm.t_w, 0);
2254                 SS_ABlt(gm.tlp_a);
2255                 break;
2256         }
2257 
2258         // marble on animation
2259         if (gm.c_lvl->map[gm.m_ani[i].x][gm.m_ani[i].y].m != -1 &&
2260             ( ((gm.blink_time / 250) & 1) || gm.l_done ) ) {
2261             D_DST(sdl.scr, x, y, gm.t_w, gm.t_h);
2262             D_SRC(gm.s_mrb, 0, gm.c_lvl->map[gm.m_ani[i].x][gm.m_ani[i].y].m * gm.t_w);
2263             SS_Blt();
2264         }
2265 
2266         // refresh rect
2267         Sdl_AddR(x, y, gm.t_w, gm.t_h);
2268     }
2269 }
2270 
2271 // shrapnells //
2272 /*
2273     add new shrapnell
2274 */
Shr_Add(int x,int y,int w,int h,Vec d,SDL_Surface * s_shr)2275 void Shr_Add(int x, int y, int w, int h, Vec d, SDL_Surface *s_shr)
2276 {
2277     Shr *s;
2278 
2279     s = (Shr*)malloc(sizeof(Shr));
2280     s->d = d;
2281     s->x = x;
2282     s->y = y;
2283     s->w = w;
2284     s->h = h;
2285     s->a = 0;
2286     if ( s_shr )
2287         s->s_shr = s_shr;
2288     else  {
2289 
2290         s->s_shr = SS_Crt(w, h, SDL_SWSURFACE);
2291         D_DST(s->s_shr, 0, 0, w, h);
2292         D_SRC(sdl.scr, x, y);
2293         SS_Blt();
2294 
2295     }
2296 
2297     DL_Add(&gm.shr, s);
2298 }
2299 
2300 /*
2301     delete shrapnell
2302 */
Shr_Del(void * p)2303 void Shr_Del(void *p)
2304 {
2305     Shr *s = (Shr*)p;
2306     if ( s->s_shr ) SDL_FreeSurface(s->s_shr);
2307     free(p);
2308 }
2309 
2310 /*
2311     hide shrapnell
2312 */
Shr_Hd()2313 void Shr_Hd()
2314 {
2315     DL_E *e = gm.shr.hd.n;
2316     Shr *s;
2317 
2318     while ( e != &gm.shr.tl ) {
2319 
2320         s = (Shr*)e->d;
2321 
2322         D_DST(sdl.scr, (int)s->x, (int)s->y, s->w, s->h);
2323         D_SRC(gm.s_bkgd, (int)s->x, (int)s->y);
2324         SS_Blt();
2325         Sdl_AddR((int)s->x, (int)s->y, s->w, s->h);
2326 
2327         e = e->n;
2328 
2329     }
2330 
2331 }
2332 
2333 /*
2334     update shrapnell
2335 */
Shr_Upd(int ms)2336 void Shr_Upd(int ms)
2337 {
2338     DL_E *n, *e = gm.shr.hd.n;
2339     Shr *s;
2340 
2341     while ( e != &gm.shr.tl ) {
2342 
2343         n = e->n;
2344 
2345         s = (Shr*)e->d;
2346 
2347         s->x += s->d.x * (float)ms;
2348         s->y += s->d.y * (float)ms;
2349         s->a += gm.shr_a_c * (float)ms;
2350 
2351         if (s->a >= 255)
2352             DL_DelE(&gm.shr, e);
2353 
2354         e = n;
2355 
2356     }
2357 }
2358 
2359 /*
2360     show shrapnell
2361 */
Shr_Shw()2362 void Shr_Shw()
2363 {
2364     DL_E *e = gm.shr.hd.n;
2365     Shr *s;
2366 
2367     while ( e != &gm.shr.tl ) {
2368 
2369         s = (Shr*)e->d;
2370 
2371         D_DST(sdl.scr, (int)s->x, (int)s->y, s->w, s->h);
2372         D_SRC(s->s_shr, 0, 0);
2373         SS_ABlt(s->a);
2374         Sdl_AddR((int)s->x, (int)s->y, s->w, s->h);
2375 
2376         e = e->n;
2377 
2378     }
2379 
2380 }
2381 
2382 // wall //
2383 /*
2384     explode crumble wall into lot of pieces
2385 */
Wl_Exp(int x,int y,int d)2386 void Wl_Exp(int x, int y, int d)
2387 {
2388     int i, j;
2389     int sz = 4;
2390     Vec v;
2391     int x_r, x_off, y_r, y_off; // direction values
2392     SDL_Surface *s_shr;
2393 
2394     if ( !cfg.ani ) return;
2395 
2396     x_r = y_r = 200;
2397     x_off = y_off = 100;
2398 
2399     // adjust direction values
2400     switch (d) {
2401 
2402         case 0:
2403             y_r = y_off = 100;
2404             break;
2405 
2406         case 1:
2407             x_r = 100;
2408             x_off = 0;
2409             break;
2410 
2411         case 2:
2412             y_r = 100;
2413             y_off = 0;
2414             break;
2415 
2416         case 3:
2417             x_r = x_off = 100;
2418             break;
2419 
2420     }
2421 
2422     for ( i = 0; i < gm.t_w; i += sz )
2423         for ( j = 0; j < gm.t_h; j += sz ) {
2424 
2425             v.x = (float)((rand() % x_r ) - x_off) / 1000;
2426             v.y = (float)((rand() % y_r ) - y_off) / 1000;
2427 
2428             s_shr = SS_Crt(sz, sz, SDL_SWSURFACE);
2429             D_DST(s_shr, 0, 0, sz, sz);
2430             D_SRC(gm.c_g_st->s_crmbl, i, j);
2431             SS_Blt();
2432 
2433             Shr_Add(x + i, y + j, sz, sz, v, s_shr);
2434 
2435         }
2436 }
2437 
2438 // figure animation //
2439 /*
2440     main animation function; select and explode marbles one by one
2441 */
FA_Run()2442 void FA_Run()
2443 {
2444     int i, j, k;
2445     int m_cnt = 0; // marble count
2446     int m_pos[gm.c_lvl->f_w * gm.c_lvl->f_h][2], b;
2447     int ms;
2448     SDL_Event e;
2449     int leave = 0;
2450     int tm, c_tm; // time in ms
2451 
2452     if (!cfg.ani) return;
2453 
2454     if (gm.m_sel)
2455         Mr_Ins();
2456 
2457     // count marbles and get position
2458     for ( i = 0; i < gm.c_lvl->m_w; i++ )
2459         for (j = 0; j < gm.c_lvl->m_h; j++ )
2460             if ( gm.c_lvl->map[i][j].m != - 1 ) {
2461 
2462                 m_pos[m_cnt][0] = i;
2463                 m_pos[m_cnt][1] = j;
2464                 m_cnt++;
2465 
2466             }
2467 
2468     // unsort positions
2469     for ( k = 0; k < m_cnt * 5; k++) {
2470 
2471         i = rand() % m_cnt;
2472         j = rand() % m_cnt;
2473 
2474         b = m_pos[i][0];
2475         m_pos[i][0] = m_pos[j][0];
2476         m_pos[j][0] = b;
2477         b = m_pos[i][1];
2478         m_pos[i][1] = m_pos[j][1];
2479         m_pos[j][1] = b;
2480 
2481     }
2482 
2483     // explosions
2484     MF_Hd();
2485     T_Rst();
2486     tm = 250;
2487     c_tm = 0;
2488     m_cnt--;
2489     SDL_SetCursor(gm.c_w);
2490     while ( (m_cnt >= 0 || gm.shr.cntr > 0) && !trm_gm && !leave ) {
2491 
2492         // termination ?
2493         if (SDL_PollEvent(&e)) {
2494             switch (e.type) {
2495                 case SDL_QUIT:
2496                     trm_gm = 1;
2497                     break;
2498                 case SDL_MOUSEBUTTONUP:
2499                 case SDL_KEYUP:
2500                     if (e.key.keysym.sym == SDLK_TAB)
2501                         SnapShot();
2502                     else
2503                         leave = 1;
2504                     break;
2505             }
2506         }
2507 
2508         // show shrapnells
2509         Shr_Hd();
2510         ms = T_Gt();
2511         c_tm -= ms;
2512         MA_Upd(ms);
2513         Shr_Upd(ms);
2514         MA_Shw();
2515         Shr_Shw();
2516         Tm_Shw();
2517         Inf_Shw();
2518         Sdl_UpdR();
2519 
2520         //add new shrapnells
2521         if (m_cnt >= 0 && c_tm <= 0) {
2522 
2523             FA_Add(m_pos[m_cnt][0],
2524                    m_pos[m_cnt][1],
2525                    gm.c_lvl->map[m_pos[m_cnt][0]][m_pos[m_cnt][1]].m);
2526             c_tm = tm;
2527             m_cnt--;
2528 #ifdef SOUND
2529             sound_play(gm.wv_exp);
2530 #endif
2531 
2532         }
2533 
2534     }
2535 
2536 }
2537 
2538 /*
2539     add shrapnells at x,y with marble-id m
2540 */
FA_Add(int mx,int my,int m)2541 void FA_Add(int mx, int my, int m)
2542 {
2543     int x, y;
2544     int i, j;
2545     int sz = 4; // size
2546     SDL_Surface *s_shr;
2547     Vec v;
2548 
2549     x = gm.l_x + mx * gm.t_w;
2550     y = gm.l_y + my * gm.t_h;
2551 
2552     // delete from screne
2553     gm.c_lvl->map[mx][my].m = -1;
2554     L_DrwMpTl(mx, my);
2555     Sdl_AddR(x, y, gm.t_w, gm.t_h);
2556 
2557     // create shrapnells
2558     for ( i = 0; i < gm.t_w; i += sz )
2559         for ( j = 0; j < gm.t_h; j += sz ) {
2560 
2561             v.x = (float)((rand() % 200 ) - 100) / 1000;
2562             v.y = (float)((rand() % 200 ) - 100) / 1000;
2563 
2564             s_shr = SS_Crt(sz, sz, SDL_SWSURFACE);
2565             D_DST(s_shr, 0, 0, sz, sz);
2566             D_SRC(gm.s_mrb, i, gm.t_h * m + j);
2567             SS_Blt();
2568 
2569             Shr_Add(x + i, y + j, sz, sz, v, s_shr);
2570 
2571         }
2572 }
2573 
2574 // credits //
2575 /*
2576     initiate credits
2577 */
Cr_Ini()2578 void Cr_Ini()
2579 {
2580     gm.cr_st = 0;
2581     gm.cr_a = 255;
2582     gm.cr_c_tm = gm.cr_tm;
2583     sprintf(gm.cr_str, "'%s' (Author: %s)", gm.c_l_st->ch[gm.c_ch].nm, gm.c_l_st->ch[gm.c_ch].authr);
2584     gm.cr_w = SF_TxtW(gm.f_sml, gm.cr_str);
2585     gm.cr_h = gm.f_sml->h;
2586     gm.cr_x = (gm.scr_w - gm.brd_w - gm.cr_w) / 2;
2587 }
2588 
2589 /*
2590     hide credits
2591 */
Cr_Hd()2592 void Cr_Hd()
2593 {
2594     if ( gm.cr_st == 3 ) return;
2595 
2596     D_DST(sdl.scr, gm.cr_x, gm.cr_y, gm.cr_w, gm.cr_h);
2597     D_SRC(gm.s_bkgd, gm.cr_x, gm.cr_y);
2598     SS_Blt();
2599 }
2600 
2601 /*
2602     update credits
2603 */
Cr_Upd(int ms)2604 void Cr_Upd(int ms)
2605 {
2606     if ( gm.cr_st == 3 ) return;
2607 
2608     switch ( gm.cr_st ) {
2609 
2610         case 0:
2611             // undim
2612             gm.cr_a -= gm.cr_a_c * (float)ms;
2613             if ( gm.cr_a <= 0 ) {
2614 
2615                 gm.cr_a = 0;
2616                 gm.cr_st = 1;
2617 
2618             }
2619             break;
2620 
2621         case 1:
2622             // just show till timeout
2623             gm.cr_c_tm -= ms;
2624             if ( gm.cr_c_tm <= 0 )
2625                 gm.cr_st = 2;
2626             break;
2627 
2628         case 2:
2629             // undim
2630             gm.cr_a += gm.cr_a_c * (float)ms;
2631             if ( gm.cr_a >= 255 ) {
2632 
2633                 gm.cr_a = 255;
2634                 gm.cr_st = 3;
2635 
2636             }
2637             break;
2638 
2639     }
2640 }
2641 
2642 /*
2643     show credits
2644 */
Cr_Shw()2645 void Cr_Shw()
2646 {
2647     if ( gm.cr_st == 3) return;
2648 
2649     gm.f_sml->algn = TA_X_L | TA_Y_T;
2650     SF_Wrt(gm.f_sml, sdl.scr, gm.cr_x, gm.cr_y, gm.cr_str, (int)gm.cr_a);
2651     Sdl_AddR(gm.cr_x, gm.cr_y, gm.cr_w, gm.cr_h);
2652 }
2653 
2654 // modify score //
modify_score(int * b_lvl,int * b_tm)2655 void modify_score( int *b_lvl, int *b_tm )
2656 {
2657     /* modify score according to difficulty level */
2658     switch (cfg.diff) {
2659         case DIFF_EASY:
2660             *b_lvl /= 2;
2661             *b_tm  /= 2;
2662             break;
2663         case DIFF_NORMAL: break;
2664         case DIFF_HARD:
2665             *b_lvl *= 2;
2666             *b_tm  *= 2;
2667             break;
2668         case DIFF_BRAINSTORM:
2669             *b_tm  *= 5;
2670             *b_lvl *= 5;
2671             break;
2672     }
2673 }
2674 
2675 // bonus summary //
2676 /*
2677     give a bonus summary
2678 */
BS_Run(float b_lvl,float b_tm)2679 void BS_Run(float b_lvl, float b_tm)
2680 {
2681     SDL_Surface *buf;
2682     SDL_Event e;
2683     int leave = 0;
2684     int coff, cy; // level completed
2685     int toff, ty; // time bonus
2686     int soff, sy; // score
2687     int ms;
2688     int sw = 80, sh = gm.f_sml->h; // string width, height
2689     float b_c = 1.0; // bonus change
2690     float scr = gm.c_prf->scr;
2691     int end_scr;
2692     int old_scr;
2693 
2694     end_scr = gm.c_prf->scr + (int)b_lvl + (int)b_tm;
2695 
2696     // normal cursor
2697     SDL_SetCursor(gm.c_n);
2698 
2699     // darken screen
2700     buf = SS_Crt(gm.scr_w, gm.scr_h, SDL_SWSURFACE);
2701     SDL_SetColorKey(buf, 0, 0);
2702     D_FDST(buf);
2703     SS_Fill(0x0);
2704     D_FDST(sdl.scr);
2705     D_FSRC(buf);
2706     SS_ABlt(128);
2707     SDL_FreeSurface(buf);
2708     D_FDST(gm.s_bkgd);
2709     D_FSRC(sdl.scr);
2710     SS_Blt();
2711 
2712     // positions
2713     cy = 200; coff = 200;
2714     ty = 220; toff = 200;
2715     sy = 250; soff = 200;
2716 
2717     // info
2718     gm.f_sml->algn = TA_X_L | TA_Y_T;
2719     SF_Wrt(gm.f_sml, sdl.scr, coff, cy, "Level Bonus:", 0);
2720     SF_Wrt(gm.f_sml, sdl.scr, toff, ty, "Move Bonus:", 0);
2721     SF_Wrt(gm.f_sml, sdl.scr, soff, sy, "Total Score:", 0);
2722     Sdl_FUpd();
2723 
2724     // show bonus first time
2725     gm.f_sml->algn = TA_X_R | TA_Y_T;
2726     BS_Shw(gm.scr_w - soff, sy, (int)scr);
2727     Sdl_UpdR();
2728     SDL_Delay(500);
2729     BS_Shw(gm.scr_w - coff, cy, (int)b_lvl);
2730     Sdl_UpdR();
2731 #ifdef SOUND
2732     sound_play(gm.wv_exp);
2733 #endif
2734     SDL_Delay(500);
2735     BS_Shw(gm.scr_w - toff, ty, (int)b_tm);
2736     Sdl_UpdR();
2737 #ifdef SOUND
2738     sound_play(gm.wv_exp);
2739 #endif
2740     SDL_Delay(500);
2741 
2742     T_Rst();
2743     while ( !leave ) {
2744 
2745         // break?
2746         if ( SDL_PollEvent(&e) )
2747             switch ( e.type ) {
2748 
2749                 case SDL_QUIT:
2750                     trm_gm = 1;
2751                     break;
2752 
2753                 case SDL_MOUSEBUTTONUP:
2754                 case SDL_KEYUP:
2755                     leave = 1;
2756                     break;
2757 
2758             }
2759 
2760         // time
2761         ms = T_Gt();
2762 
2763         // hide
2764         BS_Hd(gm.scr_w - coff - sw, cy, sw, sh);
2765         BS_Hd(gm.scr_w - toff - sw, ty, sw, sh);
2766         BS_Hd(gm.scr_w - soff - sw, sy, sw, sh);
2767 
2768         // update
2769         old_scr = (int)scr;
2770         if ( b_lvl > 0 ) {
2771 
2772             b_lvl -= b_c * (float)ms;
2773             scr += b_c * (float)ms;
2774             if ( b_lvl < 0 )
2775                 b_lvl = 0;
2776 
2777         }
2778         if ( b_tm > 0 ) {
2779 
2780             b_tm -= b_c * (float)ms;
2781             scr += b_c * (float)ms;
2782             if ( b_tm < 0 )
2783                 b_tm = 0;
2784 
2785         }
2786         if ( (int)scr >= end_scr)
2787             scr = end_scr;
2788         if (b_lvl == 0 && b_tm == 0)
2789             scr = end_scr;
2790 #ifdef SOUND
2791         if ( (old_scr / 50) != (int)scr / 50 )
2792             sound_play(gm.wv_scr);
2793 #endif
2794 
2795         // show
2796         BS_Shw(gm.scr_w - coff, cy, (int)b_lvl);
2797         BS_Shw(gm.scr_w - toff, ty, (int)b_tm);
2798         BS_Shw(gm.scr_w - soff, sy, (int)scr);
2799 
2800         Sdl_UpdR();
2801     }
2802 }
2803 
2804 /*
2805     hide number
2806 */
BS_Hd(int x,int y,int w,int h)2807 void BS_Hd(int x, int y, int w, int h)
2808 {
2809     D_DST(sdl.scr, x, y, w, h);
2810     D_SRC(gm.s_bkgd, x, y);
2811     SS_Blt();
2812     Sdl_AddR(x, y, w, h);
2813 }
2814 
2815 /*
2816     show number
2817 */
BS_Shw(int x,int y,int v)2818 void BS_Shw(int x, int y, int v)
2819 {
2820     char str[10];
2821 
2822     sprintf(str, "%i", v);
2823     SF_Wrt(gm.f_sml, sdl.scr, x, y, str, 0);
2824     Sdl_AddR(x - SF_TxtW(gm.f_sml, str), y, SF_TxtW(gm.f_sml, str), gm.f_sml->h);
2825 }
2826 
2827 // snap shot //
2828 /*
2829     take a screenshot
2830 */
SnapShot()2831 void SnapShot()
2832 {
2833 	char filename[32];
2834 #ifdef SOUND
2835     	sound_play(gm.wv_clk);
2836 #endif
2837 	sprintf(filename, "snapshot_%i.bmp", gm.snap++);
2838 	SDL_SaveBMP(sdl.scr, filename);
2839 }
2840