xs.c 17 KB

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