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