1 /*                             */
2 /* xemeraldia   -----  games.c */
3 /*                             */
4 
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8 
9 #include "games.h"
10 #include <stdlib.h>
11 
12 #if defined(SYSV) || defined(SVR4)
13 #define srandom srand48
14 #define random lrand48
15 #endif
16 
17 #if defined(WIN32)
18 #define srandom srand
19 #define random rand
20 #endif
21 
22 static void decideMaxRnd(void), decideNextItem(void), pauseProc(void), endGame(void);
23 static void initGame(void), restart(void);
24 
25 struct Board     board[BOARD_WIDTH + 2][BOARD_HEIGHT + 1];
26 struct DropItem  drop_i, next_i;
27 
28 static int  max_rnd, star_gauge;
29 
30 gboolean  gameover_flag = TRUE;
31 long sc;
32 
33 /** How many blocks have been cracked in this game. */
34 long blocks;
35 
36 long tmp_blocks, chain_step;
37 int  movedown_counter;
38 gboolean  paused = FALSE;
39 gboolean  star_comes;
40 int offset_down = 0;
41 
42 const int  iRot_vx[4][3] = {{1,  0,  0}, {0,  0,  1}, {0,  1,  1}, { 1,  1,  0}};
43 const int  iRot_vy[4][3] = {{0,  0, -1}, {0, -1, -1}, {-1, -1, 0}, {-1,  0,  0}};
44 const int  iCrChk[4][2] = {{0, 1}, {0, 2}, {0, 2}, {1, 2}};
45 
46 
initGame()47 static void  initGame ()
48 {
49   int  x, y;
50 
51   sc = 0;
52   blocks = 0;
53   star_gauge = 0;
54   printScore ();
55   printLevel ();
56   for (y = 0; y <= BOARD_HEIGHT; y++)
57     {
58       board[0][y].blk = OBSTACLE;
59       board[BOARD_WIDTH + 1][y].blk = OBSTACLE;
60       board[0][y].chk = OBSTACLE;
61       board[BOARD_WIDTH + 1][y].chk = OBSTACLE;
62       for (x = 1; x <= BOARD_WIDTH; x++)
63 	{
64 	  board[x][y].blk = EMPTY;
65 	  board[x][y].sub = EMPTY_SUB;
66 	  board[x][y].chk = EMPTY;
67 	}
68     }
69   for (x = 0; x <= BOARD_WIDTH + 1; x++)
70     {
71       board[x][BOARD_HEIGHT].blk = OBSTACLE;
72       board[x][BOARD_HEIGHT].chk = OBSTACLE;
73     }
74 
75   decideNextItem ();
76 }
77 
78 
decideNextItem()79 static void  decideNextItem ()
80 {
81   decideMaxRnd ();
82   if ((blocks > 200) && ((random () % max_rnd + 1) == LUCKY_NUMBER))
83     {
84       next_i.col[0] = STAR;
85     }
86   else
87     {
88 	  int  reduce_blocks;
89       if (blocks < 200)  reduce_blocks = 2;
90       else if (blocks < 600)  reduce_blocks = 1;
91       else  reduce_blocks = 0;
92 
93       next_i.col[0] = (cellstatus_t)(random () % (BLOCK_VARIETY - reduce_blocks) + 1);
94       do
95 	{
96 	  next_i.col[1] = (cellstatus_t)(random () % (BLOCK_VARIETY - reduce_blocks) + 1);
97 	} while  (next_i.col[1] == next_i.col[0]);
98       do
99 	{
100 	  next_i.col[2] = (cellstatus_t)(random () % (BLOCK_VARIETY - reduce_blocks) + 1);
101 	} while  ((next_i.col[2] == next_i.col[0])
102 		  || (next_i.col[2] == next_i.col[1]));
103 
104       next_i.rot = 0;
105     }
106 }
107 
108 
restart()109 static void  restart ()
110 {
111 	gtk_button_set_label(GTK_BUTTON(start), _("Pause"));
112 	paused = FALSE;
113 	gdk_draw_drawable(board_pix, draw_gc, saved_screen, 0, 0, 0, 0, -1, -1);
114 	g_object_unref(saved_screen);
115 	gtk_widget_queue_draw(board_w);
116 	saved_screen = NULL;
117 	RedrawNextItem();
118 	startTimer ();
119 }
120 
121 
StartGame()122 void  StartGame ()
123 {
124   if (gameover_flag)
125     {
126       gtk_button_set_label(GTK_BUTTON(start), _("Pause"));
127       gameover_flag = FALSE;
128       srandom (time (NULL));
129       initGame ();
130       clearScreen();
131       gtk_widget_queue_draw(board_w);
132       makeNext ();
133       printItem ();
134       startTimer ();
135     }
136   else
137     {
138       if (! paused)
139 	pauseProc ();
140       else
141 	restart ();
142     }
143 }
144 
145 
addScore(int sc_x,int sc_y)146 void  addScore (int sc_x, int sc_y)
147 {
148   long tmp_sc;
149 
150   if (tmp_blocks > 0)
151     {
152       if (chain_step == 0)
153 	tmp_sc = 1000;
154       else
155 	tmp_sc = tmp_blocks * 10
156 	  * chain_step * (chain_step + 3) * (tmp_blocks / 3 + 1);
157       showTmpScore (tmp_sc, sc_x, sc_y, chain_step);
158       usleep (200000);
159 //      RedrawBoard (board_w); XXX
160       sc += tmp_sc;
161       blocks += tmp_blocks;
162     }
163 }
164 
165 
makeNext()166 void  makeNext ()
167 {
168   static int counter = 0;
169 
170   if (next_i.col[0] == STAR)
171     {
172       drop_i.col[0] = EMPTY;
173       star_comes = TRUE;
174       drop_i.x = 4;
175       drop_i.y = 0;
176     }
177   else
178     {
179 		int i;
180       star_comes = FALSE;
181       for (i = 0; i < 3; i++)
182 	drop_i.col[i] = next_i.col[i];
183       drop_i.rot = next_i.rot;
184       drop_i.x = 4;
185       drop_i.y = 1;
186     }
187   drop_i.blocknum = counter++;
188   movedown_counter = 0;
189 
190   decideNextItem ();
191   printNextItem ();
192 
193   if (! star_comes)
194     {
195 		int i;
196 		for(i = 0 ; i < 3 ; i++)
197 		{
198 			  int rx = drop_i.x + iRot_vx[drop_i.rot][i];
199 			  int ry = drop_i.y + iRot_vy[drop_i.rot][i];
200 			  if(board[rx][ry].blk != EMPTY || board[rx][ry+1].blk != EMPTY)
201 				  endGame();
202 		}
203     }
204   else
205     {
206       if (! (board[drop_i.x][drop_i.y].blk == EMPTY))
207 	endGame ();
208     }
209 }
210 
211 
pauseProc()212 static void  pauseProc ()
213 {
214 	PangoLayout *layout;
215 	PangoRectangle rect;
216 	gtk_button_set_label(GTK_BUTTON(start), _("Start"));
217 	paused = TRUE;
218 	stopTimer ();
219 
220 	saved_screen = gdk_pixmap_new(board_pix, WIN_WIDTH, WIN_HEIGHT, -1);
221 	gdk_draw_drawable(saved_screen, draw_gc, board_pix, 0, 0, 0, 0, -1, -1);
222 
223 	gdk_draw_rectangle(board_pix, delete_gc, TRUE, 0, 0,
224 		WIN_WIDTH, WIN_HEIGHT);
225 
226 	gdk_draw_rectangle(board_pix, draw_gc, FALSE, DIFF_X / 2, DIFF_Y / 2,
227 		  BLOCK_WIDTH * BOARD_WIDTH + DIFF_X,
228 		  BLOCK_HEIGHT * BOARD_HEIGHT + DIFF_Y);
229 
230 	layout = gtk_widget_create_pango_layout (board_w, _("PAUSE!"));
231 	pango_layout_set_font_description(layout, pause_font);
232 	pango_layout_get_pixel_extents(layout, &rect, NULL);
233 	gdk_draw_layout(board_pix, draw_gc,
234 		(WIN_WIDTH/2)-(rect.width/2), 220, layout);
235 	g_object_unref (layout);
236 
237 	clearNextItem ();
238 
239 	gtk_widget_queue_draw(board_w);
240 }
241 
242 
endGame()243 static void  endGame ()
244 {
245 	PangoLayout *layout;
246 	PangoRectangle rect;
247 	gtk_button_set_label(GTK_BUTTON(start), _("Start"));
248 	gameover_flag = TRUE;
249 	if (timer)
250 		stopTimer ();
251 	layout = gtk_widget_create_pango_layout (board_w, _("<<< GAME OVER >>>"));
252 	pango_layout_set_font_description(layout, game_over_font);
253 	pango_layout_get_pixel_extents(layout, &rect, NULL);
254 	gdk_draw_layout(board_pix, draw_gc,
255 		(WIN_WIDTH/2)-(rect.width/2), 220, layout);
256 	g_object_unref (layout);
257 	gtk_widget_queue_draw(board_w);
258 
259   update_highscore_table ();
260   PrintHighScores ();
261 }
262 
263 
decideMaxRnd()264 static void  decideMaxRnd ()
265 {
266   int  x, y, danger_blocks = 0;
267 
268   for (y = 0; y <= 4; y++)
269     for (x = 1; x <= BOARD_WIDTH; x++)
270       if (board[x][y].blk != EMPTY)
271 	danger_blocks++;
272   if (danger_blocks < 6)  max_rnd = 120 - (blocks / 200) / 2;
273   else if (danger_blocks < 12)  max_rnd = 60 - (blocks / 200) / 4;
274   else if (danger_blocks < 20)  max_rnd = 10 - (blocks / 200) / 16;
275   else  max_rnd = 5;
276   star_gauge += danger_blocks;
277   if (star_gauge > 100)
278     {
279       max_rnd = 4;
280       star_gauge = 0;
281     }
282 }
283