File: | src/games/robots/move.c |
Warning: | line 213, column 4 The left operand of '+' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: move.c,v 1.13 2016/08/27 02:02:44 guenther 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 <sys/time.h> | |||
34 | #include <ctype.h> | |||
35 | #include <poll.h> | |||
36 | #include <termios.h> | |||
37 | #include <unistd.h> | |||
38 | ||||
39 | #include "robots.h" | |||
40 | ||||
41 | #define ESC'\033' '\033' | |||
42 | ||||
43 | /* | |||
44 | * get_move: | |||
45 | * Get and execute a move from the player | |||
46 | */ | |||
47 | void | |||
48 | get_move(void) | |||
49 | { | |||
50 | int c; | |||
51 | int retval; | |||
52 | struct timespec t, tn; | |||
53 | #ifdef FANCY | |||
54 | int lastmove; | |||
55 | #endif | |||
56 | ||||
57 | if (Waiting) | |||
| ||||
58 | return; | |||
59 | ||||
60 | #ifdef FANCY | |||
61 | if (Pattern_roll) { | |||
62 | if (Next_move >= Move_list) | |||
63 | lastmove = *Next_move; | |||
64 | else | |||
65 | lastmove = -1; /* flag for "first time in" */ | |||
66 | } | |||
67 | #endif | |||
68 | if (Real_time) { | |||
69 | t = tv; | |||
70 | clock_gettime(CLOCK_MONOTONIC3, &tn); | |||
71 | } | |||
72 | for (;;) { | |||
73 | if (Teleport && must_telep()) | |||
74 | goto teleport; | |||
75 | if (Running) | |||
76 | c = Run_ch; | |||
77 | else if (Count != 0) | |||
78 | c = Cnt_move; | |||
79 | #ifdef FANCY | |||
80 | else if (Num_robots > 1 && Stand_still) | |||
81 | c = '>'; | |||
82 | else if (Num_robots > 1 && Pattern_roll) { | |||
83 | if (*++Next_move == '\0') { | |||
84 | if (lastmove < 0) | |||
85 | goto over; | |||
86 | Next_move = Move_list; | |||
87 | } | |||
88 | c = *Next_move; | |||
89 | mvaddch(0, 0, c)(wmove(stdscr,0,0) == (-1) ? (-1) : waddch(stdscr,c)); | |||
90 | if (c == lastmove) | |||
91 | goto over; | |||
92 | } | |||
93 | #endif | |||
94 | else { | |||
95 | over: | |||
96 | if (Real_time) { | |||
97 | struct pollfd pfd[1]; | |||
98 | ||||
99 | pfd[0].fd = STDIN_FILENO0; | |||
100 | pfd[0].events = POLLIN0x0001; | |||
101 | retval = ppoll(pfd, 1, &t, NULL((void *)0)); | |||
102 | if (retval > 0) | |||
103 | c = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget( (&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc) ((&__sF[0]))); | |||
104 | else /* Don't move if timed out or error */ | |||
105 | c = ' '; | |||
106 | } else { | |||
107 | c = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget( (&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc) ((&__sF[0]))); | |||
108 | /* Can't use digits in real time mode, or digit/ESC | |||
109 | * is an effective way to stop the game. | |||
110 | */ | |||
111 | if (isdigit(c)) { | |||
112 | Count = (c - '0'); | |||
113 | while (isdigit(c = getchar()(!__isthreaded ? (--((&__sF[0]))->_r < 0 ? __srget( (&__sF[0])) : (int)(*((&__sF[0]))->_p++)) : (getc) ((&__sF[0]))))) | |||
114 | Count = Count * 10 + (c - '0'); | |||
115 | if (c == ESC'\033') | |||
116 | goto over; | |||
117 | Cnt_move = c; | |||
118 | if (Count) | |||
119 | leaveok(stdscr, TRUE1); | |||
120 | } | |||
121 | } | |||
122 | } | |||
123 | ||||
124 | switch (c) { | |||
125 | case ' ': | |||
126 | case '.': | |||
127 | if (do_move(0, 0)) | |||
128 | goto ret; | |||
129 | break; | |||
130 | case 'y': | |||
131 | if (do_move(-1, -1)) | |||
132 | goto ret; | |||
133 | break; | |||
134 | case 'k': | |||
135 | if (do_move(-1, 0)) | |||
136 | goto ret; | |||
137 | break; | |||
138 | case 'u': | |||
139 | if (do_move(-1, 1)) | |||
140 | goto ret; | |||
141 | break; | |||
142 | case 'h': | |||
143 | if (do_move(0, -1)) | |||
144 | goto ret; | |||
145 | break; | |||
146 | case 'l': | |||
147 | if (do_move(0, 1)) | |||
148 | goto ret; | |||
149 | break; | |||
150 | case 'b': | |||
151 | if (do_move(1, -1)) | |||
152 | goto ret; | |||
153 | break; | |||
154 | case 'j': | |||
155 | if (do_move(1, 0)) | |||
156 | goto ret; | |||
157 | break; | |||
158 | case 'n': | |||
159 | if (do_move(1, 1)) | |||
160 | goto ret; | |||
161 | break; | |||
162 | case 'Y': case 'U': case 'H': case 'J': | |||
163 | case 'K': case 'L': case 'B': case 'N': | |||
164 | case '>': | |||
165 | Running = TRUE1; | |||
166 | if (c == '>') | |||
167 | Run_ch = ' '; | |||
168 | else | |||
169 | Run_ch = tolower(c); | |||
170 | leaveok(stdscr, TRUE1); | |||
171 | break; | |||
172 | case 'q': | |||
173 | case 'Q': | |||
174 | if (query("Really quit?")) | |||
175 | quit(0); | |||
176 | refresh()wrefresh(stdscr); | |||
177 | break; | |||
178 | case 'w': | |||
179 | case 'W': | |||
180 | Waiting = TRUE1; | |||
181 | leaveok(stdscr, TRUE1); | |||
182 | #ifndef NCURSES_VERSION"5.7" | |||
183 | flushok(stdscr, FALSE0); | |||
184 | #endif | |||
185 | goto ret; | |||
186 | case 't': | |||
187 | case 'T': | |||
188 | teleport: | |||
189 | Running = FALSE0; | |||
190 | mvaddch(My_pos.y, My_pos.x, ' ')(wmove(stdscr,My_pos.y,My_pos.x) == (-1) ? (-1) : waddch(stdscr ,' ')); | |||
191 | My_pos = *rnd_pos(); | |||
192 | mvaddch(My_pos.y, My_pos.x, PLAYER)(wmove(stdscr,My_pos.y,My_pos.x) == (-1) ? (-1) : waddch(stdscr ,'@')); | |||
193 | leaveok(stdscr, FALSE0); | |||
194 | refresh()wrefresh(stdscr); | |||
195 | flushinp(); | |||
196 | goto ret; | |||
197 | case CTRL('L')('L'&037): | |||
198 | wrefresh(curscr); | |||
199 | break; | |||
200 | case EOF(-1): | |||
201 | quit(0); | |||
202 | break; | |||
203 | default: | |||
204 | beep(); | |||
205 | reset_count(); | |||
206 | break; | |||
207 | } | |||
208 | if (Real_time) { | |||
209 | /* Update current time. */ | |||
210 | clock_gettime(CLOCK_MONOTONIC3, &t); | |||
211 | ||||
212 | /* Check whether tv time has passed. */ | |||
213 | timespecadd(&tn, &tv, &tn)do { (&tn)->tv_sec = (&tn)->tv_sec + (&tv)-> tv_sec; (&tn)->tv_nsec = (&tn)->tv_nsec + (& tv)->tv_nsec; if ((&tn)->tv_nsec >= 1000000000L) { (&tn)->tv_sec++; (&tn)->tv_nsec -= 1000000000L ; } } while (0); | |||
| ||||
214 | if (timespeccmp(&tn, &t, <)(((&tn)->tv_sec == (&t)->tv_sec) ? ((&tn)-> tv_nsec < (&t)->tv_nsec) : ((&tn)->tv_sec < (&t)->tv_sec))) | |||
215 | goto ret; | |||
216 | ||||
217 | /* Keep the difference otherwise. */ | |||
218 | timespecsub(&tn, &t, &t)do { (&t)->tv_sec = (&tn)->tv_sec - (&t)-> tv_sec; (&t)->tv_nsec = (&tn)->tv_nsec - (& t)->tv_nsec; if ((&t)->tv_nsec < 0) { (&t)-> tv_sec--; (&t)->tv_nsec += 1000000000L; } } while (0); | |||
219 | } | |||
220 | } | |||
221 | ret: | |||
222 | if (Count > 0) | |||
223 | if (--Count == 0) | |||
224 | leaveok(stdscr, FALSE0); | |||
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_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 TRUE1; | |||
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_FIELDSIZE23) | |||
246 | continue; | |||
247 | for (x = -1; x <= 1; x++) { | |||
248 | newpos.x = My_pos.x + x; | |||
249 | if (newpos.x <= 0 || newpos.x >= X_FIELDSIZE60) | |||
250 | continue; | |||
251 | if (Field[newpos.y][newpos.x] > 0) | |||
252 | continue; | |||
253 | if (!eaten(&newpos)) | |||
254 | return FALSE0; | |||
255 | } | |||
256 | } | |||
257 | return TRUE1; | |||
258 | } | |||
259 | ||||
260 | /* | |||
261 | * do_move: | |||
262 | * Execute a move | |||
263 | */ | |||
264 | bool_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_FIELDSIZE23 || | |||
272 | newpos.x <= 0 || newpos.x >= X_FIELDSIZE60 || | |||
273 | Field[newpos.y][newpos.x] > 0 || eaten(&newpos)) { | |||
274 | if (Running) { | |||
275 | Running = FALSE0; | |||
276 | leaveok(stdscr, FALSE0); | |||
277 | move(My_pos.y, My_pos.x)wmove(stdscr,My_pos.y,My_pos.x); | |||
278 | refresh()wrefresh(stdscr); | |||
279 | } else { | |||
280 | beep(); | |||
281 | reset_count(); | |||
282 | } | |||
283 | return FALSE0; | |||
284 | } | |||
285 | else if (dy == 0 && dx == 0) | |||
286 | return TRUE1; | |||
287 | mvaddch(My_pos.y, My_pos.x, ' ')(wmove(stdscr,My_pos.y,My_pos.x) == (-1) ? (-1) : waddch(stdscr ,' ')); | |||
288 | My_pos = newpos; | |||
289 | mvaddch(My_pos.y, My_pos.x, PLAYER)(wmove(stdscr,My_pos.y,My_pos.x) == (-1) ? (-1) : waddch(stdscr ,'@')); | |||
290 | if (!jumping()) | |||
291 | refresh()wrefresh(stdscr); | |||
292 | return TRUE1; | |||
293 | } | |||
294 | ||||
295 | /* | |||
296 | * eaten: | |||
297 | * Player would get eaten at this place | |||
298 | */ | |||
299 | bool_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_FIELDSIZE23) | |||
306 | continue; | |||
307 | for (x = pos->x - 1; x <= pos->x + 1; x++) { | |||
308 | if (x <= 0 || x >= X_FIELDSIZE60) | |||
309 | continue; | |||
310 | if (Field[y][x] == 1) | |||
311 | return TRUE1; | |||
312 | } | |||
313 | } | |||
314 | return FALSE0; | |||
315 | } | |||
316 | ||||
317 | /* | |||
318 | * reset_count: | |||
319 | * Reset the count variables | |||
320 | */ | |||
321 | void | |||
322 | reset_count(void) | |||
323 | { | |||
324 | Count = 0; | |||
325 | Running = FALSE0; | |||
326 | leaveok(stdscr, FALSE0); | |||
327 | refresh()wrefresh(stdscr); | |||
328 | } | |||
329 | ||||
330 | /* | |||
331 | * jumping: | |||
332 | * See if we are jumping, i.e., we should not refresh. | |||
333 | */ | |||
334 | bool_Bool | |||
335 | jumping(void) | |||
336 | { | |||
337 | return (Jump && (Count || Running || Waiting)); | |||
338 | } |