1 #include "xs.h"
2
3 /*
4 * engine for 4s, 5s, etc
5 */
6
7 Cursor whitearrow = {
8 {0, 0},
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, }
17 };
18
19 enum
20 {
21 CNone = 0,
22 CBounds = 1,
23 CPiece = 2,
24 NX = 10,
25 NY = 20,
26 };
27
28 enum{
29 TIMER,
30 MOUSE,
31 RESHAPE,
32 KBD,
33 SUSPEND,
34 NALT
35 };
36
37 char board[NY][NX];
38 Rectangle rboard;
39 Point pscore;
40 Point scoresz;
41 int pcsz = 32;
42 Point pos;
43 Image *bb, *bbmask, *bb2, *bb2mask;
44 Image *whitemask;
45 Rectangle br, br2;
46 long points;
47 int dt;
48 int DY;
49 int DMOUSE;
50 int lastmx;
51 Mouse mouse;
52 int newscreen;
53 Channel *timerc;
54 Channel *suspc;
55 Channel *mousec;
56 Channel *kbdc;
57 Mousectl *mousectl;
58 Keyboardctl *kbdctl;
59 int suspended;
60
61 void redraw(int);
62
63 int tsleep;
64
65 Piece *piece;
66
67 #define NCOL 10
68
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},
110 };
111
112 int txpix[NCOL] = {
113 DYellow, /* yellow */
114 DCyan, /* cyan */
115 DGreen, /* lime green */
116 DGreyblue, /* slate */
117 DRed, /* red */
118 DGreygreen, /* olive green */
119 DBlue, /* blue */
120 0xFF55AAFF, /* pink */
121 0xFFAAFFFF, /* lavender */
122 0xBB005DFF, /* maroon */
123 };
124
125 Image *tx[NCOL];
126
127 int
movemouse(void)128 movemouse(void)
129 {
130 mouse.xy = Pt(rboard.min.x + Dx(rboard)/2, rboard.min.y +Dy(rboard)/2);
131 moveto(mousectl, mouse.xy);
132 return mouse.xy.x;
133 }
134
135 int
warp(Point p,int x)136 warp(Point p, int x)
137 {
138 if (!suspended && piece != nil) {
139 x = pos.x + piece->sz.x*pcsz/2;
140 if (p.y < rboard.min.y)
141 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));
145 }
146 return x;
147 }
148
149 Piece *
rotr(Piece * p)150 rotr(Piece *p)
151 {
152 if(p->rot == 3)
153 return p-3;
154 return p+1;
155 }
156
157 Piece *
rotl(Piece * p)158 rotl(Piece *p)
159 {
160 if(p->rot == 0)
161 return p+3;
162 return p-1;
163 }
164
165 int
collide(Point pt,Piece * p)166 collide(Point pt, Piece *p)
167 {
168 int i;
169 int c = CNone;
170
171 pt.x = (pt.x - rboard.min.x) / pcsz;
172 pt.y = (pt.y - rboard.min.y) / pcsz;
173 for(i=0; i<N; i++){
174 pt.x += p->d[i].x;
175 pt.y += p->d[i].y;
176 if(pt.x<0 || pt.x>=NX || pt.y<0 || pt.y>=NY)
177 c |= CBounds;
178 if(board[pt.y][pt.x])
179 c |= CPiece;
180 }
181 return c;
182 }
183
184 int
collider(Point pt,Point pmax)185 collider(Point pt, Point pmax)
186 {
187 int i, j, pi, pj, n, m;
188
189 pi = (pt.x - rboard.min.x) / pcsz;
190 pj = (pt.y - rboard.min.y) / pcsz;
191 n = pmax.x / 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++)
195 if(board[j][i])
196 return 1;
197 return 0;
198 }
199
200 void
setpiece(Piece * p)201 setpiece(Piece *p){
202 int i;
203 Rectangle r, r2;
204 Point op, delta;
205
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);
209 br2 = br;
210 piece = p;
211 if(p == 0)
212 return;
213 r.min = bb->r.min;
214 for(i=0; i<N; i++){
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;
219 if(i == 0){
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);
223 op = r.min;
224 }else{
225 draw(bb, r, bb, nil, op);
226 draw(bbmask, r, bbmask, nil, op);
227 }
228 if(br.max.x < r.max.x)
229 br.max.x = r.max.x;
230 if(br.max.y < r.max.y)
231 br.max.y = r.max.y;
232 }
233 br.max = subpt(br.max, bb->r.min);
234 delta = Pt(0,DY);
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);
243 }
244
245 void
drawpiece(void)246 drawpiece(void){
247 draw(screen, rectaddpt(br, pos), bb, bbmask, bb->r.min);
248 if (suspended)
249 draw(screen, rectaddpt(br, pos), display->white, whitemask, ZP);
250 }
251
252 void
undrawpiece(void)253 undrawpiece(void)
254 {
255 Image *mask = nil;
256 if(collider(pos, br.max))
257 mask = bbmask;
258 draw(screen, rectaddpt(br, pos), display->white, mask, bb->r.min);
259 }
260
261 void
rest(void)262 rest(void)
263 {
264 int i;
265 Point pt;
266
267 pt = divpt(subpt(pos, rboard.min), pcsz);
268 for(i=0; i<N; i++){
269 pt.x += piece->d[i].x;
270 pt.y += piece->d[i].y;
271 board[pt.y][pt.x] = piece->tx+16;
272 }
273 }
274
275 int
canfit(Piece * p)276 canfit(Piece *p)
277 {
278 static int dx[]={0, -1, 1, -2, 2, -3, 3, 4, -4};
279 int i, j;
280 Point z;
281
282 j = N + 1;
283 if(j >= 4){
284 j = p->sz.x;
285 if(j<p->sz.y)
286 j = p->sz.y;
287 j = 2*j-1;
288 }
289 for(i=0; i<j; i++){
290 z.x = pos.x + dx[i]*pcsz;
291 z.y = pos.y;
292 if(!collide(z, p)){
293 z.y = pos.y + pcsz-1;
294 if(!collide(z, p)){
295 undrawpiece();
296 pos.x = z.x;
297 return 1;
298 }
299 }
300 }
301 return 0;
302 }
303
304 void
score(int p)305 score(int p)
306 {
307 char buf[128];
308
309 points += p;
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);
313 }
314
315 void
drawsq(Image * b,Point p,int ptx)316 drawsq(Image *b, Point p, int ptx){
317 Rectangle r;
318
319 r.min = p;
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);
324 }
325
326 void
drawboard(void)327 drawboard(void)
328 {
329 int i, j;
330
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);
334 for(i=0; i<NY; i++)
335 for(j=0; j<NX; j++)
336 if(board[i][j])
337 drawsq(screen, Pt(rboard.min.x+j*pcsz, rboard.min.y+i*pcsz), board[i][j]-16);
338 score(0);
339 if (suspended)
340 draw(screen, screen->r, display->white, whitemask, ZP);
341 }
342
343 void
choosepiece(void)344 choosepiece(void)
345 {
346 int i;
347
348 do{
349 i = nrand(NP);
350 setpiece(&pieces[i]);
351 pos = rboard.min;
352 pos.x += nrand(NX)*pcsz;
353 }while(collide(Pt(pos.x, pos.y+pcsz-DY), piece));
354 drawpiece();
355 flushimage(display, 1);
356 }
357
358 int
movepiece(void)359 movepiece(void)
360 {
361 Image *mask = nil;
362
363 if(collide(Pt(pos.x, pos.y+pcsz), piece))
364 return 0;
365 if(collider(pos, br2.max))
366 mask = bb2mask;
367 draw(screen, rectaddpt(br2, pos), bb2, mask, bb2->r.min);
368 pos.y += DY;
369 flushimage(display, 1);
370 return 1;
371 }
372
373 void
suspend(int s)374 suspend(int s)
375 {
376 suspended = s;
377 if (suspended)
378 setcursor(mousectl, &whitearrow);
379 else
380 setcursor(mousectl, nil);
381 if (!suspended)
382 drawpiece();
383 drawboard();
384 flushimage(display, 1);
385 }
386
387 void
pause(int t)388 pause(int t)
389 {
390 int s;
391 Alt alts[NALT+1];
392
393 alts[TIMER].c = timerc;
394 alts[TIMER].v = nil;
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;
407 alts[KBD].c = kbdc;
408 alts[KBD].v = nil;
409 alts[KBD].op = CHANRCV;
410 alts[NALT].op = CHANEND;
411
412 flushimage(display, 1);
413 for(;;)
414 switch(alt(alts)){
415 case SUSPEND:
416 if (!suspended && s) {
417 suspend(1);
418 } else if (suspended && !s) {
419 suspend(0);
420 lastmx = warp(mouse.xy, lastmx);
421 }
422 break;
423 case TIMER:
424 if(suspended)
425 break;
426 if((t -= tsleep) < 0)
427 return;
428 break;
429 case RESHAPE:
430 redraw(1);
431 break;
432 }
433 }
434
435 int
horiz(void)436 horiz(void)
437 {
438 int lev[MAXN];
439 int i, j, h;
440 Rectangle r;
441
442 h = 0;
443 for(i=0; i<NY; i++){
444 for(j=0; board[i][j]; j++)
445 if(j == NX-1){
446 lev[h++] = i;
447 break;
448 }
449 }
450 if(h == 0)
451 return 0;
452 r = rboard;
453 newscreen = 0;
454 for(j=0; j<h; 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);
459 }
460 for(i=0; i<3; i++){
461 pause(250);
462 if(newscreen){
463 drawboard();
464 break;
465 }
466 for(j=0; j<h; j++){
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);
470 }
471 flushimage(display, 1);
472 }
473 r = rboard;
474 for(j=0; j<h; j++){
475 i = NY - lev[j] - 1;
476 score(250+10*i*i);
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);
484 }
485 flushimage(display, 1);
486 return 1;
487 }
488
489 void
mright(void)490 mright(void)
491 {
492 if(!collide(Pt(pos.x+pcsz, pos.y), piece))
493 if(!collide(Pt(pos.x+pcsz, pos.y+pcsz-DY), piece)){
494 undrawpiece();
495 pos.x += pcsz;
496 drawpiece();
497 flushimage(display, 1);
498 }
499 }
500
501 void
mleft(void)502 mleft(void)
503 {
504 if(!collide(Pt(pos.x-pcsz, pos.y), piece))
505 if(!collide(Pt(pos.x-pcsz, pos.y+pcsz-DY), piece)){
506 undrawpiece();
507 pos.x -= pcsz;
508 drawpiece();
509 flushimage(display, 1);
510 }
511 }
512
513 void
rright(void)514 rright(void)
515 {
516 if(canfit(rotr(piece))){
517 setpiece(rotr(piece));
518 drawpiece();
519 flushimage(display, 1);
520 }
521 }
522
523 void
rleft(void)524 rleft(void)
525 {
526 if(canfit(rotl(piece))){
527 setpiece(rotl(piece));
528 drawpiece();
529 flushimage(display, 1);
530 }
531 }
532
533 int fusst = 0;
534 int
drop(int f)535 drop(int f)
536 {
537 if(f){
538 score(5L*(rboard.max.y-pos.y)/pcsz);
539 do; while(movepiece());
540 }
541 fusst = 0;
542 rest();
543 if(pos.y==rboard.min.y && !horiz())
544 return 1;
545 horiz();
546 setpiece(0);
547 pause(1500);
548 choosepiece();
549 lastmx = warp(mouse.xy, lastmx);
550 return 0;
551 }
552
553 int
play(void)554 play(void)
555 {
556 int i;
557 Mouse om;
558 int s;
559 Rune r;
560 Alt alts[NALT+1];
561
562 alts[TIMER].c = timerc;
563 alts[TIMER].v = nil;
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;
574 alts[KBD].c = kbdc;
575 alts[KBD].v = &r;
576 alts[KBD].op = CHANRCV;
577 alts[NALT].op = CHANEND;
578
579 dt = 64;
580 lastmx = -1;
581 lastmx = movemouse();
582 choosepiece();
583 lastmx = warp(mouse.xy, lastmx);
584 for(;;)
585 switch(alt(alts)){
586 case MOUSE:
587 if(suspended) {
588 om = mouse;
589 break;
590 }
591 if(lastmx < 0)
592 lastmx = mouse.xy.x;
593 if(mouse.xy.x > lastmx+DMOUSE){
594 mright();
595 lastmx = mouse.xy.x;
596 }
597 if(mouse.xy.x < lastmx-DMOUSE){
598 mleft();
599 lastmx = mouse.xy.x;
600 }
601 if(mouse.buttons&1 && !(om.buttons&1))
602 rleft();
603 if(mouse.buttons&2 && !(om.buttons&2))
604 if(drop(1))
605 return 1;
606 if(mouse.buttons&4 && !(om.buttons&4))
607 rright();
608 om = mouse;
609 break;
610 case SUSPEND:
611 if (!suspended && s)
612 suspend(1);
613 else
614 if (suspended && !s) {
615 suspend(0);
616 lastmx = warp(mouse.xy, lastmx);
617 }
618 break;
619 case RESHAPE:
620 redraw(1);
621 break;
622 case KBD:
623 if(suspended)
624 break;
625 switch(r){
626 case 'f':
627 case ';':
628 mright();
629 break;
630 case 'a':
631 case 'j':
632 mleft();
633 break;
634 case 'd':
635 case 'l':
636 rright();
637 break;
638 case 's':
639 case 'k':
640 rleft();
641 break;
642 case ' ':
643 if(drop(1))
644 return 1;
645 break;
646 }
647 break;
648 case TIMER:
649 if(suspended)
650 break;
651 dt -= tsleep;
652 if(dt < 0){
653 i = 1;
654 dt = 16 * (points+nrand(10000)-5000) / 10000;
655 if(dt >= 32){
656 i += (dt-32)/16;
657 dt = 32;
658 }
659 dt = 52-dt;
660 while(i-- > 0)
661 if(movepiece()==0 && ++fusst==40){
662 if(drop(0))
663 return 1;
664 break;
665 }
666 }
667 break;
668 }
669 }
670
671 void
setparms(void)672 setparms(void)
673 {
674 char buf[32];
675 int fd, n;
676
677 tsleep = 50;
678 fd = open("/dev/hz", OREAD);
679 if(fd < 0)
680 return;
681 n = read(fd, buf, sizeof buf - 1);
682 close(fd);
683 if(n < 0)
684 return;
685 buf[n] = '\0';
686 tsleep = strtoul(buf, 0, 10);
687 tsleep = (1000 + tsleep - 1) / tsleep;
688 }
689
690 void
timerproc(void * v)691 timerproc(void *v)
692 {
693 Channel *c;
694 void **arg;
695
696 arg = v;
697 c = (Channel*)arg;
698
699 for(;;){
700 sleep(tsleep);
701 send(c, nil);
702 }
703 }
704
705 void
suspproc(void *)706 suspproc(void *)
707 {
708 Mouse mouse;
709 Rune r;
710 int s;
711 Alt alts[NALT+1];
712
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;
720 alts[KBD].v = &r;
721 alts[KBD].op = CHANRCV;
722 alts[NALT].op = CHANEND;
723
724 s = 0;
725 for(;;)
726 switch(alt(alts)){
727 case MOUSE:
728 send(mousec, &mouse);
729 break;
730 case KBD:
731 switch(r){
732 case 'q':
733 case 'Q':
734 case 0x04:
735 case 0x7F:
736 threadexitsall(nil);
737 default:
738 if(s) {
739 s = 0;
740 send(suspc, &s);
741 } else
742 switch(r){
743 case 'z':
744 case 'Z':
745 case 'p':
746 case 'P':
747 case 0x1B:
748 s = 1;
749 send(suspc, &s);
750 break;
751 default:
752 send(kbdc, &r);
753 }
754 break;
755 }
756 }
757 }
758
759 void
redraw(int new)760 redraw(int new)
761 {
762 Rectangle r;
763 long dx, dy;
764
765 if(new && getwindow(display, Refmesg) < 0)
766 sysfatal("can't reattach to window");
767 r = screen->r;
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;
772 DY = dx / NX;
773 if(DY > dy / NY)
774 DY = dy / NY;
775 DY /= 8;
776 if(DY > 4)
777 DY = 4;
778 pcsz = DY*8;
779 DMOUSE = pcsz/3;
780 if(pcsz < 8)
781 sysfatal("screen too small: %d", pcsz);
782 rboard = screen->r;
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;
792 if(bb){
793 freeimage(bb);
794 freeimage(bbmask);
795 freeimage(bb2);
796 freeimage(bb2mask);
797 }
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);
805 drawboard();
806 setpiece(piece);
807 if(piece)
808 drawpiece();
809 lastmx = movemouse();
810 newscreen = 1;
811 flushimage(display, 1);
812 }
813
814 void
usage(void)815 usage(void)
816 {
817 fprint(2, "usage: %s\n", argv0);
818 exits("usage");
819 }
820
821 void
threadmain(int argc,char * argv[])822 threadmain(int argc, char *argv[])
823 {
824 Image *tb;
825 char buf[200];
826 int i, scores;
827 long starttime, endtime;
828
829 ARGBEGIN{
830 default:
831 usage();
832 }ARGEND
833 if(argc)
834 usage();
835
836 suspended = 0;
837 setparms();
838 snprint(buf, sizeof(buf), "%ds", N);
839 initdraw(0, 0, buf);
840 mousectl = initmouse(nil, display->image); /* BUG? */
841 if(mousectl == nil)
842 sysfatal("[45]s: mouse init failed: %r");
843 kbdctl = initkeyboard(nil); /* BUG? */
844 if(kbdctl == nil)
845 sysfatal("[45]s: keyboard init failed: %r");
846 starttime = time(0);
847 srand(starttime);
848 snprint(buf, sizeof(buf), "/sys/games/lib/%dscores", N);
849 scores = open(buf, OWRITE);
850 if(scores < 0)
851 sysfatal("can't open %s: %r", buf);
852 tb = 0;
853 if(screen->depth < 3){
854 tb = allocimage(display, Rect(0,0,16,16), 0, 1, -1);
855 if(tb == 0)
856 sysfatal("allocimage fail (tb)");
857 }
858 for(i = 0; i<NCOL; i++){
859 tx[i] = allocimage(display, Rect(0, 0, 16, 16), screen->chan, 1, txpix[i]);
860 if(tx[i] == 0)
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);
865 }
866 }
867 if(tb != 0)
868 freeimage(tb);
869
870 whitemask = allocimage(display, Rect(0,0,1,1), CMAP8, 1, setalpha(DWhite, 0x7F));
871 if(whitemask==0)
872 sysfatal("allocimage fail (whitemask)");
873
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);
881 points = 0;
882 memset(board, 0, sizeof(board));
883 redraw(0);
884 if(play()){
885 endtime = time(0);
886 fprint(scores, "%ld\t%s\t%lud\t%ld\n",
887 points, getuser(), starttime, endtime-starttime);
888 }
889 threadexitsall(nil);
890 exits(0);
891 }
892