1*79af1000Sguenther /* $OpenBSD: move.c,v 1.13 2016/08/27 02:02:44 guenther Exp $ */
2df930be7Sderaadt /* $NetBSD: move.c,v 1.4 1995/04/22 10:08:58 cgd Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*
5df930be7Sderaadt * Copyright (c) 1980, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt * modification, are permitted provided that the following conditions
10df930be7Sderaadt * are met:
11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt * documentation and/or other materials provided with the distribution.
167a09557bSmillert * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt * may be used to endorse or promote products derived from this software
18df930be7Sderaadt * without specific prior written permission.
19df930be7Sderaadt *
20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt * SUCH DAMAGE.
31df930be7Sderaadt */
32df930be7Sderaadt
33*79af1000Sguenther #include <sys/time.h>
342010f3c8Smestre #include <ctype.h>
352010f3c8Smestre #include <poll.h>
362010f3c8Smestre #include <termios.h>
372010f3c8Smestre #include <unistd.h>
382010f3c8Smestre
39df930be7Sderaadt #include "robots.h"
40df930be7Sderaadt
41df930be7Sderaadt #define ESC '\033'
42df930be7Sderaadt
43df930be7Sderaadt /*
44df930be7Sderaadt * get_move:
45df930be7Sderaadt * Get and execute a move from the player
46df930be7Sderaadt */
47d648d61bSpjanzen void
get_move(void)483eb8c9edSjsg get_move(void)
49df930be7Sderaadt {
504c144bbcSpjanzen int c;
514c144bbcSpjanzen int retval;
52e5f400f5Srzalamena struct timespec t, tn;
53d648d61bSpjanzen #ifdef FANCY
54d648d61bSpjanzen int lastmove;
55d648d61bSpjanzen #endif
56df930be7Sderaadt
57df930be7Sderaadt if (Waiting)
58df930be7Sderaadt return;
59df930be7Sderaadt
60df930be7Sderaadt #ifdef FANCY
61df930be7Sderaadt if (Pattern_roll) {
62df930be7Sderaadt if (Next_move >= Move_list)
63df930be7Sderaadt lastmove = *Next_move;
64df930be7Sderaadt else
65df930be7Sderaadt lastmove = -1; /* flag for "first time in" */
66df930be7Sderaadt }
67df930be7Sderaadt #endif
684c144bbcSpjanzen if (Real_time) {
69e5f400f5Srzalamena t = tv;
70e5f400f5Srzalamena clock_gettime(CLOCK_MONOTONIC, &tn);
714c144bbcSpjanzen }
72df930be7Sderaadt for (;;) {
73df930be7Sderaadt if (Teleport && must_telep())
74df930be7Sderaadt goto teleport;
75df930be7Sderaadt if (Running)
76df930be7Sderaadt c = Run_ch;
77df930be7Sderaadt else if (Count != 0)
78df930be7Sderaadt c = Cnt_move;
79df930be7Sderaadt #ifdef FANCY
80df930be7Sderaadt else if (Num_robots > 1 && Stand_still)
81df930be7Sderaadt c = '>';
82df930be7Sderaadt else if (Num_robots > 1 && Pattern_roll) {
83df930be7Sderaadt if (*++Next_move == '\0') {
84df930be7Sderaadt if (lastmove < 0)
85df930be7Sderaadt goto over;
86df930be7Sderaadt Next_move = Move_list;
87df930be7Sderaadt }
88df930be7Sderaadt c = *Next_move;
89df930be7Sderaadt mvaddch(0, 0, c);
90df930be7Sderaadt if (c == lastmove)
91df930be7Sderaadt goto over;
92df930be7Sderaadt }
93df930be7Sderaadt #endif
94df930be7Sderaadt else {
95df930be7Sderaadt over:
964c144bbcSpjanzen if (Real_time) {
975e640057Sderaadt struct pollfd pfd[1];
985e640057Sderaadt
995e640057Sderaadt pfd[0].fd = STDIN_FILENO;
1005e640057Sderaadt pfd[0].events = POLLIN;
101e5f400f5Srzalamena retval = ppoll(pfd, 1, &t, NULL);
1024c144bbcSpjanzen if (retval > 0)
103df930be7Sderaadt c = getchar();
1044c144bbcSpjanzen else /* Don't move if timed out or error */
1054c144bbcSpjanzen c = ' ';
1064c144bbcSpjanzen } else {
1074c144bbcSpjanzen c = getchar();
1084c144bbcSpjanzen /* Can't use digits in real time mode, or digit/ESC
1094c144bbcSpjanzen * is an effective way to stop the game.
1104c144bbcSpjanzen */
111df930be7Sderaadt if (isdigit(c)) {
112df930be7Sderaadt Count = (c - '0');
113df930be7Sderaadt while (isdigit(c = getchar()))
114df930be7Sderaadt Count = Count * 10 + (c - '0');
115df930be7Sderaadt if (c == ESC)
116df930be7Sderaadt goto over;
117df930be7Sderaadt Cnt_move = c;
118df930be7Sderaadt if (Count)
119df930be7Sderaadt leaveok(stdscr, TRUE);
120df930be7Sderaadt }
121df930be7Sderaadt }
1224c144bbcSpjanzen }
123df930be7Sderaadt
124df930be7Sderaadt switch (c) {
125df930be7Sderaadt case ' ':
126df930be7Sderaadt case '.':
127df930be7Sderaadt if (do_move(0, 0))
128df930be7Sderaadt goto ret;
129df930be7Sderaadt break;
130df930be7Sderaadt case 'y':
131df930be7Sderaadt if (do_move(-1, -1))
132df930be7Sderaadt goto ret;
133df930be7Sderaadt break;
134df930be7Sderaadt case 'k':
135df930be7Sderaadt if (do_move(-1, 0))
136df930be7Sderaadt goto ret;
137df930be7Sderaadt break;
138df930be7Sderaadt case 'u':
139df930be7Sderaadt if (do_move(-1, 1))
140df930be7Sderaadt goto ret;
141df930be7Sderaadt break;
142df930be7Sderaadt case 'h':
143df930be7Sderaadt if (do_move(0, -1))
144df930be7Sderaadt goto ret;
145df930be7Sderaadt break;
146df930be7Sderaadt case 'l':
147df930be7Sderaadt if (do_move(0, 1))
148df930be7Sderaadt goto ret;
149df930be7Sderaadt break;
150df930be7Sderaadt case 'b':
151df930be7Sderaadt if (do_move(1, -1))
152df930be7Sderaadt goto ret;
153df930be7Sderaadt break;
154df930be7Sderaadt case 'j':
155df930be7Sderaadt if (do_move(1, 0))
156df930be7Sderaadt goto ret;
157df930be7Sderaadt break;
158df930be7Sderaadt case 'n':
159df930be7Sderaadt if (do_move(1, 1))
160df930be7Sderaadt goto ret;
161df930be7Sderaadt break;
162df930be7Sderaadt case 'Y': case 'U': case 'H': case 'J':
163df930be7Sderaadt case 'K': case 'L': case 'B': case 'N':
164df930be7Sderaadt case '>':
165df930be7Sderaadt Running = TRUE;
166df930be7Sderaadt if (c == '>')
167df930be7Sderaadt Run_ch = ' ';
168df930be7Sderaadt else
169df930be7Sderaadt Run_ch = tolower(c);
170df930be7Sderaadt leaveok(stdscr, TRUE);
171df930be7Sderaadt break;
172df930be7Sderaadt case 'q':
173df930be7Sderaadt case 'Q':
174df930be7Sderaadt if (query("Really quit?"))
175d648d61bSpjanzen quit(0);
176df930be7Sderaadt refresh();
177df930be7Sderaadt break;
178df930be7Sderaadt case 'w':
179df930be7Sderaadt case 'W':
180df930be7Sderaadt Waiting = TRUE;
181df930be7Sderaadt leaveok(stdscr, TRUE);
18215eabdf8Stholo #ifndef NCURSES_VERSION
183df930be7Sderaadt flushok(stdscr, FALSE);
18415eabdf8Stholo #endif
185df930be7Sderaadt goto ret;
186df930be7Sderaadt case 't':
187df930be7Sderaadt case 'T':
188df930be7Sderaadt teleport:
189df930be7Sderaadt Running = FALSE;
190df930be7Sderaadt mvaddch(My_pos.y, My_pos.x, ' ');
191df930be7Sderaadt My_pos = *rnd_pos();
192df930be7Sderaadt mvaddch(My_pos.y, My_pos.x, PLAYER);
193df930be7Sderaadt leaveok(stdscr, FALSE);
194df930be7Sderaadt refresh();
1954c144bbcSpjanzen flushinp();
196df930be7Sderaadt goto ret;
197df930be7Sderaadt case CTRL('L'):
198df930be7Sderaadt wrefresh(curscr);
199df930be7Sderaadt break;
200df930be7Sderaadt case EOF:
201859369c2Spjanzen quit(0);
202df930be7Sderaadt break;
203df930be7Sderaadt default:
2044c144bbcSpjanzen beep();
205df930be7Sderaadt reset_count();
206df930be7Sderaadt break;
207df930be7Sderaadt }
2084c144bbcSpjanzen if (Real_time) {
209e5f400f5Srzalamena /* Update current time. */
210e5f400f5Srzalamena clock_gettime(CLOCK_MONOTONIC, &t);
211e5f400f5Srzalamena
212e5f400f5Srzalamena /* Check whether tv time has passed. */
213e5f400f5Srzalamena timespecadd(&tn, &tv, &tn);
214e5f400f5Srzalamena if (timespeccmp(&tn, &t, <))
2154c144bbcSpjanzen goto ret;
216e5f400f5Srzalamena
217e5f400f5Srzalamena /* Keep the difference otherwise. */
218e5f400f5Srzalamena timespecsub(&tn, &t, &t);
2194c144bbcSpjanzen }
220df930be7Sderaadt }
221df930be7Sderaadt ret:
222df930be7Sderaadt if (Count > 0)
223df930be7Sderaadt if (--Count == 0)
224df930be7Sderaadt leaveok(stdscr, FALSE);
225df930be7Sderaadt }
226df930be7Sderaadt
227df930be7Sderaadt /*
228df930be7Sderaadt * must_telep:
229df930be7Sderaadt * Must I teleport; i.e., is there anywhere I can move without
230df930be7Sderaadt * being eaten?
231df930be7Sderaadt */
232d648d61bSpjanzen bool
must_telep(void)2333eb8c9edSjsg must_telep(void)
234df930be7Sderaadt {
23597419aa0Spjanzen int x, y;
236df930be7Sderaadt static COORD newpos;
237df930be7Sderaadt
238df930be7Sderaadt #ifdef FANCY
239df930be7Sderaadt if (Stand_still && Num_robots > 1 && eaten(&My_pos))
240df930be7Sderaadt return TRUE;
241df930be7Sderaadt #endif
242df930be7Sderaadt
243df930be7Sderaadt for (y = -1; y <= 1; y++) {
244df930be7Sderaadt newpos.y = My_pos.y + y;
245df930be7Sderaadt if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE)
246df930be7Sderaadt continue;
247df930be7Sderaadt for (x = -1; x <= 1; x++) {
248df930be7Sderaadt newpos.x = My_pos.x + x;
249df930be7Sderaadt if (newpos.x <= 0 || newpos.x >= X_FIELDSIZE)
250df930be7Sderaadt continue;
251df930be7Sderaadt if (Field[newpos.y][newpos.x] > 0)
252df930be7Sderaadt continue;
253df930be7Sderaadt if (!eaten(&newpos))
254df930be7Sderaadt return FALSE;
255df930be7Sderaadt }
256df930be7Sderaadt }
257df930be7Sderaadt return TRUE;
258df930be7Sderaadt }
259df930be7Sderaadt
260df930be7Sderaadt /*
261df930be7Sderaadt * do_move:
262df930be7Sderaadt * Execute a move
263df930be7Sderaadt */
264d648d61bSpjanzen bool
do_move(int dy,int dx)2653eb8c9edSjsg do_move(int dy, int dx)
266df930be7Sderaadt {
267df930be7Sderaadt static COORD newpos;
268df930be7Sderaadt
269df930be7Sderaadt newpos.y = My_pos.y + dy;
270df930be7Sderaadt newpos.x = My_pos.x + dx;
271df930be7Sderaadt if (newpos.y <= 0 || newpos.y >= Y_FIELDSIZE ||
272df930be7Sderaadt newpos.x <= 0 || newpos.x >= X_FIELDSIZE ||
273df930be7Sderaadt Field[newpos.y][newpos.x] > 0 || eaten(&newpos)) {
274df930be7Sderaadt if (Running) {
275df930be7Sderaadt Running = FALSE;
276df930be7Sderaadt leaveok(stdscr, FALSE);
277df930be7Sderaadt move(My_pos.y, My_pos.x);
278df930be7Sderaadt refresh();
2794c144bbcSpjanzen } else {
2804c144bbcSpjanzen beep();
281df930be7Sderaadt reset_count();
282df930be7Sderaadt }
283df930be7Sderaadt return FALSE;
284df930be7Sderaadt }
285df930be7Sderaadt else if (dy == 0 && dx == 0)
286df930be7Sderaadt return TRUE;
287df930be7Sderaadt mvaddch(My_pos.y, My_pos.x, ' ');
288df930be7Sderaadt My_pos = newpos;
289df930be7Sderaadt mvaddch(My_pos.y, My_pos.x, PLAYER);
290df930be7Sderaadt if (!jumping())
291df930be7Sderaadt refresh();
292df930be7Sderaadt return TRUE;
293df930be7Sderaadt }
294df930be7Sderaadt
295df930be7Sderaadt /*
296df930be7Sderaadt * eaten:
297df930be7Sderaadt * Player would get eaten at this place
298df930be7Sderaadt */
299d648d61bSpjanzen bool
eaten(COORD * pos)3003eb8c9edSjsg eaten(COORD *pos)
301df930be7Sderaadt {
30297419aa0Spjanzen int x, y;
303df930be7Sderaadt
304df930be7Sderaadt for (y = pos->y - 1; y <= pos->y + 1; y++) {
305df930be7Sderaadt if (y <= 0 || y >= Y_FIELDSIZE)
306df930be7Sderaadt continue;
307df930be7Sderaadt for (x = pos->x - 1; x <= pos->x + 1; x++) {
308df930be7Sderaadt if (x <= 0 || x >= X_FIELDSIZE)
309df930be7Sderaadt continue;
310df930be7Sderaadt if (Field[y][x] == 1)
311df930be7Sderaadt return TRUE;
312df930be7Sderaadt }
313df930be7Sderaadt }
314df930be7Sderaadt return FALSE;
315df930be7Sderaadt }
316df930be7Sderaadt
317df930be7Sderaadt /*
318df930be7Sderaadt * reset_count:
319df930be7Sderaadt * Reset the count variables
320df930be7Sderaadt */
321d648d61bSpjanzen void
reset_count(void)3223eb8c9edSjsg reset_count(void)
323df930be7Sderaadt {
324df930be7Sderaadt Count = 0;
325df930be7Sderaadt Running = FALSE;
326df930be7Sderaadt leaveok(stdscr, FALSE);
327df930be7Sderaadt refresh();
328df930be7Sderaadt }
329df930be7Sderaadt
330df930be7Sderaadt /*
331df930be7Sderaadt * jumping:
332df930be7Sderaadt * See if we are jumping, i.e., we should not refresh.
333df930be7Sderaadt */
334d648d61bSpjanzen bool
jumping(void)3353eb8c9edSjsg jumping(void)
336df930be7Sderaadt {
337df930be7Sderaadt return (Jump && (Count || Running || Waiting));
338df930be7Sderaadt }
339