1 /* $OpenBSD: execute.c,v 1.16 2022/08/08 17:57:05 op 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 #include <sys/stat.h>
34
35 #include <err.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40
41 #include "monop.ext"
42
43 typedef struct stat STAT;
44 typedef struct tm TIME;
45
46 static char buf[257];
47
48 static bool new_play; /* set if move on to new player */
49
50 static void show_move(void);
51
52 /*
53 * This routine takes user input and puts it in buf
54 */
55 void
getbuf(void)56 getbuf(void)
57 {
58 char *sp;
59 int tmpin, i;
60
61 i = 1;
62 sp = buf;
63 while (((tmpin = getchar()) != '\n') && (i < (int)sizeof(buf)) &&
64 (tmpin != EOF)) {
65 *sp++ = tmpin;
66 i++;
67 }
68 if (tmpin == EOF) {
69 printf("user closed input stream, quitting...\n");
70 exit(0);
71 }
72 *sp = '\0';
73 }
74 /*
75 * This routine executes the given command by index number
76 */
77 void
execute(int com_num)78 execute(int com_num)
79 {
80 new_play = FALSE; /* new_play is true if fixing */
81 (*func[com_num])();
82 notify();
83 force_morg();
84 if (new_play)
85 next_play();
86 else if (num_doub)
87 printf("%s rolled doubles. Goes again\n", cur_p->name);
88 }
89 /*
90 * This routine moves a piece around.
91 */
92 void
do_move(void)93 do_move(void)
94 {
95 int r1, r2;
96 bool was_jail;
97
98 new_play = was_jail = FALSE;
99 printf("roll is %d, %d\n", r1 = roll(1, 6), r2 = roll(1, 6));
100 if (cur_p->loc == JAIL) {
101 was_jail++;
102 if (!move_jail(r1, r2)) {
103 new_play++;
104 goto ret;
105 }
106 }
107 else {
108 if (r1 == r2 && ++num_doub == 3) {
109 printf("That's 3 doubles. You go to jail\n");
110 goto_jail();
111 new_play++;
112 goto ret;
113 }
114 move(r1 + r2);
115 }
116 if (r1 != r2 || was_jail)
117 new_play++;
118 ret:
119 return;
120 }
121 /*
122 * This routine moves a normal move
123 */
124 void
move(int rl)125 move(int rl)
126 {
127 int old_loc;
128
129 old_loc = cur_p->loc;
130 cur_p->loc = (cur_p->loc + rl) % N_SQRS;
131 if (cur_p->loc < old_loc && rl > 0) {
132 cur_p->money += 200;
133 printf("You pass %s and get $200\n", board[0].name);
134 }
135 show_move();
136 }
137 /*
138 * This routine shows the results of a move
139 */
140 static void
show_move(void)141 show_move(void)
142 {
143 SQUARE *sqp;
144
145 sqp = &board[(int)cur_p->loc];
146 printf("That puts you on %s\n", sqp->name);
147 switch (sqp->type) {
148 case SAFE:
149 printf("That is a safe place\n");
150 break;
151 case CC:
152 cc();
153 break;
154 case CHANCE:
155 chance();
156 break;
157 case INC_TAX:
158 inc_tax();
159 break;
160 case GOTO_J:
161 goto_jail();
162 break;
163 case LUX_TAX:
164 lux_tax();
165 break;
166 case PRPTY:
167 case RR:
168 case UTIL:
169 if (sqp->owner < 0) {
170 printf("That would cost $%d\n", sqp->cost);
171 if (getyn("Do you want to buy? ") == 0) {
172 buy(player, sqp);
173 cur_p->money -= sqp->cost;
174 }
175 else if (num_play > 2)
176 bid();
177 }
178 else if (sqp->owner == player)
179 printf("You own it.\n");
180 else
181 rent(sqp);
182 }
183 }
184
185
186 #define MONOP_TAG "monop(6) save file"
187 /*
188 * This routine saves the current game for use at a later date
189 */
190 void
save(void)191 save(void)
192 {
193 int i, j;
194 time_t t;
195 struct stat sb;
196 char *sp;
197 FILE *outf;
198
199 printf("Which file do you wish to save it in? ");
200 getbuf();
201
202 /*
203 * check for existing files, and confirm overwrite if needed
204 */
205 if (stat(buf, &sb) == 0
206 && getyn("File exists. Do you wish to overwrite? ") > 0)
207 return;
208
209 umask(022);
210 if ((outf = fopen(buf, "w")) == NULL) {
211 warn("%s", buf);
212 return;
213 }
214 printf("\"%s\" ", buf);
215 time(&t); /* get current time */
216 fprintf(outf, "%s\n", MONOP_TAG);
217 fprintf(outf, "# %s", ctime(&t)); /* ctime() has \n */
218 fprintf(outf, "%d %d %d\n", num_play, player, num_doub);
219 for (i = 0; i < num_play; i++)
220 fprintf(outf, "%s\n", name_list[i]);
221 for (i = 0; i < num_play; i++)
222 fprintf(outf, "%d %d %d %d\n", play[i].money, play[i].loc,
223 play[i].num_gojf, play[i].in_jail);
224 /* Deck status */
225 for (i = 0; i < 2; i++) {
226 fprintf(outf, "%d %d %d\n", (int)(deck[i].num_cards),
227 (int)(deck[i].top_card), (int)(deck[i].gojf_used));
228 for (j = 0; j < deck[i].num_cards; j++)
229 fprintf(outf, "%ld ", (long)(deck[i].offsets[j]));
230 fprintf(outf, "\n");
231 }
232 /* Ownership */
233 for (i = 0; i < N_SQRS; i++) {
234 if (board[i].owner >= 0) {
235 if (board[i].type == PRPTY)
236 fprintf(outf, "%d %d %d %d\n", i, board[i].owner,
237 board[i].desc->morg, board[i].desc->houses);
238 else if (board[i].type == RR || board[i].type == UTIL)
239 fprintf(outf, "%d %d %d 0\n", i, board[i].owner,
240 board[i].desc->morg);
241 }
242 }
243 fclose(outf);
244
245 strlcpy(buf, ctime(&t), sizeof buf);
246 for (sp = buf; *sp != '\n'; sp++)
247 continue;
248 *sp = '\0';
249 printf("[%s]\n", buf);
250 }
251 /*
252 * If we are restoring during a game, try not to leak memory.
253 */
254 void
game_restore(void)255 game_restore(void)
256 {
257 int i;
258
259 free(play);
260 for (i = 0; i < num_play; i++)
261 free(name_list[i]);
262 restore();
263 }
264 /*
265 * This routine restores an old game from a file
266 */
267 void
restore(void)268 restore(void)
269 {
270 printf("Which file do you wish to restore from? ");
271 getbuf();
272 if (rest_f(buf) == FALSE) {
273 printf("Restore failed\n");
274 exit(1);
275 }
276 }
277 /*
278 * This does the actual restoring. It returns TRUE if the
279 * backup was successful, else FALSE.
280 */
281 int
rest_f(char * file)282 rest_f(char *file)
283 {
284 char *sp;
285 int i, j, num;
286 FILE *inf;
287 char *st, *a, *b;
288 size_t linesize;
289 ssize_t len;
290 STAT sbuf;
291 int t1;
292 short t2, t3, t4;
293 long tl;
294
295 printf("\"%s\" ", file);
296 if (stat(file, &sbuf) == -1) { /* get file stats */
297 warn("%s", file);
298 return(FALSE);
299 }
300 if ((inf = fopen(file, "r")) == NULL) {
301 warn("%s", file);
302 return(FALSE);
303 }
304
305 num = 1;
306 st = NULL;
307 linesize = 0;
308 len = getline(&st, &linesize, inf);
309 if (len == -1 || len != strlen(MONOP_TAG) + 1 ||
310 strncmp(st, MONOP_TAG, strlen(MONOP_TAG))) {
311 badness:
312 warnx("%s line %d", file, num);
313 free(st);
314 fclose(inf);
315 return(FALSE);
316 }
317 num++;
318 if (getline(&st, &linesize, inf) == -1)
319 goto badness;
320 num++;
321 if ((len = getline(&st, &linesize, inf)) == -1 || st[len - 1] != '\n')
322 goto badness;
323 st[len - 1] = '\0';
324 if (sscanf(st, "%d %d %d", &num_play, &player, &num_doub) != 3 ||
325 num_play > MAX_PL || num_play < 1 ||
326 player < 0 || player >= num_play ||
327 num_doub < 0 || num_doub > 2)
328 goto badness;
329 if ((play = calloc(num_play, sizeof(PLAY))) == NULL)
330 err(1, NULL);
331 cur_p = play + player;
332 /* Names */
333 for (i = 0; i < num_play; i++) {
334 num++;
335 if ((len = getline(&st, &linesize, inf)) == -1 ||
336 st[len - 1] != '\n')
337 goto badness;
338 st[len - 1] = '\0';
339 if ((name_list[i] = play[i].name = strdup(st)) == NULL)
340 err(1, NULL);
341 }
342 if ((name_list[i++] = strdup("done")) == NULL)
343 err(1, NULL);
344 name_list[i] = NULL;
345 /* Money, location, GOJF cards, turns in jail */
346 for (i = 0; i < num_play; i++) {
347 num++;
348 if ((len = getline(&st, &linesize, inf)) == -1 ||
349 st[len - 1] != '\n')
350 goto badness;
351 st[len - 1] = '\0';
352 if (sscanf(st, "%d %hd %hd %hd", &(play[i].money), &t2,
353 &t3, &t4) != 4 ||
354 t2 < 0 || t2 > N_SQRS || t3 < 0 || t3 > 2 ||
355 (t2 != JAIL && t4 != 0) || t4 < 0 || t4 > 3)
356 goto badness;
357 play[i].loc = t2;
358 play[i].num_gojf = t3;
359 play[i].in_jail = t4;
360 }
361 /* Deck status; init_decks() must have been called. */
362 for (i = 0; i < 2; i++) {
363 num++;
364 if ((len = getline(&st, &linesize, inf)) == -1 ||
365 st[len - 1] != '\n')
366 goto badness;
367 st[len - 1] = '\0';
368 if (sscanf(st, "%d %d %hd", &t1, &j, &t2) != 3 ||
369 j > t1 || t1 != deck[i].num_cards || j < 0 ||
370 (t2 != FALSE && t2 != TRUE))
371 goto badness;
372 deck[i].top_card = j;
373 deck[i].gojf_used = t2;
374 num++;
375 if ((len = getline(&st, &linesize, inf)) == -1 ||
376 st[len - 1] != '\n')
377 goto badness;
378 st[len - 1] = '\0';
379 a = st;
380 for (j = 0; j < deck[i].num_cards; j++) {
381 if ((tl = strtol(a, &b, 10)) < 0 || tl >= 0x7FFFFFFF ||
382 b == a)
383 goto badness;
384 deck[i].offsets[j] = tl;
385 b = a;
386 }
387 /* Ignore anything trailing */
388 }
389 trading = FALSE;
390 while ((len = getline(&st, &linesize, inf)) != -1) {
391 num++;
392 if (st[len - 1] != '\n')
393 goto badness;
394 st[len - 1] = '\0';
395 /* Location, owner, mortgaged, nhouses */
396 if (sscanf(st, "%d %hd %hd %hd", &t1, &t2, &t3, &t4) != 4 ||
397 t1 < 0 || t1 >= N_SQRS || (board[t1].type != PRPTY &&
398 board[t1].type != RR && board[t1].type != UTIL) ||
399 t2 < 0 || t2 >= num_play ||
400 (t3 != TRUE && t3 != FALSE) ||
401 t4 < 0 || t4 > 5 || (t4 > 0 && t3 == TRUE))
402 goto badness;
403 add_list(t2, &(play[t2].own_list), t1);
404 /* No properties on mortgaged lots */
405 if (t3 && t4)
406 goto badness;
407 board[t1].owner = t2;
408 (board[t1].desc)->morg = t3;
409 (board[t1].desc)->houses = t4;
410 /* XXX Should check that number of houses per property are all
411 * within 1 in each monopoly
412 */
413 }
414 free(st);
415 fclose(inf);
416 /* Check total hotel and house count */
417 t1 = j = 0;
418 for (i = 0; i < N_SQRS; i++) {
419 if (board[i].type == PRPTY) {
420 if ((board[i].desc)->houses == 5)
421 j++;
422 else
423 t1 += (board[i].desc)->houses;
424 }
425 }
426 if (t1 > N_HOUSE || j > N_HOTEL) {
427 warnx("too many buildings");
428 return(FALSE);
429 }
430 /* Check GOJF cards */
431 t1 = 0;
432 for (i = 0; i < num_play; i++)
433 t1 += play[i].num_gojf;
434 for (i = 0; i < 2; i++)
435 t1 -= (deck[i].gojf_used == TRUE);
436 if (t1 != 0) {
437 warnx("can't figure out the Get-out-of-jail-free cards");
438 return(FALSE);
439 }
440
441 strlcpy(buf, ctime(&sbuf.st_mtime), sizeof buf);
442 for (sp = buf; *sp != '\n'; sp++)
443 continue;
444 *sp = '\0';
445 printf("[%s]\n", buf);
446 return(TRUE);
447 }
448