graphics.c 5.6 KB

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