tools/llvm: Do not build with symbols
[minix3.git] / games / monop / execute.c
blob3466c7ec140f051acee638e0425f41e5174069e9
1 /* $NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $ */
3 /*
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)execute.c 8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $");
38 #endif
39 #endif /* not lint */
41 #include <fcntl.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44 #include <limits.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48 #include <time.h>
49 #include <errno.h>
51 #include "deck.h"
52 #include "monop.h"
54 #define MIN_FORMAT_VERSION 1
55 #define CUR_FORMAT_VERSION 1
56 #define MAX_FORMAT_VERSION 1
58 typedef struct stat STAT;
59 typedef struct tm TIME;
61 static char buf[257];
63 static bool new_play; /* set if move on to new player */
65 static void show_move(void);
67 static void restore_reset(void);
68 static int restore_parseline(char *txt);
69 static int restore_toplevel_attr(const char *attribute, char *txt);
70 static int restore_player_attr(const char *attribute, char *txt);
71 static int restore_deck_attr(const char *attribute, char *txt);
72 static int restore_square_attr(const char *attribute, char *txt);
73 static int getnum(const char *what, char *txt, int min, int max, int *ret);
74 static int getnum_withbrace(const char *what, char *txt, int min, int max,
75 int *ret);
78 * This routine executes the given command by index number
80 void
81 execute(int com_num)
83 new_play = FALSE; /* new_play is true if fixing */
84 (*func[com_num])();
85 notify();
86 force_morg();
87 if (new_play)
88 next_play();
89 else if (num_doub)
90 printf("%s rolled doubles. Goes again\n", cur_p->name);
94 * This routine moves a piece around.
96 void
97 do_move(void)
99 int r1, r2;
100 bool was_jail;
102 new_play = was_jail = FALSE;
103 printf("roll is %d, %d\n", r1=roll(1, 6), r2=roll(1, 6));
104 if (cur_p->loc == JAIL) {
105 was_jail++;
106 if (!move_jail(r1, r2)) {
107 new_play++;
108 goto ret;
111 else {
112 if (r1 == r2 && ++num_doub == 3) {
113 printf("That's 3 doubles. You go to jail\n");
114 goto_jail();
115 new_play++;
116 goto ret;
118 move(r1+r2);
120 if (r1 != r2 || was_jail)
121 new_play++;
122 ret:
123 return;
127 * This routine moves a normal move
129 void
130 move(int rl)
132 int old_loc;
134 old_loc = cur_p->loc;
135 cur_p->loc = (cur_p->loc + rl) % N_SQRS;
136 if (cur_p->loc < old_loc && rl > 0) {
137 cur_p->money += 200;
138 printf("You pass %s and get $200\n", board[0].name);
140 show_move();
144 * This routine shows the results of a move
146 static void
147 show_move(void)
149 SQUARE *sqp;
151 sqp = &board[cur_p->loc];
152 printf("That puts you on %s\n", sqp->name);
153 switch (sqp->type) {
154 case SAFE:
155 printf("That is a safe place\n");
156 break;
157 case CC:
158 cc();
159 break;
160 case CHANCE:
161 chance();
162 break;
163 case INC_TAX:
164 inc_tax();
165 break;
166 case GOTO_J:
167 goto_jail();
168 break;
169 case LUX_TAX:
170 lux_tax();
171 break;
172 case PRPTY:
173 case RR:
174 case UTIL:
175 if (sqp->owner < 0) {
176 printf("That would cost $%d\n", sqp->cost);
177 if (getyn("Do you want to buy? ") == 0) {
178 buy(player, sqp);
179 cur_p->money -= sqp->cost;
181 else if (num_play > 2)
182 bid();
184 else if (sqp->owner == player)
185 printf("You own it.\n");
186 else
187 rent(sqp);
192 * Reset the game state.
194 static void
195 reset_game(void)
197 int i;
199 for (i = 0; i < N_SQRS; i++) {
200 board[i].owner = -1;
201 if (board[i].type == PRPTY) {
202 board[i].desc->morg = 0;
203 board[i].desc->houses = 0;
204 } else if (board[i].type == RR || board[i].type == UTIL) {
205 board[i].desc->morg = 0;
209 for (i = 0; i < 2; i++) {
210 deck[i].top_card = 0;
211 deck[i].gojf_used = FALSE;
214 if (play) {
215 for (i = 0; i < num_play; i++) {
216 free(play[i].name);
217 play[i].name = NULL;
219 free(play);
220 play = NULL;
223 for (i = 0; i < MAX_PL+2; i++) {
224 name_list[i] = NULL;
227 cur_p = NULL;
228 num_play = 0;
229 player = 0;
230 num_doub = 0;
231 fixing = FALSE;
232 trading = FALSE;
233 told_em = FALSE;
234 spec = FALSE;
239 * This routine saves the current game for use at a later date
241 void
242 save(void)
244 char *sp;
245 FILE *outf;
246 time_t t;
247 struct stat sb;
248 int i, j;
250 printf("Which file do you wish to save it in? ");
251 fgets(buf, sizeof(buf), stdin);
252 if (feof(stdin))
253 return;
254 sp = strchr(buf, '\n');
255 if (sp)
256 *sp = '\0';
259 * check for existing files, and confirm overwrite if needed
262 if (stat(buf, &sb) == 0
263 && getyn("File exists. Do you wish to overwrite? ") > 0)
264 return;
266 outf = fopen(buf, "w");
267 if (outf == NULL) {
268 warn("%s", buf);
269 return;
271 printf("\"%s\" ", buf);
272 time(&t); /* get current time */
274 /* Header */
275 fprintf(outf, "NetBSD monop format v%d\n", CUR_FORMAT_VERSION);
276 fprintf(outf, "time %s", ctime(&t)); /* ctime includes a \n */
277 fprintf(outf, "numplayers %d\n", num_play);
278 fprintf(outf, "currentplayer %d\n", player);
279 fprintf(outf, "doubles %d\n", num_doub);
281 /* Players */
282 for (i = 0; i < num_play; i++) {
283 fprintf(outf, "player %d {\n", i);
284 fprintf(outf, " name %s\n", name_list[i]);
285 fprintf(outf, " money %d\n", play[i].money);
286 fprintf(outf, " loc %d\n", play[i].loc);
287 fprintf(outf, " num_gojf %d\n", play[i].num_gojf);
288 fprintf(outf, " in_jail %d\n", play[i].in_jail);
289 fprintf(outf, "}\n");
292 /* Decks */
293 for (i = 0; i < 2; i++) {
294 fprintf(outf, "deck %d {\n", i);
295 fprintf(outf, " numcards %d\n", deck[i].num_cards);
296 fprintf(outf, " topcard %d\n", deck[i].top_card);
297 fprintf(outf, " gojf_used %d\n", deck[i].gojf_used);
298 fprintf(outf, " cards");
299 for (j = 0; j < deck[i].num_cards; j++)
300 fprintf(outf, " %d", deck[i].cards[j]);
301 fprintf(outf, "\n");
302 fprintf(outf, "}\n");
305 /* Board */
306 for (i = 0; i < N_SQRS; i++) {
307 fprintf(outf, "square %d {\n", i);
308 fprintf(outf, "owner %d\n", board[i].owner);
309 if (board[i].owner < 0) {
310 /* nothing */
311 } else if (board[i].type == PRPTY) {
312 fprintf(outf, "morg %d\n", board[i].desc->morg);
313 fprintf(outf, "houses %d\n", board[i].desc->houses);
314 } else if (board[i].type == RR || board[i].type == UTIL) {
315 fprintf(outf, "morg %d\n", board[i].desc->morg);
317 fprintf(outf, "}\n");
319 if (ferror(outf) || fflush(outf))
320 warnx("write error");
321 fclose(outf);
323 strcpy(buf, ctime(&t));
324 for (sp = buf; *sp != '\n'; sp++)
325 continue;
326 *sp = '\0';
327 printf("[%s]\n", buf);
331 * This routine restores an old game from a file
333 void
334 restore(void)
336 char *sp;
338 for (;;) {
339 printf("Which file do you wish to restore from? ");
340 fgets(buf, sizeof(buf), stdin);
341 if (feof(stdin))
342 return;
343 sp = strchr(buf, '\n');
344 if (sp)
345 *sp = '\0';
346 if (rest_f(buf) == 0)
347 break;
352 * This does the actual restoring. It returns zero on success,
353 * and -1 on failure.
356 rest_f(const char *file)
358 char *sp;
359 FILE *inf;
360 char xbuf[80];
361 STAT sbuf;
362 char readbuf[512];
363 int ret = 0;
365 inf = fopen(file, "r");
366 if (inf == NULL) {
367 warn("%s", file);
368 return -1;
370 printf("\"%s\" ", file);
371 if (fstat(fileno(inf), &sbuf) < 0) {
372 err(1, "%s: fstat", file);
375 /* Clear the game state to prevent brokenness on misordered files. */
376 reset_game();
378 /* Reset the parser */
379 restore_reset();
381 /* Note: can't use buf[], file might point at it. (Lame...) */
382 while (fgets(readbuf, sizeof(readbuf), inf)) {
384 * The input buffer is long enough to handle anything
385 * that's supposed to be in the output buffer, so if
386 * we get a partial line, complain.
388 sp = strchr(readbuf, '\n');
389 if (sp == NULL) {
390 printf("file is corrupt: long lines.\n");
391 ret = -1;
392 break;
394 *sp = '\0';
396 if (restore_parseline(readbuf)) {
397 ret = -1;
398 break;
402 if (ferror(inf))
403 warnx("%s: read error", file);
404 fclose(inf);
406 if (ret < 0)
407 return -1;
409 name_list[num_play] = "done";
411 if (play == NULL || cur_p == NULL || num_play < 2) {
412 printf("save file is incomplete.\n");
413 return -1;
417 * We could at this point crosscheck the following:
418 * - there are only two GOJF cards floating around
419 * - total number of houses and hotels does not exceed maximums
420 * - no props are both built and mortgaged
421 * but for now we don't.
424 strcpy(xbuf, ctime(&sbuf.st_mtime));
425 for (sp = xbuf; *sp != '\n'; sp++)
426 continue;
427 *sp = '\0';
428 printf("[%s]\n", xbuf);
429 return 0;
433 * State of the restore parser
435 static int restore_version;
436 static enum {
437 RI_NONE,
438 RI_PLAYER,
439 RI_DECK,
440 RI_SQUARE
441 } restore_item;
442 static int restore_itemnum;
445 * Reset the restore parser
447 static void
448 restore_reset(void)
450 restore_version = -1;
451 restore_item = RI_NONE;
452 restore_itemnum = -1;
456 * Handle one line of the save file
458 static int
459 restore_parseline(char *txt)
461 char *attribute;
462 char *s;
464 if (restore_version < 0) {
465 /* Haven't seen the header yet. Demand it right away. */
466 if (!strncmp(txt, "NetBSD monop format v", 21)) {
467 return getnum("format version", txt+21,
468 MIN_FORMAT_VERSION,
469 MAX_FORMAT_VERSION,
470 &restore_version);
472 printf("file is not a monop save file.\n");
473 return -1;
476 /* Check for lines that are right braces. */
477 if (!strcmp(txt, "}")) {
478 if (restore_item == RI_NONE) {
479 printf("mismatched close brace.\n");
480 return -1;
482 restore_item = RI_NONE;
483 restore_itemnum = -1;
484 return 0;
487 /* Any other line must begin with a word, which is the attribute. */
488 s = txt;
489 while (*s==' ')
490 s++;
491 attribute = s;
492 s = strchr(attribute, ' ');
493 if (s == NULL) {
494 printf("file is corrupt: attribute %s lacks value.\n",
495 attribute);
496 return -1;
498 *(s++) = '\0';
499 while (*s==' ')
500 s++;
501 /* keep the remaining text for further handling */
502 txt = s;
504 switch (restore_item) {
505 case RI_NONE:
506 /* toplevel attributes */
507 return restore_toplevel_attr(attribute, txt);
509 case RI_PLAYER:
510 /* player attributes */
511 return restore_player_attr(attribute, txt);
513 case RI_DECK:
514 /* deck attributes */
515 return restore_deck_attr(attribute, txt);
517 case RI_SQUARE:
518 /* board square attributes */
519 return restore_square_attr(attribute, txt);
521 /* NOTREACHED */
522 printf("internal logic error\n");
523 return -1;
526 static int
527 restore_toplevel_attr(const char *attribute, char *txt)
529 if (!strcmp(attribute, "time")) {
530 /* nothing */
531 } else if (!strcmp(attribute, "numplayers")) {
532 if (getnum("numplayers", txt, 2, MAX_PL, &num_play) < 0) {
533 return -1;
535 if (play != NULL) {
536 printf("numplayers: multiple settings\n");
537 return -1;
539 play = calloc((size_t)num_play, sizeof(play[0]));
540 if (play == NULL) {
541 err(1, "calloc");
543 } else if (!strcmp(attribute, "currentplayer")) {
544 if (getnum("currentplayer", txt, 0, num_play-1, &player) < 0) {
545 return -1;
547 if (play == NULL) {
548 printf("currentplayer: before numplayers\n");
549 return -1;
551 cur_p = &play[player];
552 } else if (!strcmp(attribute, "doubles")) {
553 if (getnum("doubles", txt, 0, 2, &num_doub) < 0) {
554 return -1;
556 } else if (!strcmp(attribute, "player")) {
557 if (getnum_withbrace("player", txt, 0, num_play-1,
558 &restore_itemnum) < 0) {
559 return -1;
561 restore_item = RI_PLAYER;
562 } else if (!strcmp(attribute, "deck")) {
563 if (getnum_withbrace("deck", txt, 0, 1,
564 &restore_itemnum) < 0) {
565 return -1;
567 restore_item = RI_DECK;
568 } else if (!strcmp(attribute, "square")) {
569 if (getnum_withbrace("square", txt, 0, N_SQRS-1,
570 &restore_itemnum) < 0) {
571 return -1;
573 restore_item = RI_SQUARE;
574 } else {
575 printf("unknown attribute %s\n", attribute);
576 return -1;
578 return 0;
581 static int
582 restore_player_attr(const char *attribute, char *txt)
584 PLAY *pp;
585 int tmp;
587 if (play == NULL) {
588 printf("player came before numplayers.\n");
589 return -1;
591 pp = &play[restore_itemnum];
593 if (!strcmp(attribute, "name")) {
594 if (pp->name != NULL) {
595 printf("player has multiple names.\n");
596 return -1;
598 /* XXX should really systematize the max name length */
599 if (strlen(txt) > 256) {
600 txt[256] = 0;
602 pp->name = strdup(txt);
603 if (pp->name == NULL)
604 err(1, "strdup");
605 name_list[restore_itemnum] = pp->name;
606 } else if (!strcmp(attribute, "money")) {
607 if (getnum(attribute, txt, 0, INT_MAX, &pp->money) < 0) {
608 return -1;
610 } else if (!strcmp(attribute, "loc")) {
611 /* note: not N_SQRS-1 */
612 if (getnum(attribute, txt, 0, N_SQRS, &tmp) < 0) {
613 return -1;
615 pp->loc = tmp;
616 } else if (!strcmp(attribute, "num_gojf")) {
617 if (getnum(attribute, txt, 0, 2, &tmp) < 0) {
618 return -1;
620 pp->num_gojf = tmp;
621 } else if (!strcmp(attribute, "in_jail")) {
622 if (getnum(attribute, txt, 0, 3, &tmp) < 0) {
623 return -1;
625 pp->in_jail = tmp;
626 if (pp->in_jail > 0 && pp->loc != JAIL) {
627 printf("player escaped from jail?\n");
628 return -1;
630 } else {
631 printf("unknown attribute %s\n", attribute);
632 return -1;
634 return 0;
637 static int
638 restore_deck_attr(const char *attribute, char *txt)
640 int tmp, j;
641 char *s;
642 DECK *dp;
644 dp = &deck[restore_itemnum];
646 if (!strcmp(attribute, "numcards")) {
647 if (getnum(attribute, txt, dp->num_cards, dp->num_cards,
648 &tmp) < 0) {
649 return -1;
651 } else if (!strcmp(attribute, "topcard")) {
652 if (getnum(attribute, txt, 0, dp->num_cards,
653 &dp->top_card) < 0) {
654 return -1;
656 } else if (!strcmp(attribute, "gojf_used")) {
657 if (getnum(attribute, txt, 0, 1, &tmp) < 0) {
658 return -1;
660 dp->gojf_used = tmp;
661 } else if (!strcmp(attribute, "cards")) {
662 errno = 0;
663 s = txt;
664 for (j = 0; j<dp->num_cards; j++) {
665 tmp = strtol(s, &s, 10);
666 if (tmp < 0 || tmp >= dp->num_cards) {
667 printf("cards: out of range value\n");
668 return -1;
670 dp->cards[j] = tmp;
672 if (errno) {
673 printf("cards: invalid values\n");
674 return -1;
676 } else {
677 printf("unknown attribute %s\n", attribute);
678 return -1;
680 return 0;
683 static int
684 restore_square_attr(const char *attribute, char *txt)
686 SQUARE *sp = &board[restore_itemnum];
687 int tmp;
689 if (!strcmp(attribute, "owner")) {
690 if (getnum(attribute, txt, -1, num_play-1, &tmp) < 0) {
691 return -1;
693 sp->owner = tmp;
694 if (tmp >= 0)
695 add_list(tmp, &play[tmp].own_list, restore_itemnum);
696 } else if (!strcmp(attribute, "morg")) {
697 if (sp->type != PRPTY && sp->type != RR && sp->type != UTIL) {
698 printf("unownable property is mortgaged.\n");
699 return -1;
701 if (getnum(attribute, txt, 0, 1, &tmp) < 0) {
702 return -1;
704 sp->desc->morg = tmp;
705 } else if (!strcmp(attribute, "houses")) {
706 if (sp->type != PRPTY) {
707 printf("unbuildable property has houses.\n");
708 return -1;
710 if (getnum(attribute, txt, 0, 5, &tmp) < 0) {
711 return -1;
713 sp->desc->houses = tmp;
714 } else {
715 printf("unknown attribute %s\n", attribute);
716 return -1;
718 return 0;
721 static int
722 getnum(const char *what, char *txt, int min, int max, int *ret)
724 char *s;
725 long l;
727 errno = 0;
728 l = strtol(txt, &s, 10);
729 if (errno || strlen(s)>0) {
730 printf("%s: not a number.\n", what);
731 return -1;
733 if (l < min || l > max) {
734 printf("%s: out of range.\n", what);
736 *ret = l;
737 return 0;
740 static int
741 getnum_withbrace(const char *what, char *txt, int min, int max, int *ret)
743 char *s;
744 s = strchr(txt, ' ');
745 if (s == NULL) {
746 printf("%s: expected open brace\n", what);
747 return -1;
749 *(s++) = '\0';
750 while (*s == ' ')
751 s++;
752 if (*s != '{') {
753 printf("%s: expected open brace\n", what);
754 return -1;
756 if (s[1] != 0) {
757 printf("%s: garbage after open brace\n", what);
758 return -1;
760 return getnum(what, txt, min, max, ret);