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