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