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