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