move.c revision 1.9
1/*	$OpenBSD: move.c,v 1.9 2009/10/27 23:59:26 deraadt Exp $	*/
2/*	$NetBSD: move.c,v 1.4 1995/04/22 10:08:58 cgd Exp $	*/
3
4/*
5 * Copyright (c) 1980, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include "robots.h"
34
35#define	ESC	'\033'
36
37/*
38 * get_move:
39 *	Get and execute a move from the player
40 */
41void
42get_move(void)
43{
44	int	c;
45	int retval;
46	struct timeval t, tod;
47	struct timezone tz;
48#ifdef FANCY
49	int lastmove;
50#endif
51
52	if (Waiting)
53		return;
54
55#ifdef	FANCY
56	if (Pattern_roll) {
57		if (Next_move >= Move_list)
58			lastmove = *Next_move;
59		else
60			lastmove = -1;	/* flag for "first time in" */
61	}
62#endif
63	if (Real_time) {
64		t.tv_sec = tv.tv_sec;
65		t.tv_usec = tv.tv_usec;
66		(void)gettimeofday(&tod, &tz);
67	}
68	for (;;) {
69		if (Teleport && must_telep())
70			goto teleport;
71		if (Running)
72			c = Run_ch;
73		else if (Count != 0)
74			c = Cnt_move;
75#ifdef	FANCY
76		else if (Num_robots > 1 && Stand_still)
77			c = '>';
78		else if (Num_robots > 1 && Pattern_roll) {
79			if (*++Next_move == '\0') {
80				if (lastmove < 0)
81					goto over;
82				Next_move = Move_list;
83			}
84			c = *Next_move;
85			mvaddch(0, 0, c);
86			if (c == lastmove)
87				goto over;
88		}
89#endif
90		else {
91over:
92			if (Real_time) {
93				FD_SET(STDIN_FILENO, &rset);
94				retval = select(STDIN_FILENO + 1, &rset, NULL, NULL, &t);
95				if (retval > 0)
96					c = getchar();
97				else	/* Don't move if timed out or error */
98					c = ' ';
99			} else {
100				c = getchar();
101				/* Can't use digits in real time mode, or digit/ESC
102				 * is an effective way to stop the game.
103				 */
104				if (isdigit(c)) {
105					Count = (c - '0');
106					while (isdigit(c = getchar()))
107						Count = Count * 10 + (c - '0');
108					if (c == ESC)
109						goto over;
110					Cnt_move = c;
111					if (Count)
112						leaveok(stdscr, TRUE);
113				}
114			}
115		}
116
117		switch (c) {
118		  case ' ':
119		  case '.':
120			if (do_move(0, 0))
121				goto ret;
122			break;
123		  case 'y':
124			if (do_move(-1, -1))
125				goto ret;
126			break;
127		  case 'k':
128			if (do_move(-1, 0))
129				goto ret;
130			break;
131		  case 'u':
132			if (do_move(-1, 1))
133				goto ret;
134			break;
135		  case 'h':
136			if (do_move(0, -1))
137				goto ret;
138			break;
139		  case 'l':
140			if (do_move(0, 1))
141				goto ret;
142			break;
143		  case 'b':
144			if (do_move(1, -1))
145				goto ret;
146			break;
147		  case 'j':
148			if (do_move(1, 0))
149				goto ret;
150			break;
151		  case 'n':
152			if (do_move(1, 1))
153				goto ret;
154			break;
155		  case 'Y': case 'U': case 'H': case 'J':
156		  case 'K': case 'L': case 'B': case 'N':
157		  case '>':
158			Running = TRUE;
159			if (c == '>')
160				Run_ch = ' ';
161			else
162				Run_ch = tolower(c);
163			leaveok(stdscr, TRUE);
164			break;
165		  case 'q':
166		  case 'Q':
167			if (query("Really quit?"))
168				quit(0);
169			refresh();
170			break;
171		  case 'w':
172		  case 'W':
173			Waiting = TRUE;
174			leaveok(stdscr, TRUE);
175#ifndef NCURSES_VERSION
176			flushok(stdscr, FALSE);
177#endif
178			goto ret;
179		  case 't':
180		  case 'T':
181teleport:
182			Running = FALSE;
183			mvaddch(My_pos.y, My_pos.x, ' ');
184			My_pos = *rnd_pos();
185			mvaddch(My_pos.y, My_pos.x, PLAYER);
186			leaveok(stdscr, FALSE);
187			refresh();
188			flushinp();
189			goto ret;
190		  case CTRL('L'):
191			wrefresh(curscr);
192			break;
193		  case EOF:
194			quit(0);
195			break;
196		  default:
197			beep();
198			reset_count();
199			break;
200		}
201		if (Real_time) {
202			(void)gettimeofday(&t, &tz);
203			t.tv_sec = tod.tv_sec + tv.tv_sec - t.tv_sec;
204			t.tv_usec = tod.tv_usec + tv.tv_usec - t.tv_usec;
205			if (t.tv_usec < 0) {
206				t.tv_sec--;
207				t.tv_usec += 1000000;	/* Now it must be > 0 */
208			}
209			if (t.tv_sec < 0)
210				goto ret;
211		}
212	}
213ret:
214	if (Count > 0)
215		if (--Count == 0)
216			leaveok(stdscr, FALSE);
217}
218
219/*
220 * must_telep:
221 *	Must I teleport; i.e., is there anywhere I can move without
222 * being eaten?
223 */
224bool
225must_telep(void)
226{
227	int		x, y;
228	static COORD	newpos;
229
230#ifdef	FANCY
231	if (Stand_still && Num_robots > 1 && eaten(&My_pos))
232		return TRUE;
233#endif
234
235	for (y = -1; y <= 1; y++) {
236		newpos.y = My_pos.y + y;
237		if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE)
238			continue;
239		for (x = -1; x <= 1; x++) {
240			newpos.x = My_pos.x + x;
241			if (newpos.x <= 0 || newpos.x >= X_FIELDSIZE)
242				continue;
243			if (Field[newpos.y][newpos.x] > 0)
244				continue;
245			if (!eaten(&newpos))
246				return FALSE;
247		}
248	}
249	return TRUE;
250}
251
252/*
253 * do_move:
254 *	Execute a move
255 */
256bool
257do_move(int dy, int dx)
258{
259	static COORD	newpos;
260
261	newpos.y = My_pos.y + dy;
262	newpos.x = My_pos.x + dx;
263	if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE ||
264	    newpos.x <= 0 || newpos.x >= X_FIELDSIZE ||
265	    Field[newpos.y][newpos.x] > 0 || eaten(&newpos)) {
266		if (Running) {
267			Running = FALSE;
268			leaveok(stdscr, FALSE);
269			move(My_pos.y, My_pos.x);
270			refresh();
271		} else {
272			beep();
273			reset_count();
274		}
275		return FALSE;
276	}
277	else if (dy == 0 && dx == 0)
278		return TRUE;
279	mvaddch(My_pos.y, My_pos.x, ' ');
280	My_pos = newpos;
281	mvaddch(My_pos.y, My_pos.x, PLAYER);
282	if (!jumping())
283		refresh();
284	return TRUE;
285}
286
287/*
288 * eaten:
289 *	Player would get eaten at this place
290 */
291bool
292eaten(COORD *pos)
293{
294	int	x, y;
295
296	for (y = pos->y - 1; y <= pos->y + 1; y++) {
297		if (y <= 0 || y >= Y_FIELDSIZE)
298			continue;
299		for (x = pos->x - 1; x <= pos->x + 1; x++) {
300			if (x <= 0 || x >= X_FIELDSIZE)
301				continue;
302			if (Field[y][x] == 1)
303				return TRUE;
304		}
305	}
306	return FALSE;
307}
308
309/*
310 * reset_count:
311 *	Reset the count variables
312 */
313void
314reset_count(void)
315{
316	Count = 0;
317	Running = FALSE;
318	leaveok(stdscr, FALSE);
319	refresh();
320}
321
322/*
323 * jumping:
324 *	See if we are jumping, i.e., we should not refresh.
325 */
326bool
327jumping(void)
328{
329	return (Jump && (Count || Running || Waiting));
330}
331