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/feature_posix/sys/src/games/sokoban/sokoban.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 <u.h>
2
#include <libc.h>
3
#include <draw.h>
4
#include <event.h>
5
 
6
#include "sokoban.h"
7
 
8
#define SOKOTREE "/sys/games/lib/sokoban/"
9
 
10
char *LEasy = SOKOTREE "levels/easy.slc";
11
char *LHard = SOKOTREE "levels/hard.slc";
12
char *levelfile;
13
 
14
#define SOKOIMG SOKOTREE "images/"
15
 
16
char	*GRImage =	SOKOIMG "right.bit";
17
char	*GLImage =	SOKOIMG "left.bit";
18
char	*WallImage =	SOKOIMG "wall.bit";
19
char	*EmptyImage =	SOKOIMG "empty.bit";
20
char	*CargoImage =	SOKOIMG "cargo.bit";
21
char	*GoalCargoImage= SOKOIMG "goalcargo.bit";
22
char	*GoalImage =	SOKOIMG "goal.bit";
23
char	*WinImage =	SOKOIMG "win.bit";
24
 
25
char *buttons[] = 
26
{
27
	"restart",
28
	"easy",
29
	"hard",
30
	"noanimate", /* this menu string initialized in main */
31
	"exit",
32
 
33
};
34
 
35
char **levelnames;
36
 
37
Menu menu = 
38
{
39
	buttons,
40
};
41
 
42
Menu lmenu =
43
{
44
	levelnames,
45
};
46
 
47
void
48
buildmenu(void)
49
{
50
	int i;
51
 
52
	if (levelnames != nil) {
53
		for(i=0; levelnames[i] != 0; i++)
54
			free(levelnames[i]);
55
	}
56
	levelnames = realloc(levelnames, sizeof(char*)*(numlevels+1));
57
	if (levelnames == nil)
58
		sysfatal("cannot allocate levelnames");
59
	for(i=0; i < numlevels; i++)
60
		levelnames[i] = genlevels(i);
61
	levelnames[numlevels] = 0;
62
	lmenu.item = levelnames;
63
}
64
 
65
Image *
66
eallocimage(Rectangle r, int repl, uint color)
67
{
68
	Image *tmp;
69
 
70
	tmp = allocimage(display, r, screen->chan, repl, color);
71
	if(tmp == nil)
72
		sysfatal("cannot allocate buffer image: %r");
73
 
74
	return tmp;
75
}
76
 
77
Image *
78
eloadfile(char *path)
79
{
80
	Image *img;
81
	int fd;
82
 
83
	fd = open(path, OREAD);
84
	if(fd < 0) {
85
		fprint(2, "cannot open image file %s: %r\n", path);
86
		exits("image");
87
	}
88
	img = readimage(display, fd, 0);
89
	if(img == nil)
90
		sysfatal("cannot load image: %r");
91
	close(fd);
92
 
93
	return img;
94
}
95
 
96
 
97
void
98
allocimages(void)
99
{
100
	Rectangle one = Rect(0, 0, 1, 1);
101
 
102
	bg		= eallocimage(one, 1, DDarkyellow);
103
	text 		= eallocimage(one, 1, DBluegreen);
104
 
105
	gright = eloadfile(GRImage);
106
	gleft = eloadfile(GLImage);
107
	wall = eloadfile(WallImage);
108
	empty = eloadfile(EmptyImage);
109
	empty->repl = 1;
110
	goalcargo = eloadfile(GoalCargoImage);
111
	cargo = eloadfile(CargoImage);
112
	goal = eloadfile(GoalImage);
113
	win = eloadfile(WinImage);
114
}
115
 
116
int
117
key2move(int key)
118
{
119
	int k = 0;
120
 
121
	switch(key) {
122
	case 61454:
123
		k = Up;
124
		break;
125
	case 63488:
126
		k = Down;
127
		break;
128
	case 61457:
129
		k = Left;
130
		break;
131
	case 61458:
132
		k = Right;
133
		break;
134
	}
135
 
136
	return k;
137
}
138
 
139
static Route*
140
mouse2route(Mouse m)
141
{
142
	Point p, q;
143
	Route *r;
144
 
145
	p = subpt(m.xy, screen->r.min);
146
	p.x /= BoardX;
147
	p.y /= BoardY;
148
 
149
	q = subpt(p, level.glenda);
150
	// fprint(2, "x=%d y=%d\n", q.x, q.y);
151
 
152
	if (q.x == 0 && q.y ==  0)
153
		return nil;
154
 
155
	if (q.x == 0 || q.y ==  0) {
156
		if (q.x < 0)
157
			r = extend(nil, Left, -q.x, Pt(level.glenda.x, p.y));
158
		else if (q.x > 0)
159
			r = extend(nil, Right, q.x, Pt(level.glenda.x, p.y));
160
		else if (q.y < 0)
161
			r = extend(nil, Up, -q.y, level.glenda);
162
		else if (q.y > 0)
163
			r = extend(nil, Down, q.y, level.glenda);
164
		else
165
			r = nil;
166
 
167
		if (r != nil && isvalid(level.glenda, r, validpush))
168
			return r;
169
		freeroute(r);
170
	}
171
 
172
	return findroute(level.glenda, p);
173
}
174
 
175
char *
176
genlevels(int i)
177
{
178
 
179
	if(i >= numlevels)
180
		return 0;
181
 
182
	return smprint("level %d", i+1);
183
}
184
 
185
 
186
int
187
finished(void)
188
{
189
	int x, y;
190
	for(x = 0; x < MazeX; x++)
191
		for(y = 0; y < MazeY; y++)
192
			if(level.board[x][y] == Goal)
193
				return 0;
194
 
195
	return 1;
196
}
197
 
198
void
199
eresized(int new)
200
{
201
	Point p;
202
 
203
	if(new && getwindow(display, Refnone) < 0)
204
		sysfatal("can't reattach to window");
205
 
206
	p = Pt(Dx(screen->r), Dy(screen->r));
207
 
208
	if(!new || !eqpt(p, boardsize(level.max))) {
209
		drawlevel();
210
	}
211
	drawscreen();
212
}
213
 
214
void 
215
main(int argc, char **argv)
216
{
217
	Mouse m;
218
	Event ev;
219
	int e;
220
	Route *r;
221
	int timer;
222
	Animation a;
223
	int animate;
224
 
225
 
226
	if(argc == 2) 
227
		levelfile = argv[1];
228
	else
229
		levelfile = LEasy;
230
 
231
	if(! loadlevels(levelfile)) {
232
		fprint(2, "usage: %s [levelfile]\n", argv[0]);
233
		exits("usage");
234
	}
235
	buildmenu();
236
 
237
	animate = 0;
238
	buttons[3] = animate ? "noanimate" : "animate";
239
 
240
	if(initdraw(nil, nil, "sokoban") < 0)
241
		sysfatal("initdraw failed: %r");
242
	einit(Emouse|Ekeyboard);
243
 
244
	timer = etimer(0, 200);
245
	initanimation(&a);
246
 
247
	allocimages();
248
	glenda = gright;
249
	eresized(0);
250
 
251
	for(;;) {
252
		e = event(&ev);
253
		switch(e) {
254
		case Emouse:
255
			m = ev.mouse;
256
			if(m.buttons&1) {
257
				stopanimation(&a);
258
				r = mouse2route(m);
259
				if (r)
260
					setupanimation(&a, r);
261
				if (! animate) {
262
					while(onestep(&a))
263
						;
264
					drawscreen();
265
				}
266
			}
267
			if(m.buttons&2) {
268
				int l;
269
				/* levels start from 1 */
270
				lmenu.lasthit = level.index;
271
				l=emenuhit(2, &m, &lmenu);
272
				if(l>=0){
273
					stopanimation(&a);
274
					level = levels[l];
275
					drawlevel();
276
					drawscreen();
277
				}
278
			}
279
			if(m.buttons&4)
280
				switch(emenuhit(3, &m, &menu)) {
281
				case 0:
282
					stopanimation(&a);
283
					level = levels[level.index];
284
					drawlevel();
285
					drawscreen();
286
					break;
287
				case 1:
288
					stopanimation(&a);
289
					loadlevels(LEasy);
290
					buildmenu();
291
					drawlevel();
292
					drawscreen();
293
					break;
294
				case 2:
295
					stopanimation(&a);
296
					loadlevels(LHard);
297
					buildmenu();
298
					drawlevel();
299
					drawscreen();
300
					break;
301
				case 3:
302
					animate = !animate;
303
					buttons[3] = animate ? "noanimate" : "animate";
304
					break;
305
				case 4:
306
					exits(nil);
307
				}
308
			break;
309
 
310
		case Ekeyboard:
311
			if(level.done)
312
				break;
313
 
314
			stopanimation(&a);
315
 
316
			switch(ev.kbdc) {
317
			case 127:
318
			case 'q':
319
			case 'Q':
320
				exits(nil);
321
			case 'n':
322
			case 'N':
323
				if(level.index < numlevels - 1) {
324
					level = levels[++level.index];
325
					drawlevel();
326
					drawscreen();
327
				}
328
				break;
329
			case 'p':
330
			case 'P':
331
				if(level.index > 0) {
332
					level = levels[--level.index];
333
					drawlevel();
334
					drawscreen();
335
				}
336
				break;
337
			case 'r':
338
			case 'R':
339
				level = levels[level.index];
340
				drawlevel();
341
				drawscreen();
342
				break;
343
			case 61454:
344
			case 63488:
345
			case 61457:
346
			case 61458:
347
			case ' ':
348
				move(key2move(ev.kbdc));
349
				drawscreen();
350
				break;
351
			default:
352
				// fprint(2, "key: %d]\n", e.kbdc);
353
				break;
354
			}
355
			break;
356
 
357
		default:
358
			if (e == timer) {
359
				if (animate)
360
					onestep(&a);
361
				else
362
					while(onestep(&a))
363
						;
364
				drawscreen();
365
			}
366
			break;
367
		}
368
 
369
		if(finished()) {
370
			level.done = 1;
371
			drawwin();
372
			drawscreen();
373
			sleep(3000);
374
			if(level.index < numlevels - 1) {
375
				level = levels[++level.index];
376
				drawlevel();
377
				drawscreen();
378
			}
379
		}
380
	}
381
}