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