xref: /netbsd-src/games/sail/sync.c (revision 179b12252ecaf3553d9c2b7458ce62b6a2203d0c)
1 /*	$NetBSD: sync.c,v 1.33 2009/03/14 23:47:18 dholland Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. 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  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)sync.c	8.2 (Berkeley) 4/28/95";
36 #else
37 __RCSID("$NetBSD: sync.c,v 1.33 2009/03/14 23:47:18 dholland Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/stat.h>
42 
43 #include <fcntl.h>
44 #include <errno.h>
45 #include <limits.h>
46 #include <signal.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <time.h>
52 #include <unistd.h>
53 #include "extern.h"
54 #include "pathnames.h"
55 
56 #define BUFSIZE 4096
57 
58 /* Message types */
59 #define W_CAPTAIN	1
60 #define W_CAPTURED	2
61 #define W_CLASS		3
62 #define W_CREW		4
63 #define W_DBP		5
64 #define W_DRIFT		6
65 #define W_EXPLODE	7
66 /*      W_FILE		8   not used */
67 #define W_FOUL		9
68 #define W_GUNL		10
69 #define W_GUNR		11
70 #define W_HULL		12
71 #define W_MOVE		13
72 #define W_OBP		14
73 #define W_PCREW		15
74 #define W_UNFOUL	16
75 #define W_POINTS	17
76 #define W_QUAL		18
77 #define W_UNGRAP	19
78 #define W_RIGG		20
79 #define W_COL		21
80 #define W_DIR		22
81 #define W_ROW		23
82 #define W_SIGNAL	24
83 #define W_SINK		25
84 #define W_STRUCK	26
85 #define W_TA		27
86 #define W_ALIVE		28
87 #define W_TURN		29
88 #define W_WIND		30
89 #define W_FS		31
90 #define W_GRAP		32
91 #define W_RIG1		33
92 #define W_RIG2		34
93 #define W_RIG3		35
94 #define W_RIG4		36
95 #define W_BEGIN		37
96 #define W_END		38
97 #define W_DDEAD		39
98 
99 
100 static void recv_captain(struct ship *ship, const char *astr);
101 static void recv_captured(struct ship *ship, long a);
102 static void recv_class(struct ship *ship, long a);
103 static void recv_crew(struct ship *ship, long a, long b, long c);
104 static void recv_dbp(struct ship *ship, long a, long b, long c, long d);
105 static void recv_drift(struct ship *ship, long a);
106 static void recv_explode(struct ship *ship, long a);
107 static void recv_foul(struct ship *ship, long a);
108 static void recv_gunl(struct ship *ship, long a, long b);
109 static void recv_gunr(struct ship *ship, long a, long b);
110 static void recv_hull(struct ship *ship, long a);
111 static void recv_move(struct ship *ship, const char *astr);
112 static void recv_obp(struct ship *ship, long a, long b, long c, long d);
113 static void recv_pcrew(struct ship *ship, long a);
114 static void recv_unfoul(struct ship *ship, long a, long b);
115 static void recv_points(struct ship *ship, long a);
116 static void recv_qual(struct ship *ship, long a);
117 static void recv_ungrap(struct ship *ship, long a, long b);
118 static void recv_rigg(struct ship *ship, long a, long b, long c, long d);
119 static void recv_col(struct ship *ship, long a);
120 static void recv_dir(struct ship *ship, long a);
121 static void recv_row(struct ship *ship, long a);
122 static void recv_signal(struct ship *ship, const char *astr);
123 static void recv_sink(struct ship *ship, long a);
124 static void recv_struck(struct ship *ship, long a);
125 static void recv_ta(struct ship *ship, long a);
126 static void recv_alive(void);
127 static void recv_turn(long a);
128 static void recv_wind(long a, long b);
129 static void recv_fs(struct ship *ship, long a);
130 static void recv_grap(struct ship *ship, long a);
131 static void recv_rig1(struct ship *ship, long a);
132 static void recv_rig2(struct ship *ship, long a);
133 static void recv_rig3(struct ship *ship, long a);
134 static void recv_rig4(struct ship *ship, long a);
135 static void recv_begin(struct ship *ship);
136 static void recv_end(struct ship *ship);
137 static void recv_ddead(void);
138 
139 static void Write(int, struct ship *, long, long, long, long);
140 static void Writestr(int, struct ship *, const char *);
141 
142 static int sync_update(int, struct ship *, const char *,
143 		       long, long, long, long);
144 
145 static char sync_buf[BUFSIZE];
146 static char *sync_bp = sync_buf;
147 static long sync_seek;
148 static FILE *sync_fp;
149 
150 static const char *
151 get_sync_file(int scenario_number)
152 {
153 	static char sync_file[NAME_MAX];
154 
155 	snprintf(sync_file, sizeof(sync_file), _FILE_SYNC, scenario_number);
156 	return sync_file;
157 }
158 
159 static const char *
160 get_lock_file(int scenario_number)
161 {
162 	static char sync_lock[NAME_MAX];
163 
164 	snprintf(sync_lock, sizeof(sync_lock), _FILE_LOCK, scenario_number);
165 	return sync_lock;
166 }
167 
168 void
169 fmtship(char *buf, size_t len, const char *fmt, struct ship *ship)
170 {
171 	while (*fmt) {
172 		if (len-- == 0) {
173 			*buf = '\0';
174 			return;
175 		}
176 		if (*fmt == '$' && fmt[1] == '$') {
177 			size_t l = snprintf(buf, len, "%s (%c%c)",
178 			    ship->shipname, colours(ship), sterncolour(ship));
179 			buf += l;
180 			len -= l - 1;
181 			fmt += 2;
182 		}
183 		else
184 			*buf++ = *fmt++;
185 	}
186 
187 	if (len > 0)
188 		*buf = '\0';
189 }
190 
191 
192 /*VARARGS3*/
193 void
194 makesignal(struct ship *from, const char *fmt, struct ship *ship, ...)
195 {
196 	char message[BUFSIZ];
197 	char format[BUFSIZ];
198 	va_list ap;
199 
200 	va_start(ap, ship);
201 	fmtship(format, sizeof(format), fmt, ship);
202 	vsnprintf(message, sizeof(message), format, ap);
203 	va_end(ap);
204 	send_signal(from, message);
205 }
206 
207 /*VARARGS2*/
208 void
209 makemsg(struct ship *from, const char *fmt, ...)
210 {
211 	char message[BUFSIZ];
212 	va_list ap;
213 
214 	va_start(ap, fmt);
215 	vsnprintf(message, sizeof(message), fmt, ap);
216 	va_end(ap);
217 	send_signal(from, message);
218 }
219 
220 int
221 sync_exists(int gamenum)
222 {
223 	const char *path;
224 	struct stat s;
225 	time_t t;
226 
227 	path = get_sync_file(gamenum);
228 	time(&t);
229 	setegid(egid);
230 	if (stat(path, &s) < 0) {
231 		setegid(gid);
232 		return 0;
233 	}
234 	if (s.st_mtime < t - 60*60*2) {		/* 2 hours */
235 		unlink(path);
236 		path = get_lock_file(gamenum);
237 		unlink(path);
238 		setegid(gid);
239 		return 0;
240 	} else {
241 		setegid(gid);
242 		return 1;
243 	}
244 }
245 
246 int
247 sync_open(void)
248 {
249 	const char *sync_file;
250 	const char *sync_lock;
251 	struct stat tmp;
252 
253 	if (sync_fp != NULL)
254 		fclose(sync_fp);
255 	sync_file = get_sync_file(game);
256 	sync_lock = get_lock_file(game);
257 	setegid(egid);
258 	if (stat(sync_file, &tmp) < 0) {
259 		mode_t omask = umask(002);
260 		sync_fp = fopen(sync_file, "w+");
261 		umask(omask);
262 	} else
263 		sync_fp = fopen(sync_file, "r+");
264 	setegid(gid);
265 	if (sync_fp == NULL)
266 		return -1;
267 	sync_seek = 0;
268 	return 0;
269 }
270 
271 void
272 sync_close(int doremove)
273 {
274 	const char *sync_file;
275 
276 	if (sync_fp != 0)
277 		fclose(sync_fp);
278 	if (doremove) {
279 		sync_file = get_sync_file(game);
280 		setegid(egid);
281 		unlink(sync_file);
282 		setegid(gid);
283 	}
284 }
285 
286 static void
287 Write(int type, struct ship *ship, long a, long b, long c, long d)
288 {
289 	size_t max = sizeof(sync_buf) - (sync_bp - sync_buf);
290 	int shipindex = (ship == NULL) ? 0 : ship->file->index;
291 
292 	snprintf(sync_bp, max, "%d %d 0 %ld %ld %ld %ld\n",
293 		       type, shipindex, a, b, c, d);
294 	while (*sync_bp++)
295 		;
296 	sync_bp--;
297 	if (sync_bp >= &sync_buf[sizeof sync_buf])
298 		abort();
299 	sync_update(type, ship, NULL, a, b, c, d);
300 }
301 
302 static void
303 Writestr(int type, struct ship *ship, const char *a)
304 {
305 	size_t max = sizeof(sync_buf) - (sync_bp - sync_buf);
306 	int shipindex = (ship == NULL) ? 0 : ship->file->index;
307 
308 	snprintf(sync_bp, max, "%d %d 1 %s\n", type, shipindex, a);
309 	while (*sync_bp++)
310 		;
311 	sync_bp--;
312 	if (sync_bp >= &sync_buf[sizeof sync_buf])
313 		abort();
314 	sync_update(type, ship, a, 0, 0, 0, 0);
315 }
316 
317 int
318 Sync(void)
319 {
320 	sig_t sighup, sigint;
321 	int n;
322 	int type, shipnum, isstr;
323 	char *astr;
324 	long a, b, c, d;
325 	char buf[80];
326 	char erred = 0;
327 #ifndef LOCK_EX
328 	const char *sync_file;
329 	const char *sync_lock;
330 #endif
331 
332 	sighup = signal(SIGHUP, SIG_IGN);
333 	sigint = signal(SIGINT, SIG_IGN);
334 	for (n = TIMEOUT; --n >= 0;) {
335 #ifdef LOCK_EX
336 		if (flock(fileno(sync_fp), LOCK_EX|LOCK_NB) >= 0)
337 			break;
338 		if (errno != EWOULDBLOCK)
339 			return -1;
340 #else
341 		sync_file = get_sync_file(game);
342 		sync_lock = get_lock_file(game);
343 		setegid(egid);
344 		if (link(sync_file, sync_lock) >= 0) {
345 			setegid(gid);
346 			break;
347 		}
348 		setegid(gid);
349 		if (errno != EEXIST)
350 			return -1;
351 #endif
352 		sleep(1);
353 	}
354 	if (n <= 0)
355 		return -1;
356 	fseek(sync_fp, sync_seek, SEEK_SET);
357 	for (;;) {
358 		switch (fscanf(sync_fp, "%d%d%d", &type, &shipnum, &isstr)) {
359 		case 3:
360 			break;
361 		case EOF:
362 			goto out;
363 		default:
364 			goto bad;
365 		}
366 		if (shipnum < 0 || shipnum >= cc->vessels)
367 			goto bad;
368 		if (isstr != 0 && isstr != 1)
369 			goto bad;
370 		if (isstr) {
371 			int ch;
372 			char *p;
373 
374 			for (p = buf;;) {
375 				ch = getc(sync_fp);
376 				*p++ = ch;
377 				switch (ch) {
378 				case '\n':
379 					p--;
380 				case EOF:
381 					break;
382 				default:
383 					if (p >= buf + sizeof buf)
384 						p--;
385 					continue;
386 				}
387 				break;
388 			}
389 			*p = 0;
390 			for (p = buf; *p == ' '; p++)
391 				;
392 			astr = p;
393 			a = b = c = d = 0;
394 		} else {
395 			if (fscanf(sync_fp, "%ld%ld%ld%ld", &a, &b, &c, &d)
396 			    != 4)
397 				goto bad;
398 			astr = NULL;
399 		}
400 		if (sync_update(type, SHIP(shipnum), astr, a, b, c, d) < 0)
401 			goto bad;
402 	}
403 bad:
404 	erred++;
405 out:
406 	if (!erred && sync_bp != sync_buf) {
407 		fseek(sync_fp, 0L, SEEK_END);
408 		fwrite(sync_buf, sizeof *sync_buf, sync_bp - sync_buf,
409 			sync_fp);
410 		fflush(sync_fp);
411 		sync_bp = sync_buf;
412 	}
413 	sync_seek = ftell(sync_fp);
414 #ifdef LOCK_EX
415 	flock(fileno(sync_fp), LOCK_UN);
416 #else
417 	setegid(egid);
418 	unlink(sync_lock);
419 	setegid(gid);
420 #endif
421 	signal(SIGHUP, sighup);
422 	signal(SIGINT, sigint);
423 	return erred ? -1 : 0;
424 }
425 
426 static int
427 sync_update(int type, struct ship *ship, const char *astr,
428 	    long a, long b, long c, long d)
429 {
430 	switch (type) {
431 	case W_CAPTAIN:  recv_captain(ship, astr);    break;
432 	case W_CAPTURED: recv_captured(ship, a);      break;
433 	case W_CLASS:    recv_class(ship, a);         break;
434 	case W_CREW:     recv_crew(ship, a, b, c);    break;
435 	case W_DBP:      recv_dbp(ship, a, b, c, d);  break;
436 	case W_DRIFT:    recv_drift(ship, a);         break;
437 	case W_EXPLODE:  recv_explode(ship, a);       break;
438 	case W_FOUL:     recv_foul(ship, a);          break;
439 	case W_GUNL:     recv_gunl(ship, a, b);       break;
440 	case W_GUNR:     recv_gunr(ship, a, b);       break;
441 	case W_HULL:     recv_hull(ship, a);          break;
442 	case W_MOVE:     recv_move(ship, astr);       break;
443 	case W_OBP:      recv_obp(ship, a, b, c, d);  break;
444 	case W_PCREW:    recv_pcrew(ship, a);         break;
445 	case W_UNFOUL:   recv_unfoul(ship, a, b);     break;
446 	case W_POINTS:   recv_points(ship, a);        break;
447 	case W_QUAL:     recv_qual(ship, a);          break;
448 	case W_UNGRAP:   recv_ungrap(ship, a, b);     break;
449 	case W_RIGG:     recv_rigg(ship, a, b, c, d); break;
450 	case W_COL:      recv_col(ship, a);           break;
451 	case W_DIR:      recv_dir(ship, a);           break;
452 	case W_ROW:      recv_row(ship, a);           break;
453 	case W_SIGNAL:   recv_signal(ship, astr);     break;
454 	case W_SINK:     recv_sink(ship, a);          break;
455 	case W_STRUCK:   recv_struck(ship, a);        break;
456 	case W_TA:       recv_ta(ship, a);            break;
457 	case W_ALIVE:    recv_alive();                break;
458 	case W_TURN:     recv_turn(a);                break;
459 	case W_WIND:     recv_wind(a, b);             break;
460 	case W_FS:       recv_fs(ship, a);            break;
461 	case W_GRAP:     recv_grap(ship, a);          break;
462 	case W_RIG1:     recv_rig1(ship, a);          break;
463 	case W_RIG2:     recv_rig2(ship, a);          break;
464 	case W_RIG3:     recv_rig3(ship, a);          break;
465 	case W_RIG4:     recv_rig4(ship, a);          break;
466 	case W_BEGIN:    recv_begin(ship);            break;
467 	case W_END:      recv_end(ship);              break;
468 	case W_DDEAD:    recv_ddead();                break;
469 	default:
470 		fprintf(stderr, "sync_update: unknown type %d\r\n", type);
471 		return -1;
472 	}
473 	return 0;
474 }
475 
476 /*
477  * Messages to send
478  */
479 
480 void
481 send_captain(struct ship *ship, const char *astr)
482 {
483 	Writestr(W_CAPTAIN, ship, astr);
484 }
485 
486 void
487 send_captured(struct ship *ship, long a)
488 {
489 	Write(W_CAPTURED, ship, a, 0, 0, 0);
490 }
491 
492 void
493 send_class(struct ship *ship, long a)
494 {
495 	Write(W_CLASS, ship, a, 0, 0, 0);
496 }
497 
498 void
499 send_crew(struct ship *ship, long a, long b, long c)
500 {
501 	Write(W_CREW, ship, a, b, c, 0);
502 }
503 
504 void
505 send_dbp(struct ship *ship, long a, long b, long c, long d)
506 {
507 	Write(W_DBP, ship, a, b, c, d);
508 }
509 
510 void
511 send_drift(struct ship *ship, long a)
512 {
513 	Write(W_DRIFT, ship, a, 0, 0, 0);
514 }
515 
516 void
517 send_explode(struct ship *ship, long a)
518 {
519 	Write(W_EXPLODE, ship, a, 0, 0, 0);
520 }
521 
522 void
523 send_foul(struct ship *ship, long a)
524 {
525 	Write(W_FOUL, ship, a, 0, 0, 0);
526 }
527 
528 void
529 send_gunl(struct ship *ship, long a, long b)
530 {
531 	Write(W_GUNL, ship, a, b, 0, 0);
532 }
533 
534 void
535 send_gunr(struct ship *ship, long a, long b)
536 {
537 	Write(W_GUNR, ship, a, b, 0, 0);
538 }
539 
540 void
541 send_hull(struct ship *ship, long a)
542 {
543 	Write(W_HULL, ship, a, 0, 0, 0);
544 }
545 
546 void
547 send_move(struct ship *ship, const char *astr)
548 {
549 	Writestr(W_MOVE, ship, astr);
550 }
551 
552 void
553 send_obp(struct ship *ship, long a, long b, long c, long d)
554 {
555 	Write(W_OBP, ship, a, b, c, d);
556 }
557 
558 void
559 send_pcrew(struct ship *ship, long a)
560 {
561 	Write(W_PCREW, ship, a, 0, 0, 0);
562 }
563 
564 void
565 send_unfoul(struct ship *ship, long a, long b)
566 {
567 	Write(W_UNFOUL, ship, a, b, 0, 0);
568 }
569 
570 void
571 send_points(struct ship *ship, long a)
572 {
573 	Write(W_POINTS, ship, a, 0, 0, 0);
574 }
575 
576 void
577 send_qual(struct ship *ship, long a)
578 {
579 	Write(W_QUAL, ship, a, 0, 0, 0);
580 }
581 
582 void
583 send_ungrap(struct ship *ship, long a, long b)
584 {
585 	Write(W_UNGRAP, ship, a, b, 0, 0);
586 }
587 
588 void
589 send_rigg(struct ship *ship, long a, long b, long c, long d)
590 {
591 	Write(W_RIGG, ship, a, b, c, d);
592 }
593 
594 void
595 send_col(struct ship *ship, long a)
596 {
597 	Write(W_COL, ship, a, 0, 0, 0);
598 }
599 
600 void
601 send_dir(struct ship *ship, long a)
602 {
603 	Write(W_DIR, ship, a, 0, 0, 0);
604 }
605 
606 void
607 send_row(struct ship *ship, long a)
608 {
609 	Write(W_ROW, ship, a, 0, 0, 0);
610 }
611 
612 void
613 send_signal(struct ship *ship, const char *astr)
614 {
615 	Writestr(W_SIGNAL, ship, astr);
616 }
617 
618 void
619 send_sink(struct ship *ship, long a)
620 {
621 	Write(W_SINK, ship, a, 0, 0, 0);
622 }
623 
624 void
625 send_struck(struct ship *ship, long a)
626 {
627 	Write(W_STRUCK, ship, a, 0, 0, 0);
628 }
629 
630 void
631 send_ta(struct ship *ship, long a)
632 {
633 	Write(W_TA, ship, a, 0, 0, 0);
634 }
635 
636 void
637 send_alive(void)
638 {
639 	Write(W_ALIVE, NULL, 0, 0, 0, 0);
640 }
641 
642 void
643 send_turn(long a)
644 {
645 	Write(W_TURN, NULL, a, 0, 0, 0);
646 }
647 
648 void
649 send_wind(long a, long b)
650 {
651 	Write(W_WIND, NULL, a, b, 0, 0);
652 }
653 
654 void
655 send_fs(struct ship *ship, long a)
656 {
657 	Write(W_FS, ship, a, 0, 0, 0);
658 }
659 
660 void
661 send_grap(struct ship *ship, long a)
662 {
663 	Write(W_GRAP, ship, a, 0, 0, 0);
664 }
665 
666 void
667 send_rig1(struct ship *ship, long a)
668 {
669 	Write(W_RIG1, ship, a, 0, 0, 0);
670 }
671 
672 void
673 send_rig2(struct ship *ship, long a)
674 {
675 	Write(W_RIG2, ship, a, 0, 0, 0);
676 }
677 
678 void
679 send_rig3(struct ship *ship, long a)
680 {
681 	Write(W_RIG3, ship, a, 0, 0, 0);
682 }
683 
684 void
685 send_rig4(struct ship *ship, long a)
686 {
687 	Write(W_RIG4, ship, a, 0, 0, 0);
688 }
689 
690 void
691 send_begin(struct ship *ship)
692 {
693 	Write(W_BEGIN, ship, 0, 0, 0, 0);
694 }
695 
696 void
697 send_end(struct ship *ship)
698 {
699 	Write(W_END, ship, 0, 0, 0, 0);
700 }
701 
702 void
703 send_ddead(void)
704 {
705 	Write(W_DDEAD, NULL, 0, 0, 0, 0);
706 }
707 
708 
709 /*
710  * Actions upon message receipt
711  */
712 
713 static void
714 recv_captain(struct ship *ship, const char *astr)
715 {
716 	strlcpy(ship->file->captain, astr, sizeof ship->file->captain);
717 }
718 
719 static void
720 recv_captured(struct ship *ship, long a)
721 {
722 	if (a < 0)
723 		ship->file->captured = 0;
724 	else
725 		ship->file->captured = SHIP(a);
726 }
727 
728 static void
729 recv_class(struct ship *ship, long a)
730 {
731 	ship->specs->class = a;
732 }
733 
734 static void
735 recv_crew(struct ship *ship, long a, long b, long c)
736 {
737 	struct shipspecs *s = ship->specs;
738 
739 	s->crew1 = a;
740 	s->crew2 = b;
741 	s->crew3 = c;
742 }
743 
744 static void
745 recv_dbp(struct ship *ship, long a, long b, long c, long d)
746 {
747 	struct BP *p = &ship->file->DBP[a];
748 
749 	p->turnsent = b;
750 	p->toship = SHIP(c);
751 	p->mensent = d;
752 }
753 
754 static void
755 recv_drift(struct ship *ship, long a)
756 {
757 	ship->file->drift = a;
758 }
759 
760 static void
761 recv_explode(struct ship *ship, long a)
762 {
763 	if ((ship->file->explode = a) == 2)
764 		ship->file->dir = 0;
765 }
766 
767 static void
768 recv_foul(struct ship *ship, long a)
769 {
770 	struct snag *p = &ship->file->foul[a];
771 
772 	if (SHIP(a)->file->dir == 0)
773 		return;
774 	if (p->sn_count++ == 0)
775 		p->sn_turn = turn;
776 	ship->file->nfoul++;
777 }
778 
779 static void
780 recv_gunl(struct ship *ship, long a, long b)
781 {
782 	struct shipspecs *s = ship->specs;
783 
784 	s->gunL = a;
785 	s->carL = b;
786 }
787 
788 static void
789 recv_gunr(struct ship *ship, long a, long b)
790 {
791 	struct shipspecs *s = ship->specs;
792 
793 	s->gunR = a;
794 	s->carR = b;
795 }
796 
797 static void
798 recv_hull(struct ship *ship, long a)
799 {
800 	ship->specs->hull = a;
801 }
802 
803 static void
804 recv_move(struct ship *ship, const char *astr)
805 {
806 	strlcpy(ship->file->movebuf, astr, sizeof ship->file->movebuf);
807 }
808 
809 static void
810 recv_obp(struct ship *ship, long a, long b, long c, long d)
811 {
812 	struct BP *p = &ship->file->OBP[a];
813 
814 	p->turnsent = b;
815 	p->toship = SHIP(c);
816 	p->mensent = d;
817 }
818 
819 static void
820 recv_pcrew(struct ship *ship, long a)
821 {
822 	ship->file->pcrew = a;
823 }
824 
825 static void
826 recv_unfoul(struct ship *ship, long a, long b)
827 {
828 	struct snag *p = &ship->file->foul[a];
829 
830 	if (p->sn_count > 0) {
831 		if (b) {
832 			ship->file->nfoul -= p->sn_count;
833 			p->sn_count = 0;
834 		} else {
835 			ship->file->nfoul--;
836 			p->sn_count--;
837 		}
838 	}
839 }
840 
841 static void
842 recv_points(struct ship *ship, long a)
843 {
844 	ship->file->points = a;
845 }
846 
847 static void
848 recv_qual(struct ship *ship, long a)
849 {
850 	ship->specs->qual = a;
851 }
852 
853 static void
854 recv_ungrap(struct ship *ship, long a, long b)
855 {
856 	struct snag *p = &ship->file->grap[a];
857 
858 	if (p->sn_count > 0) {
859 		if (b) {
860 			ship->file->ngrap -= p->sn_count;
861 			p->sn_count = 0;
862 		} else {
863 			ship->file->ngrap--;
864 			p->sn_count--;
865 		}
866 	}
867 }
868 
869 static void
870 recv_rigg(struct ship *ship, long a, long b, long c, long d)
871 {
872 	struct shipspecs *s = ship->specs;
873 
874 	s->rig1 = a;
875 	s->rig2 = b;
876 	s->rig3 = c;
877 	s->rig4 = d;
878 }
879 
880 static void
881 recv_col(struct ship *ship, long a)
882 {
883 	ship->file->col = a;
884 }
885 
886 static void
887 recv_dir(struct ship *ship, long a)
888 {
889 	ship->file->dir = a;
890 }
891 
892 static void
893 recv_row(struct ship *ship, long a)
894 {
895 	ship->file->row = a;
896 }
897 
898 static void
899 recv_signal(struct ship *ship, const char *astr)
900 {
901 	if (mode == MODE_PLAYER) {
902 		if (nobells)
903 			Signal("$$: %s", ship, astr);
904 		else
905 			Signal("\a$$: %s", ship, astr);
906 	}
907 }
908 
909 static void
910 recv_sink(struct ship *ship, long a)
911 {
912 	if ((ship->file->sink = a) == 2)
913 		ship->file->dir = 0;
914 }
915 
916 static void
917 recv_struck(struct ship *ship, long a)
918 {
919 	ship->file->struck = a;
920 }
921 
922 static void
923 recv_ta(struct ship *ship, long a)
924 {
925 	ship->specs->ta = a;
926 }
927 
928 static void
929 recv_alive(void)
930 {
931 	alive = 1;
932 }
933 
934 static void
935 recv_turn(long a)
936 {
937 	turn = a;
938 }
939 
940 static void
941 recv_wind(long a, long b)
942 {
943 	winddir = a;
944 	windspeed = b;
945 }
946 
947 static void
948 recv_fs(struct ship *ship, long a)
949 {
950 	ship->file->FS = a;
951 }
952 
953 static void
954 recv_grap(struct ship *ship, long a)
955 {
956 	struct snag *p = &ship->file->grap[a];
957 
958 	if (SHIP(a)->file->dir == 0)
959 		return;
960 	if (p->sn_count++ == 0)
961 		p->sn_turn = turn;
962 	ship->file->ngrap++;
963 }
964 
965 static void
966 recv_rig1(struct ship *ship, long a)
967 {
968 	ship->specs->rig1 = a;
969 }
970 
971 static void
972 recv_rig2(struct ship *ship, long a)
973 {
974 	ship->specs->rig2 = a;
975 }
976 
977 static void
978 recv_rig3(struct ship *ship, long a)
979 {
980 	ship->specs->rig3 = a;
981 }
982 
983 static void
984 recv_rig4(struct ship *ship, long a)
985 {
986 	ship->specs->rig4 = a;
987 }
988 
989 static void
990 recv_begin(struct ship *ship)
991 {
992 	strcpy(ship->file->captain, "begin");
993 	people++;
994 }
995 
996 static void
997 recv_end(struct ship *ship)
998 {
999 	*ship->file->captain = 0;
1000 	ship->file->points = 0;
1001 	people--;
1002 }
1003 
1004 static void
1005 recv_ddead(void)
1006 {
1007 	hasdriver = 0;
1008 }
1009