move.c revision 1.7
1/*	$OpenBSD: move.c,v 1.7 2003/06/03 03:01:41 millert 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#ifndef lint
34#if 0
35static char sccsid[] = "@(#)move.c	8.1 (Berkeley) 5/31/93";
36#else
37static char rcsid[] = "$OpenBSD: move.c,v 1.7 2003/06/03 03:01:41 millert Exp $";
38#endif
39#endif /* not lint */
40
41#include "robots.h"
42
43#define	ESC	'\033'
44
45/*
46 * get_move:
47 *	Get and execute a move from the player
48 */
49void
50get_move()
51{
52	int	c;
53	int retval;
54	struct timeval t, tod;
55	struct timezone tz;
56#ifdef FANCY
57	int lastmove;
58#endif
59
60	if (Waiting)
61		return;
62
63#ifdef	FANCY
64	if (Pattern_roll) {
65		if (Next_move >= Move_list)
66			lastmove = *Next_move;
67		else
68			lastmove = -1;	/* flag for "first time in" */
69	}
70#endif
71	if (Real_time) {
72		t.tv_sec = tv.tv_sec;
73		t.tv_usec = tv.tv_usec;
74		(void)gettimeofday(&tod, &tz);
75	}
76	for (;;) {
77		if (Teleport && must_telep())
78			goto teleport;
79		if (Running)
80			c = Run_ch;
81		else if (Count != 0)
82			c = Cnt_move;
83#ifdef	FANCY
84		else if (Num_robots > 1 && Stand_still)
85			c = '>';
86		else if (Num_robots > 1 && Pattern_roll) {
87			if (*++Next_move == '\0') {
88				if (lastmove < 0)
89					goto over;
90				Next_move = Move_list;
91			}
92			c = *Next_move;
93			mvaddch(0, 0, c);
94			if (c == lastmove)
95				goto over;
96		}
97#endif
98		else {
99over:
100			if (Real_time) {
101				FD_SET(STDIN_FILENO, &rset);
102				retval = select(STDIN_FILENO + 1, &rset, NULL, NULL, &t);
103				if (retval > 0)
104					c = getchar();
105				else	/* Don't move if timed out or error */
106					c = ' ';
107			} else {
108				c = getchar();
109				/* Can't use digits in real time mode, or digit/ESC
110				 * is an effective way to stop the game.
111				 */
112				if (isdigit(c)) {
113					Count = (c - '0');
114					while (isdigit(c = getchar()))
115						Count = Count * 10 + (c - '0');
116					if (c == ESC)
117						goto over;
118					Cnt_move = c;
119					if (Count)
120						leaveok(stdscr, TRUE);
121				}
122			}
123		}
124
125		switch (c) {
126		  case ' ':
127		  case '.':
128			if (do_move(0, 0))
129				goto ret;
130			break;
131		  case 'y':
132			if (do_move(-1, -1))
133				goto ret;
134			break;
135		  case 'k':
136			if (do_move(-1, 0))
137				goto ret;
138			break;
139		  case 'u':
140			if (do_move(-1, 1))
141				goto ret;
142			break;
143		  case 'h':
144			if (do_move(0, -1))
145				goto ret;
146			break;
147		  case 'l':
148			if (do_move(0, 1))
149				goto ret;
150			break;
151		  case 'b':
152			if (do_move(1, -1))
153				goto ret;
154			break;
155		  case 'j':
156			if (do_move(1, 0))
157				goto ret;
158			break;
159		  case 'n':
160			if (do_move(1, 1))
161				goto ret;
162			break;
163		  case 'Y': case 'U': case 'H': case 'J':
164		  case 'K': case 'L': case 'B': case 'N':
165		  case '>':
166			Running = TRUE;
167			if (c == '>')
168				Run_ch = ' ';
169			else
170				Run_ch = tolower(c);
171			leaveok(stdscr, TRUE);
172			break;
173		  case 'q':
174		  case 'Q':
175			if (query("Really quit?"))
176				quit(0);
177			refresh();
178			break;
179		  case 'w':
180		  case 'W':
181			Waiting = TRUE;
182			leaveok(stdscr, TRUE);
183#ifndef NCURSES_VERSION
184			flushok(stdscr, FALSE);
185#endif
186			goto ret;
187		  case 't':
188		  case 'T':
189teleport:
190			Running = FALSE;
191			mvaddch(My_pos.y, My_pos.x, ' ');
192			My_pos = *rnd_pos();
193			mvaddch(My_pos.y, My_pos.x, PLAYER);
194			leaveok(stdscr, FALSE);
195			refresh();
196			flushinp();
197			goto ret;
198		  case CTRL('L'):
199			wrefresh(curscr);
200			break;
201		  case EOF:
202			quit(0);
203			break;
204		  default:
205			beep();
206			reset_count();
207			break;
208		}
209		if (Real_time) {
210			(void)gettimeofday(&t, &tz);
211			t.tv_sec = tod.tv_sec + tv.tv_sec - t.tv_sec;
212			t.tv_usec = tod.tv_usec + tv.tv_usec - t.tv_usec;
213			if (t.tv_usec < 0) {
214				t.tv_sec--;
215				t.tv_usec += 1000000;	/* Now it must be > 0 */
216			}
217			if (t.tv_sec < 0)
218				goto ret;
219		}
220	}
221ret:
222	if (Count > 0)
223		if (--Count == 0)
224			leaveok(stdscr, FALSE);
225}
226
227/*
228 * must_telep:
229 *	Must I teleport; i.e., is there anywhere I can move without
230 * being eaten?
231 */
232bool
233must_telep()
234{
235	int		x, y;
236	static COORD	newpos;
237
238#ifdef	FANCY
239	if (Stand_still && Num_robots > 1 && eaten(&My_pos))
240		return TRUE;
241#endif
242
243	for (y = -1; y <= 1; y++) {
244		newpos.y = My_pos.y + y;
245		if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE)
246			continue;
247		for (x = -1; x <= 1; x++) {
248			newpos.x = My_pos.x + x;
249			if (newpos.x <= 0 || newpos.x >= X_FIELDSIZE)
250				continue;
251			if (Field[newpos.y][newpos.x] > 0)
252				continue;
253			if (!eaten(&newpos))
254				return FALSE;
255		}
256	}
257	return TRUE;
258}
259
260/*
261 * do_move:
262 *	Execute a move
263 */
264bool
265do_move(dy, dx)
266	int	dy, dx;
267{
268	static COORD	newpos;
269
270	newpos.y = My_pos.y + dy;
271	newpos.x = My_pos.x + dx;
272	if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE ||
273	    newpos.x <= 0 || newpos.x >= X_FIELDSIZE ||
274	    Field[newpos.y][newpos.x] > 0 || eaten(&newpos)) {
275		if (Running) {
276			Running = FALSE;
277			leaveok(stdscr, FALSE);
278			move(My_pos.y, My_pos.x);
279			refresh();
280		} else {
281			beep();
282			reset_count();
283		}
284		return FALSE;
285	}
286	else if (dy == 0 && dx == 0)
287		return TRUE;
288	mvaddch(My_pos.y, My_pos.x, ' ');
289	My_pos = newpos;
290	mvaddch(My_pos.y, My_pos.x, PLAYER);
291	if (!jumping())
292		refresh();
293	return TRUE;
294}
295
296/*
297 * eaten:
298 *	Player would get eaten at this place
299 */
300bool
301eaten(pos)
302	COORD	*pos;
303{
304	int	x, y;
305
306	for (y = pos->y - 1; y <= pos->y + 1; y++) {
307		if (y <= 0 || y >= Y_FIELDSIZE)
308			continue;
309		for (x = pos->x - 1; x <= pos->x + 1; x++) {
310			if (x <= 0 || x >= X_FIELDSIZE)
311				continue;
312			if (Field[y][x] == 1)
313				return TRUE;
314		}
315	}
316	return FALSE;
317}
318
319/*
320 * reset_count:
321 *	Reset the count variables
322 */
323void
324reset_count()
325{
326	Count = 0;
327	Running = FALSE;
328	leaveok(stdscr, FALSE);
329	refresh();
330}
331
332/*
333 * jumping:
334 *	See if we are jumping, i.e., we should not refresh.
335 */
336bool
337jumping()
338{
339	return (Jump && (Count || Running || Waiting));
340}
341