xref: /openbsd-src/games/monop/execute.c (revision f3c231593a43f1549a9e81204b8aa2a3d944d18b)
1*f3c23159Sop /*	$OpenBSD: execute.c,v 1.16 2022/08/08 17:57:05 op Exp $	*/
2df930be7Sderaadt /*	$NetBSD: execute.c,v 1.3 1995/03/23 08:34:38 cgd Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5df930be7Sderaadt  * Copyright (c) 1980, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  * modification, are permitted provided that the following conditions
10df930be7Sderaadt  * are met:
11df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
167a09557bSmillert  * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
18df930be7Sderaadt  *    without specific prior written permission.
19df930be7Sderaadt  *
20df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt  * SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
33df930be7Sderaadt #include <sys/stat.h>
3491d73282Smestre 
35bb3b10f2Spjanzen #include <err.h>
3691d73282Smestre #include <stdio.h>
37bb3b10f2Spjanzen #include <stdlib.h>
3891d73282Smestre #include <string.h>
39ee7acb09Stb #include <time.h>
4091d73282Smestre 
4191d73282Smestre #include "monop.ext"
42df930be7Sderaadt 
43df930be7Sderaadt typedef	struct stat	STAT;
44df930be7Sderaadt typedef	struct tm	TIME;
45df930be7Sderaadt 
46bb3b10f2Spjanzen static char	buf[257];
47df930be7Sderaadt 
48df930be7Sderaadt static bool	new_play;	/* set if move on to new player		*/
49df930be7Sderaadt 
50c72b5b24Smillert static void	show_move(void);
51bb3b10f2Spjanzen 
52bb3b10f2Spjanzen /*
53bb3b10f2Spjanzen  *	This routine takes user input and puts it in buf
54bb3b10f2Spjanzen  */
55bb3b10f2Spjanzen void
getbuf(void)56211c4183Smestre getbuf(void)
57bb3b10f2Spjanzen {
58bb3b10f2Spjanzen 	char	*sp;
59bb3b10f2Spjanzen 	int	tmpin, i;
60bb3b10f2Spjanzen 
61bba3186fSpjanzen 	i = 1;
62bb3b10f2Spjanzen 	sp = buf;
63bba3186fSpjanzen 	while (((tmpin = getchar()) != '\n') && (i < (int)sizeof(buf)) &&
64bb3b10f2Spjanzen 	    (tmpin != EOF)) {
65bb3b10f2Spjanzen 		*sp++ = tmpin;
66bb3b10f2Spjanzen 		i++;
67bb3b10f2Spjanzen 	}
68bb3b10f2Spjanzen 	if (tmpin == EOF) {
69bb3b10f2Spjanzen 		printf("user closed input stream, quitting...\n");
70bb3b10f2Spjanzen                 exit(0);
71bb3b10f2Spjanzen 	}
72bb3b10f2Spjanzen 	*sp = '\0';
73bb3b10f2Spjanzen }
74df930be7Sderaadt /*
75df930be7Sderaadt  *	This routine executes the given command by index number
76df930be7Sderaadt  */
77bb3b10f2Spjanzen void
execute(int com_num)78211c4183Smestre execute(int com_num)
79bb3b10f2Spjanzen {
80df930be7Sderaadt 	new_play = FALSE;	/* new_play is true if fixing	*/
81df930be7Sderaadt 	(*func[com_num])();
82df930be7Sderaadt 	notify();
83df930be7Sderaadt 	force_morg();
84df930be7Sderaadt 	if (new_play)
85df930be7Sderaadt 		next_play();
86df930be7Sderaadt 	else if (num_doub)
87df930be7Sderaadt 		printf("%s rolled doubles.  Goes again\n", cur_p->name);
88df930be7Sderaadt }
89df930be7Sderaadt /*
90df930be7Sderaadt  *	This routine moves a piece around.
91df930be7Sderaadt  */
92bb3b10f2Spjanzen void
do_move(void)93211c4183Smestre do_move(void)
94bb3b10f2Spjanzen {
95bb3b10f2Spjanzen 	int	r1, r2;
96bb3b10f2Spjanzen 	bool	was_jail;
97df930be7Sderaadt 
98df930be7Sderaadt 	new_play = was_jail = FALSE;
99df930be7Sderaadt 	printf("roll is %d, %d\n", r1 = roll(1, 6), r2 = roll(1, 6));
100df930be7Sderaadt 	if (cur_p->loc == JAIL) {
101df930be7Sderaadt 		was_jail++;
102df930be7Sderaadt 		if (!move_jail(r1, r2)) {
103df930be7Sderaadt 			new_play++;
104df930be7Sderaadt 			goto ret;
105df930be7Sderaadt 		}
106df930be7Sderaadt 	}
107df930be7Sderaadt 	else {
108df930be7Sderaadt 		if (r1 == r2 && ++num_doub == 3) {
109df930be7Sderaadt 			printf("That's 3 doubles.  You go to jail\n");
110df930be7Sderaadt 			goto_jail();
111df930be7Sderaadt 			new_play++;
112df930be7Sderaadt 			goto ret;
113df930be7Sderaadt 		}
114df930be7Sderaadt 		move(r1 + r2);
115df930be7Sderaadt 	}
116df930be7Sderaadt 	if (r1 != r2 || was_jail)
117df930be7Sderaadt 		new_play++;
118df930be7Sderaadt ret:
119df930be7Sderaadt 	return;
120df930be7Sderaadt }
121df930be7Sderaadt /*
122df930be7Sderaadt  *	This routine moves a normal move
123df930be7Sderaadt  */
124bb3b10f2Spjanzen void
move(int rl)125211c4183Smestre move(int rl)
126bb3b10f2Spjanzen {
127bb3b10f2Spjanzen 	int	old_loc;
128df930be7Sderaadt 
129df930be7Sderaadt 	old_loc = cur_p->loc;
130df930be7Sderaadt 	cur_p->loc = (cur_p->loc + rl) % N_SQRS;
131df930be7Sderaadt 	if (cur_p->loc < old_loc && rl > 0) {
132df930be7Sderaadt 		cur_p->money += 200;
133df930be7Sderaadt 		printf("You pass %s and get $200\n", board[0].name);
134df930be7Sderaadt 	}
135df930be7Sderaadt 	show_move();
136df930be7Sderaadt }
137df930be7Sderaadt /*
138df930be7Sderaadt  *	This routine shows the results of a move
139df930be7Sderaadt  */
140bb3b10f2Spjanzen static void
show_move(void)141211c4183Smestre show_move(void)
142bb3b10f2Spjanzen {
143bb3b10f2Spjanzen 	SQUARE	*sqp;
144df930be7Sderaadt 
145bba3186fSpjanzen 	sqp = &board[(int)cur_p->loc];
146df930be7Sderaadt 	printf("That puts you on %s\n", sqp->name);
147df930be7Sderaadt 	switch (sqp->type) {
148df930be7Sderaadt 	case SAFE:
149df930be7Sderaadt 		printf("That is a safe place\n");
150df930be7Sderaadt 		break;
151df930be7Sderaadt 	case CC:
152bb3b10f2Spjanzen 		cc();
153bb3b10f2Spjanzen 		break;
154df930be7Sderaadt 	case CHANCE:
155bb3b10f2Spjanzen 		chance();
156bb3b10f2Spjanzen 		break;
157df930be7Sderaadt 	case INC_TAX:
158bb3b10f2Spjanzen 		inc_tax();
159bb3b10f2Spjanzen 		break;
160df930be7Sderaadt 	case GOTO_J:
161bb3b10f2Spjanzen 		goto_jail();
162bb3b10f2Spjanzen 		break;
163df930be7Sderaadt 	case LUX_TAX:
164bb3b10f2Spjanzen 		lux_tax();
165bb3b10f2Spjanzen 		break;
166df930be7Sderaadt 	case PRPTY:
167df930be7Sderaadt 	case RR:
168df930be7Sderaadt 	case UTIL:
169df930be7Sderaadt 		if (sqp->owner < 0) {
170df930be7Sderaadt 			printf("That would cost $%d\n", sqp->cost);
171df930be7Sderaadt 			if (getyn("Do you want to buy? ") == 0) {
172df930be7Sderaadt 				buy(player, sqp);
173df930be7Sderaadt 				cur_p->money -= sqp->cost;
174df930be7Sderaadt 			}
175df930be7Sderaadt 			else if (num_play > 2)
176bb3b10f2Spjanzen 				bid();
177df930be7Sderaadt 		}
178df930be7Sderaadt 		else if (sqp->owner == player)
179df930be7Sderaadt 			printf("You own it.\n");
180df930be7Sderaadt 		else
181df930be7Sderaadt 			rent(sqp);
182df930be7Sderaadt 	}
183df930be7Sderaadt }
184bba3186fSpjanzen 
185bba3186fSpjanzen 
186bba3186fSpjanzen #define MONOP_TAG "monop(6) save file"
187df930be7Sderaadt /*
188df930be7Sderaadt  *	This routine saves the current game for use at a later date
189df930be7Sderaadt  */
190bb3b10f2Spjanzen void
save(void)191211c4183Smestre save(void)
192bb3b10f2Spjanzen {
193bba3186fSpjanzen 	int i, j;
194df930be7Sderaadt 	time_t t;
195df930be7Sderaadt 	struct stat sb;
196bba3186fSpjanzen 	char *sp;
197bba3186fSpjanzen 	FILE *outf;
198df930be7Sderaadt 
199df930be7Sderaadt 	printf("Which file do you wish to save it in? ");
200bb3b10f2Spjanzen 	getbuf();
201df930be7Sderaadt 
202df930be7Sderaadt 	/*
203df930be7Sderaadt 	 * check for existing files, and confirm overwrite if needed
204df930be7Sderaadt 	 */
205bb3b10f2Spjanzen 	if (stat(buf, &sb) == 0
206bb3b10f2Spjanzen 	    && getyn("File exists.  Do you wish to overwrite? ") > 0)
207df930be7Sderaadt 		return;
208df930be7Sderaadt 
209bba3186fSpjanzen 	umask(022);
210bba3186fSpjanzen 	if ((outf = fopen(buf, "w")) == NULL) {
211b638aa94Smillert 		warn("%s", buf);
212df930be7Sderaadt 		return;
213df930be7Sderaadt 	}
214df930be7Sderaadt 	printf("\"%s\" ", buf);
215df930be7Sderaadt 	time(&t);			/* get current time		*/
216bba3186fSpjanzen 	fprintf(outf, "%s\n", MONOP_TAG);
217bba3186fSpjanzen 	fprintf(outf, "# %s", ctime(&t));	/* ctime() has \n */
218bba3186fSpjanzen 	fprintf(outf, "%d %d %d\n", num_play, player, num_doub);
219bba3186fSpjanzen 	for (i = 0; i < num_play; i++)
220bba3186fSpjanzen 		fprintf(outf, "%s\n", name_list[i]);
221bba3186fSpjanzen 	for (i = 0; i < num_play; i++)
222bba3186fSpjanzen 		fprintf(outf, "%d %d %d %d\n", play[i].money, play[i].loc,
223bba3186fSpjanzen 		    play[i].num_gojf, play[i].in_jail);
224bba3186fSpjanzen 	/* Deck status */
225bba3186fSpjanzen 	for (i = 0; i < 2; i++) {
226bba3186fSpjanzen 		fprintf(outf, "%d %d %d\n", (int)(deck[i].num_cards),
227bba3186fSpjanzen 		    (int)(deck[i].top_card), (int)(deck[i].gojf_used));
228bba3186fSpjanzen 		for (j = 0; j < deck[i].num_cards; j++)
229bba3186fSpjanzen 			fprintf(outf, "%ld ", (long)(deck[i].offsets[j]));
230bba3186fSpjanzen 		fprintf(outf, "\n");
231bba3186fSpjanzen 	}
232bba3186fSpjanzen 	/* Ownership */
233bba3186fSpjanzen 	for (i = 0; i < N_SQRS; i++) {
234bba3186fSpjanzen 		if (board[i].owner >= 0) {
235bba3186fSpjanzen 			if (board[i].type == PRPTY)
236bba3186fSpjanzen 				fprintf(outf, "%d %d %d %d\n", i, board[i].owner,
237bba3186fSpjanzen 				    board[i].desc->morg, board[i].desc->houses);
238bba3186fSpjanzen 			else if (board[i].type == RR || board[i].type == UTIL)
239bba3186fSpjanzen 				fprintf(outf, "%d %d %d 0\n", i, board[i].owner,
240bba3186fSpjanzen 				    board[i].desc->morg);
241bba3186fSpjanzen 		}
242bba3186fSpjanzen 	}
243bba3186fSpjanzen 	fclose(outf);
244bba3186fSpjanzen 
24542ceebb3Sderaadt 	strlcpy(buf, ctime(&t), sizeof buf);
246df930be7Sderaadt 	for (sp = buf; *sp != '\n'; sp++)
247df930be7Sderaadt 		continue;
248df930be7Sderaadt 	*sp = '\0';
249df930be7Sderaadt 	printf("[%s]\n", buf);
250df930be7Sderaadt }
251df930be7Sderaadt /*
252bba3186fSpjanzen  * If we are restoring during a game, try not to leak memory.
253bba3186fSpjanzen  */
254bba3186fSpjanzen void
game_restore(void)255211c4183Smestre game_restore(void)
256bba3186fSpjanzen {
257bba3186fSpjanzen 	int i;
258bba3186fSpjanzen 
2590affe7fcStedu 	free(play);
260bba3186fSpjanzen 	for (i = 0; i < num_play; i++)
261bba3186fSpjanzen 		free(name_list[i]);
262bba3186fSpjanzen 	restore();
263bba3186fSpjanzen }
264bba3186fSpjanzen /*
265df930be7Sderaadt  *	This routine restores an old game from a file
266df930be7Sderaadt  */
267bb3b10f2Spjanzen void
restore(void)268211c4183Smestre restore(void)
269bb3b10f2Spjanzen {
270df930be7Sderaadt 	printf("Which file do you wish to restore from? ");
271bb3b10f2Spjanzen 	getbuf();
272bba3186fSpjanzen 	if (rest_f(buf) == FALSE) {
273bba3186fSpjanzen 		printf("Restore failed\n");
274bba3186fSpjanzen 		exit(1);
275bba3186fSpjanzen 	}
276df930be7Sderaadt }
277df930be7Sderaadt /*
278df930be7Sderaadt  *	This does the actual restoring.  It returns TRUE if the
279bb3b10f2Spjanzen  *	backup was successful, else FALSE.
280df930be7Sderaadt  */
281bb3b10f2Spjanzen int
rest_f(char * file)282211c4183Smestre rest_f(char *file)
283bb3b10f2Spjanzen {
284bb3b10f2Spjanzen 	char *sp;
285bba3186fSpjanzen 	int  i, j, num;
286bba3186fSpjanzen 	FILE *inf;
287bba3186fSpjanzen 	char *st, *a, *b;
288*f3c23159Sop 	size_t linesize;
289*f3c23159Sop 	ssize_t len;
290df930be7Sderaadt 	STAT sbuf;
291bba3186fSpjanzen 	int  t1;
292bba3186fSpjanzen 	short t2, t3, t4;
293bba3186fSpjanzen 	long tl;
294df930be7Sderaadt 
295df930be7Sderaadt 	printf("\"%s\" ", file);
296df69c215Sderaadt 	if (stat(file, &sbuf) == -1) {		/* get file stats	*/
297bba3186fSpjanzen 		warn("%s", file);
298bba3186fSpjanzen 		return(FALSE);
299df930be7Sderaadt 	}
300bba3186fSpjanzen 	if ((inf = fopen(file, "r")) == NULL) {
301bba3186fSpjanzen 		warn("%s", file);
302bba3186fSpjanzen 		return(FALSE);
303bba3186fSpjanzen 	}
304bba3186fSpjanzen 
305bba3186fSpjanzen 	num = 1;
306*f3c23159Sop 	st = NULL;
307*f3c23159Sop 	linesize = 0;
308*f3c23159Sop 	len = getline(&st, &linesize, inf);
309*f3c23159Sop 	if (len == -1 || len != strlen(MONOP_TAG) + 1 ||
310bba3186fSpjanzen 	    strncmp(st, MONOP_TAG, strlen(MONOP_TAG))) {
311bba3186fSpjanzen badness:
312bba3186fSpjanzen 		warnx("%s line %d", file, num);
313*f3c23159Sop 		free(st);
314bba3186fSpjanzen 		fclose(inf);
315bba3186fSpjanzen 		return(FALSE);
316bba3186fSpjanzen 	}
317bba3186fSpjanzen 	num++;
318*f3c23159Sop 	if (getline(&st, &linesize, inf) == -1)
319bba3186fSpjanzen 		goto badness;
320bba3186fSpjanzen 	num++;
321*f3c23159Sop 	if ((len = getline(&st, &linesize, inf)) == -1 || st[len - 1] != '\n')
322bba3186fSpjanzen 		goto badness;
323bba3186fSpjanzen 	st[len - 1] = '\0';
324bba3186fSpjanzen 	if (sscanf(st, "%d %d %d", &num_play, &player, &num_doub) != 3 ||
325bba3186fSpjanzen 	    num_play > MAX_PL || num_play < 1 ||
326bba3186fSpjanzen 	    player < 0 || player >= num_play ||
327bba3186fSpjanzen 	    num_doub < 0 || num_doub > 2)
328bba3186fSpjanzen 		goto badness;
329ca161728Sderaadt 	if ((play = calloc(num_play, sizeof(PLAY))) == NULL)
330bba3186fSpjanzen 		err(1, NULL);
331bba3186fSpjanzen 	cur_p = play + player;
332bba3186fSpjanzen 	/* Names */
333bba3186fSpjanzen 	for (i = 0; i < num_play; i++) {
334bba3186fSpjanzen 		num++;
335*f3c23159Sop 		if ((len = getline(&st, &linesize, inf)) == -1 ||
336*f3c23159Sop 		    st[len - 1] != '\n')
337bba3186fSpjanzen 			goto badness;
338bba3186fSpjanzen 		st[len - 1] = '\0';
339bba3186fSpjanzen 		if ((name_list[i] = play[i].name = strdup(st)) == NULL)
340bba3186fSpjanzen 			err(1, NULL);
341bba3186fSpjanzen 	}
342bba3186fSpjanzen 	if ((name_list[i++] = strdup("done")) == NULL)
343bba3186fSpjanzen 		err(1, NULL);
344bba3186fSpjanzen 	name_list[i] = NULL;
345bba3186fSpjanzen 	/* Money, location, GOJF cards, turns in jail */
346bba3186fSpjanzen 	for (i = 0; i < num_play; i++) {
347bba3186fSpjanzen 		num++;
348*f3c23159Sop 		if ((len = getline(&st, &linesize, inf)) == -1 ||
349*f3c23159Sop 		    st[len - 1] != '\n')
350bba3186fSpjanzen 			goto badness;
351bba3186fSpjanzen 		st[len - 1] = '\0';
352bba3186fSpjanzen 		if (sscanf(st, "%d %hd %hd %hd", &(play[i].money), &t2,
353bba3186fSpjanzen 		    &t3, &t4) != 4 ||
354bba3186fSpjanzen 		    t2 < 0 || t2 > N_SQRS || t3 < 0 || t3 > 2 ||
355bba3186fSpjanzen 		    (t2 != JAIL && t4 != 0) || t4 < 0 || t4 > 3)
356bba3186fSpjanzen 			goto badness;
357bba3186fSpjanzen 		play[i].loc = t2;
358bba3186fSpjanzen 		play[i].num_gojf = t3;
359bba3186fSpjanzen 		play[i].in_jail  = t4;
360bba3186fSpjanzen 	}
361bba3186fSpjanzen 	/* Deck status; init_decks() must have been called. */
362bba3186fSpjanzen 	for (i = 0; i < 2; i++) {
363bba3186fSpjanzen 		num++;
364*f3c23159Sop 		if ((len = getline(&st, &linesize, inf)) == -1 ||
365*f3c23159Sop 		    st[len - 1] != '\n')
366bba3186fSpjanzen 			goto badness;
367bba3186fSpjanzen 		st[len - 1] = '\0';
368bba3186fSpjanzen 		if (sscanf(st, "%d %d %hd", &t1, &j, &t2) != 3 ||
369bba3186fSpjanzen 		    j > t1 || t1 != deck[i].num_cards || j < 0 ||
370bba3186fSpjanzen 		    (t2 != FALSE && t2 != TRUE))
371bba3186fSpjanzen 			goto badness;
372bba3186fSpjanzen 		deck[i].top_card = j;
373bba3186fSpjanzen 		deck[i].gojf_used = t2;
374bba3186fSpjanzen 		num++;
375*f3c23159Sop 		if ((len = getline(&st, &linesize, inf)) == -1 ||
376*f3c23159Sop 		    st[len - 1] != '\n')
377bba3186fSpjanzen 			goto badness;
378bba3186fSpjanzen 		st[len - 1] = '\0';
379bba3186fSpjanzen 		a = st;
380bba3186fSpjanzen 		for (j = 0; j < deck[i].num_cards; j++) {
381bba3186fSpjanzen 			if ((tl = strtol(a, &b, 10)) < 0 || tl >= 0x7FFFFFFF ||
382bba3186fSpjanzen 			    b == a)
383bba3186fSpjanzen 			    goto badness;
384bba3186fSpjanzen 			deck[i].offsets[j] = tl;
385bba3186fSpjanzen 			b = a;
386bba3186fSpjanzen 		}
387bba3186fSpjanzen 		/* Ignore anything trailing */
388bba3186fSpjanzen 	}
389bba3186fSpjanzen 	trading = FALSE;
390*f3c23159Sop 	while ((len = getline(&st, &linesize, inf)) != -1) {
391bba3186fSpjanzen 		num++;
392bba3186fSpjanzen 		if (st[len - 1] != '\n')
393bba3186fSpjanzen 			goto badness;
394bba3186fSpjanzen 		st[len - 1] = '\0';
395bba3186fSpjanzen 		/* Location, owner, mortgaged, nhouses */
396bba3186fSpjanzen 		if (sscanf(st, "%d %hd %hd %hd", &t1, &t2, &t3, &t4) != 4 ||
397bba3186fSpjanzen 		    t1 < 0 || t1 >= N_SQRS || (board[t1].type != PRPTY &&
398bba3186fSpjanzen 		    board[t1].type != RR && board[t1].type != UTIL) ||
399bba3186fSpjanzen 		    t2 < 0 || t2 >= num_play ||
400bba3186fSpjanzen 		    (t3 != TRUE && t3 != FALSE) ||
401bba3186fSpjanzen 		    t4 < 0 || t4 > 5 || (t4 > 0 && t3 == TRUE))
402bba3186fSpjanzen 			goto badness;
403bba3186fSpjanzen 		add_list(t2, &(play[t2].own_list), t1);
404bba3186fSpjanzen 		/* No properties on mortgaged lots */
405bba3186fSpjanzen 		if (t3 && t4)
406bba3186fSpjanzen 			goto badness;
407bba3186fSpjanzen 		board[t1].owner = t2;
408bba3186fSpjanzen 		(board[t1].desc)->morg = t3;
409bba3186fSpjanzen 		(board[t1].desc)->houses = t4;
410bba3186fSpjanzen 		/* XXX Should check that number of houses per property are all
411bba3186fSpjanzen 		 * within 1 in each monopoly
412bba3186fSpjanzen 		 */
413bba3186fSpjanzen 	}
414*f3c23159Sop 	free(st);
415bba3186fSpjanzen 	fclose(inf);
416bba3186fSpjanzen 	/* Check total hotel and house count */
417bba3186fSpjanzen 	t1 = j = 0;
418bba3186fSpjanzen 	for (i = 0; i < N_SQRS; i++) {
419bba3186fSpjanzen 		if (board[i].type == PRPTY) {
420bba3186fSpjanzen 			if ((board[i].desc)->houses == 5)
421bba3186fSpjanzen 				j++;
422bba3186fSpjanzen 			else
423bba3186fSpjanzen 				t1 += (board[i].desc)->houses;
424bba3186fSpjanzen 		}
425bba3186fSpjanzen 	}
426bba3186fSpjanzen 	if (t1 > N_HOUSE || j > N_HOTEL) {
427bba3186fSpjanzen 		warnx("too many buildings");
428bba3186fSpjanzen 		return(FALSE);
429bba3186fSpjanzen 	}
430bba3186fSpjanzen 	/* Check GOJF cards */
431bba3186fSpjanzen 	t1 = 0;
432bba3186fSpjanzen 	for (i = 0; i < num_play; i++)
433bba3186fSpjanzen 		t1 += play[i].num_gojf;
434bba3186fSpjanzen 	for (i = 0; i < 2; i++)
435bba3186fSpjanzen 		t1 -= (deck[i].gojf_used == TRUE);
436bba3186fSpjanzen 	if (t1 != 0) {
437bba3186fSpjanzen 		warnx("can't figure out the Get-out-of-jail-free cards");
438bba3186fSpjanzen 		return(FALSE);
439bba3186fSpjanzen 	}
440bba3186fSpjanzen 
44142ceebb3Sderaadt 	strlcpy(buf, ctime(&sbuf.st_mtime), sizeof buf);
442df930be7Sderaadt 	for (sp = buf; *sp != '\n'; sp++)
443df930be7Sderaadt 		continue;
444df930be7Sderaadt 	*sp = '\0';
445df930be7Sderaadt 	printf("[%s]\n", buf);
446bba3186fSpjanzen 	return(TRUE);
447df930be7Sderaadt }
448