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