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