xs.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. /*
  2. * engine for 4s, 5s, etc
  3. * need to define N and pieces table before including this
  4. */
  5. Cursor whitearrow = {
  6. {0, 0},
  7. {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
  8. 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC,
  9. 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
  10. 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
  11. {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C,
  12. 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C,
  13. 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C,
  14. 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
  15. };
  16. enum
  17. {
  18. CNone = 0,
  19. CBounds = 1,
  20. CPiece = 2,
  21. NX = 10,
  22. NY = 20,
  23. };
  24. enum{
  25. TIMER,
  26. MOUSE,
  27. RESHAPE,
  28. KBD,
  29. SUSPEND,
  30. NALT
  31. };
  32. #define NP (sizeof pieces/sizeof(Piece))
  33. char board[NY][NX];
  34. Rectangle rboard;
  35. Point pscore;
  36. Point scoresz;
  37. int pcsz = 32;
  38. Point pos;
  39. Image *bb, *bbmask, *bb2, *bb2mask;
  40. Image *whitemask;
  41. Rectangle br, br2;
  42. long points;
  43. int dt;
  44. int DY;
  45. int DMOUSE;
  46. int lastmx;
  47. Mouse mouse;
  48. int newscreen;
  49. Channel *timerc;
  50. Channel *suspc;
  51. Channel *mousec;
  52. Channel *kbdc;
  53. Mousectl *mousectl;
  54. Keyboardctl *kbdctl;
  55. int suspended;
  56. void redraw(int);
  57. int tsleep;
  58. Piece *piece;
  59. #define NCOL 10
  60. uchar txbits[NCOL][32]={
  61. {0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
  62. 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
  63. 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
  64. 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF},
  65. {0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
  66. 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
  67. 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
  68. 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77},
  69. {0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
  70. 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
  71. 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
  72. 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
  73. {0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
  74. 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
  75. 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
  76. 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
  77. {0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
  78. 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
  79. 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
  80. 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88},
  81. {0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
  82. 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
  83. 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
  84. 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00},
  85. {0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
  86. 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
  87. 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
  88. 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
  89. {0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
  90. 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
  91. 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
  92. 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
  93. {0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
  94. 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
  95. 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
  96. 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC},
  97. {0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
  98. 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
  99. 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
  100. 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33},
  101. };
  102. int txpix[NCOL] = {
  103. DYellow, /* yellow */
  104. DCyan, /* cyan */
  105. DGreen, /* lime green */
  106. DGreyblue, /* slate */
  107. DRed, /* red */
  108. DGreygreen, /* olive green */
  109. DBlue, /* blue */
  110. 0xFF55AAFF, /* pink */
  111. 0xFFAAFFFF, /* lavender */
  112. 0xBB005DFF, /* maroon */
  113. };
  114. Image *tx[NCOL];
  115. int
  116. movemouse(void)
  117. {
  118. mouse.xy = Pt(rboard.min.x + Dx(rboard)/2, rboard.min.y +Dy(rboard)/2);
  119. moveto(mousectl, mouse.xy);
  120. return mouse.xy.x;
  121. }
  122. int
  123. warp(Point p, int x)
  124. {
  125. if (!suspended && piece != nil) {
  126. x = pos.x + piece->sz.x*pcsz/2;
  127. if (p.y < rboard.min.y)
  128. p.y = rboard.min.y;
  129. if (p.y >= rboard.max.y)
  130. p.y = rboard.max.y - 1;
  131. moveto(mousectl, Pt(x, p.y));
  132. }
  133. return x;
  134. }
  135. Piece *
  136. rotr(Piece *p)
  137. {
  138. if(p->rot == 3)
  139. return p-3;
  140. return p+1;
  141. }
  142. Piece *
  143. rotl(Piece *p)
  144. {
  145. if(p->rot == 0)
  146. return p+3;
  147. return p-1;
  148. }
  149. int
  150. collide(Point pt, Piece *p)
  151. {
  152. int i;
  153. int c = CNone;
  154. pt.x = (pt.x - rboard.min.x) / pcsz;
  155. pt.y = (pt.y - rboard.min.y) / pcsz;
  156. for(i=0; i<N; i++){
  157. pt.x += p->d[i].x;
  158. pt.y += p->d[i].y;
  159. if(pt.x<0 || pt.x>=NX || pt.y<0 || pt.y>=NY)
  160. c |= CBounds;
  161. if(board[pt.y][pt.x])
  162. c |= CPiece;
  163. }
  164. return c;
  165. }
  166. int
  167. collider(Point pt, Point pmax)
  168. {
  169. int i, j, pi, pj, n, m;
  170. pi = (pt.x - rboard.min.x) / pcsz;
  171. pj = (pt.y - rboard.min.y) / pcsz;
  172. n = pmax.x / pcsz;
  173. m = pmax.y / pcsz + 1;
  174. for(i = pi; i < pi+n && i < NX; i++)
  175. for(j = pj; j < pj+m && j < NY; j++)
  176. if(board[j][i])
  177. return 1;
  178. return 0;
  179. }
  180. void
  181. setpiece(Piece *p){
  182. int i;
  183. Rectangle r, r2;
  184. Point op, delta;
  185. draw(bb, bb->r, display->white, nil, ZP);
  186. draw(bbmask, bbmask->r, display->transparent, nil, ZP);
  187. br = Rect(0, 0, 0, 0);
  188. br2 = br;
  189. piece = p;
  190. if(p == 0)
  191. return;
  192. r.min = bb->r.min;
  193. for(i=0; i<N; i++){
  194. r.min.x += p->d[i].x*pcsz;
  195. r.min.y += p->d[i].y*pcsz;
  196. r.max.x = r.min.x + pcsz;
  197. r.max.y = r.min.y + pcsz;
  198. if(i == 0){
  199. draw(bb, r, display->black, nil, ZP);
  200. draw(bb, insetrect(r, 1), tx[piece->tx], nil, ZP);
  201. draw(bbmask, r, display->opaque, nil, ZP);
  202. op = r.min;
  203. }else{
  204. draw(bb, r, bb, nil, op);
  205. draw(bbmask, r, bbmask, nil, op);
  206. }
  207. if(br.max.x < r.max.x)
  208. br.max.x = r.max.x;
  209. if(br.max.y < r.max.y)
  210. br.max.y = r.max.y;
  211. }
  212. br.max = subpt(br.max, bb->r.min);
  213. delta = Pt(0,DY);
  214. br2.max = addpt(br.max, delta);
  215. r = rectaddpt(br, bb2->r.min);
  216. r2 = rectaddpt(br2, bb2->r.min);
  217. draw(bb2, r2, display->white, nil, ZP);
  218. draw(bb2, rectaddpt(r,delta), bb, nil, bb->r.min);
  219. draw(bb2mask, r2, display->transparent, nil, ZP);
  220. draw(bb2mask, r, display->opaque, bbmask, bb->r.min);
  221. draw(bb2mask, rectaddpt(r,delta), display->opaque, bbmask, bb->r.min);
  222. }
  223. void
  224. drawpiece(void){
  225. draw(screen, rectaddpt(br, pos), bb, bbmask, bb->r.min);
  226. if (suspended)
  227. draw(screen, rectaddpt(br, pos), display->white, whitemask, ZP);
  228. }
  229. void
  230. undrawpiece(void)
  231. {
  232. Image *mask = nil;
  233. if(collider(pos, br.max))
  234. mask = bbmask;
  235. draw(screen, rectaddpt(br, pos), display->white, mask, bb->r.min);
  236. }
  237. void
  238. rest(void)
  239. {
  240. int i;
  241. Point pt;
  242. pt = divpt(subpt(pos, rboard.min), pcsz);
  243. for(i=0; i<N; i++){
  244. pt.x += piece->d[i].x;
  245. pt.y += piece->d[i].y;
  246. board[pt.y][pt.x] = piece->tx+16;
  247. }
  248. }
  249. int
  250. canfit(Piece *p)
  251. {
  252. static int dx[]={0, -1, 1, -2, 2, -3, 3, 4, -4};
  253. int i, j;
  254. Point z;
  255. j = N + 1;
  256. if(j >= 4){
  257. j = p->sz.x;
  258. if(j<p->sz.y)
  259. j = p->sz.y;
  260. j = 2*j-1;
  261. }
  262. for(i=0; i<j; i++){
  263. z.x = pos.x + dx[i]*pcsz;
  264. z.y = pos.y;
  265. if(!collide(z, p)){
  266. z.y = pos.y + pcsz-1;
  267. if(!collide(z, p)){
  268. undrawpiece();
  269. pos.x = z.x;
  270. return 1;
  271. }
  272. }
  273. }
  274. return 0;
  275. }
  276. void
  277. score(int p)
  278. {
  279. char buf[128];
  280. points += p;
  281. snprint(buf, sizeof(buf), "%.6ld", points);
  282. draw(screen, Rpt(pscore, addpt(pscore, scoresz)), display->white, nil, ZP);
  283. string(screen, pscore, display->black, ZP, font, buf);
  284. }
  285. void
  286. drawsq(Image *b, Point p, int ptx){
  287. Rectangle r;
  288. r.min = p;
  289. r.max.x = r.min.x+pcsz;
  290. r.max.y = r.min.y+pcsz;
  291. draw(b, r, display->black, nil, ZP);
  292. draw(b, insetrect(r, 1), tx[ptx], nil, ZP);
  293. }
  294. void
  295. drawboard(void)
  296. {
  297. int i, j;
  298. border(screen, insetrect(rboard, -2), 2, display->black, ZP);
  299. draw(screen, Rect(rboard.min.x, rboard.min.y-2, rboard.max.x, rboard.min.y),
  300. display->white, nil, ZP);
  301. for(i=0; i<NY; i++)
  302. for(j=0; j<NX; j++)
  303. if(board[i][j])
  304. drawsq(screen, Pt(rboard.min.x+j*pcsz, rboard.min.y+i*pcsz), board[i][j]-16);
  305. score(0);
  306. if (suspended)
  307. draw(screen, screen->r, display->white, whitemask, ZP);
  308. }
  309. void
  310. choosepiece(void)
  311. {
  312. int i;
  313. do{
  314. i = nrand(NP);
  315. setpiece(&pieces[i]);
  316. pos = rboard.min;
  317. pos.x += nrand(NX)*pcsz;
  318. }while(collide(Pt(pos.x, pos.y+pcsz-DY), piece));
  319. drawpiece();
  320. flushimage(display, 1);
  321. }
  322. int
  323. movepiece(void)
  324. {
  325. Image *mask = nil;
  326. if(collide(Pt(pos.x, pos.y+pcsz), piece))
  327. return 0;
  328. if(collider(pos, br2.max))
  329. mask = bb2mask;
  330. draw(screen, rectaddpt(br2, pos), bb2, mask, bb2->r.min);
  331. pos.y += DY;
  332. flushimage(display, 1);
  333. return 1;
  334. }
  335. void
  336. suspend(int s)
  337. {
  338. suspended = s;
  339. if (suspended)
  340. setcursor(mousectl, &whitearrow);
  341. else
  342. setcursor(mousectl, nil);
  343. if (!suspended)
  344. drawpiece();
  345. drawboard();
  346. flushimage(display, 1);
  347. }
  348. void
  349. pause(int t)
  350. {
  351. int s;
  352. Alt alts[NALT+1];
  353. alts[TIMER].c = timerc;
  354. alts[TIMER].v = nil;
  355. alts[TIMER].op = CHANRCV;
  356. alts[SUSPEND].c = suspc;
  357. alts[SUSPEND].v = &s;
  358. alts[SUSPEND].op = CHANRCV;
  359. alts[RESHAPE].c = mousectl->resizec;
  360. alts[RESHAPE].v = nil;
  361. alts[RESHAPE].op = CHANRCV;
  362. // avoid hanging up those writing ong mousec and kbdc
  363. // so just accept it all and keep mouse up-to-date
  364. alts[MOUSE].c = mousec;
  365. alts[MOUSE].v = &mouse;
  366. alts[MOUSE].op = CHANRCV;
  367. alts[KBD].c = kbdc;
  368. alts[KBD].v = nil;
  369. alts[KBD].op = CHANRCV;
  370. alts[NALT].op = CHANEND;
  371. flushimage(display, 1);
  372. for(;;)
  373. switch(alt(alts)){
  374. case SUSPEND:
  375. if (!suspended && s) {
  376. suspend(1);
  377. } else if (suspended && !s) {
  378. suspend(0);
  379. lastmx = warp(mouse.xy, lastmx);
  380. }
  381. break;
  382. case TIMER:
  383. if(suspended)
  384. break;
  385. if((t -= tsleep) < 0)
  386. return;
  387. break;
  388. case RESHAPE:
  389. redraw(1);
  390. break;
  391. }
  392. }
  393. int
  394. horiz(void)
  395. {
  396. int lev[N];
  397. int i, j, h;
  398. Rectangle r;
  399. h = 0;
  400. for(i=0; i<NY; i++){
  401. for(j=0; board[i][j]; j++)
  402. if(j == NX-1){
  403. lev[h++] = i;
  404. break;
  405. }
  406. }
  407. if(h == 0)
  408. return 0;
  409. r = rboard;
  410. newscreen = 0;
  411. for(j=0; j<h; j++){
  412. r.min.y = rboard.min.y + lev[j]*pcsz;
  413. r.max.y = r.min.y + pcsz;
  414. draw(screen, r, display->white, whitemask, ZP);
  415. flushimage(display, 1);
  416. }
  417. for(i=0; i<3; i++){
  418. pause(250);
  419. if(newscreen){
  420. drawboard();
  421. break;
  422. }
  423. for(j=0; j<h; j++){
  424. r.min.y = rboard.min.y + lev[j]*pcsz;
  425. r.max.y = r.min.y + pcsz;
  426. draw(screen, r, display->white, whitemask, ZP);
  427. }
  428. flushimage(display, 1);
  429. }
  430. r = rboard;
  431. for(j=0; j<h; j++){
  432. i = NY - lev[j] - 1;
  433. score(250+10*i*i);
  434. r.min.y = rboard.min.y;
  435. r.max.y = rboard.min.y+lev[j]*pcsz;
  436. draw(screen, rectaddpt(r, Pt(0,pcsz)), screen, nil, r.min);
  437. r.max.y = rboard.min.y+pcsz;
  438. draw(screen, r, display->white, nil, ZP);
  439. memcpy(&board[1][0], &board[0][0], NX*lev[j]);
  440. memset(&board[0][0], 0, NX);
  441. }
  442. flushimage(display, 1);
  443. return 1;
  444. }
  445. void
  446. mright(void)
  447. {
  448. if(!collide(Pt(pos.x+pcsz, pos.y), piece))
  449. if(!collide(Pt(pos.x+pcsz, pos.y+pcsz-DY), piece)){
  450. undrawpiece();
  451. pos.x += pcsz;
  452. drawpiece();
  453. flushimage(display, 1);
  454. }
  455. }
  456. void
  457. mleft(void)
  458. {
  459. if(!collide(Pt(pos.x-pcsz, pos.y), piece))
  460. if(!collide(Pt(pos.x-pcsz, pos.y+pcsz-DY), piece)){
  461. undrawpiece();
  462. pos.x -= pcsz;
  463. drawpiece();
  464. flushimage(display, 1);
  465. }
  466. }
  467. void
  468. rright(void)
  469. {
  470. if(canfit(rotr(piece))){
  471. setpiece(rotr(piece));
  472. drawpiece();
  473. flushimage(display, 1);
  474. }
  475. }
  476. void
  477. rleft(void)
  478. {
  479. if(canfit(rotl(piece))){
  480. setpiece(rotl(piece));
  481. drawpiece();
  482. flushimage(display, 1);
  483. }
  484. }
  485. int fusst = 0;
  486. int
  487. drop(int f)
  488. {
  489. if(f){
  490. score(5L*(rboard.max.y-pos.y)/pcsz);
  491. do; while(movepiece());
  492. }
  493. fusst = 0;
  494. rest();
  495. if(pos.y==rboard.min.y && !horiz())
  496. return 1;
  497. horiz();
  498. setpiece(0);
  499. pause(1500);
  500. choosepiece();
  501. lastmx = warp(mouse.xy, lastmx);
  502. return 0;
  503. }
  504. int
  505. play(void)
  506. {
  507. int i;
  508. Mouse om;
  509. int s;
  510. Rune r;
  511. Alt alts[NALT+1];
  512. alts[TIMER].c = timerc;
  513. alts[TIMER].v = nil;
  514. alts[TIMER].op = CHANRCV;
  515. alts[MOUSE].c = mousec;
  516. alts[MOUSE].v = &mouse;
  517. alts[MOUSE].op = CHANRCV;
  518. alts[SUSPEND].c = suspc;
  519. alts[SUSPEND].v = &s;
  520. alts[SUSPEND].op = CHANRCV;
  521. alts[RESHAPE].c = mousectl->resizec;
  522. alts[RESHAPE].v = nil;
  523. alts[RESHAPE].op = CHANRCV;
  524. alts[KBD].c = kbdc;
  525. alts[KBD].v = &r;
  526. alts[KBD].op = CHANRCV;
  527. alts[NALT].op = CHANEND;
  528. dt = 64;
  529. lastmx = -1;
  530. lastmx = movemouse();
  531. choosepiece();
  532. lastmx = warp(mouse.xy, lastmx);
  533. for(;;)
  534. switch(alt(alts)){
  535. case MOUSE:
  536. if(suspended) {
  537. om = mouse;
  538. break;
  539. }
  540. if(lastmx < 0)
  541. lastmx = mouse.xy.x;
  542. if(mouse.xy.x > lastmx+DMOUSE){
  543. mright();
  544. lastmx = mouse.xy.x;
  545. }
  546. if(mouse.xy.x < lastmx-DMOUSE){
  547. mleft();
  548. lastmx = mouse.xy.x;
  549. }
  550. if(mouse.buttons&1 && !(om.buttons&1))
  551. rleft();
  552. if(mouse.buttons&2 && !(om.buttons&2))
  553. if(drop(1))
  554. return 1;
  555. if(mouse.buttons&4 && !(om.buttons&4))
  556. rright();
  557. om = mouse;
  558. break;
  559. case SUSPEND:
  560. if (!suspended && s)
  561. suspend(1);
  562. else
  563. if (suspended && !s) {
  564. suspend(0);
  565. lastmx = warp(mouse.xy, lastmx);
  566. }
  567. break;
  568. case RESHAPE:
  569. redraw(1);
  570. break;
  571. case KBD:
  572. if(suspended)
  573. break;
  574. switch(r){
  575. case 'f':
  576. case ';':
  577. mright();
  578. break;
  579. case 'a':
  580. case 'j':
  581. mleft();
  582. break;
  583. case 'd':
  584. case 'l':
  585. rright();
  586. break;
  587. case 's':
  588. case 'k':
  589. rleft();
  590. break;
  591. case ' ':
  592. if(drop(1))
  593. return 1;
  594. break;
  595. }
  596. break;
  597. case TIMER:
  598. if(suspended)
  599. break;
  600. dt -= tsleep;
  601. if(dt < 0){
  602. i = 1;
  603. dt = 16 * (points+nrand(10000)-5000) / 10000;
  604. if(dt >= 32){
  605. i += (dt-32)/16;
  606. dt = 32;
  607. }
  608. dt = 52-dt;
  609. while(i-- > 0)
  610. if(movepiece()==0 && ++fusst==40){
  611. if(drop(0))
  612. return 1;
  613. break;
  614. }
  615. }
  616. break;
  617. }
  618. return 0; /* not reached */
  619. }
  620. void
  621. setparms(void)
  622. {
  623. char buf[32];
  624. int fd, n;
  625. tsleep = 50;
  626. fd = open("/dev/hz", OREAD);
  627. if(fd < 0)
  628. return;
  629. n = read(fd, buf, sizeof buf - 1);
  630. close(fd);
  631. if(n < 0)
  632. return;
  633. buf[n] = '\0';
  634. tsleep = strtoul(buf, 0, 10);
  635. tsleep = (1000 + tsleep - 1) / tsleep;
  636. }
  637. void
  638. timerproc(void *v)
  639. {
  640. Channel *c;
  641. void **arg;
  642. arg = v;
  643. c = (Channel*)arg;
  644. for(;;){
  645. sleep(tsleep);
  646. send(c, nil);
  647. }
  648. }
  649. void
  650. suspproc(void *)
  651. {
  652. Mouse mouse;
  653. Point lastm;
  654. Rune r;
  655. int s;
  656. Alt alts[NALT+1];
  657. alts[TIMER].op = CHANNOP;
  658. alts[MOUSE].c = mousectl->c;
  659. alts[MOUSE].v = &mouse;
  660. alts[MOUSE].op = CHANRCV;
  661. alts[SUSPEND].op = CHANNOP;
  662. alts[RESHAPE].op = CHANNOP;
  663. alts[KBD].c = kbdctl->c;
  664. alts[KBD].v = &r;
  665. alts[KBD].op = CHANRCV;
  666. alts[NALT].op = CHANEND;
  667. s = 0;
  668. lastm = Pt(-1,-1);
  669. for(;;)
  670. switch(alt(alts)){
  671. case MOUSE:
  672. send(mousec, &mouse);
  673. if(lastm.x < 0 || lastm.y < 0)
  674. lastm = mouse.xy;
  675. if(s && ptinrect(mouse.xy, rboard) && !ptinrect(lastm, rboard)){
  676. s = 0;
  677. send(suspc, &s);
  678. } else
  679. if(!s && !ptinrect(mouse.xy,rboard)){
  680. s = 1;
  681. send(suspc, &s);
  682. }
  683. lastm = mouse.xy;
  684. break;
  685. case KBD:
  686. switch(r){
  687. case 'q':
  688. case 'Q':
  689. case 0x04:
  690. case 0x7F:
  691. threadexitsall(nil);
  692. default:
  693. if(s) {
  694. s = 0;
  695. send(suspc, &s);
  696. } else
  697. switch(r){
  698. case 'z':
  699. case 'Z':
  700. case 'p':
  701. case 'P':
  702. case 0x1B:
  703. s = 1;
  704. send(suspc, &s);
  705. break;
  706. default:
  707. send(kbdc, &r);
  708. }
  709. break;
  710. }
  711. }
  712. }
  713. void
  714. redraw(int new)
  715. {
  716. Rectangle r;
  717. long dx, dy;
  718. if(new && getwindow(display, Refmesg) < 0)
  719. sysfatal("can't reattach to window");
  720. r = screen->r;
  721. pos.x = (pos.x - rboard.min.x) / pcsz;
  722. pos.y = (pos.y - rboard.min.y) / pcsz;
  723. dx = r.max.x - r.min.x;
  724. dy = r.max.y - r.min.y - 2*32;
  725. DY = dx / NX;
  726. if(DY > dy / NY)
  727. DY = dy / NY;
  728. DY /= 8;
  729. if(DY > 4)
  730. DY = 4;
  731. pcsz = DY*8;
  732. DMOUSE = pcsz/3;
  733. if(pcsz < 8)
  734. sysfatal("screen too small: %d", pcsz);
  735. rboard = screen->r;
  736. rboard.min.x += (dx-pcsz*NX)/2;
  737. rboard.min.y += (dy-pcsz*NY)/2+32;
  738. rboard.max.x = rboard.min.x+NX*pcsz;
  739. rboard.max.y = rboard.min.y+NY*pcsz;
  740. pscore.x = rboard.min.x+8;
  741. pscore.y = rboard.min.y-32;
  742. scoresz = stringsize(font, "000000");
  743. pos.x = pos.x*pcsz + rboard.min.x;
  744. pos.y = pos.y*pcsz + rboard.min.y;
  745. if(bb){
  746. freeimage(bb);
  747. freeimage(bbmask);
  748. freeimage(bb2);
  749. freeimage(bb2mask);
  750. }
  751. bb = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), screen->chan, 0, 0);
  752. bbmask = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), GREY1, 0, 0);
  753. bb2 = allocimage(display, Rect(0,0,N*pcsz,N*pcsz+DY), screen->chan, 0, 0);
  754. bb2mask = allocimage(display, bb2->r, GREY1, 0, 0);
  755. if(bb==0 || bbmask==0 || bb2==0 || bb2mask==0)
  756. sysfatal("allocimage fail (bb)");
  757. draw(screen, screen->r, display->white, nil, ZP);
  758. drawboard();
  759. setpiece(piece);
  760. if(piece)
  761. drawpiece();
  762. lastmx = movemouse();
  763. newscreen = 1;
  764. flushimage(display, 1);
  765. }
  766. void
  767. threadmain(int argc, char *argv[])
  768. {
  769. Image *tb;
  770. char buf[200];
  771. int i, scores;
  772. long starttime, endtime;
  773. ARGBEGIN{
  774. }ARGEND
  775. suspended = 0;
  776. setparms();
  777. snprint(buf, sizeof(buf), "%ds", N);
  778. initdraw(0, 0, buf);
  779. mousectl = initmouse(nil, display->image); /* BUG? */
  780. if(mousectl == nil)
  781. sysfatal("[45]s: mouse init failed: %r");
  782. kbdctl = initkeyboard(nil); /* BUG? */
  783. if(kbdctl == nil)
  784. sysfatal("[45]s: keyboard init failed: %r");
  785. starttime = time(0);
  786. srand(starttime);
  787. snprint(buf, sizeof(buf), "/sys/games/lib/%dscores", N);
  788. scores = open(buf, OWRITE);
  789. if(scores < 0)
  790. sysfatal("can't open %s: %r", buf);
  791. tb = 0;
  792. if(screen->depth < 3){
  793. tb = allocimage(display, Rect(0,0,16,16), 0, 1, -1);
  794. if(tb == 0)
  795. sysfatal("allocimage fail (tb)");
  796. }
  797. for(i = 0; i<NCOL; i++){
  798. tx[i] = allocimage(display, Rect(0, 0, 16, 16), screen->chan, 1, txpix[i]);
  799. if(tx[i] == 0)
  800. sysfatal("allocimage fail (tx)");
  801. if(screen->depth < 3){
  802. loadimage(tb, tb->r, txbits[i], 32);
  803. draw(tx[i], tx[i]->r, tb, nil, ZP);
  804. }
  805. }
  806. if(tb != 0)
  807. freeimage(tb);
  808. whitemask = allocimage(display, Rect(0,0,1,1), CMAP8, 1, setalpha(DWhite, 0x7F));
  809. if(whitemask==0)
  810. sysfatal("allocimage fail (whitemask)");
  811. threadsetname("4s-5s");
  812. timerc= chancreate(sizeof(int), 0);
  813. proccreate(timerproc, timerc, 1024);
  814. suspc= chancreate(sizeof(int), 0);
  815. mousec= chancreate(sizeof(Mouse), 0);
  816. kbdc= chancreate(sizeof(Rune), 0);
  817. threadcreate(suspproc, nil, 1024);
  818. points = 0;
  819. memset(board, 0, sizeof(board));
  820. redraw(0);
  821. if(play()){
  822. endtime = time(0);
  823. fprint(scores, "%ld\t%s\t%lud\t%ld\n",
  824. points, getuser(), starttime, endtime-starttime);
  825. }
  826. threadexitsall(nil);
  827. exits(0);
  828. }