answer.c revision 1.11 1 /* $NetBSD: answer.c,v 1.11 2009/06/28 21:12:35 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.
19 *
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.
31 */
32
33 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: answer.c,v 1.11 2009/06/28 21:12:35 dholland Exp $");
36 #endif /* not lint */
37
38 # include <ctype.h>
39 # include <errno.h>
40 # include <fcntl.h>
41 # include <stdlib.h>
42 # include <unistd.h>
43 # include "hunt.h"
44
45 # define SCOREDECAY 15
46
47 static char Ttyname[NAMELEN];
48
49 int
50 answer()
51 {
52 PLAYER *pp;
53 int newsock;
54 static u_long mode;
55 static char name[NAMELEN];
56 static char team;
57 static int enter_status;
58 static socklen_t socklen;
59 static uint32_t machine;
60 static uint32_t uid;
61 static SOCKET sockstruct;
62 char *cp1, *cp2;
63 int flags;
64 u_int32_t version;
65 int i;
66
67 # ifdef INTERNET
68 socklen = sizeof sockstruct;
69 # else
70 socklen = sizeof sockstruct - 1;
71 # endif
72 errno = 0;
73 newsock = accept(Socket, (struct sockaddr *) &sockstruct, &socklen);
74 if (newsock < 0)
75 {
76 if (errno == EINTR)
77 return FALSE;
78 # ifdef LOG
79 syslog(LOG_ERR, "accept: %m");
80 # else
81 perror("accept");
82 # endif
83 cleanup(1);
84 }
85
86 # ifdef INTERNET
87 machine = ntohl(((struct sockaddr_in *) &sockstruct)->sin_addr.s_addr);
88 # else
89 if (machine == 0)
90 machine = gethostid();
91 # endif
92 version = htonl((u_int32_t) HUNT_VERSION);
93 (void) write(newsock, (char *) &version, LONGLEN);
94 (void) read(newsock, (char *) &uid, LONGLEN);
95 uid = ntohl(uid);
96 (void) read(newsock, name, NAMELEN);
97 (void) read(newsock, &team, 1);
98 (void) read(newsock, (char *) &enter_status, LONGLEN);
99 enter_status = ntohl((unsigned long) enter_status);
100 (void) read(newsock, Ttyname, NAMELEN);
101 (void) read(newsock, (char *) &mode, sizeof mode);
102 mode = ntohl(mode);
103
104 /*
105 * Ensure null termination.
106 */
107 name[sizeof(name)-1] = '\0';
108 Ttyname[sizeof(Ttyname)-1] = '\0';
109
110 /*
111 * Turn off blocking I/O, so a slow or dead terminal won't stop
112 * the game. All subsequent reads check how many bytes they read.
113 */
114 flags = fcntl(newsock, F_GETFL, 0);
115 flags |= O_NDELAY;
116 (void) fcntl(newsock, F_SETFL, flags);
117
118 /*
119 * Make sure the name contains only printable characters
120 * since we use control characters for cursor control
121 * between driver and player processes
122 */
123 for (cp1 = cp2 = name; *cp1 != '\0'; cp1++)
124 if (isprint((unsigned char)*cp1) || *cp1 == ' ')
125 *cp2++ = *cp1;
126 *cp2 = '\0';
127
128 # ifdef INTERNET
129 if (mode == C_MESSAGE) {
130 char buf[BUFSIZ + 1];
131 int n;
132
133 if (team == ' ')
134 (void) snprintf(buf, sizeof(buf), "%s: ", name);
135 else
136 (void) snprintf(buf, sizeof(buf), "%s[%c]: ", name,
137 team);
138 n = strlen(buf);
139 for (pp = Player; pp < End_player; pp++) {
140 cgoto(pp, HEIGHT, 0);
141 outstr(pp, buf, n);
142 }
143 while ((n = read(newsock, buf, BUFSIZ)) > 0)
144 for (pp = Player; pp < End_player; pp++)
145 outstr(pp, buf, n);
146 for (pp = Player; pp < End_player; pp++) {
147 ce(pp);
148 sendcom(pp, REFRESH);
149 sendcom(pp, READY, 0);
150 (void) fflush(pp->p_output);
151 }
152 (void) close(newsock);
153 return FALSE;
154 }
155 else
156 # endif
157 # ifdef MONITOR
158 if (mode == C_MONITOR)
159 if (End_monitor < &Monitor[MAXMON]) {
160 pp = End_monitor++;
161 i = pp - Monitor + MAXPL + 3;
162 } else {
163 socklen = 0;
164 (void) write(newsock, (char *) &socklen,
165 sizeof socklen);
166 (void) close(newsock);
167 return FALSE;
168 }
169 else
170 # endif
171 if (End_player < &Player[MAXPL]) {
172 pp = End_player++;
173 i = pp - Player + 3;
174 } else {
175 socklen = 0;
176 (void) write(newsock, (char *) &socklen,
177 sizeof socklen);
178 (void) close(newsock);
179 return FALSE;
180 }
181
182 #ifdef MONITOR
183 if (mode == C_MONITOR && team == ' ')
184 team = '*';
185 #endif
186 pp->p_ident = get_ident(machine, uid, name, team);
187 pp->p_output = fdopen(newsock, "w");
188 pp->p_death[0] = '\0';
189 pp->p_fd = newsock;
190 fdset[i].fd = newsock;
191 fdset[i].events = POLLIN;
192
193 pp->p_y = 0;
194 pp->p_x = 0;
195
196 # ifdef MONITOR
197 if (mode == C_MONITOR)
198 stmonitor(pp);
199 else
200 # endif
201 stplayer(pp, enter_status);
202 return TRUE;
203 }
204
205 # ifdef MONITOR
206 void
207 stmonitor(pp)
208 PLAYER *pp;
209 {
210 int line;
211 PLAYER *npp;
212
213 memcpy(pp->p_maze, Maze, sizeof Maze);
214
215 drawmaze(pp);
216
217 (void) snprintf(Buf, sizeof(Buf), "%5.5s%c%-10.10s %c", " ",
218 stat_char(pp),
219 pp->p_ident->i_name, pp->p_ident->i_team);
220 line = STAT_MON_ROW + 1 + (pp - Monitor);
221 for (npp = Player; npp < End_player; npp++) {
222 cgoto(npp, line, STAT_NAME_COL);
223 outstr(npp, Buf, STAT_NAME_LEN);
224 }
225 for (npp = Monitor; npp < End_monitor; npp++) {
226 cgoto(npp, line, STAT_NAME_COL);
227 outstr(npp, Buf, STAT_NAME_LEN);
228 }
229
230 sendcom(pp, REFRESH);
231 sendcom(pp, READY, 0);
232 (void) fflush(pp->p_output);
233 }
234 # endif
235
236 void
237 stplayer(newpp, enter_status)
238 PLAYER *newpp;
239 int enter_status;
240 {
241 int x, y;
242 PLAYER *pp;
243
244 Nplayer++;
245
246 for (y = 0; y < UBOUND; y++)
247 for (x = 0; x < WIDTH; x++)
248 newpp->p_maze[y][x] = Maze[y][x];
249 for ( ; y < DBOUND; y++) {
250 for (x = 0; x < LBOUND; x++)
251 newpp->p_maze[y][x] = Maze[y][x];
252 for ( ; x < RBOUND; x++)
253 newpp->p_maze[y][x] = SPACE;
254 for ( ; x < WIDTH; x++)
255 newpp->p_maze[y][x] = Maze[y][x];
256 }
257 for ( ; y < HEIGHT; y++)
258 for (x = 0; x < WIDTH; x++)
259 newpp->p_maze[y][x] = Maze[y][x];
260
261 do {
262 x = rand_num(WIDTH - 1) + 1;
263 y = rand_num(HEIGHT - 1) + 1;
264 } while (Maze[y][x] != SPACE);
265 newpp->p_over = SPACE;
266 newpp->p_x = x;
267 newpp->p_y = y;
268 newpp->p_undershot = FALSE;
269
270 # ifdef FLY
271 if (enter_status == Q_FLY) {
272 newpp->p_flying = rand_num(20);
273 newpp->p_flyx = 2 * rand_num(6) - 5;
274 newpp->p_flyy = 2 * rand_num(6) - 5;
275 newpp->p_face = FLYER;
276 }
277 else
278 # endif
279 {
280 newpp->p_flying = -1;
281 newpp->p_face = rand_dir();
282 }
283 newpp->p_damage = 0;
284 newpp->p_damcap = MAXDAM;
285 newpp->p_nchar = 0;
286 newpp->p_ncount = 0;
287 newpp->p_nexec = 0;
288 newpp->p_ammo = ISHOTS;
289 # ifdef BOOTS
290 newpp->p_nboots = 0;
291 # endif
292 if (enter_status == Q_SCAN) {
293 newpp->p_scan = SCANLEN;
294 newpp->p_cloak = 0;
295 }
296 else {
297 newpp->p_scan = 0;
298 newpp->p_cloak = CLOAKLEN;
299 }
300 newpp->p_ncshot = 0;
301
302 do {
303 x = rand_num(WIDTH - 1) + 1;
304 y = rand_num(HEIGHT - 1) + 1;
305 } while (Maze[y][x] != SPACE);
306 Maze[y][x] = GMINE;
307 # ifdef MONITOR
308 for (pp = Monitor; pp < End_monitor; pp++)
309 check(pp, y, x);
310 # endif
311
312 do {
313 x = rand_num(WIDTH - 1) + 1;
314 y = rand_num(HEIGHT - 1) + 1;
315 } while (Maze[y][x] != SPACE);
316 Maze[y][x] = MINE;
317 # ifdef MONITOR
318 for (pp = Monitor; pp < End_monitor; pp++)
319 check(pp, y, x);
320 # endif
321
322 (void) snprintf(Buf, sizeof(Buf), "%5.2f%c%-10.10s %c",
323 newpp->p_ident->i_score,
324 stat_char(newpp), newpp->p_ident->i_name,
325 newpp->p_ident->i_team);
326 y = STAT_PLAY_ROW + 1 + (newpp - Player);
327 for (pp = Player; pp < End_player; pp++) {
328 if (pp != newpp) {
329 char smallbuf[16];
330
331 pp->p_ammo += NSHOTS;
332 newpp->p_ammo += NSHOTS;
333 cgoto(pp, y, STAT_NAME_COL);
334 outstr(pp, Buf, STAT_NAME_LEN);
335 (void) snprintf(smallbuf, sizeof(smallbuf),
336 "%3d", pp->p_ammo);
337 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
338 outstr(pp, smallbuf, 3);
339 }
340 }
341 # ifdef MONITOR
342 for (pp = Monitor; pp < End_monitor; pp++) {
343 cgoto(pp, y, STAT_NAME_COL);
344 outstr(pp, Buf, STAT_NAME_LEN);
345 }
346 # endif
347
348 drawmaze(newpp);
349 drawplayer(newpp, TRUE);
350 look(newpp);
351 # ifdef FLY
352 if (enter_status == Q_FLY)
353 /* Make sure that the position you enter in will be erased */
354 showexpl(newpp->p_y, newpp->p_x, FLYER);
355 # endif
356 sendcom(newpp, REFRESH);
357 sendcom(newpp, READY, 0);
358 (void) fflush(newpp->p_output);
359 }
360
361 /*
362 * rand_dir:
363 * Return a random direction
364 */
365 int
366 rand_dir()
367 {
368 switch (rand_num(4)) {
369 case 0:
370 return LEFTS;
371 case 1:
372 return RIGHT;
373 case 2:
374 return BELOW;
375 case 3:
376 return ABOVE;
377 }
378 /* NOTREACHED */
379 return(-1);
380 }
381
382 /*
383 * get_ident:
384 * Get the score structure of a player
385 */
386 IDENT *
387 get_ident(machine, uid, name, team)
388 uint32_t machine;
389 uint32_t uid;
390 char *name;
391 char team;
392 {
393 IDENT *ip;
394 static IDENT punt;
395
396 for (ip = Scores; ip != NULL; ip = ip->i_next)
397 if (ip->i_machine == machine
398 && ip->i_uid == uid
399 && ip->i_team == team
400 && strncmp(ip->i_name, name, NAMELEN) == 0)
401 break;
402
403 if (ip != NULL) {
404 if (ip->i_entries < SCOREDECAY)
405 ip->i_entries++;
406 else
407 ip->i_kills = (ip->i_kills * (SCOREDECAY - 1))
408 / SCOREDECAY;
409 ip->i_score = ip->i_kills / (double) ip->i_entries;
410 }
411 else {
412 ip = (IDENT *) malloc(sizeof (IDENT));
413 if (ip == NULL) {
414 /* Fourth down, time to punt */
415 ip = &punt;
416 }
417 ip->i_machine = machine;
418 ip->i_team = team;
419 ip->i_uid = uid;
420 strncpy(ip->i_name, name, NAMELEN);
421 ip->i_kills = 0;
422 ip->i_entries = 1;
423 ip->i_score = 0;
424 ip->i_absorbed = 0;
425 ip->i_faced = 0;
426 ip->i_shot = 0;
427 ip->i_robbed = 0;
428 ip->i_slime = 0;
429 ip->i_missed = 0;
430 ip->i_ducked = 0;
431 ip->i_gkills = ip->i_bkills = ip->i_deaths = 0;
432 ip->i_stillb = ip->i_saved = 0;
433 ip->i_next = Scores;
434 Scores = ip;
435 }
436
437 return ip;
438 }
439