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