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