1 /* */
2 /* xemeraldia --- graphics.c */
3 /* */
4
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8
9 #include "games.h"
10 #include "gtk-2.0/gtk/gtkprivate.h"
11
12 static gboolean animateTmpScore (void *);
13
14 guint timer, tmp_sc_timer;
15 PangoFontDescription *animated_score_font, *game_over_font, *pause_font;
16
17 struct TmpSc
18 {
19 long sc;
20 int x, y;
21 char cnt;
22 };
23
24 static struct TmpSc tmpSc[50];
25
expose_board(GtkWidget * widget,GdkEventExpose * event,gpointer data G_GNUC_UNUSED)26 gboolean expose_board(GtkWidget *widget, GdkEventExpose *event, gpointer data G_GNUC_UNUSED)
27 {
28 gdk_draw_drawable(widget->window, draw_gc, board_pix, event->area.x, event->area.y,
29 event->area.x, event->area.y,
30 event->area.width, event->area.height);
31 return TRUE;
32 }
33
invalidate_area(GtkWidget * widget,gint x,gint y,gint w,gint h)34 static void invalidate_area(GtkWidget *widget, gint x, gint y, gint w, gint h)
35 {
36 while(GTK_PRIVATE_FLAGS(widget) & GTK_NO_WINDOW)
37 {
38 x += widget->allocation.x;
39 y += widget->allocation.y;
40 widget = widget->parent;
41 }
42 gtk_widget_queue_draw_area(widget, x, y, w, h);
43 }
44
45
RedrawNextItem()46 void RedrawNextItem ()
47 {
48 clearNextItem ();
49 if ((! gameover_flag) && (! paused))
50 printNextItem ();
51 }
52
53
showTmpScore(long tmp_sc,int sc_x,int sc_y,long ch_s)54 void showTmpScore (long tmp_sc, int sc_x, int sc_y, long ch_s)
55 {
56 PangoLayout *layout;
57 char tmp_sc_str[8];
58
59 tmpSc[ch_s].x = sc_x; tmpSc[ch_s].y = sc_y;
60 tmpSc[ch_s].sc = tmp_sc;
61 tmpSc[ch_s].cnt = 8;
62 sprintf (tmp_sc_str, "%7ld", tmpSc[ch_s].sc);
63
64 layout = gtk_widget_create_pango_layout (board_w, tmp_sc_str);
65 pango_layout_set_font_description(layout, animated_score_font);
66 gdk_draw_layout(board_w->window, draw_gc,
67 (tmpSc[ch_s].x - 1) * BLOCK_WIDTH - 6,
68 ((tmpSc[ch_s].y + 1) * BLOCK_HEIGHT - 24 + tmpSc[ch_s].cnt * 3) - 25,
69 layout);
70 g_object_unref (layout);
71 gdk_flush();
72
73 gdk_flush();
74 --tmpSc[ch_s].cnt;
75 tmp_sc_timer = g_timeout_add(20, animateTmpScore, GINT_TO_POINTER(ch_s));
76 }
77
78
animateTmpScore(void * closure)79 static gboolean animateTmpScore(void *closure)
80 {
81 gint ch_s = GPOINTER_TO_INT(closure);
82 PangoLayout *layout;
83 char tmp_sc_str[8];
84
85 invalidate_area(board_w,
86 (tmpSc[ch_s].x - 1) * BLOCK_WIDTH,
87 (tmpSc[ch_s].y + 1) * BLOCK_HEIGHT - 43 + tmpSc[ch_s].cnt * 3,
88 90, 25);
89 gdk_window_process_updates (board_w->window, TRUE);
90
91 gdk_flush();
92
93 sprintf (tmp_sc_str, "%7ld", tmpSc[ch_s].sc);
94
95 layout = gtk_widget_create_pango_layout (board_w, tmp_sc_str);
96 pango_layout_set_font_description(layout, animated_score_font);
97 gdk_draw_layout(board_w->window, draw_gc,
98 (tmpSc[ch_s].x - 1) * BLOCK_WIDTH - 6,
99 ((tmpSc[ch_s].y + 1) * BLOCK_HEIGHT - 24 + tmpSc[ch_s].cnt * 3) - 25,
100 layout);
101 g_object_unref (layout);
102 gdk_flush();
103
104 if (--tmpSc[ch_s].cnt > 0)
105 tmp_sc_timer = g_timeout_add(45, animateTmpScore, GINT_TO_POINTER(ch_s));
106 else
107 invalidate_area(board_w,
108 (tmpSc[ch_s].x - 1) * BLOCK_WIDTH,
109 (tmpSc[ch_s].y + 1) * BLOCK_HEIGHT - 43 + tmpSc[ch_s].cnt * 3,
110 90, 25);
111 return FALSE;
112 }
113
114
clearNextItem()115 void clearNextItem ()
116 {
117 gdk_draw_rectangle(nextItem_w->window, delete_gc, TRUE, 0, 0,
118 BLOCK_WIDTH * 3, BLOCK_HEIGHT * 3);
119 }
120
121
printNextItem()122 void printNextItem ()
123 {
124 int i;
125
126 clearNextItem ();
127 if (next_i.col[0] == STAR)
128 gdk_draw_drawable(nextItem_w->window, draw_gc, star, 0, 0,
129 BLOCK_WIDTH / 2 + DIFF_X, BLOCK_HEIGHT /2 + DIFF_Y,
130 BLOCK_WIDTH, BLOCK_HEIGHT);
131 else
132 {
133 for (i = 0; i < 3; i++)
134 gdk_draw_drawable(nextItem_w->window, draw_gc, block[next_i.col[i]], 0, 0,
135 BLOCK_WIDTH * (iRot_vx[0][i]) + DIFF_X,
136 BLOCK_HEIGHT * (1 + iRot_vy[0][i]) + DIFF_Y,
137 BLOCK_WIDTH, BLOCK_HEIGHT);
138 }
139 }
140
141
clearScreen()142 void clearScreen()
143 {
144 gdk_draw_drawable(board_pix, draw_gc, background, 0, 0, 0, 0,
145 WIN_WIDTH, WIN_HEIGHT);
146
147 gdk_draw_rectangle(board_pix, draw_gc, FALSE, DIFF_X / 2, DIFF_Y / 2,
148 BLOCK_WIDTH * BOARD_WIDTH + DIFF_X,
149 BLOCK_HEIGHT * BOARD_HEIGHT + DIFF_Y);
150 }
151
152 /** Draws the falling block described in drop_i.
153 */
printItem()154 void printItem ()
155 {
156 /* Previous block to delete. */
157 static int prevblocknum = -1;
158 static int prevxcoord[3], prevycoord[3], prevcx, prevcy;
159 static int prevrot;
160
161 int i;
162
163 int cx = (BLOCK_WIDTH * drop_i.x) - DIFF_X;
164 int cy = (BLOCK_HEIGHT * drop_i.y) + DIFF_Y + offset_down;
165
166 if(prevblocknum == drop_i.blocknum && cy == prevcy
167 && cx == prevcx && (star_comes || drop_i.rot == prevrot))
168 return;
169
170 if(drop_i.blocknum != prevblocknum)
171 prevblocknum = -1;
172 if(prevblocknum != -1)
173 for(i = 0; i < 3 && prevxcoord[i] != -1; i++)
174 deleteCell(prevxcoord[i], prevycoord[i]);
175
176 if(prevblocknum != -1 && abs(cx - prevcx) > BLOCK_WIDTH / 2)
177 cx = prevcx + (BLOCK_WIDTH / 3) * ((cx - prevcx) < 0 ? -1 : 1);
178
179 if(star_comes)
180 {
181 gdk_draw_drawable(board_pix, draw_gc, star,
182 0,0,
183 cx, cy,
184 BLOCK_WIDTH, BLOCK_HEIGHT);
185 invalidate_area(board_w, cx, cy, BLOCK_WIDTH, BLOCK_HEIGHT);
186 prevxcoord[0] = cx;
187 prevycoord[0] = cy;
188 prevxcoord[1] = -1;
189 } else
190 {
191 for(i = 0; i < 3; i++)
192 {
193 int dx = iRot_vx[drop_i.rot][i];
194 int dy = iRot_vy[drop_i.rot][i];
195
196 int rx = drop_i.x + dx;
197 int ry = drop_i.y + dy;
198
199 int xcoord = cx + BLOCK_WIDTH * dx;
200 int ycoord = cy + BLOCK_HEIGHT * dy;
201
202 drawCell(xcoord, ycoord, drop_i.col[i], board[rx][ry].sub);
203 board[rx][ry].blk = drop_i.col[i];
204
205 prevxcoord[i] = xcoord;
206 prevycoord[i] = ycoord;
207 }
208 }
209 prevblocknum = drop_i.blocknum;
210 prevcx = cx;
211 prevcy = cy;
212 prevrot = drop_i.rot;
213 }
214
drawCell(int xcoord,int ycoord,cellstatus_t color,cellsubstatus_t sub)215 void drawCell(int xcoord, int ycoord, cellstatus_t color, cellsubstatus_t sub)
216 {
217 int pixmap_number = color;
218
219 if ((sub == CRACKED) || (sub == DELETE))
220 pixmap_number += BLOCK_VARIETY;
221
222 if ((color > 0) && (color <= BLOCK_VARIETY * 2))
223 {
224 gdk_draw_drawable(board_pix, draw_gc, block[pixmap_number], 0, 0,
225 xcoord, ycoord, BLOCK_WIDTH, BLOCK_HEIGHT);
226 invalidate_area(board_w, xcoord, ycoord, BLOCK_WIDTH, BLOCK_HEIGHT);
227 }
228 }
229
printBlock(int x,int y,cellstatus_t color)230 void printBlock(int x, int y, cellstatus_t color)
231 {
232 drawCell(BLOCK_WIDTH * x - DIFF_X, BLOCK_HEIGHT * y + DIFF_Y
233 , color, board[x][y].sub);
234 }
235
deleteCell(int xcoord,int ycoord)236 void deleteCell(int xcoord, int ycoord)
237 {
238 gdk_draw_drawable(board_pix, draw_gc, background,
239 xcoord, ycoord,
240 xcoord, ycoord,
241 BLOCK_WIDTH, BLOCK_HEIGHT);
242 invalidate_area(board_w, xcoord, ycoord, BLOCK_WIDTH, BLOCK_HEIGHT);
243 }
244
delete_1_block(int x,int y)245 void delete_1_block (int x, int y)
246 {
247 deleteCell(BLOCK_WIDTH * x - DIFF_X, BLOCK_WIDTH * y + DIFF_Y);
248 }
249
startTimer()250 void startTimer ()
251 {
252 int reduce;
253
254 if (blocks < 200) reduce = (blocks / 20) * 70;
255 else if (blocks < 400) reduce = ((blocks - 200) / 20) * 50;
256 else if (blocks < 600) reduce = 500 + ((blocks - 400) / 20) * 25;
257 else if (blocks < 800) reduce = 200 + ((blocks - 600) / 20) * 50;
258 else if (blocks < 1000) reduce = 700 + ((blocks - 800) / 20) * 10;
259 else reduce = 860;
260
261 if (star_comes) reduce = 0;
262
263 timer = g_timeout_add((MAX_DELAY - reduce) / BLOCK_HEIGHT, (GSourceFunc)DropItem, NULL);
264 }
265
266
stopTimer()267 void stopTimer ()
268 {
269 g_source_remove(timer);
270 timer = 0;
271 }
272
273
printScore()274 void printScore ()
275 {
276 char buf[30];
277
278 #ifdef __GLIBC__
279 sprintf (buf, "%'ld", sc);
280 #else
281 sprintf (buf, "%ld", sc);
282 #endif
283 gtk_label_set_label(GTK_LABEL(score_disp), buf);
284 }
285
286
printLevel()287 void printLevel ()
288 {
289 char buf[30];
290
291 sprintf (buf, "%ld", blocks / 20 + 1);
292 gtk_label_set_label(GTK_LABEL(level_disp), buf);
293 }
294
295
Done()296 void Done ()
297 {
298 }
299
300
crack_1_block(int x,int y)301 void crack_1_block(int x, int y)
302 {
303 int xcoord = BLOCK_WIDTH * x - DIFF_X;
304 int ycoord = BLOCK_HEIGHT * y + DIFF_Y;
305 if ((board[x][y].blk > 0) && (board[x][y].blk <= BLOCK_VARIETY))
306 {
307 gdk_draw_drawable(board_pix, draw_gc, block[board[x][y].blk + BLOCK_VARIETY], 0, 0,
308 xcoord, ycoord,
309 BLOCK_WIDTH, BLOCK_HEIGHT);
310 invalidate_area(board_w, xcoord, ycoord, BLOCK_WIDTH, BLOCK_HEIGHT);
311 }
312 }
313
314
crushAnimate(int x,int y,int num)315 void crushAnimate (int x, int y, int num)
316 {
317 int xcoord = BLOCK_WIDTH * x - DIFF_X;
318 int ycoord = BLOCK_HEIGHT * y + DIFF_Y;
319 gdk_draw_drawable(board_pix, draw_gc, crush[num], 0, 0,
320 xcoord, ycoord,
321 BLOCK_WIDTH, BLOCK_HEIGHT);
322 invalidate_area(board_w, xcoord, ycoord, BLOCK_WIDTH, BLOCK_HEIGHT);
323 }
324