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