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