1 /* $OpenBSD: move.c,v 1.9 2009/10/27 23:59:26 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 FD_SET(STDIN_FILENO, &rset); 94 retval = select(STDIN_FILENO + 1, &rset, NULL, NULL, &t); 95 if (retval > 0) 96 c = getchar(); 97 else /* Don't move if timed out or error */ 98 c = ' '; 99 } else { 100 c = getchar(); 101 /* Can't use digits in real time mode, or digit/ESC 102 * is an effective way to stop the game. 103 */ 104 if (isdigit(c)) { 105 Count = (c - '0'); 106 while (isdigit(c = getchar())) 107 Count = Count * 10 + (c - '0'); 108 if (c == ESC) 109 goto over; 110 Cnt_move = c; 111 if (Count) 112 leaveok(stdscr, TRUE); 113 } 114 } 115 } 116 117 switch (c) { 118 case ' ': 119 case '.': 120 if (do_move(0, 0)) 121 goto ret; 122 break; 123 case 'y': 124 if (do_move(-1, -1)) 125 goto ret; 126 break; 127 case 'k': 128 if (do_move(-1, 0)) 129 goto ret; 130 break; 131 case 'u': 132 if (do_move(-1, 1)) 133 goto ret; 134 break; 135 case 'h': 136 if (do_move(0, -1)) 137 goto ret; 138 break; 139 case 'l': 140 if (do_move(0, 1)) 141 goto ret; 142 break; 143 case 'b': 144 if (do_move(1, -1)) 145 goto ret; 146 break; 147 case 'j': 148 if (do_move(1, 0)) 149 goto ret; 150 break; 151 case 'n': 152 if (do_move(1, 1)) 153 goto ret; 154 break; 155 case 'Y': case 'U': case 'H': case 'J': 156 case 'K': case 'L': case 'B': case 'N': 157 case '>': 158 Running = TRUE; 159 if (c == '>') 160 Run_ch = ' '; 161 else 162 Run_ch = tolower(c); 163 leaveok(stdscr, TRUE); 164 break; 165 case 'q': 166 case 'Q': 167 if (query("Really quit?")) 168 quit(0); 169 refresh(); 170 break; 171 case 'w': 172 case 'W': 173 Waiting = TRUE; 174 leaveok(stdscr, TRUE); 175 #ifndef NCURSES_VERSION 176 flushok(stdscr, FALSE); 177 #endif 178 goto ret; 179 case 't': 180 case 'T': 181 teleport: 182 Running = FALSE; 183 mvaddch(My_pos.y, My_pos.x, ' '); 184 My_pos = *rnd_pos(); 185 mvaddch(My_pos.y, My_pos.x, PLAYER); 186 leaveok(stdscr, FALSE); 187 refresh(); 188 flushinp(); 189 goto ret; 190 case CTRL('L'): 191 wrefresh(curscr); 192 break; 193 case EOF: 194 quit(0); 195 break; 196 default: 197 beep(); 198 reset_count(); 199 break; 200 } 201 if (Real_time) { 202 (void)gettimeofday(&t, &tz); 203 t.tv_sec = tod.tv_sec + tv.tv_sec - t.tv_sec; 204 t.tv_usec = tod.tv_usec + tv.tv_usec - t.tv_usec; 205 if (t.tv_usec < 0) { 206 t.tv_sec--; 207 t.tv_usec += 1000000; /* Now it must be > 0 */ 208 } 209 if (t.tv_sec < 0) 210 goto ret; 211 } 212 } 213 ret: 214 if (Count > 0) 215 if (--Count == 0) 216 leaveok(stdscr, FALSE); 217 } 218 219 /* 220 * must_telep: 221 * Must I teleport; i.e., is there anywhere I can move without 222 * being eaten? 223 */ 224 bool 225 must_telep(void) 226 { 227 int x, y; 228 static COORD newpos; 229 230 #ifdef FANCY 231 if (Stand_still && Num_robots > 1 && eaten(&My_pos)) 232 return TRUE; 233 #endif 234 235 for (y = -1; y <= 1; y++) { 236 newpos.y = My_pos.y + y; 237 if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE) 238 continue; 239 for (x = -1; x <= 1; x++) { 240 newpos.x = My_pos.x + x; 241 if (newpos.x <= 0 || newpos.x >= X_FIELDSIZE) 242 continue; 243 if (Field[newpos.y][newpos.x] > 0) 244 continue; 245 if (!eaten(&newpos)) 246 return FALSE; 247 } 248 } 249 return TRUE; 250 } 251 252 /* 253 * do_move: 254 * Execute a move 255 */ 256 bool 257 do_move(int dy, int dx) 258 { 259 static COORD newpos; 260 261 newpos.y = My_pos.y + dy; 262 newpos.x = My_pos.x + dx; 263 if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE || 264 newpos.x <= 0 || newpos.x >= X_FIELDSIZE || 265 Field[newpos.y][newpos.x] > 0 || eaten(&newpos)) { 266 if (Running) { 267 Running = FALSE; 268 leaveok(stdscr, FALSE); 269 move(My_pos.y, My_pos.x); 270 refresh(); 271 } else { 272 beep(); 273 reset_count(); 274 } 275 return FALSE; 276 } 277 else if (dy == 0 && dx == 0) 278 return TRUE; 279 mvaddch(My_pos.y, My_pos.x, ' '); 280 My_pos = newpos; 281 mvaddch(My_pos.y, My_pos.x, PLAYER); 282 if (!jumping()) 283 refresh(); 284 return TRUE; 285 } 286 287 /* 288 * eaten: 289 * Player would get eaten at this place 290 */ 291 bool 292 eaten(COORD *pos) 293 { 294 int x, y; 295 296 for (y = pos->y - 1; y <= pos->y + 1; y++) { 297 if (y <= 0 || y >= Y_FIELDSIZE) 298 continue; 299 for (x = pos->x - 1; x <= pos->x + 1; x++) { 300 if (x <= 0 || x >= X_FIELDSIZE) 301 continue; 302 if (Field[y][x] == 1) 303 return TRUE; 304 } 305 } 306 return FALSE; 307 } 308 309 /* 310 * reset_count: 311 * Reset the count variables 312 */ 313 void 314 reset_count(void) 315 { 316 Count = 0; 317 Running = FALSE; 318 leaveok(stdscr, FALSE); 319 refresh(); 320 } 321 322 /* 323 * jumping: 324 * See if we are jumping, i.e., we should not refresh. 325 */ 326 bool 327 jumping(void) 328 { 329 return (Jump && (Count || Running || Waiting)); 330 } 331