answer.c revision 1.9.14.1 1 /* $NetBSD: answer.c,v 1.9.14.1 2009/06/28 19:53:30 snj 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.9.14.1 2009/06/28 19:53:30 snj 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) sprintf(buf, "%s: ", name);
135 else
136 (void) sprintf(buf, "%s[%c]: ", name, team);
137 n = strlen(buf);
138 for (pp = Player; pp < End_player; pp++) {
139 cgoto(pp, HEIGHT, 0);
140 outstr(pp, buf, n);
141 }
142 while ((n = read(newsock, buf, BUFSIZ)) > 0)
143 for (pp = Player; pp < End_player; pp++)
144 outstr(pp, buf, n);
145 for (pp = Player; pp < End_player; pp++) {
146 ce(pp);
147 sendcom(pp, REFRESH);
148 sendcom(pp, READY, 0);
149 (void) fflush(pp->p_output);
150 }
151 (void) close(newsock);
152 return FALSE;
153 }
154 else
155 # endif
156 # ifdef MONITOR
157 if (mode == C_MONITOR)
158 if (End_monitor < &Monitor[MAXMON]) {
159 pp = End_monitor++;
160 i = pp - Monitor + MAXPL + 3;
161 } else {
162 socklen = 0;
163 (void) write(newsock, (char *) &socklen,
164 sizeof socklen);
165 (void) close(newsock);
166 return FALSE;
167 }
168 else
169 # endif
170 if (End_player < &Player[MAXPL]) {
171 pp = End_player++;
172 i = pp - Player + 3;
173 } else {
174 socklen = 0;
175 (void) write(newsock, (char *) &socklen,
176 sizeof socklen);
177 (void) close(newsock);
178 return FALSE;
179 }
180
181 #ifdef MONITOR
182 if (mode == C_MONITOR && team == ' ')
183 team = '*';
184 #endif
185 pp->p_ident = get_ident(machine, uid, name, team);
186 pp->p_output = fdopen(newsock, "w");
187 pp->p_death[0] = '\0';
188 pp->p_fd = newsock;
189 fdset[i].fd = newsock;
190 fdset[i].events = POLLIN;
191
192 pp->p_y = 0;
193 pp->p_x = 0;
194
195 # ifdef MONITOR
196 if (mode == C_MONITOR)
197 stmonitor(pp);
198 else
199 # endif
200 stplayer(pp, enter_status);
201 return TRUE;
202 }
203
204 # ifdef MONITOR
205 void
206 stmonitor(pp)
207 PLAYER *pp;
208 {
209 int line;
210 PLAYER *npp;
211
212 memcpy(pp->p_maze, Maze, sizeof Maze);
213
214 drawmaze(pp);
215
216 (void) sprintf(Buf, "%5.5s%c%-10.10s %c", " ", stat_char(pp),
217 pp->p_ident->i_name, pp->p_ident->i_team);
218 line = STAT_MON_ROW + 1 + (pp - Monitor);
219 for (npp = Player; npp < End_player; npp++) {
220 cgoto(npp, line, STAT_NAME_COL);
221 outstr(npp, Buf, STAT_NAME_LEN);
222 }
223 for (npp = Monitor; npp < End_monitor; npp++) {
224 cgoto(npp, line, STAT_NAME_COL);
225 outstr(npp, Buf, STAT_NAME_LEN);
226 }
227
228 sendcom(pp, REFRESH);
229 sendcom(pp, READY, 0);
230 (void) fflush(pp->p_output);
231 }
232 # endif
233
234 void
235 stplayer(newpp, enter_status)
236 PLAYER *newpp;
237 int enter_status;
238 {
239 int x, y;
240 PLAYER *pp;
241
242 Nplayer++;
243
244 for (y = 0; y < UBOUND; y++)
245 for (x = 0; x < WIDTH; x++)
246 newpp->p_maze[y][x] = Maze[y][x];
247 for ( ; y < DBOUND; y++) {
248 for (x = 0; x < LBOUND; x++)
249 newpp->p_maze[y][x] = Maze[y][x];
250 for ( ; x < RBOUND; x++)
251 newpp->p_maze[y][x] = SPACE;
252 for ( ; x < WIDTH; x++)
253 newpp->p_maze[y][x] = Maze[y][x];
254 }
255 for ( ; y < HEIGHT; y++)
256 for (x = 0; x < WIDTH; x++)
257 newpp->p_maze[y][x] = Maze[y][x];
258
259 do {
260 x = rand_num(WIDTH - 1) + 1;
261 y = rand_num(HEIGHT - 1) + 1;
262 } while (Maze[y][x] != SPACE);
263 newpp->p_over = SPACE;
264 newpp->p_x = x;
265 newpp->p_y = y;
266 newpp->p_undershot = FALSE;
267
268 # ifdef FLY
269 if (enter_status == Q_FLY) {
270 newpp->p_flying = rand_num(20);
271 newpp->p_flyx = 2 * rand_num(6) - 5;
272 newpp->p_flyy = 2 * rand_num(6) - 5;
273 newpp->p_face = FLYER;
274 }
275 else
276 # endif
277 {
278 newpp->p_flying = -1;
279 newpp->p_face = rand_dir();
280 }
281 newpp->p_damage = 0;
282 newpp->p_damcap = MAXDAM;
283 newpp->p_nchar = 0;
284 newpp->p_ncount = 0;
285 newpp->p_nexec = 0;
286 newpp->p_ammo = ISHOTS;
287 # ifdef BOOTS
288 newpp->p_nboots = 0;
289 # endif
290 if (enter_status == Q_SCAN) {
291 newpp->p_scan = SCANLEN;
292 newpp->p_cloak = 0;
293 }
294 else {
295 newpp->p_scan = 0;
296 newpp->p_cloak = CLOAKLEN;
297 }
298 newpp->p_ncshot = 0;
299
300 do {
301 x = rand_num(WIDTH - 1) + 1;
302 y = rand_num(HEIGHT - 1) + 1;
303 } while (Maze[y][x] != SPACE);
304 Maze[y][x] = GMINE;
305 # ifdef MONITOR
306 for (pp = Monitor; pp < End_monitor; pp++)
307 check(pp, y, x);
308 # endif
309
310 do {
311 x = rand_num(WIDTH - 1) + 1;
312 y = rand_num(HEIGHT - 1) + 1;
313 } while (Maze[y][x] != SPACE);
314 Maze[y][x] = MINE;
315 # ifdef MONITOR
316 for (pp = Monitor; pp < End_monitor; pp++)
317 check(pp, y, x);
318 # endif
319
320 (void) sprintf(Buf, "%5.2f%c%-10.10s %c", newpp->p_ident->i_score,
321 stat_char(newpp), newpp->p_ident->i_name,
322 newpp->p_ident->i_team);
323 y = STAT_PLAY_ROW + 1 + (newpp - Player);
324 for (pp = Player; pp < End_player; pp++) {
325 if (pp != newpp) {
326 char smallbuf[16];
327
328 pp->p_ammo += NSHOTS;
329 newpp->p_ammo += NSHOTS;
330 cgoto(pp, y, STAT_NAME_COL);
331 outstr(pp, Buf, STAT_NAME_LEN);
332 (void) sprintf(smallbuf, "%3d", pp->p_ammo);
333 cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
334 outstr(pp, smallbuf, 3);
335 }
336 }
337 # ifdef MONITOR
338 for (pp = Monitor; pp < End_monitor; pp++) {
339 cgoto(pp, y, STAT_NAME_COL);
340 outstr(pp, Buf, STAT_NAME_LEN);
341 }
342 # endif
343
344 drawmaze(newpp);
345 drawplayer(newpp, TRUE);
346 look(newpp);
347 # ifdef FLY
348 if (enter_status == Q_FLY)
349 /* Make sure that the position you enter in will be erased */
350 showexpl(newpp->p_y, newpp->p_x, FLYER);
351 # endif
352 sendcom(newpp, REFRESH);
353 sendcom(newpp, READY, 0);
354 (void) fflush(newpp->p_output);
355 }
356
357 /*
358 * rand_dir:
359 * Return a random direction
360 */
361 int
362 rand_dir()
363 {
364 switch (rand_num(4)) {
365 case 0:
366 return LEFTS;
367 case 1:
368 return RIGHT;
369 case 2:
370 return BELOW;
371 case 3:
372 return ABOVE;
373 }
374 /* NOTREACHED */
375 return(-1);
376 }
377
378 /*
379 * get_ident:
380 * Get the score structure of a player
381 */
382 IDENT *
383 get_ident(machine, uid, name, team)
384 uint32_t machine;
385 uint32_t uid;
386 char *name;
387 char team;
388 {
389 IDENT *ip;
390 static IDENT punt;
391
392 for (ip = Scores; ip != NULL; ip = ip->i_next)
393 if (ip->i_machine == machine
394 && ip->i_uid == uid
395 && ip->i_team == team
396 && strncmp(ip->i_name, name, NAMELEN) == 0)
397 break;
398
399 if (ip != NULL) {
400 if (ip->i_entries < SCOREDECAY)
401 ip->i_entries++;
402 else
403 ip->i_kills = (ip->i_kills * (SCOREDECAY - 1))
404 / SCOREDECAY;
405 ip->i_score = ip->i_kills / (double) ip->i_entries;
406 }
407 else {
408 ip = (IDENT *) malloc(sizeof (IDENT));
409 if (ip == NULL) {
410 /* Fourth down, time to punt */
411 ip = &punt;
412 }
413 ip->i_machine = machine;
414 ip->i_team = team;
415 ip->i_uid = uid;
416 strncpy(ip->i_name, name, NAMELEN);
417 ip->i_kills = 0;
418 ip->i_entries = 1;
419 ip->i_score = 0;
420 ip->i_absorbed = 0;
421 ip->i_faced = 0;
422 ip->i_shot = 0;
423 ip->i_robbed = 0;
424 ip->i_slime = 0;
425 ip->i_missed = 0;
426 ip->i_ducked = 0;
427 ip->i_gkills = ip->i_bkills = ip->i_deaths = 0;
428 ip->i_stillb = ip->i_saved = 0;
429 ip->i_next = Scores;
430 Scores = ip;
431 }
432
433 return ip;
434 }
435