Expand PMF_FN_* macros.
[netbsd-mini2440.git] / games / hunt / huntd / answer.c
blob05a1be3abe7ae4d3365bb10d7149cf0505a9d7ff
1 /* $NetBSD: answer.c,v 1.15 2009/08/12 07:42:11 dholland Exp $ */
2 /*
3 * Copyright (c) 1983-2003, Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * + Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * + Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * + Neither the name of the University of California, San Francisco nor
16 * the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: answer.c,v 1.15 2009/08/12 07:42:11 dholland Exp $");
36 #endif /* not lint */
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdlib.h>
42 #include <unistd.h>
43 #include "hunt.h"
45 #define SCOREDECAY 15
47 static char Ttyname[NAMELEN];
49 static IDENT *get_ident(uint32_t, uint32_t, char *, char);
50 static void stmonitor(PLAYER *);
51 static void stplayer(PLAYER *, int);
53 int
54 answer(void)
56 PLAYER *pp;
57 int newsock;
58 static u_long mode;
59 static char name[NAMELEN];
60 static char team;
61 static int enter_status;
62 static socklen_t socklen;
63 static uint32_t machine;
64 static uint32_t uid;
65 static SOCKET sockstruct;
66 char *cp1, *cp2;
67 int flags;
68 uint32_t version;
69 int i;
71 #ifdef INTERNET
72 socklen = sizeof sockstruct;
73 #else
74 socklen = sizeof sockstruct - 1;
75 #endif
76 errno = 0;
77 newsock = accept(Socket, (struct sockaddr *) &sockstruct, &socklen);
78 if (newsock < 0)
80 if (errno == EINTR)
81 return FALSE;
82 #ifdef LOG
83 syslog(LOG_ERR, "accept: %m");
84 #else
85 perror("accept");
86 #endif
87 cleanup(1);
90 #ifdef INTERNET
91 machine = ntohl(((struct sockaddr_in *) &sockstruct)->sin_addr.s_addr);
92 #else
93 if (machine == 0)
94 machine = gethostid();
95 #endif
96 version = htonl((uint32_t) HUNT_VERSION);
97 (void) write(newsock, &version, LONGLEN);
98 (void) read(newsock, &uid, LONGLEN);
99 uid = ntohl(uid);
100 (void) read(newsock, name, NAMELEN);
101 (void) read(newsock, &team, 1);
102 (void) read(newsock, &enter_status, LONGLEN);
103 enter_status = ntohl((unsigned long) enter_status);
104 (void) read(newsock, Ttyname, NAMELEN);
105 (void) read(newsock, &mode, sizeof mode);
106 mode = ntohl(mode);
109 * Ensure null termination.
111 name[sizeof(name)-1] = '\0';
112 Ttyname[sizeof(Ttyname)-1] = '\0';
115 * Turn off blocking I/O, so a slow or dead terminal won't stop
116 * the game. All subsequent reads check how many bytes they read.
118 flags = fcntl(newsock, F_GETFL, 0);
119 flags |= O_NDELAY;
120 (void) fcntl(newsock, F_SETFL, flags);
123 * Make sure the name contains only printable characters
124 * since we use control characters for cursor control
125 * between driver and player processes
127 for (cp1 = cp2 = name; *cp1 != '\0'; cp1++)
128 if (isprint((unsigned char)*cp1) || *cp1 == ' ')
129 *cp2++ = *cp1;
130 *cp2 = '\0';
132 #ifdef INTERNET
133 if (mode == C_MESSAGE) {
134 char buf[BUFSIZ + 1];
135 int n;
137 if (team == ' ')
138 (void) snprintf(buf, sizeof(buf), "%s: ", name);
139 else
140 (void) snprintf(buf, sizeof(buf), "%s[%c]: ", name,
141 team);
142 n = strlen(buf);
143 for (pp = Player; pp < End_player; pp++) {
144 cgoto(pp, HEIGHT, 0);
145 outstr(pp, buf, n);
147 while ((n = read(newsock, buf, BUFSIZ)) > 0)
148 for (pp = Player; pp < End_player; pp++)
149 outstr(pp, buf, n);
150 for (pp = Player; pp < End_player; pp++) {
151 ce(pp);
152 sendcom(pp, REFRESH);
153 sendcom(pp, READY, 0);
154 (void) fflush(pp->p_output);
156 (void) close(newsock);
157 return FALSE;
159 else
160 #endif
161 #ifdef MONITOR
162 if (mode == C_MONITOR)
163 if (End_monitor < &Monitor[MAXMON]) {
164 pp = End_monitor++;
165 i = pp - Monitor + MAXPL + 3;
166 } else {
167 socklen = 0;
168 (void) write(newsock, &socklen,
169 sizeof socklen);
170 (void) close(newsock);
171 return FALSE;
173 else
174 #endif
175 if (End_player < &Player[MAXPL]) {
176 pp = End_player++;
177 i = pp - Player + 3;
178 } else {
179 socklen = 0;
180 (void) write(newsock, &socklen,
181 sizeof socklen);
182 (void) close(newsock);
183 return FALSE;
186 #ifdef MONITOR
187 if (mode == C_MONITOR && team == ' ')
188 team = '*';
189 #endif
190 pp->p_ident = get_ident(machine, uid, name, team);
191 pp->p_output = fdopen(newsock, "w");
192 pp->p_death[0] = '\0';
193 pp->p_fd = newsock;
194 fdset[i].fd = newsock;
195 fdset[i].events = POLLIN;
197 pp->p_y = 0;
198 pp->p_x = 0;
200 #ifdef MONITOR
201 if (mode == C_MONITOR)
202 stmonitor(pp);
203 else
204 #endif
205 stplayer(pp, enter_status);
206 return TRUE;
209 #ifdef MONITOR
210 static void
211 stmonitor(PLAYER *pp)
213 int line;
214 PLAYER *npp;
216 memcpy(pp->p_maze, Maze, sizeof Maze);
218 drawmaze(pp);
220 (void) snprintf(Buf, sizeof(Buf), "%5.5s%c%-10.10s %c", " ",
221 stat_char(pp),
222 pp->p_ident->i_name, pp->p_ident->i_team);
223 line = STAT_MON_ROW + 1 + (pp - Monitor);
224 for (npp = Player; npp < End_player; npp++) {
225 cgoto(npp, line, STAT_NAME_COL);
226 outstr(npp, Buf, STAT_NAME_LEN);
228 for (npp = Monitor; npp < End_monitor; npp++) {
229 cgoto(npp, line, STAT_NAME_COL);
230 outstr(npp, Buf, STAT_NAME_LEN);
233 sendcom(pp, REFRESH);
234 sendcom(pp, READY, 0);
235 (void) fflush(pp->p_output);
237 #endif
239 static void
240 stplayer(PLAYER *newpp, int enter_status)
242 int x, y;
243 PLAYER *pp;
245 Nplayer++;
247 for (y = 0; y < UBOUND; y++)
248 for (x = 0; x < WIDTH; x++)
249 newpp->p_maze[y][x] = Maze[y][x];
250 for ( ; y < DBOUND; y++) {
251 for (x = 0; x < LBOUND; x++)
252 newpp->p_maze[y][x] = Maze[y][x];
253 for ( ; x < RBOUND; x++)
254 newpp->p_maze[y][x] = SPACE;
255 for ( ; x < WIDTH; x++)
256 newpp->p_maze[y][x] = Maze[y][x];
258 for ( ; y < HEIGHT; y++)
259 for (x = 0; x < WIDTH; x++)
260 newpp->p_maze[y][x] = Maze[y][x];
262 do {
263 x = rand_num(WIDTH - 1) + 1;
264 y = rand_num(HEIGHT - 1) + 1;
265 } while (Maze[y][x] != SPACE);
266 newpp->p_over = SPACE;
267 newpp->p_x = x;
268 newpp->p_y = y;
269 newpp->p_undershot = FALSE;
271 #ifdef FLY
272 if (enter_status == Q_FLY) {
273 newpp->p_flying = rand_num(20);
274 newpp->p_flyx = 2 * rand_num(6) - 5;
275 newpp->p_flyy = 2 * rand_num(6) - 5;
276 newpp->p_face = FLYER;
278 else
279 #endif
281 newpp->p_flying = -1;
282 newpp->p_face = rand_dir();
284 newpp->p_damage = 0;
285 newpp->p_damcap = MAXDAM;
286 newpp->p_nchar = 0;
287 newpp->p_ncount = 0;
288 newpp->p_nexec = 0;
289 newpp->p_ammo = ISHOTS;
290 #ifdef BOOTS
291 newpp->p_nboots = 0;
292 #endif
293 if (enter_status == Q_SCAN) {
294 newpp->p_scan = SCANLEN;
295 newpp->p_cloak = 0;
297 else {
298 newpp->p_scan = 0;
299 newpp->p_cloak = CLOAKLEN;
301 newpp->p_ncshot = 0;
303 do {
304 x = rand_num(WIDTH - 1) + 1;
305 y = rand_num(HEIGHT - 1) + 1;
306 } while (Maze[y][x] != SPACE);
307 Maze[y][x] = GMINE;
308 #ifdef MONITOR
309 for (pp = Monitor; pp < End_monitor; pp++)
310 check(pp, y, x);
311 #endif
313 do {
314 x = rand_num(WIDTH - 1) + 1;
315 y = rand_num(HEIGHT - 1) + 1;
316 } while (Maze[y][x] != SPACE);
317 Maze[y][x] = MINE;
318 #ifdef MONITOR
319 for (pp = Monitor; pp < End_monitor; pp++)
320 check(pp, y, x);
321 #endif
323 (void) snprintf(Buf, sizeof(Buf), "%5.2f%c%-10.10s %c",
324 newpp->p_ident->i_score,
325 stat_char(newpp), newpp->p_ident->i_name,
326 newpp->p_ident->i_team);
327 y = STAT_PLAY_ROW + 1 + (newpp - Player);
328 for (pp = Player; pp < End_player; pp++) {
329 if (pp != newpp) {
330 char smallbuf[16];
332 pp->p_ammo += NSHOTS;
333 newpp->p_ammo += NSHOTS;
334 cgoto(pp, y, STAT_NAME_COL);
335 outstr(pp, Buf, STAT_NAME_LEN);
336 (void) snprintf(smallbuf, sizeof(smallbuf),
337 "%3d", pp->p_ammo);
338 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
339 outstr(pp, smallbuf, 3);
342 #ifdef MONITOR
343 for (pp = Monitor; pp < End_monitor; pp++) {
344 cgoto(pp, y, STAT_NAME_COL);
345 outstr(pp, Buf, STAT_NAME_LEN);
347 #endif
349 drawmaze(newpp);
350 drawplayer(newpp, TRUE);
351 look(newpp);
352 #ifdef FLY
353 if (enter_status == Q_FLY)
354 /* Make sure that the position you enter in will be erased */
355 showexpl(newpp->p_y, newpp->p_x, FLYER);
356 #endif
357 sendcom(newpp, REFRESH);
358 sendcom(newpp, READY, 0);
359 (void) fflush(newpp->p_output);
363 * rand_dir:
364 * Return a random direction
367 rand_dir(void)
369 switch (rand_num(4)) {
370 case 0:
371 return LEFTS;
372 case 1:
373 return RIGHT;
374 case 2:
375 return BELOW;
376 case 3:
377 return ABOVE;
379 /* NOTREACHED */
380 return(-1);
384 * get_ident:
385 * Get the score structure of a player
387 static IDENT *
388 get_ident(uint32_t machine, uint32_t uid, char *name, char team)
390 IDENT *ip;
391 static IDENT punt;
393 for (ip = Scores; ip != NULL; ip = ip->i_next)
394 if (ip->i_machine == machine
395 && ip->i_uid == uid
396 && ip->i_team == team
397 && strncmp(ip->i_name, name, NAMELEN) == 0)
398 break;
400 if (ip != NULL) {
401 if (ip->i_entries < SCOREDECAY)
402 ip->i_entries++;
403 else
404 ip->i_kills = (ip->i_kills * (SCOREDECAY - 1))
405 / SCOREDECAY;
406 ip->i_score = ip->i_kills / (double) ip->i_entries;
408 else {
409 ip = malloc(sizeof(*ip));
410 if (ip == NULL) {
411 /* Fourth down, time to punt */
412 ip = &punt;
414 ip->i_machine = machine;
415 ip->i_team = team;
416 ip->i_uid = uid;
417 strncpy(ip->i_name, name, NAMELEN);
418 ip->i_kills = 0;
419 ip->i_entries = 1;
420 ip->i_score = 0;
421 ip->i_absorbed = 0;
422 ip->i_faced = 0;
423 ip->i_shot = 0;
424 ip->i_robbed = 0;
425 ip->i_slime = 0;
426 ip->i_missed = 0;
427 ip->i_ducked = 0;
428 ip->i_gkills = ip->i_bkills = ip->i_deaths = 0;
429 ip->i_stillb = ip->i_saved = 0;
430 ip->i_next = Scores;
431 Scores = ip;
434 return ip;