4 * engine for 4s, 5s, etc
9 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
10 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC,
11 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
12 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
13 {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C,
14 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C,
15 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C,
16 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
43 Image *bb, *bbmask, *bb2, *bb2mask;
69 uchar txbits[NCOL][32]={
70 {0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
71 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
72 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
73 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF},
74 {0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
75 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
76 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
77 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77},
78 {0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
79 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
80 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
81 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
82 {0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
83 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
84 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
85 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
86 {0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
87 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
88 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
89 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88},
90 {0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
91 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
92 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
93 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00},
94 {0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
95 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
96 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
97 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
98 {0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
99 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
100 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
101 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
102 {0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
103 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
104 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
105 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC},
106 {0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
107 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
108 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
109 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33},
113 DYellow, /* yellow */
115 DGreen, /* lime green */
116 DGreyblue, /* slate */
118 DGreygreen, /* olive green */
120 0xFF55AAFF, /* pink */
121 0xFFAAFFFF, /* lavender */
122 0xBB005DFF, /* maroon */
130 mouse.xy = Pt(rboard.min.x + Dx(rboard)/2, rboard.min.y +Dy(rboard)/2);
131 moveto(mousectl, mouse.xy);
138 if (!suspended && piece != nil) {
139 x = pos.x + piece->sz.x*pcsz/2;
140 if (p.y < rboard.min.y)
142 if (p.y >= rboard.max.y)
143 p.y = rboard.max.y - 1;
144 moveto(mousectl, Pt(x, p.y));
166 collide(Point pt, Piece *p)
171 pt.x = (pt.x - rboard.min.x) / pcsz;
172 pt.y = (pt.y - rboard.min.y) / pcsz;
176 if(pt.x<0 || pt.x>=NX || pt.y<0 || pt.y>=NY)
178 if(board[pt.y][pt.x])
185 collider(Point pt, Point pmax)
187 int i, j, pi, pj, n, m;
189 pi = (pt.x - rboard.min.x) / pcsz;
190 pj = (pt.y - rboard.min.y) / pcsz;
192 m = pmax.y / pcsz + 1;
193 for(i = pi; i < pi+n && i < NX; i++)
194 for(j = pj; j < pj+m && j < NY; j++)
206 draw(bb, bb->r, display->white, nil, ZP);
207 draw(bbmask, bbmask->r, display->transparent, nil, ZP);
208 br = Rect(0, 0, 0, 0);
215 r.min.x += p->d[i].x*pcsz;
216 r.min.y += p->d[i].y*pcsz;
217 r.max.x = r.min.x + pcsz;
218 r.max.y = r.min.y + pcsz;
220 draw(bb, r, display->black, nil, ZP);
221 draw(bb, insetrect(r, 1), tx[piece->tx], nil, ZP);
222 draw(bbmask, r, display->opaque, nil, ZP);
225 draw(bb, r, bb, nil, op);
226 draw(bbmask, r, bbmask, nil, op);
228 if(br.max.x < r.max.x)
230 if(br.max.y < r.max.y)
233 br.max = subpt(br.max, bb->r.min);
235 br2.max = addpt(br.max, delta);
236 r = rectaddpt(br, bb2->r.min);
237 r2 = rectaddpt(br2, bb2->r.min);
238 draw(bb2, r2, display->white, nil, ZP);
239 draw(bb2, rectaddpt(r,delta), bb, nil, bb->r.min);
240 draw(bb2mask, r2, display->transparent, nil, ZP);
241 draw(bb2mask, r, display->opaque, bbmask, bb->r.min);
242 draw(bb2mask, rectaddpt(r,delta), display->opaque, bbmask, bb->r.min);
247 draw(screen, rectaddpt(br, pos), bb, bbmask, bb->r.min);
249 draw(screen, rectaddpt(br, pos), display->white, whitemask, ZP);
256 if(collider(pos, br.max))
258 draw(screen, rectaddpt(br, pos), display->white, mask, bb->r.min);
267 pt = divpt(subpt(pos, rboard.min), pcsz);
269 pt.x += piece->d[i].x;
270 pt.y += piece->d[i].y;
271 board[pt.y][pt.x] = piece->tx+16;
278 static int dx[]={0, -1, 1, -2, 2, -3, 3, 4, -4};
290 z.x = pos.x + dx[i]*pcsz;
293 z.y = pos.y + pcsz-1;
310 snprint(buf, sizeof(buf), "%.6ld", points);
311 draw(screen, Rpt(pscore, addpt(pscore, scoresz)), display->white, nil, ZP);
312 string(screen, pscore, display->black, ZP, font, buf);
316 drawsq(Image *b, Point p, int ptx){
320 r.max.x = r.min.x+pcsz;
321 r.max.y = r.min.y+pcsz;
322 draw(b, r, display->black, nil, ZP);
323 draw(b, insetrect(r, 1), tx[ptx], nil, ZP);
331 border(screen, insetrect(rboard, -2), 2, display->black, ZP);
332 draw(screen, Rect(rboard.min.x, rboard.min.y-2, rboard.max.x, rboard.min.y),
333 display->white, nil, ZP);
337 drawsq(screen, Pt(rboard.min.x+j*pcsz, rboard.min.y+i*pcsz), board[i][j]-16);
340 draw(screen, screen->r, display->white, whitemask, ZP);
350 setpiece(&pieces[i]);
352 pos.x += nrand(NX)*pcsz;
353 }while(collide(Pt(pos.x, pos.y+pcsz-DY), piece));
355 flushimage(display, 1);
363 if(collide(Pt(pos.x, pos.y+pcsz), piece))
365 if(collider(pos, br2.max))
367 draw(screen, rectaddpt(br2, pos), bb2, mask, bb2->r.min);
369 flushimage(display, 1);
378 setcursor(mousectl, &whitearrow);
380 setcursor(mousectl, nil);
384 flushimage(display, 1);
393 alts[TIMER].c = timerc;
395 alts[TIMER].op = CHANRCV;
396 alts[SUSPEND].c = suspc;
397 alts[SUSPEND].v = &s;
398 alts[SUSPEND].op = CHANRCV;
399 alts[RESHAPE].c = mousectl->resizec;
400 alts[RESHAPE].v = nil;
401 alts[RESHAPE].op = CHANRCV;
402 // avoid hanging up those writing ong mousec and kbdc
403 // so just accept it all and keep mouse up-to-date
404 alts[MOUSE].c = mousec;
405 alts[MOUSE].v = &mouse;
406 alts[MOUSE].op = CHANRCV;
409 alts[KBD].op = CHANRCV;
410 alts[NALT].op = CHANEND;
412 flushimage(display, 1);
416 if (!suspended && s) {
418 } else if (suspended && !s) {
420 lastmx = warp(mouse.xy, lastmx);
426 if((t -= tsleep) < 0)
444 for(j=0; board[i][j]; j++)
455 r.min.y = rboard.min.y + lev[j]*pcsz;
456 r.max.y = r.min.y + pcsz;
457 draw(screen, r, display->white, whitemask, ZP);
458 flushimage(display, 1);
467 r.min.y = rboard.min.y + lev[j]*pcsz;
468 r.max.y = r.min.y + pcsz;
469 draw(screen, r, display->white, whitemask, ZP);
471 flushimage(display, 1);
477 r.min.y = rboard.min.y;
478 r.max.y = rboard.min.y+lev[j]*pcsz;
479 draw(screen, rectaddpt(r, Pt(0,pcsz)), screen, nil, r.min);
480 r.max.y = rboard.min.y+pcsz;
481 draw(screen, r, display->white, nil, ZP);
482 memcpy(&board[1][0], &board[0][0], NX*lev[j]);
483 memset(&board[0][0], 0, NX);
485 flushimage(display, 1);
492 if(!collide(Pt(pos.x+pcsz, pos.y), piece))
493 if(!collide(Pt(pos.x+pcsz, pos.y+pcsz-DY), piece)){
497 flushimage(display, 1);
504 if(!collide(Pt(pos.x-pcsz, pos.y), piece))
505 if(!collide(Pt(pos.x-pcsz, pos.y+pcsz-DY), piece)){
509 flushimage(display, 1);
516 if(canfit(rotr(piece))){
517 setpiece(rotr(piece));
519 flushimage(display, 1);
526 if(canfit(rotl(piece))){
527 setpiece(rotl(piece));
529 flushimage(display, 1);
538 score(5L*(rboard.max.y-pos.y)/pcsz);
539 do; while(movepiece());
543 if(pos.y==rboard.min.y && !horiz())
549 lastmx = warp(mouse.xy, lastmx);
562 alts[TIMER].c = timerc;
564 alts[TIMER].op = CHANRCV;
565 alts[MOUSE].c = mousec;
566 alts[MOUSE].v = &mouse;
567 alts[MOUSE].op = CHANRCV;
568 alts[SUSPEND].c = suspc;
569 alts[SUSPEND].v = &s;
570 alts[SUSPEND].op = CHANRCV;
571 alts[RESHAPE].c = mousectl->resizec;
572 alts[RESHAPE].v = nil;
573 alts[RESHAPE].op = CHANRCV;
576 alts[KBD].op = CHANRCV;
577 alts[NALT].op = CHANEND;
581 lastmx = movemouse();
583 lastmx = warp(mouse.xy, lastmx);
593 if(mouse.xy.x > lastmx+DMOUSE){
597 if(mouse.xy.x < lastmx-DMOUSE){
601 if(mouse.buttons&1 && !(om.buttons&1))
603 if(mouse.buttons&2 && !(om.buttons&2))
606 if(mouse.buttons&4 && !(om.buttons&4))
614 if (suspended && !s) {
616 lastmx = warp(mouse.xy, lastmx);
654 dt = 16 * (points+nrand(10000)-5000) / 10000;
661 if(movepiece()==0 && ++fusst==40){
678 fd = open("/dev/hz", OREAD);
681 n = read(fd, buf, sizeof buf - 1);
686 tsleep = strtoul(buf, 0, 10);
687 tsleep = (1000 + tsleep - 1) / tsleep;
713 alts[TIMER].op = CHANNOP;
714 alts[MOUSE].c = mousectl->c;
715 alts[MOUSE].v = &mouse;
716 alts[MOUSE].op = CHANRCV;
717 alts[SUSPEND].op = CHANNOP;
718 alts[RESHAPE].op = CHANNOP;
719 alts[KBD].c = kbdctl->c;
721 alts[KBD].op = CHANRCV;
722 alts[NALT].op = CHANEND;
728 send(mousec, &mouse);
765 if(new && getwindow(display, Refmesg) < 0)
766 sysfatal("can't reattach to window");
768 pos.x = (pos.x - rboard.min.x) / pcsz;
769 pos.y = (pos.y - rboard.min.y) / pcsz;
770 dx = r.max.x - r.min.x;
771 dy = r.max.y - r.min.y - 2*32;
781 sysfatal("screen too small: %d", pcsz);
783 rboard.min.x += (dx-pcsz*NX)/2;
784 rboard.min.y += (dy-pcsz*NY)/2+32;
785 rboard.max.x = rboard.min.x+NX*pcsz;
786 rboard.max.y = rboard.min.y+NY*pcsz;
787 pscore.x = rboard.min.x+8;
788 pscore.y = rboard.min.y-32;
789 scoresz = stringsize(font, "000000");
790 pos.x = pos.x*pcsz + rboard.min.x;
791 pos.y = pos.y*pcsz + rboard.min.y;
798 bb = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), screen->chan, 0, 0);
799 bbmask = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), GREY1, 0, 0);
800 bb2 = allocimage(display, Rect(0,0,N*pcsz,N*pcsz+DY), screen->chan, 0, 0);
801 bb2mask = allocimage(display, bb2->r, GREY1, 0, 0);
802 if(bb==0 || bbmask==0 || bb2==0 || bb2mask==0)
803 sysfatal("allocimage fail (bb)");
804 draw(screen, screen->r, display->white, nil, ZP);
809 lastmx = movemouse();
811 flushimage(display, 1);
817 fprint(2, "usage: %s\n", argv0);
822 threadmain(int argc, char *argv[])
827 long starttime, endtime;
838 snprint(buf, sizeof(buf), "%ds", N);
840 mousectl = initmouse(nil, display->image); /* BUG? */
842 sysfatal("[45]s: mouse init failed: %r");
843 kbdctl = initkeyboard(nil); /* BUG? */
845 sysfatal("[45]s: keyboard init failed: %r");
848 snprint(buf, sizeof(buf), "/sys/games/lib/%dscores", N);
849 scores = open(buf, OWRITE);
851 print("can't open %s: %r\n", buf);
853 if(screen->depth < 3){
854 tb = allocimage(display, Rect(0,0,16,16), 0, 1, -1);
856 sysfatal("allocimage fail (tb)");
858 for(i = 0; i<NCOL; i++){
859 tx[i] = allocimage(display, Rect(0, 0, 16, 16), screen->chan, 1, txpix[i]);
861 sysfatal("allocimage fail (tx)");
862 if(screen->depth < 3){
863 loadimage(tb, tb->r, txbits[i], 32);
864 draw(tx[i], tx[i]->r, tb, nil, ZP);
870 whitemask = allocimage(display, Rect(0,0,1,1), CMAP8, 1, setalpha(DWhite, 0x7F));
872 sysfatal("allocimage fail (whitemask)");
874 threadsetname("4s-5s");
875 timerc= chancreate(sizeof(int), 0);
876 proccreate(timerproc, timerc, 1024);
877 suspc= chancreate(sizeof(int), 0);
878 mousec= chancreate(sizeof(Mouse), 0);
879 kbdc= chancreate(sizeof(Rune), 0);
880 threadcreate(suspproc, nil, 1024);
882 memset(board, 0, sizeof(board));
884 if(play() && scores >= 0){
886 fprint(scores, "%ld\t%s\t%lud\t%ld\n",
887 points, getuser(), starttime, endtime-starttime);