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