games: Remove (void) casts.
[dragonfly.git] / games / hunt / hunt / playit.c
1 /*-
2  * Copyright (c) 1983-2003, Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the University of California, San Francisco nor
15  *    the names of its contributors may be used to endorse or promote
16  *    products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $OpenBSD: playit.c,v 1.8 2003/06/11 08:45:25 pjanzen Exp $
32  * $NetBSD: playit.c,v 1.4 1997/10/20 00:37:15 lukem Exp $
33  */
34
35 #include <sys/types.h>
36 #include <sys/file.h>
37 #include <arpa/inet.h>
38
39 #include <err.h>
40 #include <errno.h>
41 #include <ctype.h>
42 #include <termios.h>
43 #include <signal.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include "hunt.h"
48 #include "display.h"
49 #include "client.h"
50
51 static int      nchar_send;
52 static FLAG     Last_player;
53 static int      Otto_expect;
54
55 # define        MAX_SEND        5
56
57 /*
58  * ibuf is the input buffer used for the stream from the driver.
59  * It is small because we do not check for user input when there
60  * are characters in the input buffer.
61  */
62 static int              icnt = 0;
63 static unsigned char    ibuf[256], *iptr = ibuf;
64
65 #define GETCHR()        (--icnt < 0 ? getchr() : *iptr++)
66
67 static  unsigned char   getchr(void);
68 static  void            send_stuff(void);
69
70 /*
71  * playit:
72  *      Play a given game, handling all the curses commands from
73  *      the driver.
74  */
75 void
76 playit(void)
77 {
78         int             ch;
79         int             y, x;
80         u_int32_t       version;
81         int             otto_y, otto_x;
82         char            otto_face = ' ';
83         int             chars_processed;
84
85         if (read(Socket, &version, sizeof version) != sizeof version) {
86                 bad_con();
87                 /* NOTREACHED */
88         }
89         if (ntohl(version) != (unsigned int)HUNT_VERSION) {
90                 bad_ver();
91                 /* NOTREACHED */
92         }
93         errno = 0;
94         nchar_send = MAX_SEND;
95         Otto_expect = 0;
96         while ((ch = GETCHR()) != EOF) {
97                 switch (ch & 0377) {
98                   case MOVE:
99                         y = GETCHR();
100                         x = GETCHR();
101                         display_move(y, x);
102                         break;
103
104                   case CLRTOEOL:
105                         display_clear_eol();
106                         break;
107                   case CLEAR:
108                         display_clear_the_screen();
109                         break;
110                   case REFRESH:
111                         display_refresh();
112                         break;
113                   case REDRAW:
114                         display_redraw_screen();
115                         display_refresh();
116                         break;
117                   case ENDWIN:
118                         display_refresh();
119                         if ((ch = GETCHR()) == LAST_PLAYER)
120                                 Last_player = TRUE;
121                         ch = EOF;
122                         goto out;
123                   case BELL:
124                         display_beep();
125                         break;
126                   case READY:
127                         chars_processed = GETCHR();
128                         display_refresh();
129                         if (nchar_send < 0)
130                                 tcflush(STDIN_FILENO, TCIFLUSH);
131                         nchar_send = MAX_SEND;
132                         if (Otto_mode) {
133                                 /*
134                                  * The driver returns the number of keypresses
135                                  * that it has processed. Use this to figure
136                                  * out if otto's commands have completed.
137                                  */
138                                 Otto_expect -= chars_processed;
139                                 if (Otto_expect == 0) {
140                                         /* not very fair! */
141                                         static char buf[MAX_SEND * 2];
142                                         int len;
143
144                                         /* Ask otto what it wants to do: */
145                                         len = otto(otto_y, otto_x, otto_face,
146                                                 buf, sizeof buf);
147                                         if (len) {
148                                                 /* Pass it on to the driver: */
149                                                 write(Socket, buf, len);
150                                                 /* Update expectations: */
151                                                 Otto_expect += len;
152                                         }
153                                 }
154                         }
155                         break;
156                   case ADDCH:
157                         ch = GETCHR();
158                         /* FALLTHROUGH */
159                   default:
160                         if (!isprint(ch))
161                                 ch = ' ';
162                         display_put_ch(ch);
163                         if (Otto_mode)
164                                 switch (ch) {
165                                 case '<':
166                                 case '>':
167                                 case '^':
168                                 case 'v':
169                                         otto_face = ch;
170                                         display_getyx(&otto_y, &otto_x);
171                                         otto_x--;
172                                         break;
173                                 }
174                         break;
175                 }
176         }
177 out:
178         close(Socket);
179 }
180
181 /*
182  * getchr:
183  *      Grab input and pass it along to the driver
184  *      Return any characters from the driver
185  *      When this routine is called by GETCHR, we already know there are
186  *      no characters in the input buffer.
187  */
188 static unsigned char
189 getchr(void)
190 {
191         fd_set  readfds, s_readfds;
192         int     nfds, s_nfds;
193
194         FD_ZERO(&s_readfds);
195         FD_SET(Socket, &s_readfds);
196         FD_SET(STDIN_FILENO, &s_readfds);
197         s_nfds = (Socket > STDIN_FILENO) ? Socket : STDIN_FILENO;
198         s_nfds++;
199
200 one_more_time:
201         do {
202                 errno = 0;
203                 readfds = s_readfds;
204                 nfds = s_nfds;
205                 nfds = select(nfds, &readfds, NULL, NULL, NULL);
206         } while (nfds <= 0 && errno == EINTR);
207
208         if (FD_ISSET(STDIN_FILENO, &readfds))
209                 send_stuff();
210         if (!FD_ISSET(Socket, &readfds))
211                 goto one_more_time;
212         icnt = read(Socket, ibuf, sizeof ibuf);
213         if (icnt <= 0) {
214                 bad_con();
215                 /* NOTREACHED */
216         }
217         iptr = ibuf;
218         icnt--;
219         return *iptr++;
220 }
221
222 /*
223  * send_stuff:
224  *      Send standard input characters to the driver
225  */
226 static void
227 send_stuff(void)
228 {
229         int             count;
230         char            *sp, *nsp;
231         static char     inp[BUFSIZ];
232         static char     Buf[BUFSIZ];
233
234         /* Drain the user's keystrokes: */
235         count = read(STDIN_FILENO, Buf, sizeof Buf);
236         if (count < 0)
237                 err(1, "read");
238         if (count == 0)
239                 return;
240
241         if (nchar_send <= 0 && !no_beep) {
242                 display_beep();
243                 return;
244         }
245
246         /*
247          * look for 'q'uit commands; if we find one,
248          * confirm it.  If it is not confirmed, strip
249          * it out of the input
250          */
251         Buf[count] = '\0';
252         for (sp = Buf, nsp = inp; *sp != '\0'; sp++, nsp++) {
253                 *nsp = map_key[(int)*sp];
254                 if (*nsp == 'q')
255                         intr(0);
256         }
257         count = nsp - inp;
258         if (count) {
259                 nchar_send -= count;
260                 if (nchar_send < 0)
261                         count += nchar_send;
262                 write(Socket, inp, count);
263                 if (Otto_mode) {
264                         /*
265                          * The user can insert commands over otto.
266                          * So, otto shouldn't be alarmed when the
267                          * server processes more than otto asks for.
268                          */
269                         Otto_expect += count;
270                 }
271         }
272 }
273
274 /*
275  * quit:
276  *      Handle the end of the game when the player dies
277  */
278 int
279 quit(int old_status)
280 {
281         int     explain, ch;
282
283         if (Last_player)
284                 return Q_QUIT;
285         if (Otto_mode)
286                 return otto_quit(old_status);
287         display_move(HEIGHT, 0);
288         display_put_str("Re-enter game [ynwo]? ");
289         display_clear_eol();
290         explain = FALSE;
291         for (;;) {
292                 display_refresh();
293                 if (isupper(ch = getchar()))
294                         ch = tolower(ch);
295                 if (ch == 'y')
296                         return old_status;
297                 else if (ch == 'o')
298                         break;
299                 else if (ch == 'n') {
300                         display_move(HEIGHT, 0);
301                         display_put_str("Write a parting message [yn]? ");
302                         display_clear_eol();
303                         display_refresh();
304                         for (;;) {
305                                 if (isupper(ch = getchar()))
306                                         ch = tolower(ch);
307                                 if (ch == 'y')
308                                         goto get_message;
309                                 if (ch == 'n')
310                                         return Q_QUIT;
311                         }
312                 }
313                 else if (ch == 'w') {
314                         static  char    buf[WIDTH + WIDTH % 2];
315                         char            *cp, c;
316
317 get_message:
318                         c = ch;         /* save how we got here */
319                         display_move(HEIGHT, 0);
320                         display_put_str("Message: ");
321                         display_clear_eol();
322                         display_refresh();
323                         cp = buf;
324                         for (;;) {
325                                 display_refresh();
326                                 if ((ch = getchar()) == '\n' || ch == '\r')
327                                         break;
328                                 if (display_iserasechar(ch))
329                                 {
330                                         if (cp > buf) {
331                                                 int y, x;
332
333                                                 display_getyx(&y, &x);
334                                                 display_move(y, x - 1);
335                                                 cp -= 1;
336                                                 display_clear_eol();
337                                         }
338                                         continue;
339                                 }
340                                 else if (display_iskillchar(ch))
341                                 {
342                                         int y, x;
343
344                                         display_getyx(&y, &x);
345                                         display_move(y, x - (cp - buf));
346                                         cp = buf;
347                                         display_clear_eol();
348                                         continue;
349                                 } else if (!isprint(ch)) {
350                                         display_beep();
351                                         continue;
352                                 }
353                                 display_put_ch(ch);
354                                 *cp++ = ch;
355                                 if (cp + 1 >= buf + sizeof buf)
356                                         break;
357                         }
358                         *cp = '\0';
359                         Send_message = buf;
360                         return (c == 'w') ? old_status : Q_MESSAGE;
361                 }
362                 display_beep();
363                 if (!explain) {
364                         display_put_str("(Yes, No, Write message, or Options) ");
365                         explain = TRUE;
366                 }
367         }
368
369         display_move(HEIGHT, 0);
370         display_put_str("Scan, Cloak, Flying, or Quit? ");
371         display_clear_eol();
372         display_refresh();
373         explain = FALSE;
374         for (;;) {
375                 if (isupper(ch = getchar()))
376                         ch = tolower(ch);
377                 if (ch == 's')
378                         return Q_SCAN;
379                 else if (ch == 'c')
380                         return Q_CLOAK;
381                 else if (ch == 'f')
382                         return Q_FLY;
383                 else if (ch == 'q')
384                         return Q_QUIT;
385                 display_beep();
386                 if (!explain) {
387                         display_put_str("[SCFQ] ");
388                         explain = TRUE;
389                 }
390                 display_refresh();
391         }
392 }
393
394 /*
395  * do_message:
396  *      Send a message to the driver and return
397  */
398 void
399 do_message(void)
400 {
401         u_int32_t       version;
402
403         if (read(Socket, &version, sizeof version) != sizeof version) {
404                 bad_con();
405                 /* NOTREACHED */
406         }
407         if (ntohl(version) != (unsigned int)HUNT_VERSION) {
408                 bad_ver();
409                 /* NOTREACHED */
410         }
411         if (write(Socket, Send_message, strlen(Send_message)) < 0) {
412                 bad_con();
413                 /* NOTREACHED */
414         }
415         close(Socket);
416 }