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