#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <cursor.h>
#include "rushhour.h"
enum {
LRestart,
LWeird = 1,
LBegin,
LInter,
LTInter,
LAdv,
LTAdv,
LExpert,
LTExpert,
LMaster,
LArgv,
Lbeyond,
LRegen = Lbeyond,
LView,
LExit,
};
int ttnrs[] = {
LTInter,
LTAdv,
LTExpert
};
char *lvlfiles[] = {
[LWeird] "/sys/games/lib/rushhour/levels/weird.slc",
[LBegin] "/sys/games/lib/rushhour/levels/begin.slc",
[LInter] "/sys/games/lib/rushhour/levels/inter.slc",
[LAdv] "/sys/games/lib/rushhour/levels/adv.slc",
[LExpert] "/sys/games/lib/rushhour/levels/expert.slc",
[LMaster] "/sys/games/lib/rushhour/levels/master.slc",
[LTInter] "/mnt/trafficfs/inter",
[LTAdv] "/mnt/trafficfs/adv",
[LTExpert] "/mnt/trafficfs/expert",
[LArgv] "",
};
char *ctlfile = "/mnt/trafficfs/ctl";
char *gencommands[] = {
[LTInter] "gen inter 20 30 200\n",
[LTAdv] "gen adv 30 40 200\n",
[LTExpert] "gen expert 40 55 200\n",
};
char *resetcommands[] = {
[LTInter] "reset inter\n",
[LTAdv] "reset adv\n",
[LTExpert] "reset expert\n",
};
int LFaces;
char *imgdir;
char *buttons[] =
{
"restart",
"weird",
"beginner",
"intermediate",
"tt intermediate",
"advanced",
"tt advanced",
"expert",
"tt expert",
"grand master",
"(no input file)",
"regenerate tt",
"faces",
"exit",
0
};
char *facesorcars[] = {
"faces",
"cars",
};
char *nottbuttons[] =
{
[LTInter] "(no tt intermediate)",
[LTAdv] "(no tt advanced)",
[LTExpert] "(no tt expert)",
};
char **levelnames;
Menu menu =
{
buttons,
};
Menu lmenu =
{
levelnames,
};
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, }
};
static int
istt(int n)
{
switch(n) {
case LTInter:
case LTAdv:
case LTExpert:
return 1;
default:
return 0;
}
}
void*
erealloc(void *p, ulong sz)
{
void *v;
v = realloc(p, sz);
if(v == nil)
sysfatal("realloc %lud fails\n", sz);
return v;
}
char *
estrdup(char *s)
{
char *r;
r = strdup(s);
if(r == nil)
sysfatal("strdup fails\n");
return r;
}
Image *
eallocimage(Rectangle r, int repl, uint color)
{
Image *tmp;
tmp = allocimage(display, r, screen->chan, repl, color);
if(tmp == nil)
sysfatal("cannot allocate buffer image: %r");
return tmp;
}
enum {
Facesize = 48
};
static Image*
readbit(int fd, ulong chan, char *path)
{
char buf[4096], hx[4], *p;
uchar data[Facesize*Facesize]; /* more than enough */
int nhx, i, n, ndata, nbit;
Image *img;
n = readn(fd, buf, sizeof buf);
if(n <= 0)
return nil;
if(n >= sizeof buf)
n = sizeof(buf)-1;
buf[n] = '\0';
n = 0;
nhx = 0;
nbit = chantodepth(chan);
ndata = (Facesize*Facesize*nbit)/8;
p = buf;
while(n < ndata) {
p = strpbrk(p+1, "0123456789abcdefABCDEF");
if(p == nil)
break;
if(p[0] == '0' && p[1] == 'x')
continue;
hx[nhx] = *p;
if(++nhx == 2) {
hx[nhx] = 0;
i = strtoul(hx, 0, 16);
data[n++] = ~i;
nhx = 0;
}
}
if(n < ndata)
sysfatal("short face %s", path);
img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, 0);
if(img == nil)
return nil;
loadimage(img, img->r, data, ndata);
return img;
}
static Image*
resample(Image *src)
{
int p[2], q[2], kid, pid;
Image *img;
if(pipe(p) < 0 || pipe(q) < 0)
sysfatal("can't make a pipe: %r");
kid = fork();
switch(kid){
case -1:
sysfatal("can't fork: %r");
default:
close(p[0]);
close(q[1]);
if (writeimage(p[1], src, 0) < 0)
fprint(2, "error writeimage\n");
close(p[1]);
img = readimage(display, q[0], 0);
close(q[0]);
/*
* we may have unknown children forked by a previous
* program (e.g., rc) that then execed us.
*/
while ((pid = waitpid()) != kid && pid != -1)
continue;
return img;
case 0:
close(p[1]);
close(q[0]);
dup(p[0], 0);
dup(q[1], 1);
execl("/bin/resample", "resample", "-x50%", (char *)nil);
sysfatal("can't exec resample: %r");
}
return nil;
}
Image *
openimage(char *dir, char *file)
{
Image *img;
int fd;
char path[1024];
if (dir != nil)
sprint(path, "%s/%s", dir, file);
else
strcpy(path, file);
fd = open(path, OREAD);
if(fd < 0)
sysfatal("open %s: %r", path);
img = readimage(display, fd, 0);
if(img == nil)
sysfatal("readimage %s: %r", path);
close(fd);
return img;
}
Image*
openface(char *path)
{
char *p;
int fd, n;
Image *tmp, *img;
p = strstr(path, "48x48x");
if(p == nil)
img = openimage(nil, path);
else {
n = atoi(p+6);
if(n < 4){
if((fd = open(path, OREAD)) < 0)
sysfatal("open %s: %r", path);
img = readbit(fd, n==1 ? GREY1 : GREY2, path);
} else
img = openimage(nil, path);
}
if (tinyflag) {
tmp = resample(img);
if (tmp != nil)
return tmp;
return img;
}
return img;
}
static void
allocimages(void)
{
int i;
Rectangle one = Rect(0, 0, 1, 1);
bg = eallocimage(one, 1, 0xAAAAAAFF);//0xEEEEEEFF
text = eallocimage(one, 1, DBluegreen);
black = eallocimage(one, 1, DBlack);
wall = openimage(imgdir, "wall.bit");
empty = openimage(imgdir, "empty.bit");
empty->repl = 1;
win = openimage(imgdir, "win.bit");
col[CarX] = eallocimage(one, 1, 0xFF0000FF);
col[CarY] = eallocimage(one, 1, 0xFF0000FF);
col[CarZ] = eallocimage(one, 1, 0xFF0000FF);
col[CarA] = eallocimage(one, 1, 0x00FF55FF);
col[CarB] = eallocimage(one, 1, 0xCC8800FF);
col[CarC] = eallocimage(one, 1, 0x00AAFFFF);
col[CarD] = eallocimage(one, 1, 0xFF00FFFF);
col[CarE] = eallocimage(one, 1, 0x770077FF);
col[CarF] = eallocimage(one, 1, 0x008844FF);
col[CarG] = eallocimage(one, 1, 0x333333FF); //0x222222FF
col[CarH] = eallocimage(one, 1, 0xBBBB5DFF); //0xCCCC88FF
col[CarI] = eallocimage(one, 1, 0xFFFF00FF);
col[CarJ] = eallocimage(one, 1, 0x884400FF);
col[CarK] = eallocimage(one, 1, 0x555500FF);
for(i=CarL; i <= CarN; i++)
col[i] = col[CarA-CarL+i];
col[TruckO] = eallocimage(one, 1, 0xFFAA00FF);
col[TruckP] = eallocimage(one, 1, 0xBB5DBBFF);
col[TruckQ] = eallocimage(one, 1, 0x0000FFFF);
col[TruckR] = eallocimage(one, 1, 0x00BB5DFF);
for(i=TruckS; i <= TruckV; i++)
col[i] = col[TruckO-TruckS+i];
face[CarX] = openface("/lib/face/48x48x4/g/glenda.1");
face[CarY] = face[CarX];
face[CarZ] = face[CarX];
face[CarA] = openface("/lib/face/48x48x2/k/ken.1");
face[CarB] = openface("/lib/face/48x48x4/b/bobf.1");
face[CarC] = openface("/lib/face/48x48x4/p/philw.1");
face[CarD] = openface("/lib/face/48x48x4/p/presotto.1");
face[CarE] = openface("/lib/face/48x48x4/r/rob.1");
face[CarF] = openface("/lib/face/48x48x4/s/sean.1");
face[CarG] = openface("/lib/face/48x48x4/b/bwk.1");
face[CarH] = openface("/lib/face/48x48x4/c/cyoung.1");
face[CarI] = openface("/lib/face/48x48x4/d/dmr.1");
face[CarJ] = openface("/lib/face/48x48x4/d/doug.1");
face[CarK] = openface("/lib/face/48x48x4/h/howard.1");
for(i=CarL; i <= CarN; i++)
face[i] = face[CarA-CarL+i];
face[TruckO] = openface("/lib/face/48x48x4/j/jmk.1");
face[TruckP] = openface("/lib/face/48x48x4/s/sape.1");
face[TruckQ] = openface("/lib/face/48x48x4/s/seanq.1");
face[TruckR] = openface("/lib/face/48x48x4/t/td.1");
for(i=TruckS; i <= TruckV; i++)
face[i] = face[TruckO-TruckS+i];
face[Wall] = openface("/lib/face/48x48x2/p/pjw+9ball.2");
car[CarX][OHoriz] = openimage(imgdir, "redcarEW.bit");
car[CarX][OVert] = openimage(imgdir, "redcarNS.bit");
car[CarY][OHoriz] = openimage(imgdir, "limoEW.bit");
car[CarY][OVert] = openimage(imgdir, "limoNS.bit");
car[CarZ][OHoriz] = car[CarX][OHoriz];
car[CarZ][OVert] = car[CarX][OVert];
car[CarA][OHoriz] = openimage(imgdir, "AcarEW.bit");
car[CarA][OVert] = openimage(imgdir, "AcarNS.bit");
car[CarB][OHoriz] = openimage(imgdir, "BcarEW.bit");
car[CarB][OVert] = openimage(imgdir, "BcarNS.bit");
car[CarC][OHoriz] = openimage(imgdir, "CcarEW.bit");
car[CarC][OVert] = openimage(imgdir, "CcarNS.bit");
car[CarD][OHoriz] = openimage(imgdir, "DcarEW.bit");
car[CarD][OVert] = openimage(imgdir, "DcarNS.bit");
car[CarE][OHoriz] = openimage(imgdir, "EcarEW.bit");
car[CarE][OVert] = openimage(imgdir, "EcarNS.bit");
car[CarF][OHoriz] = openimage(imgdir, "FcarEW.bit");
car[CarF][OVert] = openimage(imgdir, "FcarNS.bit");
car[CarG][OHoriz] = openimage(imgdir, "GcarEW.bit");
car[CarG][OVert] = openimage(imgdir, "GcarNS.bit");
car[CarH][OHoriz] = openimage(imgdir, "HcarEW.bit");
car[CarH][OVert] = openimage(imgdir, "HcarNS.bit");
car[CarI][OHoriz] = openimage(imgdir, "IcarEW.bit");
car[CarI][OVert] = openimage(imgdir, "IcarNS.bit");
car[CarJ][OHoriz] = openimage(imgdir, "JcarEW.bit");
car[CarJ][OVert] = openimage(imgdir, "JcarNS.bit");
car[CarK][OHoriz] = openimage(imgdir, "KcarEW.bit");
car[CarK][OVert] = openimage(imgdir, "KcarNS.bit");
for(i=CarL; i <= CarN; i++) {
car[i][OHoriz] = car[CarA-CarL+i][OHoriz];
car[i][OVert] = car[CarA-CarL+i][OVert];
}
car[TruckO][OHoriz] = openimage(imgdir, "OlorryEW.bit");
car[TruckO][OVert] = openimage(imgdir, "OlorryNS.bit");
car[TruckP][OHoriz] = openimage(imgdir, "PlorryEW.bit");
car[TruckP][OVert] = openimage(imgdir, "PlorryNS.bit");
car[TruckQ][OHoriz] = openimage(imgdir, "QlorryEW.bit");
car[TruckQ][OVert] = openimage(imgdir, "QlorryNS.bit");
car[TruckR][OHoriz] = openimage(imgdir, "RlorryEW.bit");
car[TruckR][OVert] = openimage(imgdir, "RlorryNS.bit");
for(i=TruckS; i <= TruckV; i++) {
car[i][OHoriz] = car[TruckO-TruckS+i][OHoriz];
car[i][OVert] = car[TruckO-TruckS+i][OVert];
}
msk[CarX][OHoriz] = openimage(imgdir, "redcarEW-msk.bit");
msk[CarX][OVert] = openimage(imgdir, "redcarNS-msk.bit");
msk[CarY][OHoriz] = openimage(imgdir, "limoEW-msk.bit");
msk[CarY][OVert] = openimage(imgdir, "limoNS-msk.bit");
msk[CarZ][OHoriz] = msk[CarX][OHoriz];
msk[CarZ][OVert] = msk[CarX][OVert];
msk[CarA][OHoriz] = openimage(imgdir, "AcarEW-msk.bit");
msk[CarA][OVert] = openimage(imgdir, "AcarNS-msk.bit");
for(i=CarB; i <= CarN; i++) {
msk[i][OHoriz] = msk[CarA][OHoriz];
msk[i][OVert] = msk[CarA][OVert];
}
msk[TruckO][OHoriz] = openimage(imgdir, "OlorryEW-msk.bit");
msk[TruckO][OVert] = openimage(imgdir, "OlorryNS-msk.bit");
for(i=TruckP; i <= TruckV; i++) {
msk[i][OHoriz] = msk[TruckO][OHoriz];
msk[i][OVert] = msk[TruckO][OVert];
}
}
static Point
point2pos(Point p)
{
p.x /= BoardX;
p.x += Off;
p.y /= BoardY;
p.y += Off;
return p;
}
static Point
mouse2point(Mouse m)
{
Point p;
p = subpt(m.xy, screen->r.min);
return p;
}
static Point
point2mouse(Point mp)
{
Point p;
p = addpt(mp, screen->r.min);
return p;
}
static Point
project(Point p, Point dir)
{
if (dir.x == 0)
p.x = 0;
if (dir.y == 0)
p.y = 0;
return p;
}
static int
writectl(char *s)
{
int ctlfd;
ctlfd = open(ctlfile, OWRITE);
if (ctlfd < 0) {
fprint(2, "cannot open trafficfs ctl: %r\n");
return 0;
} else {
fprint(ctlfd, "%s", s);
close(ctlfd);
return 1;
}
}
static void
initttlevels(void)
{
int i, n;
if (access(ctlfile,0) == 0)
for (i=0; i < nelem(ttnrs); i++) {
n = ttnrs[i];
if (access(lvlfiles[n],0) < 0 && ! writectl(gencommands[n])) {
lvlfiles[n] = "";
buttons[n] = nottbuttons[n];
}
}
else
for (i=0; i < nelem(ttnrs); i++) {
n = ttnrs[i];
lvlfiles[n] = "";
buttons[n] = nottbuttons[n];
}
}
char *
genlevels(int i)
{
char *s;
if(i >= numlevels)
return 0;
if (levels[i].name == nil)
s = smprint("level %d", i+1);
else
s = smprint("level %d (%s)", i+1, levels[i].name);
return s;
}
static void
buildmenu(void)
{
int i;
if (levelnames != nil) {
for(i=0; levelnames[i] != 0; i++)
free(levelnames[i]);
}
levelnames = erealloc(levelnames, sizeof(char*)*(numlevels+1));
for(i=0; i < numlevels; i++)
levelnames[i] = genlevels(i);
levelnames[numlevels] = 0;
lmenu.item = levelnames;
}
static void
doloadlevels(int n)
{
int r;
r = loadlevels(lvlfiles[n]);
if (! istt(n))
return;
if (r < 0 && access(ctlfile,0) < 0) {
lvlfiles[n] = "";
buttons[n] = nottbuttons[n];
} else if (numlevels == 0 && access(ctlfile,0) == 0) {
writectl(resetcommands[n]);
writectl(gencommands[n]);
loadlevels(lvlfiles[n]);
}
}
static void
activatelevel(Level l, Point *topleft)
{
*topleft = Pt(-1,-1);
level = l;
drawlevel();
drawscreen();
}
static void
uselevels(int l, int *lvlindex, Point *topleft)
{
if (strcmp(lvlfiles[l], "") != 0) {
*lvlindex = l;
doloadlevels(*lvlindex);
buildmenu();
activatelevel(levels[0], topleft);
}
}
static void
nextlevel(int *lvlindex, Point *topleft)
{
if(level.index < numlevels - 1)
activatelevel(levels[++level.index], topleft);
else if (*lvlindex < Lbeyond -1 &&
strcmp(lvlfiles[(*lvlindex)+1], "") != 0) {
doloadlevels(++(*lvlindex));
buildmenu();
activatelevel(levels[0], topleft);
} else
*topleft = Pt(-1,-1);
}
static void
prevlevel(int *lvlindex, Point *topleft)
{
if(level.index > 0)
activatelevel(levels[--level.index], topleft);
else if (*lvlindex > 1) {
doloadlevels(--(*lvlindex));
buildmenu();
activatelevel(levels[numlevels-1], topleft);
} else
*topleft = Pt(-1,-1);
}
static void
regenlevels(int lvlindex, Point *topleft)
{
if (istt(lvlindex) && access(ctlfile,0) == 0) {
writectl(gencommands[lvlindex]);
doloadlevels(lvlindex);
buildmenu();
activatelevel(levels[0], topleft);
}
}
static void
toggleview(void)
{
if (usefaces)
usefaces = 0;
else
usefaces = 1;
buttons[LFaces] = facesorcars[usefaces];
drawlevel();
drawscreen();
}
static int
finished(void)
{
int x, y;
for(x = 0; x < MazeX; x++)
for(y = 0; y < MazeY; y++)
if(level.board[x][y] == level.us)
return 0;
return 1;
}
void
eresized(int new)
{
Point p;
if(new && getwindow(display, Refnone) < 0)
sysfatal("can't reattach to window");
p = Pt(Dx(screen->r), Dy(screen->r));
if(!new || !eqpt(p, boardsize(subpt(level.max,Pt(Off,Off))))) {
drawlevel();
}
drawscreen();
}
static char*
mklabel(char *s)
{
char *p, *e, c;
p = strrchr(s, '/');
if (p != nil)
p++;
else
p = s;
e = strchr(p, '.');
if (e != nil) {
c = *e;
*e = '\0';
p = estrdup(p);
*e = c;
} else
p = estrdup(p);
return p;
}
static Point
key2dir(int kbdc)
{
switch(kbdc){
case 61454: /*Up*/
return Pt(0,-1);
case 63488: /*Down*/
return Pt(0,1);
case 61457: /*Left*/
return Pt(-1,0);
case 61458: /*Right*/
return Pt(1,0);
default:
return Pt(0,0);
}
}
void
main(int argc, char **argv)
{
Mouse m, mprev;
Event ev;
int e, start, up, lvlindex, l, cursoronly, mouseinitialized;
Point p, d, off, dir, prevdir, topleft, vacant, dst, winoff, tl, tdir;
char *fontfile, **bp;
Rectangle *drp, *srp;
imgdir = "/sys/games/lib/rushhour/images/normal";
fontfile = nil;
BoardX = 48;
BoardY = 48;
winoff = Pt(6,6);
OutlineWidth = 2;
LFaces = LView;
lvlindex = LBegin;
levelnames = nil;
start = 1;
up = 0;
topleft = Pt(-1,-1);
cursoronly = 0;
mouseinitialized = 0;
ARGBEGIN{
case 'b':
boutflag = 1;
break;
case 'f':
usefaces = 1;
buttons[LFaces] = facesorcars[usefaces];
break;
case 't':
tinyflag = 1;
imgdir = "/sys/games/lib/rushhour/images/small";
fontfile = "/lib/font/bit/lucidasans/unicode.6.font";
BoardX = 24;
BoardY = 24;
winoff = Pt(3,3);
OutlineWidth = 1;
break;
default:
fprint(2, "Usage: %s [-f] [-t] [levelfile]\n", argv0);
exits("usage");
}ARGEND
switch(argc) {
case 1:
lvlindex = LArgv;
lvlfiles[LArgv] = argv[0];
buttons[LArgv] = mklabel(argv[0]);
break;
case 0:
buttons[LArgv] = "";
/* remove empty LArgv buttons menu entry */
bp = &buttons[LArgv];
memmove(bp, bp+1, sizeof(char*)*(nelem(buttons)-LArgv-1));
LFaces--;
break;
default:
fprint(2, "Usage: %s [-f] [-t] [levelfile]\n", argv0);
exits("usage");
}
if(loadlevels(lvlfiles[lvlindex]) < 0) {
fprint(2, "Usage: %s [-f] [-t] [levelfile]\n", argv0);
exits("usage");
}
initttlevels();
buildmenu();
if(initdraw(nil, fontfile, "rushhour") < 0)
sysfatal("initdraw failed: %r");
einit(Emouse|Ekeyboard);
SizeX = MazeX*BoardX+10,
SizeY = MazeY*BoardY+10,
allocimages();
eresized(0);
for(;;) {
e = event(&ev);
switch(e) {
case Emouse:
m = ev.mouse;
if (start) {
mprev = m;
start = 0;
}
if(m.buttons&1) {
/* setting up here instead of in next else branch
* did make a difference in the version with
* explicit selection making. should not matter here?
*/
up = 1;
if (! mprev.buttons&1) {
d = mouse2point(m);
topleft = gettopleft(point2pos(d));
prevdir = ZP;
} else {
/* up = 1; moved upwards */
if (! eqpt(topleft, Pt(-1,-1)) && isvehicle(item(topleft))) {
p = mouse2point(m);
off = subpt(p, d);
dir = getdir(topleft, off);
if (!eqpt(prevdir, ZP) && !eqpt(prevdir, dir)) {
dst = destof(topleft, prevdir);
drawboard(dst, 0, ZP);
}
prevdir = dir;
off = project(off, dir);
while(canmove(topleft,dir) && !intile(off, dir)) {
/*
* superflous:
* dst = destof(tl, dir);
* drawboard(dst, 0, ZP);
*/
onestep(topleft, dir, &vacant);
topleft = addpt(topleft, dir);
drawboard(vacant, 0, ZP);
off = subtile(off, dir);
d = addtile(d, dir);
}
if (!canmove(topleft, dir))
off = ZP;
dst = destof(topleft, dir);
drawboard(dst, 0, ZP);
drawboard(topleft, 0, off);
drawscreen();
}
}
} else if (up) {
up = 0;
if (!eqpt(topleft, Pt(-1,-1)) && isvehicle(item(topleft))){
p = mouse2point(m);
dir = getdir(topleft, off);
if (canmove(topleft, dir) && !inhalftile(off, dir)) {
onestep(topleft, dir, &vacant);
topleft = addpt(topleft, dir);
drawboard(vacant, 0, ZP);
} else {
dst = destof(topleft, dir);
drawboard(dst, 0, ZP);
}
drawboard(topleft, 0, ZP);
drawscreen();
}
/*
* superflous; does clean up if we messed up
* which we don't, of course
* drawlevel();
* drawscreen();
*/
} else {
if(m.buttons&2) {
lmenu.lasthit = level.index;
l = emenuhit(2, &m, &lmenu);
if (l >= 0)
activatelevel(levels[l], &topleft);
}
if(m.buttons&4) {
menu.lasthit = lvlindex;
l = emenuhit(3, &m, &menu);
/* deal with removed empty LArgv menu entry */
if (l >= LArgv && strcmp(lvlfiles[LArgv], "") == 0)
l += 1;
switch(l) {
case LRestart:
activatelevel(levels[level.index], &topleft);
break;
case LWeird:
case LBegin:
case LInter:
case LTInter:
case LAdv:
case LTAdv:
case LExpert:
case LTExpert:
case LMaster:
case LArgv:
uselevels(l, &lvlindex, &topleft);
break;
case LRegen:
regenlevels(lvlindex, &topleft);
break;
case LView:
toggleview();
break;
case LExit:
exits(nil);
}
}
}
mprev = m;
break;
case Ekeyboard:
switch(ev.kbdc) {
case 127:
case 'q':
case 'Q':
exits(nil);
case 'n':
case 'N':
nextlevel(&lvlindex, &topleft);
break;
case 'p':
case 'P':
prevlevel(&lvlindex, &topleft);
break;
case 'r':
case 'R':
activatelevel(levels[level.index], &topleft);
break;
case 27: /*Esc*/
case ' ':
if (cursoronly) {
cursoronly = 0;
esetcursor(nil);
} else {
Point m0, p0, p1,p2;
drp = &display->image->r;
srp = &screen->r;
cursoronly = 1;
esetcursor(&whitearrow);
if (!ptinrect(m.xy, *srp)) {
//fprint(2, "m0 %R %P", *srp, m.xy);
if (eqpt(m.xy, Pt(0,0)) && !mouseinitialized)
m.xy = addpt(srp->min, Pt(Dx(*srp)/2, Dy(*srp)/2));
else if (ptinrect(m.xy, Rect(srp->min.x, drp->min.y, srp->max.x, srp->min.y)))
m.xy.y = srp->min.y + 1; /*above game window*/
else if (ptinrect(m.xy, Rect(srp->max.x, srp->min.y, drp->max.x, srp->max.y)))
m.xy.x = srp->max.x - 1; /*to right of game window*/
else if (ptinrect(m.xy, Rect(srp->min.x, srp->max.y, srp->max.x, drp->max.y)))
m.xy.y = srp->max.y - 1; /*below game window*/
else if (ptinrect(m.xy, Rect(drp->min.x,drp->min.y, srp->min.x, srp->max.y)))
m.xy.x = srp->max.x + 1; /*left of game window*/
//fprint(2, " m1 %P\n", m.xy);
}
mouseinitialized = 1;
m0 = mouse2point(m);
p0 = point2pos(m0);
p1 = subpt(p0, Pt(Off,Off));
p2 = addpt(Pt(p1.x*BoardX,p1.y*BoardY), divpt(Pt(BoardX,BoardY),2));
m.xy = point2mouse(p2);
//fprint(2, "m0%P p0%P p1%P p2%P m1%P\n", m0, p0, p1, p2, m.xy);
emoveto(m.xy);
}
break;
case 61454: /*Up*/
case 63488: /*Down*/
case 61457: /*Left*/
case 61458: /*Right*/
if (cursoronly) {
Point m1;
tdir = key2dir(ev.kbdc);
m1 = addpt(m.xy, Pt(tdir.x*BoardX,tdir.y*BoardY));
if (ptinrect(m1, screen->r)){
m.xy = m1;
emoveto(m.xy);
}
} else {
/* avoid updating global variables: topleft, d (dir?)
* unless condition in this case holds
* (if they are updated, they interfere with the
* handling of mouse-button1-move events
* if cursor keys are used while at the same time
* mouse button 1 is continuiously pressed,
* and the mouse is occasionally moved).
* currently there is minor interference if
* we B1press and move with mouse tiny bits
* back and forth, while one side is blocked.
* e.g. right side blocked, we move 1/4 tile left,
* then 1/8 back right, back left a bit, etc.,
* and then start pressing cursor keys:
* nothhing happens, until we mouse-move
* the car to the next tile grid border.
*/
tl = gettopleft(point2pos(mouse2point(m)));
tdir = getdir(tl, key2dir(ev.kbdc));
if (! eqpt(tl, Pt(-1,-1)) &&
isvehicle(item(tl)) &&
canmove(tl,tdir)) {
topleft = tl;
dir = tdir;
if (!eqpt(prevdir, ZP) && !eqpt(prevdir, dir)) {
dst = destof(topleft, prevdir);
drawboard(dst, 0, ZP);
}
prevdir = ZP;
onestep(topleft, dir, &vacant);
topleft = addpt(topleft, dir);
dst = destof(topleft, dir);
m.xy = addpt(m.xy, Pt(dir.x*BoardX,dir.y*BoardY));
d = mouse2point(m);
emoveto(m.xy);
drawboard(dst, 0, ZP);
drawboard(vacant, 0, ZP);
drawboard(topleft, 0, ZP);
drawscreen();
}
}
break;
default:
// fprint(2, "key: %d\n", ev.kbdc);
break;
}
break;
default:
break;
}
if(finished() && ! level.done) {
level.done = 1;
level.win = vacant; /* set tile of 'you win' msg */
drawwin(winoff);
drawscreen();
sleep(3000);
nextlevel(&lvlindex, &topleft);
}
}
}
|