Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/games/xs.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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 *
150
rotr(Piece *p)
151
{
152
	if(p->rot == 3)
153
		return p-3;
154
	return p+1;
155
}
156
 
157
Piece *
158
rotl(Piece *p)
159
{
160
	if(p->rot == 0)
161
		return p+3;
162
	return p-1;
163
}
164
 
165
int
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
514
rright(void)
515
{
516
	if(canfit(rotr(piece))){
517
		setpiece(rotr(piece));
518
		drawpiece();
519
		flushimage(display, 1);
520
	}
521
}
522
 
523
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
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
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
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
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
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
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
815
usage(void)
816
{
817
	fprint(2, "usage: %s\n", argv0);
818
	exits("usage");
819
}
820
 
821
void
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
}