ref: d551a83ae4e3e42c4d7da9638ec1f937200844cb
dir: /sys/src/games/mahjongg/graphics.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <event.h> #include "mahjongg.h" /* * mark tiles that partially obscure the given tile. * relies on Depth*Dxy <= Tilex/2 */ void markabove(int d, int x, int y) { int dx, dy; for(d++; d < Depth; d++) for(dx = -1; dx <= 2; dx++) for(dy = -1; dy <= 2; dy++) if(x+dx < Lx && x+dx >= 0 && y+dy < Ly && y+dy >= 0) level.board[d][x+dx][y+dy].redraw = 1; } void markbelow(int d, int x, int y) { int dx, dy; for(d--; d >= 0; d--) for(dx = -2; dx <= 1; dx++) for(dy = -2; dy <= 1; dy++) if(x+dx < Lx && x+dx >= 0 && y+dy < Ly && y+dy >= 0) level.board[d][x+dx][y+dy].redraw = 1; } Rectangle tilerect(Click c) { Point p; Rectangle r; p = Pt(c.x*(Facex/2)-(c.d*TileDxy), c.y*(Facey/2)-(c.d*TileDxy)); r = Rpt(p, addpt(p, Pt(Facex, Facey))); return rectaddpt(r, Pt(Depth*TileDxy, Depth*TileDxy)); } void clearbrick(Click c) { Rectangle r; level.hist[--level.remaining] = c; level.board[c.d][c.x][c.y].which = None; level.board[c.d][c.x+1][c.y].which = None; level.board[c.d][c.x][c.y+1].which = None; level.board[c.d][c.x+1][c.y+1].which = None; r = tilerect(c); draw(img, r, background, nil, r.min); markabove(c.d, c.x, c.y); markbelow(c.d, c.x, c.y); } void drawbrick(Click c) { Rectangle r; r = tilerect(c); draw(img, r, tileset, nil, level.board[c.d][c.x][c.y].start); if(level.board[c.d][c.x][c.y].clicked) draw(img, r, selected, nil, ZP); if(eqcl(level.l, c)) border(img, r, 2, litbrdr, level.board[c.d][c.x][c.y].start); /* looks better without borders, uncomment to check it out with'em */ // r = Rpt(r.min, addpt(r.min, Pt(Tilex, Tiley))); // draw(img, r, brdr, nil, ZP); } void redrawlevel(int all) { Brick *b; int d, x, y; for(d = 0; d < Depth; d++) for(y = 0; y < Ly; y++) for(x = 0; x < Lx; x++) { b = &level.board[d][x][y]; if(b->which == TL && (all || b->redraw)) { drawbrick(Cl(d,x,y)); markabove(d,x,y); } b->redraw = 0; } draw(screen, screen->r, img, nil, ZP); flushimage(display, 1); } void updatelevel(void) { redrawlevel(0); } void drawlevel(void) { draw(img, img->r, background, nil, ZP); redrawlevel(1); } void resize(Point p) { int fd; fd = open("/dev/wctl", OWRITE); if(fd >= 0){ fprint(fd, "resize -dx %d -dy %d", p.x, p.y); close(fd); } } void hint(void) { int d = 0, x = 0, y = 0; Brick *a, *b = nil; if(level.c.d != -1) { if((b = bmatch(level.c)) != nil) { d = level.c.d; x = level.c.x; y = level.c.y; } } else for(d = Depth - 1; d >= 0; d--) for(y = 0; y < Ly; y++) for(x = 0; x < Lx; x++) if(level.board[d][x][y].which == TL && isfree(Cl(d,x,y)) && (b = bmatch(Cl(d,x,y))) != nil) goto Matched; Matched: if (b == nil) return; a = &level.board[d][x][y]; a->clicked = 1; a->redraw = 1; b->clicked = 1; b->redraw = 1; updatelevel(); sleep(100); if(level.c.d == -1){ a->clicked = 0; a->redraw = 1; } b->clicked = 0; b->redraw = 1; updatelevel(); sleep(100); a->clicked = 1; a->redraw = 1; b->clicked = 1; b->redraw = 1; updatelevel(); sleep(100); if(level.c.d == -1){ a->clicked = 0; a->redraw = 1; } b->clicked = 0; b->redraw = 1; updatelevel(); } void done(void) { level.done = 1; draw(screen, screen->r, selected, gameover, ZP); flushimage(display, 1); } Click findclick(Point coord) { Click c; for(c.d = Depth - 1; c.d >= 0; c.d--) { c.x = (coord.x + TileDxy*c.d)/(Facex/2); c.y = (coord.y + TileDxy*c.d)/(Facey/2); switch(level.board[c.d][c.x][c.y].which) { case None: break; case TL: return c; case TR: c.x = c.x - 1; return c; case BR: c.x = c.x - 1; c.y = c.y - 1; return c; case BL: c.y = c.y - 1; return c; } } return NC; } void clicked(Point coord) { Click c; Brick *b, *bc; c = findclick(coord); if (c.d == -1) return; b = &level.board[c.d][c.x][c.y]; if(isfree(c)) { if(level.c.d == -1) { level.c = c; b->clicked = 1; b->redraw = 1; } else if(eqcl(c, level.c)) { level.c = NC; b->clicked = 0; b->redraw = 1; } else { bc = &level.board[level.c.d][level.c.x][level.c.y]; if(b->type == bc->type) { clearbrick(c); bc->clicked = 0; clearbrick(level.c); level.c = NC; } else { bc->clicked = 0; bc->redraw = 1; b->clicked = 1; b->redraw = 1; level.c = c; } } updatelevel(); if(!canmove()) done(); } } void undo(void) { int i, j, d, x, y; if(level.remaining >= Tiles) return; for(i=1; i<=2; i++) { j = level.remaining++; d = level.hist[j].d; x = level.hist[j].x; y = level.hist[j].y; level.board[d][x][y].which = TL; level.board[d][x+1][y].which = TR; level.board[d][x+1][y+1].which = BR; level.board[d][x][y+1].which = BL; level.board[d][x][y].redraw = 1; } updatelevel(); } void deselect(void) { Brick *b; if(level.c.d == -1) return; b = &level.board[level.c.d][level.c.x][level.c.y]; level.c = NC; b->clicked = 0; b->redraw = 1; updatelevel(); } void light(Point coord) { Click c = findclick(coord); if (c.d == -1) return; if(eqcl(level.l, c)) return; if (level.l.d != -1) { level.board[level.l.d][level.l.x][level.l.y].redraw = 1; level.l = NC; } if(isfree(c)) { level.l = c; level.board[c.d][c.x][c.y].redraw = 1; } updatelevel(); } void clearlevel(void) { Click c, cm; for(c.d = Depth - 1; c.d >= 0; c.d--) for(c.y = 0; c.y < Ly; c.y++) for(c.x = 0; c.x < Lx; c.x++) if(level.board[c.d][c.x][c.y].which == TL && isfree(c)) { cm = cmatch(c, c.d); if(cm.d != -1) { clearbrick(cm); clearbrick(c); updatelevel(); clearlevel(); } } }