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