xref: /plan9/sys/src/games/mahjongg/graphics.c (revision f6cb8efc55e3205e92b0b2968ab530864b0e144b)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <event.h>
5 
6 #include "mahjongg.h"
7 
8 
9 /*
10  * mark tiles that partially obscure the given tile.
11  * relies on Depth*Dxy <= Tilex/2
12  */
13 void
markabove(int d,int x,int y)14 markabove(int d, int x, int y)
15 {
16 	int dx, dy;
17 
18 	for(d++; d < Depth; d++)
19 		for(dx = -1; dx <= 2; dx++)
20 			for(dy = -1; dy <= 2; dy++)
21 				if(x+dx < Lx && x+dx >= 0 &&
22 				    y+dy < Ly && y+dy >= 0)
23 					level.board[d][x+dx][y+dy].redraw = 1;
24 }
25 
26 void
markbelow(int d,int x,int y)27 markbelow(int d, int x, int y)
28 {
29 	int dx, dy;
30 
31 	for(d--; d >= 0; d--)
32 		for(dx = -2; dx <= 1; dx++)
33 			for(dy = -2; dy <= 1; dy++)
34 				if(x+dx < Lx && x+dx >= 0 &&
35 				    y+dy < Ly && y+dy >= 0)
36 					level.board[d][x+dx][y+dy].redraw = 1;
37 }
38 
39 Rectangle
tilerect(Click c)40 tilerect(Click c)
41 {
42 	Point p;
43 	Rectangle r;
44 
45 	p = Pt(c.x*(Facex/2)-(c.d*TileDxy), c.y*(Facey/2)-(c.d*TileDxy));
46 	r = Rpt(p, addpt(p, Pt(Facex, Facey)));
47 	return rectaddpt(r, Pt(Depth*TileDxy, Depth*TileDxy));
48 }
49 
50 void
clearbrick(Click c)51 clearbrick(Click c)
52 {
53 	Rectangle r;
54 
55 	level.hist[--level.remaining] = c;
56 
57 	level.board[c.d][c.x][c.y].which = None;
58 	level.board[c.d][c.x+1][c.y].which = None;
59 	level.board[c.d][c.x][c.y+1].which = None;
60 	level.board[c.d][c.x+1][c.y+1].which = None;
61 
62 	r = tilerect(c);
63 	draw(img, r, background, nil, r.min);
64 
65 	markabove(c.d, c.x, c.y);
66 	markbelow(c.d, c.x, c.y);
67 }
68 
69 void
drawbrick(Click c)70 drawbrick(Click c)
71 {
72 	Rectangle r;
73 
74 	r = tilerect(c);
75 	draw(img, r, tileset, nil, level.board[c.d][c.x][c.y].start);
76 
77 	if(level.board[c.d][c.x][c.y].clicked)
78 		draw(img, r, selected, nil, ZP);
79 
80 	if(eqcl(level.l, c))
81 		border(img, r, 2, litbrdr, level.board[c.d][c.x][c.y].start);
82 
83 	/* looks better without borders, uncomment to check it out with'em */
84 //	r = Rpt(r.min, addpt(r.min, Pt(Tilex, Tiley)));
85 //	draw(img, r, brdr, nil, ZP);
86 }
87 
88 void
redrawlevel(int all)89 redrawlevel(int all)
90 {
91 	Brick *b;
92 	int d, x, y;
93 
94 	for(d = 0; d < Depth; d++)
95 		for(y = 0; y < Ly; y++)
96 			for(x = 0; x < Lx; x++) {
97 				b = &level.board[d][x][y];
98 				if(b->which == TL && (all || b->redraw)) {
99 					drawbrick(Cl(d,x,y));
100 					markabove(d,x,y);
101 				}
102 				b->redraw = 0;
103 			}
104 
105 	draw(screen, screen->r, img, nil, ZP);
106 	flushimage(display, 1);
107 }
108 
109 void
updatelevel(void)110 updatelevel(void)
111 {
112 	redrawlevel(0);
113 }
114 
115 void
drawlevel(void)116 drawlevel(void)
117 {
118 	draw(img, img->r, background, nil, ZP);
119 	redrawlevel(1);
120 }
121 
122 void
resize(Point p)123 resize(Point p)
124 {
125 	int fd;
126 
127 	fd = open("/dev/wctl", OWRITE);
128 	if(fd >= 0){
129 		fprint(fd, "resize -dx %d -dy %d", p.x, p.y);
130 		close(fd);
131 	}
132 }
133 
134 void
hint(void)135 hint(void)
136 {
137 	int d = 0, x = 0, y = 0;
138 	Brick *b = nil;
139 
140 	if(level.c.d != -1) {
141 		if((b = bmatch(level.c)) != nil) {
142 			d = level.c.d;
143 			x = level.c.x;
144 			y = level.c.y;
145 		}
146 	} else
147 		for(d = Depth - 1; d >= 0; d--)
148 			for(y = 0; y < Ly; y++)
149 				for(x = 0; x < Lx; x++)
150 					if(level.board[d][x][y].which == TL &&
151 					    isfree(Cl(d,x,y)) &&
152 					    (b = bmatch(Cl(d,x,y))) != nil)
153 						goto Matched;
154 Matched:
155 	if (b == nil)
156 		return;
157 	level.board[d][x][y].clicked = 1;
158 	b->clicked = 1;
159 	b->redraw = 1;
160 	updatelevel();
161 	sleep(500);
162 	if(level.c.d == -1)
163 		level.board[d][x][y].clicked = 0;
164 	b->clicked = 0;
165 	b->redraw = 1;
166 	updatelevel();
167 	sleep(500);
168 	level.board[d][x][y].clicked = 1;
169 	b->clicked = 1;
170 	b->redraw = 1;
171 	updatelevel();
172 	sleep(500);
173 	if(level.c.d == -1)
174 		level.board[d][x][y].clicked = 0;
175 	b->clicked = 0;
176 	b->redraw = 1;
177 	updatelevel();
178 }
179 
180 void
done(void)181 done(void)
182 {
183 	level.done = 1;
184 	draw(screen, screen->r, selected, gameover, ZP);
185 	flushimage(display, 1);
186 }
187 
188 Click
findclick(Point coord)189 findclick(Point coord)
190 {
191 	Click c;
192 
193 	for(c.d = Depth - 1; c.d >= 0; c.d--) {
194 		c.x = (coord.x + TileDxy*c.d)/(Facex/2);
195 		c.y = (coord.y + TileDxy*c.d)/(Facey/2);
196 		switch(level.board[c.d][c.x][c.y].which) {
197 		case None:
198 			break;
199 		case TL:
200 			return c;
201 		case TR:
202 			c.x = c.x - 1;
203 			return c;
204 		case BR:
205 			c.x = c.x - 1;
206 			c.y = c.y - 1;
207 			return c;
208 		case BL:
209 			c.y = c.y - 1;
210 			return c;
211 		}
212 	}
213 	return NC;
214 }
215 
216 void
clicked(Point coord)217 clicked(Point coord)
218 {
219 	Click c;
220 	Brick *b, *bc;
221 
222 	c = findclick(coord);
223 	if (c.d == -1)
224 		return;
225 
226 	b = &level.board[c.d][c.x][c.y];
227 	if(isfree(c)) {
228 		if(level.c.d == -1) {
229 			level.c = c;
230 			b->clicked = 1;
231 			b->redraw = 1;
232 		} else if(eqcl(c, level.c)) {
233 			level.c = NC;
234 			b->clicked = 0;
235 			b->redraw = 1;
236 		} else {
237 			bc = &level.board[level.c.d][level.c.x][level.c.y];
238 			if(b->type == bc->type) {
239 				clearbrick(c);
240 				bc->clicked = 0;
241 				clearbrick(level.c);
242 				level.c = NC;
243 			} else {
244 				bc->clicked = 0;
245 				bc->redraw = 1;
246 				b->clicked = 1;
247 				b->redraw = 1;
248 				level.c = c;
249 			}
250 		}
251 		updatelevel();
252 		if(!canmove())
253 			done();
254 	}
255 }
256 
257 void
undo(void)258 undo(void)
259 {
260 	int i, j, d, x, y;
261 
262 	if(level.remaining >= Tiles)
263 		return;
264 
265 	for(i=1; i<=2; i++) {
266 		j = level.remaining++;
267 		d = level.hist[j].d;
268 		x = level.hist[j].x;
269 		y = level.hist[j].y;
270 		level.board[d][x][y].which = TL;
271 		level.board[d][x+1][y].which = TR;
272 		level.board[d][x+1][y+1].which = BR;
273 		level.board[d][x][y+1].which = BL;
274 		level.board[d][x][y].redraw = 1;
275 	}
276 	updatelevel();
277 }
278 
279 void
deselect(void)280 deselect(void)
281 {
282 	Brick *b;
283 
284 	if(level.c.d == -1)
285 		return;
286 	b = &level.board[level.c.d][level.c.x][level.c.y];
287 	level.c = NC;
288 	b->clicked = 0;
289 	b->redraw = 1;
290 	updatelevel();
291 }
292 
293 void
light(Point coord)294 light(Point coord)
295 {
296 	Click c = findclick(coord);
297 	if (c.d == -1)
298 		return;
299 
300 	if(eqcl(level.l, c))
301 		return;
302 
303 	if (level.l.d != -1) {
304 		level.board[level.l.d][level.l.x][level.l.y].redraw = 1;
305 		level.l = NC;
306 	}
307 
308 	if(isfree(c)) {
309 		level.l = c;
310 		level.board[c.d][c.x][c.y].redraw = 1;
311 	}
312 
313 	updatelevel();
314 }
315 
316 void
clearlevel(void)317 clearlevel(void)
318 {
319 	Click c, cm;
320 
321 	for(c.d = Depth - 1; c.d >= 0; c.d--)
322 		for(c.y = 0; c.y < Ly; c.y++)
323 			for(c.x = 0; c.x < Lx; c.x++)
324 				if(level.board[c.d][c.x][c.y].which == TL &&
325 				    isfree(c)) {
326 					cm = cmatch(c, c.d);
327 					if(cm.d != -1) {
328 						clearbrick(cm);
329 						clearbrick(c);
330 						updatelevel();
331 						clearlevel();
332 					}
333 				}
334 }
335