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