1 /*
2   Block Rage - the arcade game
3   Copyright (C) 1999-2005 Jiri Svoboda
4 
5   This file is part of Block Rage.
6 
7   Block Rage is free software; you can redistribute it and/or
8   modify it under the terms of the GNU General Public License
9   as published by the Free Software Foundation; either version 2
10   of the License, or (at your option) any later version.
11 
12   Block Rage is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16 
17   You should have received a copy of the GNU General Public License
18   along with Block Rage; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 
21   Jiri Svoboda
22   jirik.svoboda@seznam.cz
23 */
24 
25 /*
26   This module implements the gameplay itself, as well as
27   argument parsing, rc and configfile parsing.
28 */
29 
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/time.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <SDL.h>
40 #include "global.h"
41 #include "gfxout.h"
42 #include "gfxlib.h"
43 #include "menus.h"
44 #include "keyboard.h"
45 #include "bg.h"
46 #include "sound.h"
47 #include "timer.h"
48 
49 #include "main.h"
50 
51 static int first_execution;
52 
53 player_t player[2];
54 int players;
55 int piecetypes;
56 static float fl_piecetypes;
57 int startinglevel;
58 static int board_x_size,board_y_size;
59 static int board_x_center;
60 int box_x_size,box_y_size;
61 int endgame,gameover;
62 int pausemenu;
63 static int paused;
64 static int board_left[3], board_bottom[3], board_top[3];
65 
66 unsigned char *mypal;
67 #ifdef DIRECT_COLOR
68 pix_t mypalx[256];
69 #endif
70 
71 unsigned char *fontn;
72 bmp_t bmp_menu;
73 bmp_t bmp_pmenu,bmp_intro;
74 unsigned char *bground;
75 bmp_t bmp_game[2];
76 static piece_t *piece;
77 static float piece_spd,piece_spd_drop; /* time in secs it takes the piece to fall
78  				          all the way down */
79 static float fall_spd, rise_spd;
80 float framerate;
81 static float gravity,maxdefspd;
82 int board_y_pix_size,board_x_pix_size;
83 static int nx_x0[3],nx_y0[3]; /* "NEXT" block coordinates for P1,P2, single P.*/
84 static int nx_t_x0[3],nx_t_y0[3]; /* "NEXT" label coordinates for P1,P2, single P.*/
85 
86 static int key_quit;
87 int key_left[2],key_right[2],key_drop[2],key_shift_up[2],key_shift_down[2];
88 
89 static int level,blocksleft;
90 static int lnumframes;
91 int bgnumframes;	/* game frames till bg display */
92 
93 int dbackground; /* 1: draw background effects, 0: bitmap background */
94 int showintro;
95 
96 static int turndone;
97 char dataset[100];
98 static char *sys_config_file;
99 static char *usr_config_file;
100 char *datadir;
101 char *topten_file;
102 
103 int immedstart;
104 int quit;
105 static int statx[6],staty[6];
106 int diffx,diffy;   /* coordinates of the difficulty level display box */
107 int ts_x0,ts_x1;   /* x-coordinates of the top-ten names(ts_x0) & scores(ts_x1) */
108 int no_of_sets;
109 int setn;
110 static int p_curframe[6]; /* piece: current frame number */
111 static float p_timeleft[6];  /* piece:remaining time for current frame (in secs) */
112 static float gboomdelay; /* delay(in secs) between line blowing when gameover */
113 int dispframenum;
114 static int framenum;
115 
116 static int no_of_particle_frames;
117 static frame_t *particle_frame;
118 
119 // returns an int between <base> and <base+range-1>
randint(long base,long range)120 long randint(long base,long range) {
121   float frange=range;
122 
123   return base+(int) (frange*rand()/(RAND_MAX+1.0));
124 }
125 
126 // returns a float between <base> and <base+range>
randfloat(float base,float range)127 static float randfloat(float base,float range) {
128   return base+(range*rand()/RAND_MAX);
129 }
130 
131 
box_draw(int x0,int y0,int type)132 void box_draw(int x0, int y0, int type)
133 {
134   int x,y;
135   pix_t c,*sp;
136   pix_t *dp;
137   pix_t key_color;
138   piece_t *piecep;
139 
140   piecep = &piece[setn*P_PER_S+type-1];
141 
142   sp=&(piecep->bmp[p_curframe[type-1]*(box_x_size*box_y_size)]);
143   key_color = piecep->key_color;
144 
145   if(type) {
146     for(y=0;y<box_y_size;y++) {
147       dp=&(vscr[(y0+y)*scr_x_size+x0]);
148       for(x=0;x<box_x_size;x++) {
149         if((c=*sp++)!=key_color) *dp=c;
150 	dp++;
151       }
152     }
153   }
154 }
155 
156 
piece_drawnext(player_t * p,int redraw)157 static void piece_drawnext(player_t *p, int redraw) {
158   int i,animated;
159   int bi=(players==1) ? 2 : (p->number);
160 
161   animated=0;
162 
163   for(i=0;i<3;i++)
164     if(piece[setn*P_PER_S+(p->p_nxt[i]-1)].frames>1) animated=1;
165 
166   if(animated || redraw) {
167 
168     t_align = T_CENTER;
169     v_print(nx_t_x0[bi],nx_t_y0[bi],FONT_NORMAL,"NEXT");
170     virt_cpyarea(nx_t_x0[bi],nx_t_y0[bi],
171                strpixlen("NEXT",FONT_NORMAL),font[FONT_NORMAL].ch);
172 
173     v_copyarea(bmp_game[players-1].data,vscr,scr_x_size,scr_x_size,
174                nx_x0[bi],nx_y0[bi],
175                box_x_size,3*box_y_size,
176 	       nx_x0[bi],nx_y0[bi]);
177 
178     for(i=0;i<3;i++)
179       box_draw(nx_x0[bi],nx_y0[bi]+i*box_y_size,p->p_nxt[2-i]);
180 
181     virt_cpyarea(nx_x0[bi],nx_y0[bi],box_x_size,3*box_y_size);
182   }
183 }
184 
game_over(void)185 static void game_over(void) { /* someone has died */
186   if(!gameover) {
187     gameover=1;
188     sound_fx(2);
189   }
190 }
191 
game_drawscore(player_t * p,int bgvcpy)192 static void game_drawscore(player_t *p, int bgvcpy) {
193   if(bgvcpy) {
194     v_drawscrarea(bmp_game[players-1].data,statx[1],staty[1],
195                 strpixlen("0000000",FONT_HIGHLIGHTED),font[FONT_HIGHLIGHTED].ch);
196   }
197   t_align=T_LEFT;
198   v_printf(statx[1],staty[1],FONT_HIGHLIGHTED,"%07d",p->score);
199 
200   if(bgvcpy) {
201     virt_cpyarea(statx[1],staty[1],
202                strpixlen("00000000",FONT_HIGHLIGHTED),font[FONT_HIGHLIGHTED].ch);
203   }
204 }
205 
game_drawlevelnum(int bgvcpy)206 static void game_drawlevelnum(int bgvcpy) {
207 
208   if(bgvcpy) {
209     v_drawscrarea(bmp_game[players-1].data,statx[3],staty[3],
210                 strpixlen("00",FONT_HIGHLIGHTED),font[FONT_HIGHLIGHTED].ch);
211   }
212   t_align=T_LEFT;
213   v_printf(statx[3],staty[3],FONT_HIGHLIGHTED,"%02d",level);
214 
215   if(bgvcpy) {
216     virt_cpyarea(statx[3],staty[3],
217                strpixlen("00",FONT_HIGHLIGHTED),font[FONT_HIGHLIGHTED].ch);
218   }
219 }
220 
game_drawblocksleft(int bgvcpy)221 static void game_drawblocksleft(int bgvcpy) {
222   if(bgvcpy) {
223     v_drawscrarea(bmp_game[players-1].data,statx[5],staty[5],
224                 strpixlen("00",FONT_HIGHLIGHTED),font[FONT_HIGHLIGHTED].ch);
225   }
226   t_align=T_LEFT;
227   v_printf(statx[5],staty[5],FONT_HIGHLIGHTED,"%02d",blocksleft);
228 
229   if(bgvcpy) {
230     virt_cpyarea(statx[5],staty[5],
231                strpixlen("00",FONT_HIGHLIGHTED),font[FONT_HIGHLIGHTED].ch);
232   }
233 }
234 
board_draw(player_t * p,int hidepieces,int vcpy)235 void board_draw(player_t *p, int hidepieces, int vcpy) {
236   int i,x,y,yshift,x0,y0;
237   int pn=p->number;
238   int bi=(players==1)?2:pn;
239   char s[20];
240   p_list_t *pp;
241   unsigned char *ucp;
242 
243   /* board background */
244   if(dbackground) {     /* special effects */
245     if(bgnumframes==0) {
246       ucp=bground;
247       for(y=0;y<board_y_pix_size;y++)
248         for(x=0;x<board_x_pix_size;x++) {
249           vscr[(y+board_top[bi])*scr_x_size+x+board_left[bi]]=
250 #ifdef DIRECT_COLOR
251             mypalx[(*ucp++)+BGPALBASE];
252 #else
253 	    (*ucp++)+BGPALBASE;
254 #endif
255         }
256     } else { /* black */
257       ucp=bground;
258       for(y=0;y<board_y_pix_size;y++)
259         for(x=0;x<board_x_pix_size;x++) {
260           vscr[(y+board_top[bi])*scr_x_size+x+board_left[bi]]=0;
261         }
262     }
263   } else { /* bitmap bacground */
264     v_copyarea(bmp_game[players-1].data,vscr,scr_x_size,scr_x_size,
265              board_left[bi],board_top[bi],
266              board_x_size*box_x_size,board_y_size*box_y_size,
267 	     board_left[bi],board_top[bi]);
268   }
269 
270   if(!hidepieces) {
271     /* pieces stuck on board */
272     for(y=0;y<board_y_size;y++)
273       for(x=0;x<board_x_size;x++) {
274        if((p->bflags[y*board_x_size+x] != BF_BLOW)
275           || /*!(p->explode_frames & 1)*/ (dispframenum & 1)) {
276   	     switch(p->status) {
277 	       case S_FALL:  yshift=(p->bflags[y*board_x_size+x]==BF_FALL)?
278 	              -p->fall_pix : 0; break;
279 	       case S_RISE: yshift=p->rise_pix; break;
280 	       default: yshift=0; break;
281 	     }
282              box_draw(board_left[bi]+x*box_x_size,
283                       board_bottom[bi]-y*box_y_size+yshift,
284                       p->board[y*board_x_size+x]);
285 
286        }
287     }
288 
289     /* falling piece */
290     if(p->status==S_NORMAL && !gameover) {
291       for(i=0;i<3;i++) if(p->piecey+i<board_y_size) {
292         box_draw(board_left[bi]+p->piecex*box_x_size,
293                  board_bottom[bi]-(p->piecey+i)*box_y_size-p->pieceypix,
294                  p->p_cur[i]);
295       }
296     }
297 
298     /* clean some garbage above and below the board */
299     v_copyarea(bmp_game[players-1].data,vscr,scr_x_size,scr_x_size,
300                board_left[bi],board_top[bi]-box_y_size,
301                board_x_size*box_x_size,box_y_size,
302     	       board_left[bi],board_top[bi]-box_y_size);
303 
304     v_copyarea(bmp_game[players-1].data,vscr,scr_x_size,scr_x_size,
305                board_left[bi],board_bottom[bi]+box_y_size,
306                board_x_size*box_x_size,box_y_size,
307                board_left[bi],board_bottom[bi]+box_y_size);
308 
309     /* adjust clipping for particle drawing */
310     clip_x0=board_left[bi]; clip_y0=board_top[bi];
311     clip_x1=clip_x0+board_x_pix_size-1;
312     clip_y1=clip_y0+board_y_pix_size-1;
313 
314 
315 
316     // Draw all the particles
317     pp=p->particles;
318     while(pp) {
319       v_drawbmp(board_left[bi] + pp->x,
320                   board_top[bi] + board_y_pix_size - pp->y,
321   	  	  particle_frame[pp->frame].bmp.key_color,
322 		  particle_frame[pp->frame].bmp.xs,
323 		  particle_frame[pp->frame].bmp.ys,
324 		  particle_frame[pp->frame].bmp.data);
325       pp=pp->next;
326     }
327   }
328 
329   if(paused) {
330     t_align=T_CENTER;
331     x0=board_left[bi]+(board_x_pix_size/2);
332     y0=board_top[bi]+(board_y_pix_size/2);
333 
334     v_print(x0,y0-(font[0].ch/2),FONT_NORMAL,"PAUSED");
335   }
336 
337   /* loser/winner/gameover text */
338   if(gameover) {
339     t_align=T_CENTER;
340     x0=board_left[bi]+(board_x_pix_size/2);
341     y0=board_top[bi]+(board_y_pix_size/2);
342 
343     if(players==2) {
344       if(player[0].loser && player[1].loser) strcpy(s,"TIE");
345        else {
346          if(p->loser) strcpy(s,"LOSER");
347            else strcpy(s,"WINNER");
348        }
349     } else {
350       if(player[0].loser) strcpy(s,"GAME OVER");
351 	else strcpy(s,"GAME COMPLETED");
352     }
353 
354     v_print(x0,y0-(font[0].ch),FONT_NORMAL,s);
355   }
356   else if(lnumframes>0) {	/* level %d text */
357     t_align=T_CENTER;
358     x0=board_left[bi]+board_x_pix_size/2;
359     y0=board_top[bi]+board_y_pix_size/2;
360 
361     v_printf(x0,y0-font[0].ch/2,FONT_NORMAL,"Level %d",level);
362   }
363 
364   /* copy to screen */
365   if(vcpy) {
366     virt_cpyarea(board_left[bi],board_top[bi],
367                  board_x_size*box_x_size,board_y_size*box_y_size);
368   }
369 }
370 
game_statistics_draw(void)371 void game_statistics_draw(void) {
372   if(players==1) {
373     t_align=T_LEFT;
374     v_print(statx[0],staty[0],FONT_NORMAL,"Score:");
375     v_print(statx[2],staty[2],FONT_NORMAL,"Level:");
376     v_print(statx[4],staty[4],FONT_NORMAL,"Blocks:");
377     game_drawlevelnum(0);
378     game_drawblocksleft(0);
379     game_drawscore(&(player[0]),0);
380   }
381 }
382 
game_draw(void)383 static void game_draw(void) {
384   int i;
385 #ifdef DEBUG
386   char s[30];
387 #endif
388 
389   for(i=0;i<scr_x_size*scr_y_size;i++)
390     vscr[i]=bmp_game[players-1].data[i];
391 
392   game_statistics_draw();
393 
394   if(!paused) {
395     for(i=0;i<players;i++)
396       piece_drawnext(&(player[i]),1);
397   }
398 
399   for(i=0;i<players;i++)
400     board_draw(&(player[i]),paused,1);
401 
402 #ifdef DEBUG
403   t_align=T_LEFT;
404   v_printf(0,0,FONT_HIGHLIGHTED,"%f",
405               (float)framerate*(float)dispframenum/(float)framenum);
406 #endif
407 
408   virt_cpy();
409 }
410 
particle_create(p_list_t * next,float x,float y,float vx,float vy,float fr_age,int frame)411 static p_list_t *particle_create(p_list_t *next,
412             float x, float y, float vx, float vy, float fr_age, int frame) {
413   p_list_t *tmp;
414 
415   tmp=calloc_verify(1,sizeof(p_list_t));
416 
417   tmp->x=x;
418   tmp->y=y;
419   tmp->vx=vx;
420   tmp->vy=vy;
421   tmp->fr_age=fr_age;
422   tmp->next=next;
423   tmp->frame=frame;
424 
425   return tmp;
426 }
427 
piece_collides(player_t * p,int x,int y)428 static int piece_collides(player_t *p, int x, int y) {
429   return y<0 ? 1 : (p->board[y*board_x_size+x] |
430                     p->board[(y+1)*board_x_size+x] |
431 		    p->board[(y+2)*board_x_size+x])!=0;
432 }
433 
player_givepiece(player_t * p)434 static void player_givepiece(player_t *p) {
435   int i;
436 
437 
438   for(i=0;i<3;i++) {
439 
440     p->p_cur[i]=p->p_nxt[i];
441     fl_piecetypes=piecetypes;
442     p->p_nxt[i]=randint(1,fl_piecetypes); // 1..fl_piecetypes
443   }
444   p->piecey=board_y_size-1;
445   p->pieceypix=box_y_size;
446   p->piecex=board_x_center;
447   p->pieceyfrac=0;
448 
449   if(piece_collides(p,p->piecex,p->piecey)) {
450     //game_over();
451     p->loser=1;
452   }
453 
454   if(!gameover)
455     piece_drawnext(p,1);
456 }
457 
pgoto_normal(player_t * p)458 static void pgoto_normal(player_t *p) {
459   p->status=S_NORMAL;
460   player_givepiece(p);
461 }
462 
player_init(player_t * p,int pn)463 static int player_init(player_t *p, int pn) {
464   int x,y;
465 
466   p->number=pn;
467 
468   p->score=0;
469 
470   p->board=malloc_verify((board_y_size+5)*board_x_size);
471   if(!(p->board)) return 0;
472 
473   p->bflags=malloc_verify((board_y_size+5)*board_x_size);
474   if(!(p->bflags)) return 0;
475 
476   /* clear game board */
477   for(y=0;y<board_y_size+3;y++)
478     for(x=0;x<board_x_size;x++) {
479       p->board[y*board_x_size+x]=0;
480       p->bflags[y*board_x_size+x]=0;
481     }
482 
483   p->piece_dropping=0;
484 
485   p->explode_frames=-1; /* nothing exploding right now */
486   p->fall_pix=-1;    /* nothing falling */
487   p->fall_frac=0;
488   p->rise_pix=-1;    /* and we're not raising */
489   p->rise_frac=0;
490 
491   p->status=S_NORMAL;
492 
493   p->rows2rise=0;
494   p->loser=0;
495 
496   p->particles=NULL;
497   p->gboomy=board_y_size-1;
498   p->gttb=gboomdelay;
499 
500   p->chain=-1;
501   p->lines[0]=0;
502   p->lines[1]=0;
503   p->lines[2]=0;
504 
505   return 1;
506 }
507 
player_done(player_t * p)508 static void player_done(player_t *p) {
509   free(p->board);
510   free(p->bflags);
511 }
512 
game_level_init(void)513 static void game_level_init(void) {
514   blocksleft+=35+5*level;
515   piece_spd=board_y_pix_size/framerate/(30/(level+2));
516   piece_spd_drop=board_y_pix_size/framerate/0.80;
517   if(piece_spd>piece_spd_drop) piece_spd_drop=piece_spd;
518 
519   lnumframes=framerate*3; /* show for 3 seconds */
520   bgnumframes=framerate*2; /* display ater 2 seconds */
521 }
522 
blocks_sub(int num)523 static void blocks_sub(int num) {
524   if(players==1) {
525     blocksleft-=num;
526     while(blocksleft<=0) {  /* advance level */
527       if(level<99) level++; /* I DOUBT anybody will get to the level 99,
528                                but I don't take any risks */
529 	else game_over(); /* otherwise end the game and congratulate the player */
530       bg_done();
531       game_level_init();
532       bg_init(level);
533 
534       DEBUG1(printf("bg_init(level=%d)\n",level));
535     }
536   }
537 }
538 
539 /*
540   Add one row to the bottom of ones playfield.
541 
542   The trick is that this row contains random tiles,
543   but must not trigger any explosions.
544 */
player_rise(player_t * p)545 static void player_rise(player_t *p) {
546   int x,y;
547   int i,t,nsuit;
548   float fnsuit;
549   int suits[MAX_PIECE_TYPES];
550 
551 //  suits = malloc_verify(sizeof(int)*(piecetypes+1));
552 
553   for(y=board_y_size-1;y>0;y--)
554     for(x=0;x<board_x_size;x++)
555       p->board[y*board_x_size+x]=p->board[(y-1)*board_x_size+x];
556 
557   for(i=1;i<=piecetypes;i++) suits[i]=1;
558   suits[(int)p->board[board_x_size+board_x_center-1]]=0;
559   suits[(int)p->board[board_x_size+board_x_center  ]]=0;
560   suits[(int)p->board[board_x_size+board_x_center+1]]=0;
561 
562   nsuit=0;
563   for(i=1;i<=piecetypes;i++) if(suits[i]) nsuit++;
564 
565   t=1;
566   fnsuit=nsuit;
567   x=randint(0,fnsuit);  // 0 ..fnsuit-1
568   while(!suits[t]) t++;
569   for(i=0;i<x;i++) {
570     t++;
571     while(!suits[t]) t++;
572   }
573   p->board[board_x_center]=t;
574 
575   /* The center square -1 */
576   for(i=1;i<=piecetypes;i++) suits[i]=1;
577   suits[(int)p->board[board_x_size+board_x_center-1  ]]=0;
578   suits[(int)p->board[board_x_size+board_x_center-1+1]]=0;
579   suits[(int)p->board[             board_x_center-1+1]]=0;
580 
581   nsuit=0;for(i=1;i<=piecetypes;i++) if(suits[i]) nsuit++;
582 
583   t=1;
584   fnsuit=nsuit;
585   x=randint(0,fnsuit);  // 0 ..fnsuit-1
586   while(!suits[t]) t++;
587   for(i=0;i<x;i++) {
588     t++;
589     while(!suits[t]) t++;
590   }
591   p->board[board_x_center-1]=t;
592 
593   /* The center square +1 */
594   for(i=1;i<=piecetypes;i++) suits[i]=1;
595   suits[(int)p->board[board_x_size+board_x_center+1-1]]=0;
596   suits[(int)p->board[board_x_size+board_x_center+1  ]]=0;
597   suits[(int)p->board[             board_x_center+1-1]]=0;
598 
599   nsuit=0;for(i=1;i<=piecetypes;i++) if(suits[i]) nsuit++;
600 
601   t=1; //x=rand()%nsuit;
602   fnsuit=nsuit;
603   x=randint(0,fnsuit);  // 0 ..fnsuit-1
604   while(!suits[t]) t++;
605   for(i=0;i<x;i++) {
606     t++;
607     while(!suits[t]) t++;
608   }
609   p->board[board_x_center+1]=t;
610 
611   /* The left square */
612   for(i=1;i<=piecetypes;i++) suits[i]=1;
613   suits[(int)p->board[board_x_size  ]]=0;
614   suits[(int)p->board[board_x_size+1]]=0;
615   suits[(int)p->board[            +1]]=0;
616 
617   nsuit=0;for(i=1;i<=piecetypes;i++) if(suits[i]) nsuit++;
618 
619   t=1;
620   fnsuit=nsuit;
621   x=randint(0,fnsuit);  // 0 ..fnsuit-1
622   while(!suits[t]) t++;
623   for(i=0;i<x;i++) {
624     t++;
625     while(!suits[t]) t++;
626   }
627   p->board[board_x_center-2]=t;
628 
629 
630   /* The right square */
631   for(i=1;i<=piecetypes;i++) suits[i]=1;
632   suits[(int)p->board[board_x_size+4-1]]=0;
633   suits[(int)p->board[board_x_size+4  ]]=0;
634   suits[(int)p->board[             4-1]]=0;
635 
636   nsuit=0;for(i=1;i<=piecetypes;i++) if(suits[i]) nsuit++;
637 
638   t=1;
639   fnsuit=nsuit;
640   x=randint(0,fnsuit);  // 0 ..fnsuit-1
641   while(!suits[t]) t++;
642   for(i=0;i<x;i++) {
643     t++;
644     while(!suits[t]) t++;
645   }
646   p->board[board_x_center+2]=t;
647 
648 //  free(suits);
649 }
650 
player_checkrows2rise(player_t * p)651 static void player_checkrows2rise(player_t *p) {
652   if(p->rows2rise>0) {
653     player_rise(p);
654     p->rise_pix+=box_y_size;
655     p->rise_frac=1;
656 
657     p->rows2rise--;
658     p->status=S_RISE;
659   } else pgoto_normal(p);
660 }
661 
piece_shift_up(player_t * p)662 static void piece_shift_up(player_t *p) {
663   char tmp;
664 
665   tmp        =p->p_cur[2];
666   p->p_cur[2]=p->p_cur[1];
667   p->p_cur[1]=p->p_cur[0];
668   p->p_cur[0]=tmp;
669 
670 }
671 
piece_shift_down(player_t * p)672 static void piece_shift_down(player_t *p) {
673   char tmp;
674 
675   tmp        =p->p_cur[0];
676   p->p_cur[0]=p->p_cur[1];
677   p->p_cur[1]=p->p_cur[2];
678   p->p_cur[2]=tmp;
679 
680 }
681 
less_num(int a,int b)682 static int less_num(int a, int b) {
683   return (a<b)?a:b;
684 }
685 
player_checkexplosions_line(player_t * p,int x0,int y0,int dx,int dy,int len)686 static int player_checkexplosions_line(player_t *p,
687   int x0, int y0, int dx, int dy, int len) {
688   int i=0,anyboom=0,n,b;
689 
690   while (i<len) {
691       n=1;
692       if(p->board[(y0+i*dy)*board_x_size+x0+i*dx] != 0) {
693         while ( (i+n < len) &&
694 	     (p->board[(y0+(i+n)*dy)*board_x_size+x0+(i+n)*dx]
695              ==p->board[(y0+i*dy)*board_x_size+x0+i*dx])) n++;
696       }
697       if(n>=3) {
698         for(b=0;b<n;b++) {
699 	  p->bflags[(y0+(i+b)*dy)*board_x_size+x0+((i+b)*dx)] = BF_BLOW;
700 	}
701 	anyboom=1;
702 	p->lines[n-3]++;
703       }
704       i+=n;
705     }
706   return anyboom;
707 }
708 
player_checkexplosions(player_t * p)709 static int player_checkexplosions(player_t *p) {
710   int i,anyboom=0;
711   int oldscore;
712 
713   /* rows */
714   for(i=0;i<board_y_size;i++) {
715     anyboom |= player_checkexplosions_line(p,0,i,1,0,board_x_size);
716   }
717 
718   /* columns */
719   for(i=0;i<board_x_size;i++) {
720     anyboom |= player_checkexplosions_line(p,i,0,0,1,board_y_size);
721   }
722 
723   /* "/" diagonal */
724   for(i=board_x_size-1;i>0;i--) {
725     anyboom |= player_checkexplosions_line(p,i,0,1,1,
726       less_num(board_x_size-i,board_y_size));
727   }
728   for(i=0;i<board_y_size;i++) {
729     anyboom |= player_checkexplosions_line(p,0,i,1,1,
730       less_num(board_x_size,board_y_size-i));
731   }
732 
733   /* "\" diagonal */
734   for(i=board_x_size-1;i>0;i--) {
735     anyboom |= player_checkexplosions_line(p,i,board_y_size-1,1,-1,
736       less_num(board_x_size-i,board_y_size));
737   }
738   for(i=board_y_size-1;i>=0;i--) {
739     anyboom |= player_checkexplosions_line(p,0,i,1,-1,
740       less_num(board_x_size,i+1));
741   }
742 
743 
744   if(anyboom) {
745     p->explode_frames=0.25*framerate;
746     p->status=S_BLOW;
747     p->chain++;
748   } else {
749     oldscore= p->score;
750     p->status=S_CHECKR;
751     p->rise_pix=-1;
752     if(players==2 && p->chain>0) player[1-(p->number)].rows2rise+=p->chain;
753     if(p->chain>0) p->score+=p->chain*1000;
754     p->score+=(p->lines[0]*500)+(p->lines[1]*1000)+(p->lines[2]*1500);
755     if(players==1 && oldscore!=p->score) {
756       //game_draw();
757       game_drawscore(p,1);
758     }
759   }
760   return anyboom;
761 }
762 
player_fixpiece(player_t * p)763 static void player_fixpiece(player_t *p) {
764   int i;
765 
766   if(p->piecey+2>=board_y_size) {
767     //game_over();
768     p->loser=1;
769   }
770 
771   for(i=0;i<3;i++) {
772     p->board[(p->piecey + i)*board_x_size+(p->piecex)]
773       = p->p_cur[i];
774   }
775   if(!gameover) {
776     p->status=S_CHECKX;
777     p->chain=-1;
778     p->lines[0]=0;
779     p->lines[1]=0;
780     p->lines[2]=0;
781   }
782 }
783 
board_clearflags(player_t * p)784 static void board_clearflags(player_t *p) {
785   int x,y;
786 
787   for(y=0;y<board_y_size;y++)
788     for(x=0;x<board_x_size;x++)
789       p->bflags[y*board_x_size+x]=0;
790 }
791 
player_spawnparticles(player_t * p,int x,int y)792 static void player_spawnparticles(player_t *p, int x, int y) {
793   int i;
794   for(i=0;i<2;i++) {
795     p->particles=particle_create(p->particles, x*box_x_size,y*box_y_size,
796 				randfloat(-maxdefspd,2*maxdefspd),
797 				randfloat(-maxdefspd,2*maxdefspd),
798 				0,no_of_particle_frames-1);
799   }
800 }
801 
player_blow(player_t * p)802 static void player_blow(player_t *p) {
803   int x,y,oldlevel,oldscore,oldblocks,anyblow=0;
804 
805   oldlevel=level;
806   oldscore=p->score;
807   oldblocks=blocksleft;
808 
809   for(y=0;y<board_y_size;y++) {
810     for(x=0;x<board_x_size;x++) {
811       if(p->bflags[y*board_x_size+x]!=0) {
812         if(p->bflags[y*board_x_size+x]==BF_BLOW) {
813           p->board[y*board_x_size+x]=0;
814 	  blocks_sub(1);
815 	  player_spawnparticles(p,x,y);
816 	  anyblow=1;
817         }
818 	p->bflags[y*board_x_size+x]=0;
819       }
820     }
821   }
822   if(players==1) {
823 /*    if(level!=oldlevel || p->score!=oldscore || blocksleft!=oldblocks) {
824 
825       game_draw();
826 
827     }*/
828     if(p->score!=oldscore) {
829       game_drawscore(p,1);
830     }
831     if(level!=oldlevel) {
832       game_drawlevelnum(1);
833     }
834     if(blocksleft!=oldblocks) {
835       game_drawblocksleft(1);
836     }
837   }
838   if(anyblow) sound_fx(FX_BLOW);
839 }
840 
player_checkfall(player_t * p)841 static void player_checkfall(player_t *p) {
842   int x,y,anyfall=0;
843 
844   for(y=1;y<board_y_size;y++) {
845     for(x=0;x<board_x_size;x++) {
846       if ((p->board[y*board_x_size+x]!=0)
847         && (p->board[(y-1)*board_x_size+x]==0)) {
848 
849 	  p->board[(y-1)*board_x_size+x]=p->board[y*board_x_size+x];
850 	  p->board[y*board_x_size+x]=0;
851           p->bflags[(y-1)*board_x_size+x]=BF_FALL;
852 	  anyfall=1;
853       }
854     }
855   }
856   if(anyfall) {
857     //p->fall_pix=box_y_size-1;
858     p->status=S_FALL;
859   } else {
860     p->status=S_CHECKX;
861   }
862 }
863 
864 
865 
player_updatepiece(player_t * p)866 static void player_updatepiece(player_t *p) {
867   if(!gameover)
868     p->pieceyfrac -= (p->piece_dropping ? piece_spd_drop : piece_spd);
869 
870   while (p->pieceyfrac < 0.0) {
871     p->pieceypix--;
872     p->pieceyfrac+=1.0;
873   }
874   while (p->pieceypix < 0) {
875     if (piece_collides(p,p->piecex,p->piecey-1)) {
876       player_fixpiece(p);
877       sound_fx(FX_HIT);
878       return;
879     } else {
880       //p->score++;
881       p->piecey--;
882       p->pieceypix+=box_y_size;
883     }
884   }
885   turndone=1;
886 }
887 
player_updateblow(player_t * p)888 static void player_updateblow(player_t *p) {
889   p->explode_frames--;
890   if(p->explode_frames<0) {
891     player_blow(p);
892     p->status=S_CHECKF;
893     p->fall_pix=box_y_size-1;
894   }
895   turndone=1;
896 }
897 
player_updatefall(player_t * p)898 static void player_updatefall(player_t *p) {
899   p->fall_frac-=fall_spd;
900   while (p->fall_frac < 0.0) {
901     p->fall_pix--;
902     p->fall_frac+=1.0;
903   }
904   if(p->fall_pix<=0) {
905     p->status=S_CHECKF;
906     p->fall_pix+=box_y_size;
907     board_clearflags(p);
908   }
909   turndone=1;
910 }
911 
player_updaterise(player_t * p)912 static void player_updaterise(player_t *p)
913 {
914   p->rise_frac-=rise_spd;
915   while (p->rise_frac < 0.0) {
916     p->rise_pix--;
917     p->rise_frac+=1.0;
918   }
919   if(p->rise_pix<=0) {
920     p->status=S_CHECKR;
921   }
922   turndone=1;
923 }
924 
player_updateparticles(player_t * p)925 static void player_updateparticles(player_t *p) {
926   p_list_t *tmp, *pp=p->particles, *last=NULL;
927   int something,xsize;
928 
929   while(pp) {
930     pp->fr_age+= 1/framerate;
931     while(pp->fr_age>particle_frame[pp->frame].delay) {
932       pp->frame--;
933       pp->fr_age=0;
934     }
935     pp->x += pp->vx*(1/framerate);
936     xsize=particle_frame[pp->frame].bmp.xs;
937     do {
938       something=0;
939       if(pp->vx<0  &&  pp->x < 0) {
940         pp->vx= -pp->vx;
941         pp->x = -pp->x;
942 	something=1;
943       }
944       if(pp->vx>0  &&  pp->x > board_x_pix_size-xsize) {
945         pp->vx= -pp->vx;
946         pp->x = (board_x_pix_size)-(pp->x+xsize-(board_x_pix_size))-xsize;
947 	something=1;
948       }
949     } while(something);
950 
951     pp->vy -= gravity*(1/framerate);
952     pp->y += pp->vy*(1/framerate);
953 
954     if(pp->y < 0 || pp->frame<0) {
955       tmp=pp->next;
956       if(last) last->next=tmp; else p->particles=tmp;
957       free(pp);
958       pp=tmp;
959     } else {
960       last=pp;
961       pp=pp->next;
962     }
963   }
964 }
965 
player_blowline(player_t * p,int y)966 static void player_blowline(player_t *p, int y) {
967   int x;
968 
969   for(x=0;x<board_x_size;x++) {
970     if(p->board[y*board_x_size+x]>0) {
971       player_spawnparticles(p,x,y);
972       p->board[y*board_x_size+x]=0;
973       p->bflags[y*board_x_size+x]=0;
974     }
975   }
976 }
977 
player_update(player_t * p)978 static void player_update(player_t *p) {
979   player_updateparticles(p);
980 
981   /* blowing the blocks line by line, when game over */
982   if(p->loser && p->gboomy>=0) {
983     p->gttb -= 1/framerate;
984     while(p->gttb<0) {
985       player_blowline(p,p->gboomy--);
986       p->gttb += gboomdelay;
987     }
988   }
989   do {
990     //if(gameover) return;
991     turndone=0;
992     switch(p->status) {
993       case S_NORMAL: player_updatepiece(p); break;
994       case S_CHECKX: player_checkexplosions(p); break;
995       case S_BLOW:   player_updateblow(p); break;
996       case S_CHECKF: player_checkfall(p); break;
997       case S_FALL:   player_updatefall(p); break;
998       case S_CHECKR: player_checkrows2rise(p); break;
999       case S_RISE:   player_updaterise(p); break;
1000     }
1001   } while (!turndone);
1002 }
1003 
1004 /*
1005   Make a screenshot and save it to blockrage-scr.pcx in the
1006   $HOME directory. If HOME is not set, save it to the working
1007   directory.
1008 */
make_screenshot(void)1009 static void make_screenshot(void) {
1010   char *home;
1011   char *fpathname;
1012   char *fname = "blockrage-scr.pcx";
1013   int home_l;
1014 
1015   home = getenv("HOME");
1016   home_l = strlen(home);
1017 
1018   if(home_l > SANE_PATH_LEN) {
1019     fprintf(stderr,"HOME length is not sane\n");
1020     home=NULL;
1021   }
1022 
1023   if(!home) {
1024     fputs("Saving screenshot to ./blockrage-scr.pcx\n",stdout);
1025     pcx_save(scr_x_size,scr_y_size,vscr,mypal, "./blockrage-scr.pcx");
1026   } else {
1027     fpathname = malloc_verify(home_l+1+strlen(fname)+1);
1028     strncpy(fpathname,home,home_l);
1029     fpathname[home_l]=0;
1030     cat_with_slash(fpathname,fname);
1031 
1032     printf("Saving screenshot to %s\n",fpathname);
1033     pcx_save(scr_x_size,scr_y_size,vscr,mypal, fpathname);
1034 
1035     free(fpathname);
1036   }
1037 }
1038 
global_key_hnd(int sym,int mod,int press)1039 static int global_key_hnd(int sym, int mod, int press) {
1040   mod = mod & ~(KMOD_CAPS|KMOD_NUM);
1041   if(press && mod == KMOD_LALT) {
1042     switch(sym) {
1043       case SDLK_x:
1044         quit=1;
1045 	return 0;
1046 
1047       case SDLK_RETURN:
1048         gfx_set_fullscreen(!gfx_get_fullscreen());
1049 	virt_cpy();
1050 	return 0;
1051 
1052       case SDLK_BACKSLASH:
1053         gfx_set_doublesize(!gfx_get_doublesize());
1054 	virt_cpy();
1055 	return 0;
1056 
1057       default:
1058         break;
1059     }
1060   }
1061 
1062   if(press) {
1063     switch(sym) {
1064       case SDLK_PRINT:
1065         make_screenshot();
1066 	return 0;
1067 
1068       default:
1069         break;
1070     }
1071   }
1072 
1073   return 1;
1074 }
1075 
key_handler(int scancode,int press)1076 static void key_handler(int scancode, int press) {
1077   int i;
1078 
1079  // printf("[KP:%d,%d]",scancode,press);
1080   if(scancode>=KSTAT_SIZE) return;         /* error! */
1081   keyboard_state[scancode]=press;
1082 
1083   if(!gameover && !paused) {
1084     for(i=0;i<players;i++) {
1085       if(scancode==key_left[i] && press) {
1086         if(!piece_collides(&(player[i]),player[i].piecex-1,player[i].piecey)) {
1087           if(player[i].piecex>0) player[i].piecex--;
1088         }
1089       }
1090       if(scancode==key_right[i] && press) {
1091         if(!piece_collides(&(player[i]),player[i].piecex+1,player[i].piecey)) {
1092           if(player[i].piecex+1<board_x_size) player[i].piecex++;
1093         }
1094       }
1095       if(scancode==key_shift_up[i] && press)
1096         piece_shift_up(&(player[i]));
1097       if(scancode==key_shift_down[i] && press)
1098         piece_shift_down(&(player[i]));
1099       if(scancode==key_drop[i])
1100         player[i].piece_dropping = !!press;
1101     }
1102   }
1103   if(scancode==key_quit && press) {
1104     if(gameover) endgame=1;		/* go to main menu */
1105       else pausemenu=1;			/* show the pause-menu */
1106   }
1107   if(scancode==SDLK_1 && press) sound_fx(0);
1108   if(scancode==SDLK_2 && press) sound_fx(1);
1109   if(scancode==SDLK_3 && press) sound_fx(2);
1110   if(scancode==SDLK_4 && press) sound_fx(3);
1111   if(scancode==SDLK_5 && press) sound_fx(4);
1112   if(scancode==SDLK_6 && press) sound_fx(5);
1113   if(scancode==SDLK_7 && press) sound_fx(6);
1114   if(scancode==SDLK_8 && press) sound_fx(7);
1115   if(scancode==SDLK_9 && press) sound_fx(8);
1116   if(scancode==SDLK_0 && press) sound_fx(9);
1117 
1118 //  if(scancode==SDLK_PRINT && press) make_screenshot();
1119 
1120   if(scancode==SDLK_p && press) {
1121     if(!gameover) {
1122       paused ^=1;
1123       if(paused) {
1124         game_draw();
1125       }
1126     }
1127   }
1128 }
1129 
input_update(void)1130 static void input_update(void) {
1131   int code, press;
1132 
1133   while(key_get(&code,&press)!=0) {
1134     key_handler(code,press);
1135   }
1136 }
1137 
game_init(void)1138 static int game_init(void) {
1139   int i;
1140 
1141   DEBUG2(printf("running game_init\n");)
1142 
1143   level=startinglevel;
1144   blocksleft=0;
1145 
1146   lnumframes=0;
1147   gboomdelay=0.1; /* in secs */
1148 
1149   paused=0;
1150 
1151   board_bottom[0]=board_top[0]+(board_y_size-1)*box_y_size;
1152   board_bottom[1]=board_top[1]+(board_y_size-1)*box_y_size;
1153   board_bottom[2]=board_top[2]+(board_y_size-1)*box_y_size;
1154 
1155   board_x_pix_size=board_x_size*box_x_size;
1156   board_y_pix_size=board_y_size*box_y_size;
1157 
1158   /* the number equals the time it takes for the piece to fall
1159      from the top to the bottom (in seconds) */
1160   rise_spd = board_y_pix_size/framerate/2.00;
1161   fall_spd = board_y_pix_size/framerate/2.00;
1162 
1163   dispframenum=0; /* init displayed frames' counter */
1164   framenum=0;
1165 
1166   game_level_init();
1167 
1168   player[1].loser=0;
1169   for(i=0;i<players;i++) {
1170     if(!player_init(&(player[i]),i)) {
1171       DEBUG1(printf("game_init failed on player_init\n");)
1172       return 0;
1173     }
1174   }
1175 
1176   for(i=0;i<players;i++) {
1177     player_givepiece(&(player[i]));
1178     player_givepiece(&(player[i]));
1179   }
1180 
1181   bg_init(level);
1182   DEBUG1(printf("bg_init(level=%d)\n",level));
1183 
1184 //  printf("time_init\n");
1185 
1186   time_init();
1187 
1188  // printf("game_i done\n");
1189 
1190   return 1;
1191 }
1192 
game_deinit(void)1193 static void game_deinit(void) {
1194   int i;
1195 
1196   bg_done();
1197 
1198   for(i=0;i<players;i++)
1199     player_done(&(player[i]));
1200 }
1201 
1202 
1203 
pieces_anim_update(void)1204 void pieces_anim_update(void) {
1205   int i;
1206 
1207   for(i=0;i<P_PER_S;i++) {
1208     p_timeleft[i] -= 1/framerate;
1209     if(p_timeleft[i]<0) {
1210       p_curframe[i]++;
1211       if(p_curframe[i]>=piece[setn*P_PER_S+i].frames) p_curframe[i]=0;
1212       p_timeleft[i] += piece[setn*P_PER_S+i].delay.data[p_curframe[i]];
1213     }
1214   }
1215 }
1216 
1217 
piece_readinfo(char * name,int * frames,flp_t * delay)1218 static int piece_readinfo(char *name, int *frames, flp_t *delay) {
1219   FILE *f;
1220   int i;
1221 
1222   f = file_open(name,"rb");
1223   if(!f) {
1224     fprintf(stderr,"blockrage: cannot open %s in data dir\n",name);
1225     return 0;
1226   }
1227 
1228   fscanf(f,"%d",frames);
1229   delay->data=calloc_verify(*frames,sizeof(float));
1230 
1231   for(i=0;i<*frames;i++) {
1232     fscanf(f,"%f",&(delay->data[i]));
1233   }
1234 
1235   fclose(f);
1236   return 1;
1237 }
1238 
screen_setpal(void)1239 void screen_setpal(void) {
1240 #ifdef DIRECT_COLOR
1241   int i;
1242   unsigned rv,gv,bv;
1243 
1244   for(i=0;i<256;i++) {
1245     rv=mypal[3*i]>>1;
1246     gv=mypal[3*i+1];
1247     bv=mypal[3*i+2]>>1;
1248     mypalx[i]=bv|(gv<<5)|(rv<<11);
1249   }
1250 #else
1251   gfx_setpalette(mypal,0,256);
1252 #endif
1253 }
1254 
screen_init(void)1255 static int screen_init(void) {
1256   int i,j;
1257   char s[30];
1258   bmp_t tempbmp;
1259   int ok;
1260 
1261   if(!gfx_init()) return 0;
1262   vscr=malloc_verify(scr_x_size*scr_y_size*sizeof(pix_t));
1263   bground=calloc_verify(board_x_size*box_x_size*board_y_size*box_y_size,sizeof(pix_t));
1264 
1265   if(!(mypal=pal_load("game.col"))) return 0;
1266   screen_setpal();
1267 
1268   ok =       pcx_load(&bmp_menu,"menu.pcx");
1269   ok = ok && pcx_load(&bmp_pmenu,"pmenu.pcx");
1270   ok = ok && pcx_load(&bmp_game[0],"g1p.pcx");
1271   ok = ok && pcx_load(&bmp_game[1],"g2p.pcx");
1272   ok = ok && pcx_load(&bmp_intro,"logo.pcx");
1273 
1274   if(!ok) return 0;
1275 
1276   piece=calloc_verify(no_of_sets*P_PER_S,sizeof(piece_t));
1277 
1278   for(j=0;j<no_of_sets;j++) {
1279     for(i=0;i<P_PER_S;i++) {
1280       sprintf(s,"s%02dp%d.pcx",j,i+1);
1281       if(!pcx_load(&tempbmp,s)) return 0;
1282       piece[j*P_PER_S+i].bmp=tempbmp.data;
1283       piece[j*P_PER_S+i].key_color = tempbmp.key_color;
1284       sprintf(s,"s%02dp%d.txt",j,i+1);
1285       if( !piece_readinfo(s,&(piece[j*P_PER_S+i].frames),
1286         &(piece[j*P_PER_S+i].delay) ) ) return 0;
1287     }
1288   }
1289 
1290   /* init frame counters for the pieces */
1291   for(i=0;i<P_PER_S;i++) {
1292     p_curframe[i]=0;
1293     p_timeleft[i]=piece[setn*P_PER_S+i].delay.data[0];
1294   }
1295 
1296   /* load particle bitmaps */
1297   for(i=0;i<no_of_particle_frames;i++) {
1298     sprintf(s,"pa%d.pcx",i);
1299     DEBUG2(printf("reading %s\n",s);)
1300     if(!pcx_load(&particle_frame[i].bmp,s)) return 0;
1301   }
1302 
1303   if(!font_load("fonth",&(font[FONT_HIGHLIGHTED])))
1304     return 0;
1305 
1306   if(!font_load("fontn",&(font[FONT_NORMAL])))
1307     return 0;
1308 
1309   return 1;
1310 }
1311 
screen_deinit(void)1312 static void screen_deinit(void) {
1313 //  free(bmp_piece);
1314   gfx_deinit();
1315 }
1316 
init(void)1317 static int init(void) {
1318   /* sound MUST be initialised BEFORE video (because this forks a child
1319      process */
1320   if(!sound_init()) {
1321     /* we can live even without this */
1322     fprintf(stderr,"sound could not be initialised.\n");
1323   }
1324   if(!screen_init()) return 0;
1325   if(!input_init(global_key_hnd)) return 0;
1326   topten_load();
1327   return 1;
1328 }
1329 
deinit(void)1330 static void deinit(void) {
1331   DEBUG1(printf("sound_done()...\n"));
1332   sound_done();
1333   DEBUG1(printf("input_deinit()...\n"));
1334   input_deinit();
1335   DEBUG1(printf("screen_deinit()...\n"));
1336   screen_deinit();
1337 }
1338 
pieces_checkfnum(void)1339 void pieces_checkfnum(void) {
1340   int i;
1341 
1342   for(i=0;i<6;i++) {
1343     p_curframe[i] %= piece[setn*P_PER_S].frames;
1344     p_timeleft[i]=piece[setn*P_PER_S].delay.data[p_curframe[i]];
1345   }
1346 }
1347 
game(void)1348 void game(void) {
1349   int i,turns=1;
1350 
1351   endgame=0; gameover=0; pausemenu=0;
1352 
1353   if(!game_init()) return;
1354 
1355   game_draw();
1356 
1357   while (!endgame && !quit) {
1358     if(turns<=1) {
1359       if(dbackground && bgnumframes==0) bg_update();
1360       for(i=0;i<players;i++) {
1361         board_draw(&(player[i]),paused,1);
1362 
1363 	if(!paused) piece_drawnext(&(player[i]),0);
1364       }
1365       dispframenum++;
1366     }
1367     framenum+=turns;
1368     if(!paused) {
1369       for(i=0;i<players;i++) {
1370         player_update(&(player[i]));
1371       }
1372       if(player[0].loser || player[1].loser) game_over();
1373     }
1374 
1375     pieces_anim_update();
1376 
1377     input_update();
1378 
1379     //sound_update();
1380 
1381     if(lnumframes>0) lnumframes--;
1382     if(bgnumframes>0) bgnumframes--;
1383 
1384     while (!(turns=is_next_turn()))
1385       SDL_Delay(SLEEP_MS);
1386 
1387     if(pausemenu) {
1388       pause_menu();
1389       game_draw();
1390     }
1391   }
1392   game_deinit();
1393   if(players==1) {
1394     if(topten_update(player[0].score)) {
1395       topten();
1396     };
1397   }
1398 }
1399 
1400 
process_args(int argc,char * argv[])1401 static int process_args(int argc,char *argv[]) {
1402   int i=1,j,res;
1403 
1404   while (i<argc) {
1405 
1406     if(strcmp(argv[i],"+p")==0) {
1407 
1408       if(i>=argc) {
1409         fprintf(stderr,"missing value\n");
1410         return 0;
1411       }
1412       i++;
1413       res=sscanf(argv[i],"%d",&players);
1414       if(res==1 && players>=1 && players<=2) {
1415         immedstart=1;
1416       }
1417       else {
1418         fprintf(stderr,"Wrong # of players param %d '%s'\n",i,argv[i]);
1419 	return 0;
1420       }
1421     } else
1422     if(strcmp(argv[i],"+d")==0) {
1423 
1424       if(i>=argc) {
1425         fprintf(stderr,"missing value\n");
1426         return 0;
1427       }
1428       i++;
1429       res=sscanf(argv[i],"%d",&piecetypes);
1430       if(res!=1 || piecetypes<MIN_PIECE_TYPES || piecetypes>MAX_PIECE_TYPES) {
1431         fprintf(stderr,"Wrong difficulty #(must be %d-%d) param %d '%s'\n",
1432 	  MIN_PIECE_TYPES,MAX_PIECE_TYPES,i,argv[i]);
1433 	return 0;
1434       }
1435     } else
1436     if(strcmp(argv[i],"+l")==0) {
1437 
1438       if(i>=argc) {
1439         fprintf(stderr,"missing value\n");
1440         return 0;
1441       }
1442       i++;
1443       res=sscanf(argv[i],"%d",&startinglevel);
1444       if(res==1 && startinglevel>=1 && startinglevel<=10) {
1445         ;
1446       }
1447       else {
1448         fprintf(stderr,"Wrong startinglevel #(must be 1-10) param %d '%s'\n",i,argv[i]);
1449 	return 0;
1450       }
1451     } else
1452     if(strcmp(argv[i],"+b")==0) {
1453 
1454       if(i>=argc) {
1455         fprintf(stderr,"missing value\n");
1456         return 0;
1457       }
1458       i++;
1459       res=sscanf(argv[i],"%d",&setn);
1460       if(res==1 && setn>=0) {
1461         ;
1462       }
1463       else {
1464         fprintf(stderr,"Wrong blockset #(must be >=0) param %d '%s'\n",i,argv[i]);
1465 	return 0;
1466       }
1467     } else
1468     if(strcmp(argv[i],"+k1")==0 || strcmp(argv[i],"+k2")==0) {
1469       j=argv[i][2]-'1'; // player's number ( 0 / 1 )
1470 
1471       if(i+4>=argc) {
1472         fprintf(stderr,"missing value\n");
1473         return 0;
1474       }
1475 
1476       res=1;
1477       res*=sscanf(argv[++i],"%d",&key_left[j]);
1478       res*=sscanf(argv[++i],"%d",&key_right[j]);
1479       res*=sscanf(argv[++i],"%d",&key_shift_up[j]);
1480       res*=sscanf(argv[++i],"%d",&key_shift_down[j]);
1481       res*=sscanf(argv[++i],"%d",&key_drop[j]);
1482       if(res!=1) {
1483         fprintf(stderr,"Wrong keys for player 1 (param %d \"%s\")\n",i,argv[i]);
1484 	return 0;
1485       }
1486 
1487     }
1488     else if(strcmp(argv[i],"+data")==0) {
1489 
1490       if(i>=argc) return 0;
1491       i++;
1492       if(strlen(argv[i])<=32) {
1493         strcpy(dataset,argv[i]);
1494       } else {
1495         fprintf(stderr,"dataset name too long\n");
1496 	return 0;
1497       }
1498     }
1499     else if(strcmp(argv[i],"+a8")==0) {
1500       sound_cfg_8bit();
1501     }
1502     else {
1503       fprintf(stderr,"Wrong param #%d '%s'\n",i,argv[i]);
1504       return 0;
1505     }
1506     i++;
1507   }
1508   return 1;
1509 }
1510 
dataconfig_read(void)1511 static int dataconfig_read(void) {
1512   FILE *f;
1513   int i;
1514 
1515   f = file_open("dataset.cfg","rb");
1516   if(!f) {
1517     fprintf(stderr,"blockrage: cannot open dataset.cfg in data dir\n");
1518     return 0;
1519   }
1520 
1521   fscanf(f,"%d %d",&scr_x_size,&scr_y_size);
1522   fscanf(f,"%d %d",&box_x_size,&box_y_size);
1523 
1524   fscanf(f,"%d %d %d",&board_left[0],&board_left[1],&board_left[2]);
1525   fscanf(f,"%d %d %d",&board_top[0],&board_top[1],&board_top[2]);
1526 
1527   fscanf(f,"%d %d %d %d %d %d",&nx_t_x0[0],&nx_t_y0[0],
1528   &nx_t_x0[1],&nx_t_y0[1],&nx_t_x0[2],&nx_t_y0[2]);
1529 
1530   fscanf(f,"%d %d %d %d %d %d",&nx_x0[0],&nx_y0[0],
1531   &nx_x0[1],&nx_y0[1],&nx_x0[2],&nx_y0[2]);
1532 
1533   fscanf(f,"%d %d %d %d",&statx[0],&staty[0],&statx[1],&staty[1]);
1534   fscanf(f,"%d %d %d %d",&statx[2],&staty[2],&statx[3],&staty[3]);
1535   fscanf(f,"%d %d %d %d",&statx[4],&staty[4],&statx[5],&staty[5]);
1536 
1537   fscanf(f,"%d %d",&diffx,&diffy);
1538   fscanf(f,"%d %d",&ts_x0,&ts_x1);
1539 
1540   fscanf(f,"%d",&no_of_sets);
1541 
1542 
1543   fscanf(f,"%f %f",&gravity,&maxdefspd);
1544   fscanf(f,"%d",&no_of_particle_frames);
1545 
1546   particle_frame=calloc_verify(no_of_particle_frames,sizeof(frame_t));
1547 
1548   for(i=0;i<no_of_particle_frames;i++)
1549     fscanf(f,"%f",&(particle_frame[i].delay));
1550 
1551  /* printf("%d %d\n%d %d\n%d %d %d\n%d %d %d\n%d %d %d %d %d %d\n",
1552   scr_x_size,scr_y_size,
1553   box_x_size,box_y_size,
1554   board_left[0],board_left[1],board_left[2],
1555   board_top[0],board_top[1],board_top[2],
1556   nx_x0[0],nx_y0[0],nx_x0[1],nx_y0[1],nx_x0[2],nx_y0[2]);*/
1557 
1558   fclose(f);
1559 
1560   return 1;
1561 }
1562 
keys_default(void)1563 static void keys_default(void) {
1564 
1565   key_left[0]=SDLK_LEFT;
1566   key_right[0]=SDLK_RIGHT;
1567   key_drop[0]=SDLK_RSHIFT;
1568   key_shift_up[0]=SDLK_UP;
1569   key_shift_down[0]=SDLK_DOWN;
1570   key_left[1]=SDLK_a;
1571   key_right[1]=SDLK_d;
1572   key_drop[1]=SDLK_q;
1573   key_shift_up[1]=SDLK_w;
1574   key_shift_down[1]=SDLK_s;
1575 }
1576 
fget_rc_line(FILE * f)1577 static char *fget_rc_line(FILE *f) {
1578   char *buf;
1579   int buf_size;
1580   int c;
1581   int buf_pos;
1582   char *home;
1583   int home_l;
1584 
1585   buf_size=64;
1586   buf_pos=0;
1587 
1588   buf=malloc_verify(buf_size);
1589 
1590   while(1) {
1591     c = fgetc(f);
1592     if(c==EOF || c=='\n') break;
1593 
1594     if(!buf_pos && c=='~') {
1595       /* tilde expansion */
1596       home=getenv("HOME");
1597       if(!home) {
1598         fprintf(stderr,"error: HOME environment variable is not set.\n");
1599 	return NULL;
1600       }
1601       home_l = strlen(home);
1602       if(home_l+1>buf_size) {
1603         buf_size=home_l+1;
1604 	buf=realloc_verify(buf, buf_size);
1605       }
1606       buf_pos=home_l;
1607       strncpy(buf,home,home_l);
1608     } else {
1609 
1610       if(buf_pos+1>=buf_size) {
1611         buf_size = 2*buf_size;
1612         buf = realloc(buf, buf_size);
1613         if(!buf) return NULL;
1614       }
1615       buf[buf_pos++]=c;
1616     }
1617   }
1618   buf[buf_pos]=0;
1619 
1620   return buf;
1621 }
1622 
1623 /*
1624   Load the blockrage.rc file containing paths to Block Rage files
1625   and directories
1626 */
rc_load(char * fname)1627 static int rc_load(char *fname) {
1628   FILE *f;
1629   char *tmp;
1630 
1631   if((f=fopen(fname,"rt"))==NULL) return 0;
1632   sys_config_file = fget_rc_line(f);
1633   usr_config_file = fget_rc_line(f);
1634   datadir = fget_rc_line(f);
1635   topten_file = fget_rc_line(f);
1636   tmp = fget_rc_line(f);
1637   if(strlen(tmp)>32) {
1638     fprintf(stderr,"rc_load(): dataset name too long\n");
1639     return 0;
1640   }
1641   if(tmp) {
1642     strcpy(dataset,tmp);
1643     free(tmp);
1644   }
1645   fclose(f);
1646 
1647   if(!datadir || !topten_file) return 0;
1648 
1649   return 1;
1650 }
1651 
1652 /*
1653   Find a rc file in one of the possible locations and load it.
1654   Returns 1 on success, 0 on failure.
1655 */
rc_find_load(void)1656 static int rc_find_load(void) {
1657   int rc_loaded;
1658   char *home;
1659   char *fpathname;
1660   char *frelname = ".blockrage/blockrage.rc";
1661   int home_l;
1662 
1663   rc_loaded = rc_load("./blockrage.rc");
1664   if(!rc_loaded) {
1665     home = getenv("HOME");
1666     home_l = strlen(home);
1667     if(home_l > SANE_PATH_LEN) {
1668       fprintf(stderr,"Length of HOME is not sane\n");
1669       home=NULL;
1670     }
1671     if(home) {
1672       fpathname = malloc_verify( home_l + 1 + strlen(frelname) + 1);
1673       strncpy(fpathname,home,home_l);
1674       fpathname[home_l]=0;
1675       cat_with_slash(fpathname,frelname);
1676 
1677       rc_loaded=rc_load(fpathname);
1678 
1679       free(fpathname);
1680     }
1681   }
1682   if(!rc_loaded) {
1683     rc_loaded=rc_load(SYSCONFDIR "/blockrage.rc");
1684   }
1685   if(!rc_loaded) {
1686     fprintf(stderr,"cannot open any rc file, including %s\n",SYSCONFDIR "/blockrage.rc");
1687   }
1688   return rc_loaded;
1689 }
1690 
config_load(char * fname)1691 static int config_load(char *fname) {
1692   FILE *f;
1693   int v1,v2,v3;
1694   int cfg_fs,cfg_ds;
1695 
1696   if((f=fopen(fname,"rt"))==NULL) return 0;
1697   fscanf(f,"%d %d %d\n",&v1,&v2,&v3);
1698   if(v1!=VER1 || v2!=VER2 || v3!=VER3) {
1699     fclose(f);
1700     return 0;
1701   }
1702 
1703   fscanf(f,"%d%d%d%d%d",&piecetypes,&startinglevel,&setn,&dbackground,
1704          &showintro);
1705   fscanf(f,"%d%d%d%d%d",&key_left[0],&key_right[0],&key_drop[0],
1706     &key_shift_up[0],&key_shift_down[0]);
1707   fscanf(f,"%d%d%d%d%d\n",&key_left[1],&key_right[1],&key_drop[1],
1708     &key_shift_up[1],&key_shift_down[1]);
1709 
1710   fscanf(f,"%d%d\n",&cfg_fs,&cfg_ds);
1711   gfx_set_fullscreen(cfg_fs);
1712   gfx_set_doublesize(cfg_ds);
1713   fclose(f);
1714 
1715   return 1;
1716 }
1717 
1718 /*
1719   Create a directory
1720 */
make_dir(char * fname,int mode)1721 static int make_dir(char *fname, int mode) {
1722 #ifdef _WIN32
1723   return mkdir(fname);
1724 #else
1725   return mkdir(fname,mode);
1726 #endif
1727 }
1728 
1729 /*
1730   Create any nonexistent directories in the file's path.
1731 */
make_pdir(char * fname)1732 static int make_pdir(char *fname) {
1733   char *p;
1734   int len;
1735   char *buf;
1736   int res;
1737 
1738   printf("make_pdir('%s');\n",fname);
1739 
1740   buf = NULL;
1741 
1742   p= strrchr(fname,'/');
1743   if(!p) return 0;
1744 
1745   len=p-fname;
1746   if(!len) return 0;
1747   buf=malloc_verify(len+1);
1748   strncpy(buf,fname,len);
1749   buf[len]=0;
1750 
1751   res = 1;
1752 
1753   printf("try mkdir('%s')\n",buf);
1754   if(make_dir(buf,0755)<0 && errno==ENOENT) {
1755     /* Probably neither the parent of this directory exists.
1756        Make it recursively. (Do some memory wasting...) */
1757     if(make_pdir(buf)==0) {
1758       res=0;
1759     } else {
1760       if(make_dir(buf,0755)<0)
1761         res=0;
1762     }
1763   }
1764   free(buf);
1765   return res;
1766 }
1767 
config_save(char * fname)1768 static int config_save(char *fname) {
1769   FILE *f;
1770 
1771   if((f=fopen(fname,"wt"))==NULL) {
1772     /* Maybe we need to create some directories in which
1773        the file resides */
1774     if(errno==ENOENT) {
1775       if(!make_pdir(fname)) {
1776         return 0;
1777       } else {
1778         f=fopen(fname,"wt");
1779 	if(!f) return 0;
1780       }
1781     }
1782   }
1783 
1784   fprintf(f,"%d %d %d\n",VER1,VER2,VER3);
1785   fprintf(f,"%d\n%d\n%d\n%d\n%d\n",piecetypes,startinglevel,setn,dbackground,
1786   showintro);
1787   fprintf(f,"%d %d %d %d %d\n",key_left[0],key_right[0],key_drop[0],
1788     key_shift_up[0],key_shift_down[0]);
1789   fprintf(f,"%d %d %d %d %d\n",key_left[1],key_right[1],key_drop[1],
1790     key_shift_up[1],key_shift_down[1]);
1791   fprintf(f,"%d %d\n",gfx_get_fullscreen(),gfx_get_doublesize());
1792   fclose(f);
1793   return 1;
1794 }
1795 
config_default(void)1796 static void config_default(void) {
1797   /* default config */
1798 
1799   piecetypes=5;
1800   startinglevel=1;
1801   setn=0;
1802   dbackground=1;
1803   showintro=0;
1804 
1805   keys_default();
1806 }
1807 
1808 
main(int argc,char * argv[])1809 int main(int argc, char *argv[]) {
1810 
1811   key_quit=SDLK_ESCAPE;		/* important! */
1812 
1813   framerate=50;
1814   turn_interval_usec=1000000L/framerate;
1815 
1816   topscores_default();
1817   sound_cfg_defaults();
1818 
1819   strcpy(dataset,"br320");
1820 
1821   immedstart=0;
1822 
1823   players=1;
1824 
1825   board_x_size=5; board_y_size=13;
1826   board_x_center=2;
1827 
1828   first_execution=0;
1829 
1830   if(!rc_find_load())
1831     return EXIT_FAILURE;
1832 
1833   if(!config_load(usr_config_file)) {
1834     first_execution = 1;
1835     printf("Welcome to Block Rage!\n");
1836 
1837     if(!config_load(sys_config_file)) {
1838       fprintf(stderr,"No config file found, assuming defaults.\n");
1839       config_default();
1840     }
1841   }
1842 
1843   if(!process_args(argc,argv)) return -1;
1844   if(!dataconfig_read()) return -1;
1845 
1846   if(setn>=no_of_sets) {
1847     fprintf(stderr,"Wrong blockset # (must be 0-%d)\n",no_of_sets-1);
1848     return EXIT_FAILURE;
1849   }
1850 
1851 
1852   if(!init())
1853     return EXIT_FAILURE;
1854 
1855   DEBUG1(printf("initied.\n"));
1856 
1857   quit=0;
1858   if(first_execution || showintro) intro();
1859 
1860   DEBUG1(printf("run menu...\n"));
1861 
1862   quit=0;
1863   menu();
1864 
1865   DEBUG1(printf("deinit...\n"));
1866 
1867   deinit();
1868 
1869   DEBUG1(printf("save config...\n"));
1870 
1871   if(!config_save(usr_config_file)) {
1872     fprintf(stderr,"blockrage error: cannot write user config file '%s'\n",
1873       usr_config_file);
1874   }
1875 
1876   DEBUG1(printf("exit...\n"));
1877 
1878   return EXIT_SUCCESS;
1879 }
1880