Browse Source

Plan 9 from Bell Labs 2005-10-03

David du Colombier 18 years ago
parent
commit
0f4b670ae5

+ 16 - 13
dist/replica/_plan9.db

@@ -396,7 +396,7 @@
 386/bin/snap - 775 sys sys 1125346012 303711
 386/bin/snapfs - 775 sys sys 1125346013 372678
 386/bin/sniffer - 775 sys sys 1038443185 99028
-386/bin/snoopy - 775 sys sys 1125346014 157537
+386/bin/snoopy - 775 sys sys 1128222506 168209
 386/bin/sort - 775 sys sys 1125346014 82276
 386/bin/spin - 775 sys sys 1127360605 758519
 386/bin/split - 775 sys sys 1125346015 75635
@@ -503,7 +503,7 @@
 386/bin/webcookies - 775 sys sys 1125346039 161625
 386/bin/webfs - 775 sys sys 1127360616 350516
 386/bin/webfsget - 775 sys sys 1115950144 39143
-386/bin/wikifs - 775 sys sys 1125889831 202134
+386/bin/wikifs - 775 sys sys 1128222506 202486
 386/bin/winwatch - 775 sys sys 1115950145 154555
 386/bin/xd - 775 sys sys 1125346040 64044
 386/bin/xmr - 775 sys sys 1115950145 40157
@@ -7312,7 +7312,7 @@ sys/man/1/mkdir - 664 sys sys 1082593141 717
 sys/man/1/mlmgr - 664 sys sys 1116513886 2542
 sys/man/1/ms2html - 664 sys sys 960001562 856
 sys/man/1/nedmail - 664 sys sys 1114697978 6820
-sys/man/1/netstat - 664 sys sys 953344523 827
+sys/man/1/netstat - 664 sys sys 1128255431 942
 sys/man/1/news - 664 sys sys 1113743329 1151
 sys/man/1/nm - 664 sys sys 944959673 1539
 sys/man/1/ns - 664 sys sys 944959677 893
@@ -7919,7 +7919,7 @@ sys/src/9/pc/devarch.c - 664 sys sys 1115566123 18554
 sys/src/9/pc/devether.c - 664 sys sys 1116173410 10327
 sys/src/9/pc/devfloppy.c - 664 sys sys 1055689885 20024
 sys/src/9/pc/devi82365.c - 664 sys sys 1099761153 20505
-sys/src/9/pc/devlm78.c - 664 sys sys 1091129037 6255
+sys/src/9/pc/devlm78.c - 664 sys sys 1128255048 6291
 sys/src/9/pc/devlml.c - 664 sys sys 1026847636 7486
 sys/src/9/pc/devlml.h - 664 sys sys 1026847636 2948
 sys/src/9/pc/devlpt.c - 664 sys sys 1015014514 4420
@@ -9218,7 +9218,7 @@ sys/src/cmd/9660srv/9660srv.c - 664 sys sys 1115039888 17143
 sys/src/cmd/9660srv/dat.h - 664 sys sys 1091904429 2097
 sys/src/cmd/9660srv/data.c - 664 sys sys 944960735 373
 sys/src/cmd/9660srv/fns.h - 664 sys sys 1019425186 428
-sys/src/cmd/9660srv/iobuf.c - 664 sys sys 1022085197 3125
+sys/src/cmd/9660srv/iobuf.c - 664 sys sys 1128255068 3126
 sys/src/cmd/9660srv/iso9660.h - 664 sys sys 1014924873 2607
 sys/src/cmd/9660srv/main.c - 664 sys sys 1020313483 9680
 sys/src/cmd/9660srv/mkfile - 664 sys sys 1048644372 238
@@ -10031,7 +10031,7 @@ sys/src/cmd/fossil/9auth.c - 664 sys sys 1061530721 3393
 sys/src/cmd/fossil/9dir.c - 664 sys sys 1085333382 2219
 sys/src/cmd/fossil/9excl.c - 664 sys sys 1042005502 1887
 sys/src/cmd/fossil/9fid.c - 664 sys sys 1045600016 5521
-sys/src/cmd/fossil/9fsys.c - 664 sys sys 1104858629 33296
+sys/src/cmd/fossil/9fsys.c - 664 sys sys 1128255102 33313
 sys/src/cmd/fossil/9lstn.c - 664 sys sys 1042005503 2865
 sys/src/cmd/fossil/9p.c - 664 sys sys 1104940048 21862
 sys/src/cmd/fossil/9ping.c - 664 sys sys 1042005503 1563
@@ -12264,7 +12264,7 @@ sys/src/cmd/ndb/mkhash.c - 664 sys sys 1014926160 2899
 sys/src/cmd/ndb/mkhosts.c - 664 sys sys 957402054 4294
 sys/src/cmd/ndb/query.c - 664 sys sys 1078840016 1120
 sys/src/cmd/ndb/time.c - 664 sys sys 957402055 321
-sys/src/cmd/netstat.c - 664 sys sys 1078839959 3846
+sys/src/cmd/netstat.c - 664 sys sys 1128255434 4086
 sys/src/cmd/news.c - 664 sys sys 1014926614 3778
 sys/src/cmd/nfs.c - 664 sys sys 1050068720 31096
 sys/src/cmd/nm.c - 664 sys sys 1073313392 4912
@@ -13782,8 +13782,8 @@ sys/src/fs/sony/mem.h - 664 sys sys 1015110103 2865
 sys/src/fs/sony/mkfile - 664 sys sys 1091803623 1594
 sys/src/fs/worms - 664 sys sys 1015110031 2806
 sys/src/games - 20000000775 sys sys 1095792091 0
-sys/src/games/4s.c - 664 sys sys 1120564580 1486
-sys/src/games/5s.c - 664 sys sys 1120564580 3822
+sys/src/games/4s.c - 664 sys sys 1128271724 1285
+sys/src/games/5s.c - 664 sys sys 1128271724 3621
 sys/src/games/catback.p - 664 sys sys 1108184106 35763
 sys/src/games/catclock.c - 664 sys sys 1108184106 10354
 sys/src/games/eyes.p - 664 sys sys 1108184106 1128
@@ -13795,7 +13795,7 @@ sys/src/games/mahjongg/mahjongg.c - 664 sys sys 1095792293 3452
 sys/src/games/mahjongg/mahjongg.h - 664 sys sys 1095792293 1606
 sys/src/games/mahjongg/mkfile - 664 sys sys 1095792293 230
 sys/src/games/memo.c - 664 sys sys 1125514848 6321
-sys/src/games/mkfile - 664 sys sys 1118672535 567
+sys/src/games/mkfile - 664 sys sys 1128271766 586
 sys/src/games/music - 20000000775 sys sys 1103793915 0
 sys/src/games/music/Readme - 664 sys sys 1103793914 488
 sys/src/games/music/debug.h - 664 sys sys 1103793914 201
@@ -13864,7 +13864,8 @@ sys/src/games/sudoku/levels.c - 664 sys sys 1117226433 3186
 sys/src/games/sudoku/mkfile - 664 sys sys 1117226432 218
 sys/src/games/sudoku/sudoku.c - 664 sys sys 1117636441 7809
 sys/src/games/sudoku/sudoku.h - 664 sys sys 1117226432 1159
-sys/src/games/xs.h - 664 sys sys 1120564579 17389
+sys/src/games/xs.c - 664 sys sys 1128271724 17124
+sys/src/games/xs.h - 664 sys sys 1128271724 292
 sys/src/lib9p - 20000000775 sys sys 1015023311 0
 sys/src/lib9p/_post.c - 664 sys sys 1103565871 1642
 sys/src/lib9p/dirread.c - 664 sys sys 1015023310 641
@@ -14973,5 +14974,7 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
-386/bin/wikifs - 775 sys sys 1128222506 202486
-386/bin/snoopy - 775 sys sys 1128222506 168209
+386/bin/games/4s - 775 sys sys 1128309084 177871
+386/bin/games/5s - 775 sys sys 1128309084 180159
+386/bin/netstat - 775 sys sys 1128309084 84664
+386/bin/fossil/fossil - 775 sys sys 1128309083 360426

+ 14 - 13
dist/replica/plan9.db

@@ -231,7 +231,7 @@
 386/bin/fossil/conf - 775 sys sys 1085077052 1506
 386/bin/fossil/flchk - 775 sys sys 1125345972 237504
 386/bin/fossil/flfmt - 775 sys sys 1125345973 245653
-386/bin/fossil/fossil - 775 sys sys 1119496648 360407
+386/bin/fossil/fossil - 775 sys sys 1128309083 360426
 386/bin/fossil/last - 775 sys sys 1115950071 63298
 386/bin/freq - 775 sys sys 1125345973 61793
 386/bin/fs - 20000000775 sys sys 954380769 0
@@ -245,8 +245,8 @@
 386/bin/fs/zipfs - 775 sys sys 1125345976 109079
 386/bin/ftpfs - 775 sys sys 1127360573 272753
 386/bin/games - 20000000775 sys sys 1096298711 0
-386/bin/games/4s - 775 sys sys 1120619353 177844
-386/bin/games/5s - 775 sys sys 1120619353 180356
+386/bin/games/4s - 775 sys sys 1128309084 177871
+386/bin/games/5s - 775 sys sys 1128309084 180159
 386/bin/games/catclock - 775 sys sys 1115950075 140798
 386/bin/games/juggle - 775 sys sys 1118202754 125319
 386/bin/games/jukebox - 775 sys sys 1105589128 264821
@@ -341,7 +341,7 @@
 386/bin/ndb/mkhosts - 775 sys sys 1125346000 84954
 386/bin/ndb/query - 775 sys sys 1125346000 83041
 386/bin/netkey - 775 sys sys 1115950098 72307
-386/bin/netstat - 775 sys sys 1125346001 84376
+386/bin/netstat - 775 sys sys 1128309084 84664
 386/bin/news - 775 sys sys 1125346001 71660
 386/bin/nfs - 775 sys sys 1125346002 315509
 386/bin/nm - 775 sys sys 1125346002 121794
@@ -7312,7 +7312,7 @@ sys/man/1/mkdir - 664 sys sys 1082593141 717
 sys/man/1/mlmgr - 664 sys sys 1116513886 2542
 sys/man/1/ms2html - 664 sys sys 960001562 856
 sys/man/1/nedmail - 664 sys sys 1114697978 6820
-sys/man/1/netstat - 664 sys sys 953344523 827
+sys/man/1/netstat - 664 sys sys 1128255431 942
 sys/man/1/news - 664 sys sys 1113743329 1151
 sys/man/1/nm - 664 sys sys 944959673 1539
 sys/man/1/ns - 664 sys sys 944959677 893
@@ -7919,7 +7919,7 @@ sys/src/9/pc/devarch.c - 664 sys sys 1115566123 18554
 sys/src/9/pc/devether.c - 664 sys sys 1116173410 10327
 sys/src/9/pc/devfloppy.c - 664 sys sys 1055689885 20024
 sys/src/9/pc/devi82365.c - 664 sys sys 1099761153 20505
-sys/src/9/pc/devlm78.c - 664 sys sys 1091129037 6255
+sys/src/9/pc/devlm78.c - 664 sys sys 1128255048 6291
 sys/src/9/pc/devlml.c - 664 sys sys 1026847636 7486
 sys/src/9/pc/devlml.h - 664 sys sys 1026847636 2948
 sys/src/9/pc/devlpt.c - 664 sys sys 1015014514 4420
@@ -9218,7 +9218,7 @@ sys/src/cmd/9660srv/9660srv.c - 664 sys sys 1115039888 17143
 sys/src/cmd/9660srv/dat.h - 664 sys sys 1091904429 2097
 sys/src/cmd/9660srv/data.c - 664 sys sys 944960735 373
 sys/src/cmd/9660srv/fns.h - 664 sys sys 1019425186 428
-sys/src/cmd/9660srv/iobuf.c - 664 sys sys 1022085197 3125
+sys/src/cmd/9660srv/iobuf.c - 664 sys sys 1128255068 3126
 sys/src/cmd/9660srv/iso9660.h - 664 sys sys 1014924873 2607
 sys/src/cmd/9660srv/main.c - 664 sys sys 1020313483 9680
 sys/src/cmd/9660srv/mkfile - 664 sys sys 1048644372 238
@@ -10031,7 +10031,7 @@ sys/src/cmd/fossil/9auth.c - 664 sys sys 1061530721 3393
 sys/src/cmd/fossil/9dir.c - 664 sys sys 1085333382 2219
 sys/src/cmd/fossil/9excl.c - 664 sys sys 1042005502 1887
 sys/src/cmd/fossil/9fid.c - 664 sys sys 1045600016 5521
-sys/src/cmd/fossil/9fsys.c - 664 sys sys 1104858629 33296
+sys/src/cmd/fossil/9fsys.c - 664 sys sys 1128255102 33313
 sys/src/cmd/fossil/9lstn.c - 664 sys sys 1042005503 2865
 sys/src/cmd/fossil/9p.c - 664 sys sys 1104940048 21862
 sys/src/cmd/fossil/9ping.c - 664 sys sys 1042005503 1563
@@ -12264,7 +12264,7 @@ sys/src/cmd/ndb/mkhash.c - 664 sys sys 1014926160 2899
 sys/src/cmd/ndb/mkhosts.c - 664 sys sys 957402054 4294
 sys/src/cmd/ndb/query.c - 664 sys sys 1078840016 1120
 sys/src/cmd/ndb/time.c - 664 sys sys 957402055 321
-sys/src/cmd/netstat.c - 664 sys sys 1078839959 3846
+sys/src/cmd/netstat.c - 664 sys sys 1128255434 4086
 sys/src/cmd/news.c - 664 sys sys 1014926614 3778
 sys/src/cmd/nfs.c - 664 sys sys 1050068720 31096
 sys/src/cmd/nm.c - 664 sys sys 1073313392 4912
@@ -13782,8 +13782,8 @@ sys/src/fs/sony/mem.h - 664 sys sys 1015110103 2865
 sys/src/fs/sony/mkfile - 664 sys sys 1091803623 1594
 sys/src/fs/worms - 664 sys sys 1015110031 2806
 sys/src/games - 20000000775 sys sys 1095792091 0
-sys/src/games/4s.c - 664 sys sys 1120564580 1486
-sys/src/games/5s.c - 664 sys sys 1120564580 3822
+sys/src/games/4s.c - 664 sys sys 1128271724 1285
+sys/src/games/5s.c - 664 sys sys 1128271724 3621
 sys/src/games/catback.p - 664 sys sys 1108184106 35763
 sys/src/games/catclock.c - 664 sys sys 1108184106 10354
 sys/src/games/eyes.p - 664 sys sys 1108184106 1128
@@ -13795,7 +13795,7 @@ sys/src/games/mahjongg/mahjongg.c - 664 sys sys 1095792293 3452
 sys/src/games/mahjongg/mahjongg.h - 664 sys sys 1095792293 1606
 sys/src/games/mahjongg/mkfile - 664 sys sys 1095792293 230
 sys/src/games/memo.c - 664 sys sys 1125514848 6321
-sys/src/games/mkfile - 664 sys sys 1118672535 567
+sys/src/games/mkfile - 664 sys sys 1128271766 586
 sys/src/games/music - 20000000775 sys sys 1103793915 0
 sys/src/games/music/Readme - 664 sys sys 1103793914 488
 sys/src/games/music/debug.h - 664 sys sys 1103793914 201
@@ -13864,7 +13864,8 @@ sys/src/games/sudoku/levels.c - 664 sys sys 1117226433 3186
 sys/src/games/sudoku/mkfile - 664 sys sys 1117226432 218
 sys/src/games/sudoku/sudoku.c - 664 sys sys 1117636441 7809
 sys/src/games/sudoku/sudoku.h - 664 sys sys 1117226432 1159
-sys/src/games/xs.h - 664 sys sys 1120564579 17389
+sys/src/games/xs.c - 664 sys sys 1128271724 17124
+sys/src/games/xs.h - 664 sys sys 1128271724 292
 sys/src/lib9p - 20000000775 sys sys 1015023311 0
 sys/src/lib9p/_post.c - 664 sys sys 1103565871 1642
 sys/src/lib9p/dirread.c - 664 sys sys 1015023310 641

+ 14 - 0
dist/replica/plan9.log

@@ -21527,3 +21527,17 @@
 1128180608 29 c sys/src/cmd/wikifs/tohtml.c - 664 sys sys 1128179598 14527
 1128223818 0 c 386/bin/wikifs - 775 sys sys 1128222506 202486
 1128223818 1 c 386/bin/snoopy - 775 sys sys 1128222506 168209
+1128256225 0 c sys/man/1/netstat - 664 sys sys 1128255431 942
+1128256225 1 c sys/src/9/pc/devlm78.c - 664 sys sys 1128255048 6291
+1128256225 2 c sys/src/cmd/9660srv/iobuf.c - 664 sys sys 1128255068 3126
+1128256225 3 c sys/src/cmd/netstat.c - 664 sys sys 1128255434 4086
+1128256225 4 c sys/src/cmd/fossil/9fsys.c - 664 sys sys 1128255102 33313
+1128272427 0 c sys/src/games/4s.c - 664 sys sys 1128271724 1285
+1128272427 1 c sys/src/games/5s.c - 664 sys sys 1128271724 3621
+1128272427 2 c sys/src/games/mkfile - 664 sys sys 1128271766 586
+1128272427 3 a sys/src/games/xs.c - 664 sys sys 1128271724 17124
+1128272427 4 c sys/src/games/xs.h - 664 sys sys 1128271724 292
+1128310238 0 c 386/bin/games/4s - 775 sys sys 1128309084 177871
+1128310238 1 c 386/bin/games/5s - 775 sys sys 1128309084 180159
+1128310238 2 c 386/bin/netstat - 775 sys sys 1128309084 84664
+1128310238 3 c 386/bin/fossil/fossil - 775 sys sys 1128309083 360426

+ 23 - 11
sys/man/1/netstat

@@ -6,6 +6,9 @@ netstat \- summarize network connections
 [
 .B -in
 ] [
+.B -p
+.I proto
+] [
 .I netmtpt
 ]
 .SH DESCRIPTION
@@ -14,23 +17,32 @@ prints information about network mounted at
 .IR netmtpt ,
 default
 .BR /net .
-With the
-.B \-i
-option, it reports one line per network interface listing the
-device, MTU, local address, masl, remote address, packets in,
-packets out, errors in, and errors out for this interface.
 For
 .I IP
-connections
+connections,
 .I netstat
-reports the connection number, user,
+reports the protocol, connection number, user,
 connection state, local port, remote port and
 remote address.
-.I Netstat
-looks up port numbers and addresses in the network databases
-to print symbolic names if possible, but if the
+.PP
+The options are:
+.TP
+.B -i
+Instead of the usual listing, print one line per network interface.
+Each line gives the
+device, MTU, local address, mask, remote address, packets in,
+packets out, errors in, and errors out for this interface.
+.TP
 .B -n
-option is specified, it does not translate to symbolic form.
+By default,
+.I netstat
+looks up port numbers and addresses in the network databases
+to print symbolic names if possible.
+This option disables such translation.
+.TP
+.B -p
+Show only connections with the given protocol.
+.PD
 .SH FILES
 .B /net/*/*
 .SH SOURCE

+ 1 - 0
sys/src/9/pc/devlm78.c

@@ -57,6 +57,7 @@ enum
 };
 
 static Dirtab lm78dir[] = {
+	".",			{ Qdir, 0, QTDIR},	0,	0555,
 	"lm78vram",	{ Qlm78vram, 0 },	0,	0444,
 };
 

+ 1 - 1
sys/src/cmd/9660srv/iobuf.c

@@ -42,7 +42,7 @@ iobuf_init(void)
 
 	n = NCLUST*sizeof(Ioclust)+NCLUST*BUFPERCLUST*(sizeof(Iobuf)+Sectorsize);
 	mem = sbrk(n);
-	if((long)mem == -1)
+	if(mem == (void*)-1)
 		panic(0, "iobuf_init");
 	memset(mem, 0, n);
 

+ 3 - 2
sys/src/cmd/fossil/9fsys.c

@@ -284,7 +284,8 @@ fsysClose(Fsys* fsys, int argc, char* argv[])
 	if(argc)
 		return cliError(usage);
 
-	return cliError("close isn't working yet; sync and then kill fossil");
+	return cliError("close isn't working yet; halt %s and then kill fossil",
+		fsys->name);
 
 	/*
 	 * Oooh. This could be hard. What if fsys->ref != 1?
@@ -292,7 +293,6 @@ fsysClose(Fsys* fsys, int argc, char* argv[])
 	 * gracefully detect it's still busy?
 	 *
 	 * More thought and care needed here.
-	 */
 	fsClose(fsys->fs);
 	fsys->fs = nil;
 	vtClose(fsys->session);
@@ -304,6 +304,7 @@ fsysClose(Fsys* fsys, int argc, char* argv[])
 	}
 
 	return 1;
+	 */
 }
 
 static int

+ 24 - 12
sys/src/cmd/netstat.c

@@ -10,11 +10,14 @@ void	pipifc(void);
 
 Biobuf	out;
 char	*netroot;
+char *proto[20];
+int nproto;
 int	notrans;
 
 void
-usage(void){
-	fprint(2, "usage: %s [-in] [network-dir]\n", argv0);
+usage(void)
+{
+	fprint(2, "usage: %s [-in] [-p proto] [network-dir]\n", argv0);
 	exits("usage");
 }
 
@@ -27,11 +30,16 @@ main(int argc, char *argv[])
 	char buf[128];
 
 	ARGBEGIN{
+	case 'i':
+		justinterfaces = 1;
+		break;
 	case 'n':
 		notrans = 1;
 		break;
-	case 'i':
-		justinterfaces = 1;
+	case 'p':
+		if(nproto >= nelem(proto))
+			sysfatal("too many protos");
+		proto[nproto++] = EARGF(usage());
 		break;
 	default:
 		usage();
@@ -59,15 +67,19 @@ main(int argc, char *argv[])
 	if(fd < 0)
 		sysfatal("open %s: %r", netroot);
 
-	tot = dirreadall(fd, &d);
-	for(i=0; i<tot; i++){
-		if(strcmp(d[i].name, "ipifc") == 0)
-			continue;
-		snprint(buf, sizeof buf, "%s/%s/0/local", netroot, d[i].name);
-		if(access(buf, 0) >= 0)
-			nstat(d[i].name, pip);
+	if(nproto){
+		for(i=0; i<nproto; i++)
+			nstat(proto[i], pip);
+	}else{
+		tot = dirreadall(fd, &d);
+		for(i=0; i<tot; i++){
+			if(strcmp(d[i].name, "ipifc") == 0)
+				continue;
+			snprint(buf, sizeof buf, "%s/%s/0/local", netroot, d[i].name);
+			if(access(buf, 0) >= 0)
+				nstat(d[i].name, pip);
+		}
 	}
-
 	exits(0);
 }
 

+ 5 - 18
sys/src/games/4s.c

@@ -1,20 +1,6 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-
-#define	N	4
-
-typedef struct Piece Piece;
-struct Piece{
-	short	rot;
-	short	tx;
-	Point	sz;
-	Point	d[N];
-};
+#include "xs.h"
+
+int N = 4;
 
 Piece pieces[]={
 	{ 0, 0, 4,1,  { 0,0,  1,0,  1,0,  1,0 }},
@@ -53,4 +39,5 @@ Piece pieces[]={
 	{ 3, 6, 2,3,  { 0,0,  0,1,  1,0,  0,1 }},
 };
 
-#include "xs.h"
+int NP = nelem(pieces);
+

+ 5 - 18
sys/src/games/5s.c

@@ -1,20 +1,6 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <thread.h>
-#include <cursor.h>
-#include <mouse.h>
-#include <keyboard.h>
-
-#define	N	5
-
-typedef struct Piece Piece;
-struct Piece{
-	short	rot;
-	short	tx;
-	Point	sz;
-	Point	d[N];
-};
+#include "xs.h"
+
+int N = 5;
 
 Piece pieces[]={
 	{ 0, 1, 5,1,  { 0,0,  1,0,  1,0,  1,0,  1,0 }},
@@ -109,4 +95,5 @@ Piece pieces[]={
 
 };
 
-#include "xs.h"
+int NP = nelem(pieces);
+

+ 2 - 2
sys/src/games/mkfile

@@ -16,8 +16,8 @@ DIRS=\
 	mahjongg\
 	sokoban\
 
-4s.$O:	xs.h
-5s.$O:	xs.h
+4s.$O 5s.$O xs.$O:	xs.h
+$O.4s $O.5s: xs.$O
 catclock.$O:	catback.p eyes.p
 
 all:V:	dirall

+ 892 - 0
sys/src/games/xs.c

@@ -0,0 +1,892 @@
+#include "xs.h"
+
+/*
+ * engine for 4s, 5s, etc
+ */
+
+Cursor whitearrow = {
+	{0, 0},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 
+	 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 
+	 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 
+	 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
+	{0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, 
+	 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, 
+	 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, 
+	 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
+};
+
+enum
+{
+	CNone	= 0,
+	CBounds	= 1,
+	CPiece	= 2,
+	NX	= 10,
+	NY	= 20,
+};
+
+enum{
+	TIMER,
+	MOUSE,
+	RESHAPE,
+	KBD,
+	SUSPEND,
+	NALT
+};
+
+char		board[NY][NX];
+Rectangle	rboard;
+Point		pscore;
+Point		scoresz;
+int		pcsz = 32;
+Point		pos;
+Image	*bb, *bbmask, *bb2, *bb2mask;
+Image	*whitemask;
+Rectangle	br, br2;
+long		points;
+int		dt;
+int		DY;
+int		DMOUSE;
+int		lastmx;
+Mouse	mouse;
+int		newscreen;
+Channel	*timerc;
+Channel	*suspc;
+Channel	*mousec;
+Channel	*kbdc;
+Mousectl	*mousectl;
+Keyboardctl	*kbdctl;
+int		suspended;
+
+void		redraw(int);
+
+int	tsleep;
+
+Piece *piece;
+
+#define	NCOL	10
+
+uchar txbits[NCOL][32]={
+	{0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
+	 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
+	 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
+	 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF},
+	{0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
+	 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
+	 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
+	 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77},
+	{0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
+	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
+	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
+	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
+	{0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
+	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
+	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
+	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
+	{0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
+	 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
+	 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
+	 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88},
+	{0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
+	 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
+	 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
+	 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00},
+	{0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
+	{0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
+	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
+	{0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+	 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+	 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+	 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC},
+	{0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
+	 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
+	 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
+	 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33},
+};
+
+int txpix[NCOL] = {
+	DYellow,	/* yellow */
+	DCyan,	/* cyan */
+	DGreen,	/* lime green */
+	DGreyblue,	/* slate */
+	DRed,	/* red */
+	DGreygreen,	/* olive green */
+	DBlue,	/* blue */
+	0xFF55AAFF,	/* pink */
+	0xFFAAFFFF,	/* lavender */
+	0xBB005DFF,	/* maroon */
+};
+
+Image *tx[NCOL];
+
+int
+movemouse(void)
+{
+	mouse.xy = Pt(rboard.min.x + Dx(rboard)/2, rboard.min.y +Dy(rboard)/2);
+	moveto(mousectl, mouse.xy);
+	return mouse.xy.x;
+}
+
+int
+warp(Point p, int x)
+{
+	if (!suspended && piece != nil) {
+		x = pos.x + piece->sz.x*pcsz/2;
+		if (p.y < rboard.min.y)
+			p.y = rboard.min.y;
+		if (p.y >= rboard.max.y)
+			p.y = rboard.max.y - 1;
+		moveto(mousectl, Pt(x, p.y));
+	}
+	return x;
+}
+
+Piece *
+rotr(Piece *p)
+{
+	if(p->rot == 3)
+		return p-3;
+	return p+1;
+}
+
+Piece *
+rotl(Piece *p)
+{
+	if(p->rot == 0)
+		return p+3;
+	return p-1;
+}
+
+int
+collide(Point pt, Piece *p)
+{
+	int i;
+	int c = CNone;
+
+	pt.x = (pt.x - rboard.min.x) / pcsz;
+	pt.y = (pt.y - rboard.min.y) / pcsz;
+	for(i=0; i<N; i++){
+		pt.x += p->d[i].x;
+		pt.y += p->d[i].y;
+		if(pt.x<0 || pt.x>=NX || pt.y<0 || pt.y>=NY)
+			c |= CBounds;
+		if(board[pt.y][pt.x])
+			c |= CPiece;
+	}
+	return c;
+}
+
+int
+collider(Point pt, Point pmax)
+{
+	int i, j, pi, pj, n, m;
+
+	pi = (pt.x - rboard.min.x) / pcsz;
+	pj = (pt.y - rboard.min.y) / pcsz;
+	n = pmax.x / pcsz;
+	m = pmax.y / pcsz + 1;
+	for(i = pi; i < pi+n && i < NX; i++)
+		for(j = pj; j < pj+m && j < NY; j++)
+			if(board[j][i])
+				return 1;
+	return 0;
+}
+
+void
+setpiece(Piece *p){
+	int i;
+	Rectangle r, r2;
+	Point op, delta;
+
+	draw(bb, bb->r, display->white, nil, ZP);
+	draw(bbmask, bbmask->r, display->transparent, nil, ZP);
+	br = Rect(0, 0, 0, 0);
+	br2 = br;
+	piece = p;
+	if(p == 0)
+		return;
+	r.min = bb->r.min;
+	for(i=0; i<N; i++){
+		r.min.x += p->d[i].x*pcsz;
+		r.min.y += p->d[i].y*pcsz;
+		r.max.x = r.min.x + pcsz;
+		r.max.y = r.min.y + pcsz;
+		if(i == 0){
+			draw(bb, r, display->black, nil, ZP);
+			draw(bb, insetrect(r, 1), tx[piece->tx], nil, ZP);
+			draw(bbmask, r, display->opaque, nil, ZP);
+			op = r.min;
+		}else{
+			draw(bb, r, bb, nil, op);
+			draw(bbmask, r, bbmask, nil, op);
+		}
+		if(br.max.x < r.max.x)
+			br.max.x = r.max.x;
+		if(br.max.y < r.max.y)
+			br.max.y = r.max.y;
+	}
+	br.max = subpt(br.max, bb->r.min);
+	delta = Pt(0,DY);
+	br2.max = addpt(br.max, delta);
+	r = rectaddpt(br, bb2->r.min);
+	r2 = rectaddpt(br2, bb2->r.min);
+	draw(bb2, r2, display->white, nil, ZP);
+	draw(bb2, rectaddpt(r,delta), bb, nil, bb->r.min);
+	draw(bb2mask, r2, display->transparent, nil, ZP);
+	draw(bb2mask, r, display->opaque, bbmask, bb->r.min);
+	draw(bb2mask, rectaddpt(r,delta), display->opaque, bbmask, bb->r.min);
+}
+
+void
+drawpiece(void){
+	draw(screen, rectaddpt(br, pos), bb, bbmask, bb->r.min);
+	if (suspended)
+		draw(screen, rectaddpt(br, pos), display->white, whitemask, ZP);
+}
+
+void
+undrawpiece(void)
+{
+	Image *mask = nil;
+	if(collider(pos, br.max))
+		mask = bbmask;
+	draw(screen, rectaddpt(br, pos), display->white, mask, bb->r.min);
+}
+
+void
+rest(void)
+{
+	int i;
+	Point pt;
+
+	pt = divpt(subpt(pos, rboard.min), pcsz);
+	for(i=0; i<N; i++){
+		pt.x += piece->d[i].x;
+		pt.y += piece->d[i].y;
+		board[pt.y][pt.x] = piece->tx+16;
+	}
+}
+
+int
+canfit(Piece *p)
+{
+	static int dx[]={0, -1, 1, -2, 2, -3, 3, 4, -4};
+	int i, j;
+	Point z;
+
+	j = N + 1;
+	if(j >= 4){
+		j = p->sz.x;
+		if(j<p->sz.y)
+			j = p->sz.y;
+		j = 2*j-1;
+	}
+	for(i=0; i<j; i++){
+		z.x = pos.x + dx[i]*pcsz;
+		z.y = pos.y;
+		if(!collide(z, p)){
+			z.y = pos.y + pcsz-1;
+			if(!collide(z, p)){
+				undrawpiece();
+				pos.x = z.x;
+				return 1;
+			}
+		}
+	}
+	return 0;
+}
+
+void
+score(int p)
+{
+	char buf[128];
+
+	points += p;
+	snprint(buf, sizeof(buf), "%.6ld", points);
+	draw(screen, Rpt(pscore, addpt(pscore, scoresz)), display->white, nil, ZP);
+	string(screen, pscore, display->black, ZP, font, buf);
+}
+
+void
+drawsq(Image *b, Point p, int ptx){
+	Rectangle r;
+
+	r.min = p;
+	r.max.x = r.min.x+pcsz;
+	r.max.y = r.min.y+pcsz;
+	draw(b, r, display->black, nil, ZP);
+	draw(b, insetrect(r, 1), tx[ptx], nil, ZP);
+}
+
+void
+drawboard(void)
+{
+	int i, j;
+
+	border(screen, insetrect(rboard, -2), 2, display->black, ZP);
+	draw(screen, Rect(rboard.min.x, rboard.min.y-2, rboard.max.x, rboard.min.y),
+		display->white, nil, ZP);
+	for(i=0; i<NY; i++)
+		for(j=0; j<NX; j++)
+			if(board[i][j])
+				drawsq(screen, Pt(rboard.min.x+j*pcsz, rboard.min.y+i*pcsz), board[i][j]-16);
+	score(0);
+	if (suspended)
+		draw(screen, screen->r, display->white, whitemask, ZP);
+}
+
+void
+choosepiece(void)
+{
+	int i;
+
+	do{
+		i = nrand(NP);
+		setpiece(&pieces[i]);
+		pos = rboard.min;
+		pos.x += nrand(NX)*pcsz;
+	}while(collide(Pt(pos.x, pos.y+pcsz-DY), piece));
+	drawpiece();
+	flushimage(display, 1);
+}
+
+int
+movepiece(void)
+{
+	Image *mask = nil;
+
+	if(collide(Pt(pos.x, pos.y+pcsz), piece))
+		return 0;
+	if(collider(pos, br2.max))
+		mask = bb2mask;
+	draw(screen, rectaddpt(br2, pos), bb2, mask, bb2->r.min);
+	pos.y += DY;
+	flushimage(display, 1);
+	return 1;
+}
+
+void
+suspend(int s)
+{
+	suspended = s;
+	if (suspended)
+		setcursor(mousectl, &whitearrow);
+	else
+		setcursor(mousectl, nil);
+	if (!suspended)
+		drawpiece();
+	drawboard();
+	flushimage(display, 1);
+}
+
+void
+pause(int t)
+{
+	int s;
+	Alt alts[NALT+1];
+
+	alts[TIMER].c = timerc;
+	alts[TIMER].v = nil;
+	alts[TIMER].op = CHANRCV;
+	alts[SUSPEND].c = suspc;
+	alts[SUSPEND].v = &s;
+	alts[SUSPEND].op = CHANRCV;
+	alts[RESHAPE].c = mousectl->resizec;
+	alts[RESHAPE].v = nil;
+	alts[RESHAPE].op = CHANRCV;
+	// avoid hanging up those writing ong mousec and kbdc
+	// so just accept it all and keep mouse up-to-date
+	alts[MOUSE].c = mousec;
+	alts[MOUSE].v = &mouse;
+	alts[MOUSE].op = CHANRCV;
+	alts[KBD].c = kbdc;
+	alts[KBD].v = nil;
+	alts[KBD].op = CHANRCV;
+	alts[NALT].op = CHANEND;
+
+	flushimage(display, 1);
+	for(;;)
+		switch(alt(alts)){
+		case SUSPEND:
+			if (!suspended && s) {
+				suspend(1);
+			} else if (suspended && !s) {
+				suspend(0);
+				lastmx = warp(mouse.xy, lastmx);
+			}
+			break;
+		case TIMER:
+			if(suspended)
+				break;
+			if((t -= tsleep) < 0)
+				return;
+			break;
+		case RESHAPE:
+			redraw(1);
+			break;		
+		}
+}
+
+int
+horiz(void)
+{
+	int lev[MAXN];
+	int i, j, h;
+	Rectangle r;
+
+	h = 0;
+	for(i=0; i<NY; i++){
+		for(j=0; board[i][j]; j++)
+			if(j == NX-1){
+				lev[h++] = i;
+				break;
+			}
+	}
+	if(h == 0)
+		return 0;
+	r = rboard;
+	newscreen = 0;
+	for(j=0; j<h; j++){
+		r.min.y = rboard.min.y + lev[j]*pcsz;
+		r.max.y = r.min.y + pcsz;
+		draw(screen, r, display->white, whitemask, ZP);
+		flushimage(display, 1);
+	}
+	for(i=0; i<3; i++){
+		pause(250);
+		if(newscreen){
+			drawboard();
+			break;
+		}
+		for(j=0; j<h; j++){
+			r.min.y = rboard.min.y + lev[j]*pcsz;
+			r.max.y = r.min.y + pcsz;
+			draw(screen, r, display->white, whitemask, ZP);
+		}
+		flushimage(display, 1);
+	}
+	r = rboard;
+	for(j=0; j<h; j++){
+		i = NY - lev[j] - 1;
+		score(250+10*i*i);
+		r.min.y = rboard.min.y;
+		r.max.y = rboard.min.y+lev[j]*pcsz;
+		draw(screen, rectaddpt(r, Pt(0,pcsz)), screen, nil, r.min);
+		r.max.y = rboard.min.y+pcsz;
+		draw(screen, r, display->white, nil, ZP);
+		memcpy(&board[1][0], &board[0][0], NX*lev[j]);
+		memset(&board[0][0], 0, NX);
+	}
+	flushimage(display, 1);
+	return 1;
+}
+
+void
+mright(void)
+{
+	if(!collide(Pt(pos.x+pcsz, pos.y), piece))
+	if(!collide(Pt(pos.x+pcsz, pos.y+pcsz-DY), piece)){
+		undrawpiece();
+		pos.x += pcsz;
+		drawpiece();
+		flushimage(display, 1);
+	}
+}
+
+void
+mleft(void)
+{
+	if(!collide(Pt(pos.x-pcsz, pos.y), piece))
+	if(!collide(Pt(pos.x-pcsz, pos.y+pcsz-DY), piece)){
+		undrawpiece();
+		pos.x -= pcsz;
+		drawpiece();
+		flushimage(display, 1);
+	}
+}
+
+void
+rright(void)
+{
+	if(canfit(rotr(piece))){
+		setpiece(rotr(piece));
+		drawpiece();
+		flushimage(display, 1);
+	}
+}
+
+void
+rleft(void)
+{
+	if(canfit(rotl(piece))){
+		setpiece(rotl(piece));
+		drawpiece();
+		flushimage(display, 1);
+	}
+}
+
+int fusst = 0;
+int
+drop(int f)
+{
+	if(f){
+		score(5L*(rboard.max.y-pos.y)/pcsz);
+		do; while(movepiece());
+	}
+	fusst = 0;
+	rest();
+	if(pos.y==rboard.min.y && !horiz())
+		return 1;
+	horiz();
+	setpiece(0);
+	pause(1500);
+	choosepiece();
+	lastmx = warp(mouse.xy, lastmx);
+	return 0;
+}
+
+int
+play(void)
+{
+	int i;
+	Mouse om;
+	int s;
+	Rune r;
+	Alt alts[NALT+1];
+
+	alts[TIMER].c = timerc;
+	alts[TIMER].v = nil;
+	alts[TIMER].op = CHANRCV;
+	alts[MOUSE].c = mousec;
+	alts[MOUSE].v = &mouse;
+	alts[MOUSE].op = CHANRCV;
+	alts[SUSPEND].c = suspc;
+	alts[SUSPEND].v = &s;
+	alts[SUSPEND].op = CHANRCV;
+	alts[RESHAPE].c = mousectl->resizec;
+	alts[RESHAPE].v = nil;
+	alts[RESHAPE].op = CHANRCV;
+	alts[KBD].c = kbdc;
+	alts[KBD].v = &r;
+	alts[KBD].op = CHANRCV;
+	alts[NALT].op = CHANEND;
+
+	dt = 64;
+	lastmx = -1;
+	lastmx = movemouse();
+	choosepiece();
+	lastmx = warp(mouse.xy, lastmx);
+	for(;;)
+	switch(alt(alts)){
+	case MOUSE:
+		if(suspended) {
+			om = mouse;
+			break;
+		}
+		if(lastmx < 0)
+			lastmx = mouse.xy.x;
+		if(mouse.xy.x > lastmx+DMOUSE){
+			mright();
+			lastmx = mouse.xy.x;
+		}
+		if(mouse.xy.x < lastmx-DMOUSE){
+			mleft();
+			lastmx = mouse.xy.x;
+		}
+		if(mouse.buttons&1 && !(om.buttons&1))
+			rleft();
+		if(mouse.buttons&2 && !(om.buttons&2))
+			if(drop(1))
+				return 1;
+		if(mouse.buttons&4 && !(om.buttons&4))
+			rright();
+		om = mouse;
+		break;
+	case SUSPEND:
+		if (!suspended && s)
+			suspend(1);
+		else
+		if (suspended && !s) {
+			suspend(0);
+			lastmx = warp(mouse.xy, lastmx);
+		}
+		break;
+	case RESHAPE:
+		redraw(1);
+		break;		
+	case KBD:
+		if(suspended)
+			break;
+		switch(r){
+		case 'f':
+		case ';':
+			mright();
+			break;
+		case 'a':
+		case 'j':
+			mleft();
+			break;
+		case 'd':
+		case 'l':
+			rright();
+			break;
+		case 's':
+		case 'k':
+			rleft();
+			break;
+		case ' ':
+			if(drop(1))
+				return 1;
+			break;
+		}
+		break;
+	case TIMER:
+		if(suspended)
+			break;
+		dt -= tsleep;
+		if(dt < 0){
+			i = 1;
+			dt = 16 * (points+nrand(10000)-5000) / 10000;
+			if(dt >= 32){
+				i += (dt-32)/16;
+				dt = 32;
+			}
+			dt = 52-dt;
+			while(i-- > 0)
+				if(movepiece()==0 && ++fusst==40){
+					if(drop(0))
+						return 1;
+					break;
+				}
+		}
+		break;
+	}
+	return 0;		/* not reached */
+}
+
+void
+setparms(void)
+{
+	char buf[32];
+	int fd, n;
+
+	tsleep = 50;
+	fd = open("/dev/hz", OREAD);
+	if(fd < 0)
+		return;
+	n = read(fd, buf, sizeof buf - 1);
+	close(fd);
+	if(n < 0)
+		return;
+	buf[n] = '\0';
+	tsleep = strtoul(buf, 0, 10);
+	tsleep = (1000 + tsleep - 1) / tsleep;
+}
+
+void
+timerproc(void *v)
+{
+	Channel *c;
+	void **arg;
+
+	arg = v;
+	c = (Channel*)arg;
+
+	for(;;){
+		sleep(tsleep);
+		send(c, nil);
+	}
+}
+
+void
+suspproc(void *)
+{
+	Mouse mouse;
+	Rune r;
+	int s;
+	Alt alts[NALT+1];
+
+	alts[TIMER].op = CHANNOP;
+	alts[MOUSE].c = mousectl->c;
+	alts[MOUSE].v = &mouse;
+	alts[MOUSE].op = CHANRCV;
+	alts[SUSPEND].op = CHANNOP;
+	alts[RESHAPE].op = CHANNOP;
+	alts[KBD].c = kbdctl->c;
+	alts[KBD].v = &r;
+	alts[KBD].op = CHANRCV;
+	alts[NALT].op = CHANEND;
+
+	s = 0;
+	for(;;)
+		switch(alt(alts)){
+		case MOUSE:
+			send(mousec, &mouse);
+			break;
+		case KBD:
+			switch(r){
+			case 'q':
+			case 'Q':
+			case 0x04:
+			case 0x7F:
+				threadexitsall(nil);
+			default:
+				if(s) {
+					s = 0;
+					send(suspc, &s);
+				} else
+					switch(r){
+					case 'z':
+					case 'Z':
+					case 'p':
+					case 'P':
+					case 0x1B:
+						s = 1;
+						send(suspc, &s);
+						break;
+					default:
+						send(kbdc, &r);
+					}
+				break;
+			}
+		}
+}
+
+void
+redraw(int new)
+{
+	Rectangle r;
+	long dx, dy;
+
+	if(new && getwindow(display, Refmesg) < 0)
+		sysfatal("can't reattach to window");
+	r = screen->r;
+	pos.x = (pos.x - rboard.min.x) / pcsz;
+	pos.y = (pos.y - rboard.min.y) / pcsz;
+	dx = r.max.x - r.min.x;
+	dy = r.max.y - r.min.y - 2*32;
+	DY = dx / NX;
+	if(DY > dy / NY)
+		DY = dy / NY;
+	DY /= 8;
+	if(DY > 4)
+		DY = 4;
+	pcsz = DY*8;
+	DMOUSE = pcsz/3;
+	if(pcsz < 8)
+		sysfatal("screen too small: %d", pcsz);
+	rboard = screen->r;
+	rboard.min.x += (dx-pcsz*NX)/2;
+	rboard.min.y += (dy-pcsz*NY)/2+32;
+	rboard.max.x = rboard.min.x+NX*pcsz;
+	rboard.max.y = rboard.min.y+NY*pcsz;
+	pscore.x = rboard.min.x+8;
+	pscore.y = rboard.min.y-32;
+	scoresz = stringsize(font, "000000");
+	pos.x = pos.x*pcsz + rboard.min.x;
+	pos.y = pos.y*pcsz + rboard.min.y;
+	if(bb){
+		freeimage(bb);
+		freeimage(bbmask);
+		freeimage(bb2);
+		freeimage(bb2mask);
+	}
+	bb = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), screen->chan, 0, 0);
+	bbmask = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), GREY1, 0, 0);
+	bb2 = allocimage(display, Rect(0,0,N*pcsz,N*pcsz+DY), screen->chan, 0, 0);
+	bb2mask = allocimage(display, bb2->r, GREY1, 0, 0);
+	if(bb==0 || bbmask==0 || bb2==0 || bb2mask==0)
+		sysfatal("allocimage fail (bb)");
+	draw(screen, screen->r, display->white, nil, ZP);
+	drawboard();
+	setpiece(piece);
+	if(piece)
+		drawpiece();
+	lastmx = movemouse();
+	newscreen = 1;
+	flushimage(display, 1);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s\n", argv0);
+	exits("usage");
+}
+
+void
+threadmain(int argc, char *argv[])
+{
+	Image *tb;
+	char buf[200];
+	int i, scores;
+	long starttime, endtime;
+
+	ARGBEGIN{
+	default:
+		usage();
+	}ARGEND
+	if(argc)
+		usage();
+
+	suspended = 0;
+	setparms();
+	snprint(buf, sizeof(buf), "%ds", N);
+	initdraw(0, 0, buf);
+	mousectl = initmouse(nil, display->image);	/* BUG? */
+	if(mousectl == nil)
+		sysfatal("[45]s: mouse init failed: %r");
+	kbdctl = initkeyboard(nil);	/* BUG? */
+	if(kbdctl == nil)
+		sysfatal("[45]s: keyboard init failed: %r");
+	starttime = time(0);
+	srand(starttime);
+	snprint(buf, sizeof(buf), "/sys/games/lib/%dscores", N);
+	scores = open(buf, OWRITE);
+	if(scores < 0)
+		sysfatal("can't open %s: %r", buf);
+	tb = 0;
+	if(screen->depth < 3){
+		tb = allocimage(display, Rect(0,0,16,16), 0, 1, -1);
+		if(tb == 0)
+			sysfatal("allocimage fail (tb)");
+	}
+	for(i = 0; i<NCOL; i++){
+		tx[i] = allocimage(display, Rect(0, 0, 16, 16), screen->chan, 1, txpix[i]);
+		if(tx[i] == 0)
+			sysfatal("allocimage fail (tx)");
+		if(screen->depth < 3){
+			loadimage(tb, tb->r, txbits[i], 32);
+			draw(tx[i], tx[i]->r, tb, nil, ZP);
+		}
+	}
+	if(tb != 0)
+		freeimage(tb);
+
+	whitemask = allocimage(display, Rect(0,0,1,1), CMAP8, 1, setalpha(DWhite, 0x7F));
+	if(whitemask==0)
+		sysfatal("allocimage fail (whitemask)");
+
+	threadsetname("4s-5s");
+	timerc= chancreate(sizeof(int), 0);
+	proccreate(timerproc, timerc, 1024);
+	suspc= chancreate(sizeof(int), 0);
+	mousec= chancreate(sizeof(Mouse), 0);
+	kbdc= chancreate(sizeof(Rune), 0);
+	threadcreate(suspproc, nil, 1024);
+	points = 0;
+	memset(board, 0, sizeof(board));
+	redraw(0);
+	if(play()){
+		endtime = time(0);
+		fprint(scores, "%ld\t%s\t%lud\t%ld\n",
+			points, getuser(), starttime, endtime-starttime);
+	}
+	threadexitsall(nil);
+	exits(0);
+}

+ 16 - 887
sys/src/games/xs.h

@@ -1,895 +1,24 @@
-/*
- * engine for 4s, 5s, etc
- * need to define N and pieces table before including this
- */
-
-Cursor whitearrow = {
-	{0, 0},
-	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 
-	 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, 
-	 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, 
-	 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
-	{0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, 
-	 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, 
-	 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, 
-	 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
-};
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <cursor.h>
+#include <mouse.h>
+#include <keyboard.h>
 
 enum
 {
-	CNone	= 0,
-	CBounds	= 1,
-	CPiece	= 2,
-	NX	= 10,
-	NY	= 20,
-};
-
-enum{
-	TIMER,
-	MOUSE,
-	RESHAPE,
-	KBD,
-	SUSPEND,
-	NALT
-};
-
-#define	NP	(sizeof pieces/sizeof(Piece))
-
-char		board[NY][NX];
-Rectangle	rboard;
-Point		pscore;
-Point		scoresz;
-int		pcsz = 32;
-Point		pos;
-Image	*bb, *bbmask, *bb2, *bb2mask;
-Image	*whitemask;
-Rectangle	br, br2;
-long		points;
-int		dt;
-int		DY;
-int		DMOUSE;
-int		lastmx;
-Mouse	mouse;
-int		newscreen;
-Channel	*timerc;
-Channel	*suspc;
-Channel	*mousec;
-Channel	*kbdc;
-Mousectl	*mousectl;
-Keyboardctl	*kbdctl;
-int		suspended;
-
-void		redraw(int);
-
-int	tsleep;
-
-Piece *piece;
-
-#define	NCOL	10
-
-uchar txbits[NCOL][32]={
-	{0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
-	 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
-	 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF,
-	 0xDD,0xDD,0xFF,0xFF,0x77,0x77,0xFF,0xFF},
-	{0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
-	 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
-	 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77,
-	 0xDD,0xDD,0x77,0x77,0xDD,0xDD,0x77,0x77},
-	{0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
-	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
-	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
-	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
-	{0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
-	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
-	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55,
-	 0xAA,0xAA,0x55,0x55,0xAA,0xAA,0x55,0x55},
-	{0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
-	 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
-	 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88,
-	 0x22,0x22,0x88,0x88,0x22,0x22,0x88,0x88},
-	{0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
-	 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
-	 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00,
-	 0x22,0x22,0x00,0x00,0x88,0x88,0x00,0x00},
-	{0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
-	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
-	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
-	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
-	{0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
-	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
-	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,
-	 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00},
-	{0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
-	 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
-	 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
-	 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC},
-	{0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
-	 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
-	 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33,
-	 0xCC,0xCC,0xCC,0xCC,0x33,0x33,0x33,0x33},
+	MAXN = 5
 };
 
-int txpix[NCOL] = {
-	DYellow,	/* yellow */
-	DCyan,	/* cyan */
-	DGreen,	/* lime green */
-	DGreyblue,	/* slate */
-	DRed,	/* red */
-	DGreygreen,	/* olive green */
-	DBlue,	/* blue */
-	0xFF55AAFF,	/* pink */
-	0xFFAAFFFF,	/* lavender */
-	0xBB005DFF,	/* maroon */
+typedef struct Piece Piece;
+struct Piece{
+	short	rot;
+	short	tx;
+	Point	sz;
+	Point	d[MAXN];
 };
 
-Image *tx[NCOL];
-
-int
-movemouse(void)
-{
-	mouse.xy = Pt(rboard.min.x + Dx(rboard)/2, rboard.min.y +Dy(rboard)/2);
-	moveto(mousectl, mouse.xy);
-	return mouse.xy.x;
-}
-
-int
-warp(Point p, int x)
-{
-	if (!suspended && piece != nil) {
-		x = pos.x + piece->sz.x*pcsz/2;
-		if (p.y < rboard.min.y)
-			p.y = rboard.min.y;
-		if (p.y >= rboard.max.y)
-			p.y = rboard.max.y - 1;
-		moveto(mousectl, Pt(x, p.y));
-	}
-	return x;
-}
-
-Piece *
-rotr(Piece *p)
-{
-	if(p->rot == 3)
-		return p-3;
-	return p+1;
-}
-
-Piece *
-rotl(Piece *p)
-{
-	if(p->rot == 0)
-		return p+3;
-	return p-1;
-}
-
-int
-collide(Point pt, Piece *p)
-{
-	int i;
-	int c = CNone;
-
-	pt.x = (pt.x - rboard.min.x) / pcsz;
-	pt.y = (pt.y - rboard.min.y) / pcsz;
-	for(i=0; i<N; i++){
-		pt.x += p->d[i].x;
-		pt.y += p->d[i].y;
-		if(pt.x<0 || pt.x>=NX || pt.y<0 || pt.y>=NY)
-			c |= CBounds;
-		if(board[pt.y][pt.x])
-			c |= CPiece;
-	}
-	return c;
-}
-
-int
-collider(Point pt, Point pmax)
-{
-	int i, j, pi, pj, n, m;
-
-	pi = (pt.x - rboard.min.x) / pcsz;
-	pj = (pt.y - rboard.min.y) / pcsz;
-	n = pmax.x / pcsz;
-	m = pmax.y / pcsz + 1;
-	for(i = pi; i < pi+n && i < NX; i++)
-		for(j = pj; j < pj+m && j < NY; j++)
-			if(board[j][i])
-				return 1;
-	return 0;
-}
-
-void
-setpiece(Piece *p){
-	int i;
-	Rectangle r, r2;
-	Point op, delta;
-
-	draw(bb, bb->r, display->white, nil, ZP);
-	draw(bbmask, bbmask->r, display->transparent, nil, ZP);
-	br = Rect(0, 0, 0, 0);
-	br2 = br;
-	piece = p;
-	if(p == 0)
-		return;
-	r.min = bb->r.min;
-	for(i=0; i<N; i++){
-		r.min.x += p->d[i].x*pcsz;
-		r.min.y += p->d[i].y*pcsz;
-		r.max.x = r.min.x + pcsz;
-		r.max.y = r.min.y + pcsz;
-		if(i == 0){
-			draw(bb, r, display->black, nil, ZP);
-			draw(bb, insetrect(r, 1), tx[piece->tx], nil, ZP);
-			draw(bbmask, r, display->opaque, nil, ZP);
-			op = r.min;
-		}else{
-			draw(bb, r, bb, nil, op);
-			draw(bbmask, r, bbmask, nil, op);
-		}
-		if(br.max.x < r.max.x)
-			br.max.x = r.max.x;
-		if(br.max.y < r.max.y)
-			br.max.y = r.max.y;
-	}
-	br.max = subpt(br.max, bb->r.min);
-	delta = Pt(0,DY);
-	br2.max = addpt(br.max, delta);
-	r = rectaddpt(br, bb2->r.min);
-	r2 = rectaddpt(br2, bb2->r.min);
-	draw(bb2, r2, display->white, nil, ZP);
-	draw(bb2, rectaddpt(r,delta), bb, nil, bb->r.min);
-	draw(bb2mask, r2, display->transparent, nil, ZP);
-	draw(bb2mask, r, display->opaque, bbmask, bb->r.min);
-	draw(bb2mask, rectaddpt(r,delta), display->opaque, bbmask, bb->r.min);
-}
-
-void
-drawpiece(void){
-	draw(screen, rectaddpt(br, pos), bb, bbmask, bb->r.min);
-	if (suspended)
-		draw(screen, rectaddpt(br, pos), display->white, whitemask, ZP);
-}
-
-void
-undrawpiece(void)
-{
-	Image *mask = nil;
-	if(collider(pos, br.max))
-		mask = bbmask;
-	draw(screen, rectaddpt(br, pos), display->white, mask, bb->r.min);
-}
-
-void
-rest(void)
-{
-	int i;
-	Point pt;
-
-	pt = divpt(subpt(pos, rboard.min), pcsz);
-	for(i=0; i<N; i++){
-		pt.x += piece->d[i].x;
-		pt.y += piece->d[i].y;
-		board[pt.y][pt.x] = piece->tx+16;
-	}
-}
-
-int
-canfit(Piece *p)
-{
-	static int dx[]={0, -1, 1, -2, 2, -3, 3, 4, -4};
-	int i, j;
-	Point z;
-
-	j = N + 1;
-	if(j >= 4){
-		j = p->sz.x;
-		if(j<p->sz.y)
-			j = p->sz.y;
-		j = 2*j-1;
-	}
-	for(i=0; i<j; i++){
-		z.x = pos.x + dx[i]*pcsz;
-		z.y = pos.y;
-		if(!collide(z, p)){
-			z.y = pos.y + pcsz-1;
-			if(!collide(z, p)){
-				undrawpiece();
-				pos.x = z.x;
-				return 1;
-			}
-		}
-	}
-	return 0;
-}
-
-void
-score(int p)
-{
-	char buf[128];
-
-	points += p;
-	snprint(buf, sizeof(buf), "%.6ld", points);
-	draw(screen, Rpt(pscore, addpt(pscore, scoresz)), display->white, nil, ZP);
-	string(screen, pscore, display->black, ZP, font, buf);
-}
-
-void
-drawsq(Image *b, Point p, int ptx){
-	Rectangle r;
-
-	r.min = p;
-	r.max.x = r.min.x+pcsz;
-	r.max.y = r.min.y+pcsz;
-	draw(b, r, display->black, nil, ZP);
-	draw(b, insetrect(r, 1), tx[ptx], nil, ZP);
-}
-
-void
-drawboard(void)
-{
-	int i, j;
-
-	border(screen, insetrect(rboard, -2), 2, display->black, ZP);
-	draw(screen, Rect(rboard.min.x, rboard.min.y-2, rboard.max.x, rboard.min.y),
-		display->white, nil, ZP);
-	for(i=0; i<NY; i++)
-		for(j=0; j<NX; j++)
-			if(board[i][j])
-				drawsq(screen, Pt(rboard.min.x+j*pcsz, rboard.min.y+i*pcsz), board[i][j]-16);
-	score(0);
-	if (suspended)
-		draw(screen, screen->r, display->white, whitemask, ZP);
-}
-
-void
-choosepiece(void)
-{
-	int i;
-
-	do{
-		i = nrand(NP);
-		setpiece(&pieces[i]);
-		pos = rboard.min;
-		pos.x += nrand(NX)*pcsz;
-	}while(collide(Pt(pos.x, pos.y+pcsz-DY), piece));
-	drawpiece();
-	flushimage(display, 1);
-}
-
-int
-movepiece(void)
-{
-	Image *mask = nil;
-
-	if(collide(Pt(pos.x, pos.y+pcsz), piece))
-		return 0;
-	if(collider(pos, br2.max))
-		mask = bb2mask;
-	draw(screen, rectaddpt(br2, pos), bb2, mask, bb2->r.min);
-	pos.y += DY;
-	flushimage(display, 1);
-	return 1;
-}
-
-void
-suspend(int s)
-{
-	suspended = s;
-	if (suspended)
-		setcursor(mousectl, &whitearrow);
-	else
-		setcursor(mousectl, nil);
-	if (!suspended)
-		drawpiece();
-	drawboard();
-	flushimage(display, 1);
-}
-
-void
-pause(int t)
-{
-	int s;
-	Alt alts[NALT+1];
-
-	alts[TIMER].c = timerc;
-	alts[TIMER].v = nil;
-	alts[TIMER].op = CHANRCV;
-	alts[SUSPEND].c = suspc;
-	alts[SUSPEND].v = &s;
-	alts[SUSPEND].op = CHANRCV;
-	alts[RESHAPE].c = mousectl->resizec;
-	alts[RESHAPE].v = nil;
-	alts[RESHAPE].op = CHANRCV;
-	// avoid hanging up those writing ong mousec and kbdc
-	// so just accept it all and keep mouse up-to-date
-	alts[MOUSE].c = mousec;
-	alts[MOUSE].v = &mouse;
-	alts[MOUSE].op = CHANRCV;
-	alts[KBD].c = kbdc;
-	alts[KBD].v = nil;
-	alts[KBD].op = CHANRCV;
-	alts[NALT].op = CHANEND;
-
-	flushimage(display, 1);
-	for(;;)
-		switch(alt(alts)){
-		case SUSPEND:
-			if (!suspended && s) {
-				suspend(1);
-			} else if (suspended && !s) {
-				suspend(0);
-				lastmx = warp(mouse.xy, lastmx);
-			}
-			break;
-		case TIMER:
-			if(suspended)
-				break;
-			if((t -= tsleep) < 0)
-				return;
-			break;
-		case RESHAPE:
-			redraw(1);
-			break;		
-		}
-}
-
-int
-horiz(void)
-{
-	int lev[N];
-	int i, j, h;
-	Rectangle r;
-
-	h = 0;
-	for(i=0; i<NY; i++){
-		for(j=0; board[i][j]; j++)
-			if(j == NX-1){
-				lev[h++] = i;
-				break;
-			}
-	}
-	if(h == 0)
-		return 0;
-	r = rboard;
-	newscreen = 0;
-	for(j=0; j<h; j++){
-		r.min.y = rboard.min.y + lev[j]*pcsz;
-		r.max.y = r.min.y + pcsz;
-		draw(screen, r, display->white, whitemask, ZP);
-		flushimage(display, 1);
-	}
-	for(i=0; i<3; i++){
-		pause(250);
-		if(newscreen){
-			drawboard();
-			break;
-		}
-		for(j=0; j<h; j++){
-			r.min.y = rboard.min.y + lev[j]*pcsz;
-			r.max.y = r.min.y + pcsz;
-			draw(screen, r, display->white, whitemask, ZP);
-		}
-		flushimage(display, 1);
-	}
-	r = rboard;
-	for(j=0; j<h; j++){
-		i = NY - lev[j] - 1;
-		score(250+10*i*i);
-		r.min.y = rboard.min.y;
-		r.max.y = rboard.min.y+lev[j]*pcsz;
-		draw(screen, rectaddpt(r, Pt(0,pcsz)), screen, nil, r.min);
-		r.max.y = rboard.min.y+pcsz;
-		draw(screen, r, display->white, nil, ZP);
-		memcpy(&board[1][0], &board[0][0], NX*lev[j]);
-		memset(&board[0][0], 0, NX);
-	}
-	flushimage(display, 1);
-	return 1;
-}
-
-void
-mright(void)
-{
-	if(!collide(Pt(pos.x+pcsz, pos.y), piece))
-	if(!collide(Pt(pos.x+pcsz, pos.y+pcsz-DY), piece)){
-		undrawpiece();
-		pos.x += pcsz;
-		drawpiece();
-		flushimage(display, 1);
-	}
-}
-
-void
-mleft(void)
-{
-	if(!collide(Pt(pos.x-pcsz, pos.y), piece))
-	if(!collide(Pt(pos.x-pcsz, pos.y+pcsz-DY), piece)){
-		undrawpiece();
-		pos.x -= pcsz;
-		drawpiece();
-		flushimage(display, 1);
-	}
-}
-
-void
-rright(void)
-{
-	if(canfit(rotr(piece))){
-		setpiece(rotr(piece));
-		drawpiece();
-		flushimage(display, 1);
-	}
-}
-
-void
-rleft(void)
-{
-	if(canfit(rotl(piece))){
-		setpiece(rotl(piece));
-		drawpiece();
-		flushimage(display, 1);
-	}
-}
-
-int fusst = 0;
-int
-drop(int f)
-{
-	if(f){
-		score(5L*(rboard.max.y-pos.y)/pcsz);
-		do; while(movepiece());
-	}
-	fusst = 0;
-	rest();
-	if(pos.y==rboard.min.y && !horiz())
-		return 1;
-	horiz();
-	setpiece(0);
-	pause(1500);
-	choosepiece();
-	lastmx = warp(mouse.xy, lastmx);
-	return 0;
-}
-
-int
-play(void)
-{
-	int i;
-	Mouse om;
-	int s;
-	Rune r;
-	Alt alts[NALT+1];
-
-	alts[TIMER].c = timerc;
-	alts[TIMER].v = nil;
-	alts[TIMER].op = CHANRCV;
-	alts[MOUSE].c = mousec;
-	alts[MOUSE].v = &mouse;
-	alts[MOUSE].op = CHANRCV;
-	alts[SUSPEND].c = suspc;
-	alts[SUSPEND].v = &s;
-	alts[SUSPEND].op = CHANRCV;
-	alts[RESHAPE].c = mousectl->resizec;
-	alts[RESHAPE].v = nil;
-	alts[RESHAPE].op = CHANRCV;
-	alts[KBD].c = kbdc;
-	alts[KBD].v = &r;
-	alts[KBD].op = CHANRCV;
-	alts[NALT].op = CHANEND;
-
-	dt = 64;
-	lastmx = -1;
-	lastmx = movemouse();
-	choosepiece();
-	lastmx = warp(mouse.xy, lastmx);
-	for(;;)
-	switch(alt(alts)){
-	case MOUSE:
-		if(suspended) {
-			om = mouse;
-			break;
-		}
-		if(lastmx < 0)
-			lastmx = mouse.xy.x;
-		if(mouse.xy.x > lastmx+DMOUSE){
-			mright();
-			lastmx = mouse.xy.x;
-		}
-		if(mouse.xy.x < lastmx-DMOUSE){
-			mleft();
-			lastmx = mouse.xy.x;
-		}
-		if(mouse.buttons&1 && !(om.buttons&1))
-			rleft();
-		if(mouse.buttons&2 && !(om.buttons&2))
-			if(drop(1))
-				return 1;
-		if(mouse.buttons&4 && !(om.buttons&4))
-			rright();
-		om = mouse;
-		break;
-	case SUSPEND:
-		if (!suspended && s)
-			suspend(1);
-		else
-		if (suspended && !s) {
-			suspend(0);
-			lastmx = warp(mouse.xy, lastmx);
-		}
-		break;
-	case RESHAPE:
-		redraw(1);
-		break;		
-	case KBD:
-		if(suspended)
-			break;
-		switch(r){
-		case 'f':
-		case ';':
-			mright();
-			break;
-		case 'a':
-		case 'j':
-			mleft();
-			break;
-		case 'd':
-		case 'l':
-			rright();
-			break;
-		case 's':
-		case 'k':
-			rleft();
-			break;
-		case ' ':
-			if(drop(1))
-				return 1;
-			break;
-		}
-		break;
-	case TIMER:
-		if(suspended)
-			break;
-		dt -= tsleep;
-		if(dt < 0){
-			i = 1;
-			dt = 16 * (points+nrand(10000)-5000) / 10000;
-			if(dt >= 32){
-				i += (dt-32)/16;
-				dt = 32;
-			}
-			dt = 52-dt;
-			while(i-- > 0)
-				if(movepiece()==0 && ++fusst==40){
-					if(drop(0))
-						return 1;
-					break;
-				}
-		}
-		break;
-	}
-	return 0;		/* not reached */
-}
-
-void
-setparms(void)
-{
-	char buf[32];
-	int fd, n;
-
-	tsleep = 50;
-	fd = open("/dev/hz", OREAD);
-	if(fd < 0)
-		return;
-	n = read(fd, buf, sizeof buf - 1);
-	close(fd);
-	if(n < 0)
-		return;
-	buf[n] = '\0';
-	tsleep = strtoul(buf, 0, 10);
-	tsleep = (1000 + tsleep - 1) / tsleep;
-}
-
-void
-timerproc(void *v)
-{
-	Channel *c;
-	void **arg;
-
-	arg = v;
-	c = (Channel*)arg;
-
-	for(;;){
-		sleep(tsleep);
-		send(c, nil);
-	}
-}
-
-void
-suspproc(void *)
-{
-	Mouse mouse;
-	Point lastm;
-	Rune r;
-	int s;
-	Alt alts[NALT+1];
-
-	alts[TIMER].op = CHANNOP;
-	alts[MOUSE].c = mousectl->c;
-	alts[MOUSE].v = &mouse;
-	alts[MOUSE].op = CHANRCV;
-	alts[SUSPEND].op = CHANNOP;
-	alts[RESHAPE].op = CHANNOP;
-	alts[KBD].c = kbdctl->c;
-	alts[KBD].v = &r;
-	alts[KBD].op = CHANRCV;
-	alts[NALT].op = CHANEND;
-
-	s = 0;
-	lastm = Pt(-1,-1);
-	for(;;)
-		switch(alt(alts)){
-		case MOUSE:
-			send(mousec, &mouse);
-			if(lastm.x < 0 || lastm.y < 0)
-				lastm = mouse.xy;
-			if(s && ptinrect(mouse.xy, rboard) && !ptinrect(lastm, rboard)){
-				s = 0;
-				send(suspc, &s);
-			} else
-			if(!s && !ptinrect(mouse.xy,rboard)){
-				s = 1;
-				send(suspc, &s);
-			}
-			lastm = mouse.xy;
-			break;
-		case KBD:
-			switch(r){
-			case 'q':
-			case 'Q':
-			case 0x04:
-			case 0x7F:
-				threadexitsall(nil);
-			default:
-				if(s) {
-					s = 0;
-					send(suspc, &s);
-				} else
-					switch(r){
-					case 'z':
-					case 'Z':
-					case 'p':
-					case 'P':
-					case 0x1B:
-						s = 1;
-						send(suspc, &s);
-						break;
-					default:
-						send(kbdc, &r);
-					}
-				break;
-			}
-		}
-}
-
-void
-redraw(int new)
-{
-	Rectangle r;
-	long dx, dy;
-
-	if(new && getwindow(display, Refmesg) < 0)
-		sysfatal("can't reattach to window");
-	r = screen->r;
-	pos.x = (pos.x - rboard.min.x) / pcsz;
-	pos.y = (pos.y - rboard.min.y) / pcsz;
-	dx = r.max.x - r.min.x;
-	dy = r.max.y - r.min.y - 2*32;
-	DY = dx / NX;
-	if(DY > dy / NY)
-		DY = dy / NY;
-	DY /= 8;
-	if(DY > 4)
-		DY = 4;
-	pcsz = DY*8;
-	DMOUSE = pcsz/3;
-	if(pcsz < 8)
-		sysfatal("screen too small: %d", pcsz);
-	rboard = screen->r;
-	rboard.min.x += (dx-pcsz*NX)/2;
-	rboard.min.y += (dy-pcsz*NY)/2+32;
-	rboard.max.x = rboard.min.x+NX*pcsz;
-	rboard.max.y = rboard.min.y+NY*pcsz;
-	pscore.x = rboard.min.x+8;
-	pscore.y = rboard.min.y-32;
-	scoresz = stringsize(font, "000000");
-	pos.x = pos.x*pcsz + rboard.min.x;
-	pos.y = pos.y*pcsz + rboard.min.y;
-	if(bb){
-		freeimage(bb);
-		freeimage(bbmask);
-		freeimage(bb2);
-		freeimage(bb2mask);
-	}
-	bb = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), screen->chan, 0, 0);
-	bbmask = allocimage(display, Rect(0,0,N*pcsz,N*pcsz), GREY1, 0, 0);
-	bb2 = allocimage(display, Rect(0,0,N*pcsz,N*pcsz+DY), screen->chan, 0, 0);
-	bb2mask = allocimage(display, bb2->r, GREY1, 0, 0);
-	if(bb==0 || bbmask==0 || bb2==0 || bb2mask==0)
-		sysfatal("allocimage fail (bb)");
-	draw(screen, screen->r, display->white, nil, ZP);
-	drawboard();
-	setpiece(piece);
-	if(piece)
-		drawpiece();
-	lastmx = movemouse();
-	newscreen = 1;
-	flushimage(display, 1);
-}
-
-void
-threadmain(int argc, char *argv[])
-{
-	Image *tb;
-	char buf[200];
-	int i, scores;
-	long starttime, endtime;
-
-	ARGBEGIN{
-	}ARGEND
-
-	suspended = 0;
-	setparms();
-	snprint(buf, sizeof(buf), "%ds", N);
-	initdraw(0, 0, buf);
-	mousectl = initmouse(nil, display->image);	/* BUG? */
-	if(mousectl == nil)
-		sysfatal("[45]s: mouse init failed: %r");
-	kbdctl = initkeyboard(nil);	/* BUG? */
-	if(kbdctl == nil)
-		sysfatal("[45]s: keyboard init failed: %r");
-	starttime = time(0);
-	srand(starttime);
-	snprint(buf, sizeof(buf), "/sys/games/lib/%dscores", N);
-	scores = open(buf, OWRITE);
-	if(scores < 0)
-		sysfatal("can't open %s: %r", buf);
-	tb = 0;
-	if(screen->depth < 3){
-		tb = allocimage(display, Rect(0,0,16,16), 0, 1, -1);
-		if(tb == 0)
-			sysfatal("allocimage fail (tb)");
-	}
-	for(i = 0; i<NCOL; i++){
-		tx[i] = allocimage(display, Rect(0, 0, 16, 16), screen->chan, 1, txpix[i]);
-		if(tx[i] == 0)
-			sysfatal("allocimage fail (tx)");
-		if(screen->depth < 3){
-			loadimage(tb, tb->r, txbits[i], 32);
-			draw(tx[i], tx[i]->r, tb, nil, ZP);
-		}
-	}
-	if(tb != 0)
-		freeimage(tb);
-
-	whitemask = allocimage(display, Rect(0,0,1,1), CMAP8, 1, setalpha(DWhite, 0x7F));
-	if(whitemask==0)
-		sysfatal("allocimage fail (whitemask)");
+extern int N, NP;
+extern Piece pieces[];
 
-	threadsetname("4s-5s");
-	timerc= chancreate(sizeof(int), 0);
-	proccreate(timerproc, timerc, 1024);
-	suspc= chancreate(sizeof(int), 0);
-	mousec= chancreate(sizeof(Mouse), 0);
-	kbdc= chancreate(sizeof(Rune), 0);
-	threadcreate(suspproc, nil, 1024);
-	points = 0;
-	memset(board, 0, sizeof(board));
-	redraw(0);
-	if(play()){
-		endtime = time(0);
-		fprint(scores, "%ld\t%s\t%lud\t%ld\n",
-			points, getuser(), starttime, endtime-starttime);
-	}
-	threadexitsall(nil);
-	exits(0);
-}