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