1 /* $OpenBSD: execute.c,v 1.15 2019/06/28 13:32:52 deraadt 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 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 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 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 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 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 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 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 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 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 len; 289 STAT sbuf; 290 int t1; 291 short t2, t3, t4; 292 long tl; 293 294 printf("\"%s\" ", file); 295 if (stat(file, &sbuf) == -1) { /* get file stats */ 296 warn("%s", file); 297 return(FALSE); 298 } 299 if ((inf = fopen(file, "r")) == NULL) { 300 warn("%s", file); 301 return(FALSE); 302 } 303 304 num = 1; 305 st = fgetln(inf, &len); 306 if (st == NULL || len != strlen(MONOP_TAG) + 1 || 307 strncmp(st, MONOP_TAG, strlen(MONOP_TAG))) { 308 badness: 309 warnx("%s line %d", file, num); 310 fclose(inf); 311 return(FALSE); 312 } 313 num++; 314 if (fgetln(inf, &len) == NULL) 315 goto badness; 316 num++; 317 if ((st = fgetln(inf, &len)) == NULL || st[len - 1] != '\n') 318 goto badness; 319 st[len - 1] = '\0'; 320 if (sscanf(st, "%d %d %d", &num_play, &player, &num_doub) != 3 || 321 num_play > MAX_PL || num_play < 1 || 322 player < 0 || player >= num_play || 323 num_doub < 0 || num_doub > 2) 324 goto badness; 325 if ((play = calloc(num_play, sizeof(PLAY))) == NULL) 326 err(1, NULL); 327 cur_p = play + player; 328 /* Names */ 329 for (i = 0; i < num_play; i++) { 330 num++; 331 if ((st = fgetln(inf, &len)) == NULL || st[len - 1] != '\n') 332 goto badness; 333 st[len - 1] = '\0'; 334 if ((name_list[i] = play[i].name = strdup(st)) == NULL) 335 err(1, NULL); 336 } 337 if ((name_list[i++] = strdup("done")) == NULL) 338 err(1, NULL); 339 name_list[i] = NULL; 340 /* Money, location, GOJF cards, turns in jail */ 341 for (i = 0; i < num_play; i++) { 342 num++; 343 if ((st = fgetln(inf, &len)) == NULL || st[len - 1] != '\n') 344 goto badness; 345 st[len - 1] = '\0'; 346 if (sscanf(st, "%d %hd %hd %hd", &(play[i].money), &t2, 347 &t3, &t4) != 4 || 348 t2 < 0 || t2 > N_SQRS || t3 < 0 || t3 > 2 || 349 (t2 != JAIL && t4 != 0) || t4 < 0 || t4 > 3) 350 goto badness; 351 play[i].loc = t2; 352 play[i].num_gojf = t3; 353 play[i].in_jail = t4; 354 } 355 /* Deck status; init_decks() must have been called. */ 356 for (i = 0; i < 2; i++) { 357 num++; 358 if ((st = fgetln(inf, &len)) == NULL || st[len - 1] != '\n') 359 goto badness; 360 st[len - 1] = '\0'; 361 if (sscanf(st, "%d %d %hd", &t1, &j, &t2) != 3 || 362 j > t1 || t1 != deck[i].num_cards || j < 0 || 363 (t2 != FALSE && t2 != TRUE)) 364 goto badness; 365 deck[i].top_card = j; 366 deck[i].gojf_used = t2; 367 num++; 368 if ((st = fgetln(inf, &len)) == NULL || st[len - 1] != '\n') 369 goto badness; 370 st[len - 1] = '\0'; 371 a = st; 372 for (j = 0; j < deck[i].num_cards; j++) { 373 if ((tl = strtol(a, &b, 10)) < 0 || tl >= 0x7FFFFFFF || 374 b == a) 375 goto badness; 376 deck[i].offsets[j] = tl; 377 b = a; 378 } 379 /* Ignore anything trailing */ 380 } 381 trading = FALSE; 382 while ((st = fgetln(inf, &len)) != NULL) { 383 num++; 384 if (st[len - 1] != '\n') 385 goto badness; 386 st[len - 1] = '\0'; 387 /* Location, owner, mortgaged, nhouses */ 388 if (sscanf(st, "%d %hd %hd %hd", &t1, &t2, &t3, &t4) != 4 || 389 t1 < 0 || t1 >= N_SQRS || (board[t1].type != PRPTY && 390 board[t1].type != RR && board[t1].type != UTIL) || 391 t2 < 0 || t2 >= num_play || 392 (t3 != TRUE && t3 != FALSE) || 393 t4 < 0 || t4 > 5 || (t4 > 0 && t3 == TRUE)) 394 goto badness; 395 add_list(t2, &(play[t2].own_list), t1); 396 /* No properties on mortgaged lots */ 397 if (t3 && t4) 398 goto badness; 399 board[t1].owner = t2; 400 (board[t1].desc)->morg = t3; 401 (board[t1].desc)->houses = t4; 402 /* XXX Should check that number of houses per property are all 403 * within 1 in each monopoly 404 */ 405 } 406 fclose(inf); 407 /* Check total hotel and house count */ 408 t1 = j = 0; 409 for (i = 0; i < N_SQRS; i++) { 410 if (board[i].type == PRPTY) { 411 if ((board[i].desc)->houses == 5) 412 j++; 413 else 414 t1 += (board[i].desc)->houses; 415 } 416 } 417 if (t1 > N_HOUSE || j > N_HOTEL) { 418 warnx("too many buildings"); 419 return(FALSE); 420 } 421 /* Check GOJF cards */ 422 t1 = 0; 423 for (i = 0; i < num_play; i++) 424 t1 += play[i].num_gojf; 425 for (i = 0; i < 2; i++) 426 t1 -= (deck[i].gojf_used == TRUE); 427 if (t1 != 0) { 428 warnx("can't figure out the Get-out-of-jail-free cards"); 429 return(FALSE); 430 } 431 432 strlcpy(buf, ctime(&sbuf.st_mtime), sizeof buf); 433 for (sp = buf; *sp != '\n'; sp++) 434 continue; 435 *sp = '\0'; 436 printf("[%s]\n", buf); 437 return(TRUE); 438 } 439