1 /* $NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $ */
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
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
32 #include <sys/cdefs.h>
35 static char sccsid
[] = "@(#)execute.c 8.1 (Berkeley) 5/31/93";
37 __RCSID("$NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $");
45 #include <sys/types.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
;
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
,
78 * This routine executes the given command by index number
83 new_play
= FALSE
; /* new_play is true if fixing */
90 printf("%s rolled doubles. Goes again\n", cur_p
->name
);
94 * This routine moves a piece around.
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
) {
106 if (!move_jail(r1
, r2
)) {
112 if (r1
== r2
&& ++num_doub
== 3) {
113 printf("That's 3 doubles. You go to jail\n");
120 if (r1
!= r2
|| was_jail
)
127 * This routine moves a normal move
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) {
138 printf("You pass %s and get $200\n", board
[0].name
);
144 * This routine shows the results of a move
151 sqp
= &board
[cur_p
->loc
];
152 printf("That puts you on %s\n", sqp
->name
);
155 printf("That is a safe place\n");
175 if (sqp
->owner
< 0) {
176 printf("That would cost $%d\n", sqp
->cost
);
177 if (getyn("Do you want to buy? ") == 0) {
179 cur_p
->money
-= sqp
->cost
;
181 else if (num_play
> 2)
184 else if (sqp
->owner
== player
)
185 printf("You own it.\n");
192 * Reset the game state.
199 for (i
= 0; i
< N_SQRS
; i
++) {
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
;
215 for (i
= 0; i
< num_play
; i
++) {
223 for (i
= 0; i
< MAX_PL
+2; i
++) {
239 * This routine saves the current game for use at a later date
250 printf("Which file do you wish to save it in? ");
251 fgets(buf
, sizeof(buf
), stdin
);
254 sp
= strchr(buf
, '\n');
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)
266 outf
= fopen(buf
, "w");
271 printf("\"%s\" ", buf
);
272 time(&t
); /* get current time */
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
);
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");
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
]);
302 fprintf(outf
, "}\n");
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) {
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");
323 strcpy(buf
, ctime(&t
));
324 for (sp
= buf
; *sp
!= '\n'; sp
++)
327 printf("[%s]\n", buf
);
331 * This routine restores an old game from a file
339 printf("Which file do you wish to restore from? ");
340 fgets(buf
, sizeof(buf
), stdin
);
343 sp
= strchr(buf
, '\n');
346 if (rest_f(buf
) == 0)
352 * This does the actual restoring. It returns zero on success,
356 rest_f(const char *file
)
365 inf
= fopen(file
, "r");
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. */
378 /* Reset the parser */
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');
390 printf("file is corrupt: long lines.\n");
396 if (restore_parseline(readbuf
)) {
403 warnx("%s: read error", file
);
409 name_list
[num_play
] = "done";
411 if (play
== NULL
|| cur_p
== NULL
|| num_play
< 2) {
412 printf("save file is incomplete.\n");
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
++)
428 printf("[%s]\n", xbuf
);
433 * State of the restore parser
435 static int restore_version
;
442 static int restore_itemnum
;
445 * Reset the restore parser
450 restore_version
= -1;
451 restore_item
= RI_NONE
;
452 restore_itemnum
= -1;
456 * Handle one line of the save file
459 restore_parseline(char *txt
)
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,
472 printf("file is not a monop save file.\n");
476 /* Check for lines that are right braces. */
477 if (!strcmp(txt
, "}")) {
478 if (restore_item
== RI_NONE
) {
479 printf("mismatched close brace.\n");
482 restore_item
= RI_NONE
;
483 restore_itemnum
= -1;
487 /* Any other line must begin with a word, which is the attribute. */
492 s
= strchr(attribute
, ' ');
494 printf("file is corrupt: attribute %s lacks value.\n",
501 /* keep the remaining text for further handling */
504 switch (restore_item
) {
506 /* toplevel attributes */
507 return restore_toplevel_attr(attribute
, txt
);
510 /* player attributes */
511 return restore_player_attr(attribute
, txt
);
514 /* deck attributes */
515 return restore_deck_attr(attribute
, txt
);
518 /* board square attributes */
519 return restore_square_attr(attribute
, txt
);
522 printf("internal logic error\n");
527 restore_toplevel_attr(const char *attribute
, char *txt
)
529 if (!strcmp(attribute
, "time")) {
531 } else if (!strcmp(attribute
, "numplayers")) {
532 if (getnum("numplayers", txt
, 2, MAX_PL
, &num_play
) < 0) {
536 printf("numplayers: multiple settings\n");
539 play
= calloc((size_t)num_play
, sizeof(play
[0]));
543 } else if (!strcmp(attribute
, "currentplayer")) {
544 if (getnum("currentplayer", txt
, 0, num_play
-1, &player
) < 0) {
548 printf("currentplayer: before numplayers\n");
551 cur_p
= &play
[player
];
552 } else if (!strcmp(attribute
, "doubles")) {
553 if (getnum("doubles", txt
, 0, 2, &num_doub
) < 0) {
556 } else if (!strcmp(attribute
, "player")) {
557 if (getnum_withbrace("player", txt
, 0, num_play
-1,
558 &restore_itemnum
) < 0) {
561 restore_item
= RI_PLAYER
;
562 } else if (!strcmp(attribute
, "deck")) {
563 if (getnum_withbrace("deck", txt
, 0, 1,
564 &restore_itemnum
) < 0) {
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) {
573 restore_item
= RI_SQUARE
;
575 printf("unknown attribute %s\n", attribute
);
582 restore_player_attr(const char *attribute
, char *txt
)
588 printf("player came before numplayers.\n");
591 pp
= &play
[restore_itemnum
];
593 if (!strcmp(attribute
, "name")) {
594 if (pp
->name
!= NULL
) {
595 printf("player has multiple names.\n");
598 /* XXX should really systematize the max name length */
599 if (strlen(txt
) > 256) {
602 pp
->name
= strdup(txt
);
603 if (pp
->name
== NULL
)
605 name_list
[restore_itemnum
] = pp
->name
;
606 } else if (!strcmp(attribute
, "money")) {
607 if (getnum(attribute
, txt
, 0, INT_MAX
, &pp
->money
) < 0) {
610 } else if (!strcmp(attribute
, "loc")) {
611 /* note: not N_SQRS-1 */
612 if (getnum(attribute
, txt
, 0, N_SQRS
, &tmp
) < 0) {
616 } else if (!strcmp(attribute
, "num_gojf")) {
617 if (getnum(attribute
, txt
, 0, 2, &tmp
) < 0) {
621 } else if (!strcmp(attribute
, "in_jail")) {
622 if (getnum(attribute
, txt
, 0, 3, &tmp
) < 0) {
626 if (pp
->in_jail
> 0 && pp
->loc
!= JAIL
) {
627 printf("player escaped from jail?\n");
631 printf("unknown attribute %s\n", attribute
);
638 restore_deck_attr(const char *attribute
, char *txt
)
644 dp
= &deck
[restore_itemnum
];
646 if (!strcmp(attribute
, "numcards")) {
647 if (getnum(attribute
, txt
, dp
->num_cards
, dp
->num_cards
,
651 } else if (!strcmp(attribute
, "topcard")) {
652 if (getnum(attribute
, txt
, 0, dp
->num_cards
,
653 &dp
->top_card
) < 0) {
656 } else if (!strcmp(attribute
, "gojf_used")) {
657 if (getnum(attribute
, txt
, 0, 1, &tmp
) < 0) {
661 } else if (!strcmp(attribute
, "cards")) {
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");
673 printf("cards: invalid values\n");
677 printf("unknown attribute %s\n", attribute
);
684 restore_square_attr(const char *attribute
, char *txt
)
686 SQUARE
*sp
= &board
[restore_itemnum
];
689 if (!strcmp(attribute
, "owner")) {
690 if (getnum(attribute
, txt
, -1, num_play
-1, &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");
701 if (getnum(attribute
, txt
, 0, 1, &tmp
) < 0) {
704 sp
->desc
->morg
= tmp
;
705 } else if (!strcmp(attribute
, "houses")) {
706 if (sp
->type
!= PRPTY
) {
707 printf("unbuildable property has houses.\n");
710 if (getnum(attribute
, txt
, 0, 5, &tmp
) < 0) {
713 sp
->desc
->houses
= tmp
;
715 printf("unknown attribute %s\n", attribute
);
722 getnum(const char *what
, char *txt
, int min
, int max
, int *ret
)
728 l
= strtol(txt
, &s
, 10);
729 if (errno
|| strlen(s
)>0) {
730 printf("%s: not a number.\n", what
);
733 if (l
< min
|| l
> max
) {
734 printf("%s: out of range.\n", what
);
741 getnum_withbrace(const char *what
, char *txt
, int min
, int max
, int *ret
)
744 s
= strchr(txt
, ' ');
746 printf("%s: expected open brace\n", what
);
753 printf("%s: expected open brace\n", what
);
757 printf("%s: garbage after open brace\n", what
);
760 return getnum(what
, txt
, min
, max
, ret
);