1 /* $NetBSD: execute.c,v 1.20 2008/02/24 06:03:35 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.20 2008/02/24 06:03:35 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
84 new_play
= FALSE
; /* new_play is true if fixing */
91 printf("%s rolled doubles. Goes again\n", cur_p
->name
);
95 * This routine moves a piece around.
103 new_play
= was_jail
= FALSE
;
104 printf("roll is %d, %d\n", r1
=roll(1, 6), r2
=roll(1, 6));
105 if (cur_p
->loc
== JAIL
) {
107 if (!move_jail(r1
, r2
)) {
113 if (r1
== r2
&& ++num_doub
== 3) {
114 printf("That's 3 doubles. You go to jail\n");
121 if (r1
!= r2
|| was_jail
)
128 * This routine moves a normal move
136 old_loc
= cur_p
->loc
;
137 cur_p
->loc
= (cur_p
->loc
+ rl
) % N_SQRS
;
138 if (cur_p
->loc
< old_loc
&& rl
> 0) {
140 printf("You pass %s and get $200\n", board
[0].name
);
146 * This routine shows the results of a move
153 sqp
= &board
[cur_p
->loc
];
154 printf("That puts you on %s\n", sqp
->name
);
157 printf("That is a safe place\n");
177 if (sqp
->owner
< 0) {
178 printf("That would cost $%d\n", sqp
->cost
);
179 if (getyn("Do you want to buy? ") == 0) {
181 cur_p
->money
-= sqp
->cost
;
183 else if (num_play
> 2)
186 else if (sqp
->owner
== player
)
187 printf("You own it.\n");
194 * Reset the game state.
201 for (i
= 0; i
< N_SQRS
; i
++) {
203 if (board
[i
].type
== PRPTY
) {
204 board
[i
].desc
->morg
= 0;
205 board
[i
].desc
->houses
= 0;
206 } else if (board
[i
].type
== RR
|| board
[i
].type
== UTIL
) {
207 board
[i
].desc
->morg
= 0;
211 for (i
= 0; i
< 2; i
++) {
212 deck
[i
].top_card
= 0;
213 deck
[i
].gojf_used
= FALSE
;
217 for (i
= 0; i
< num_play
; i
++) {
225 for (i
= 0; i
< MAX_PL
+2; i
++) {
241 * This routine saves the current game for use at a later date
252 printf("Which file do you wish to save it in? ");
253 fgets(buf
, sizeof(buf
), stdin
);
256 sp
= strchr(buf
, '\n');
261 * check for existing files, and confirm overwrite if needed
264 if (stat(buf
, &sb
) == 0
265 && getyn("File exists. Do you wish to overwrite? ") > 0)
268 outf
= fopen(buf
, "w");
273 printf("\"%s\" ", buf
);
274 time(&t
); /* get current time */
277 fprintf(outf
, "NetBSD monop format v%d\n", CUR_FORMAT_VERSION
);
278 fprintf(outf
, "time %s", ctime(&t
)); /* ctime includes a \n */
279 fprintf(outf
, "numplayers %d\n", num_play
);
280 fprintf(outf
, "currentplayer %d\n", player
);
281 fprintf(outf
, "doubles %d\n", num_doub
);
284 for (i
= 0; i
< num_play
; i
++) {
285 fprintf(outf
, "player %d {\n", i
);
286 fprintf(outf
, " name %s\n", name_list
[i
]);
287 fprintf(outf
, " money %d\n", play
[i
].money
);
288 fprintf(outf
, " loc %d\n", play
[i
].loc
);
289 fprintf(outf
, " num_gojf %d\n", play
[i
].num_gojf
);
290 fprintf(outf
, " in_jail %d\n", play
[i
].in_jail
);
291 fprintf(outf
, "}\n");
295 for (i
= 0; i
< 2; i
++) {
296 fprintf(outf
, "deck %d {\n", i
);
297 fprintf(outf
, " numcards %d\n", deck
[i
].num_cards
);
298 fprintf(outf
, " topcard %d\n", deck
[i
].top_card
);
299 fprintf(outf
, " gojf_used %d\n", deck
[i
].gojf_used
);
300 fprintf(outf
, " cards");
301 for (j
= 0; j
< deck
[i
].num_cards
; j
++)
302 fprintf(outf
, " %d", deck
[i
].cards
[j
]);
304 fprintf(outf
, "}\n");
308 for (i
= 0; i
< N_SQRS
; i
++) {
309 fprintf(outf
, "square %d {\n", i
);
310 fprintf(outf
, "owner %d\n", board
[i
].owner
);
311 if (board
[i
].owner
< 0) {
313 } else if (board
[i
].type
== PRPTY
) {
314 fprintf(outf
, "morg %d\n", board
[i
].desc
->morg
);
315 fprintf(outf
, "houses %d\n", board
[i
].desc
->houses
);
316 } else if (board
[i
].type
== RR
|| board
[i
].type
== UTIL
) {
317 fprintf(outf
, "morg %d\n", board
[i
].desc
->morg
);
319 fprintf(outf
, "}\n");
321 if (ferror(outf
) || fflush(outf
))
322 warnx("write error");
325 strcpy(buf
, ctime(&t
));
326 for (sp
= buf
; *sp
!= '\n'; sp
++)
329 printf("[%s]\n", buf
);
333 * This routine restores an old game from a file
341 printf("Which file do you wish to restore from? ");
342 fgets(buf
, sizeof(buf
), stdin
);
345 sp
= strchr(buf
, '\n');
348 if (rest_f(buf
) == 0)
354 * This does the actual restoring. It returns zero on success,
358 rest_f(const char *file
)
367 inf
= fopen(file
, "r");
372 printf("\"%s\" ", file
);
373 if (fstat(fileno(inf
), &sbuf
) < 0) {
374 err(1, "%s: fstat", file
);
377 /* Clear the game state to prevent brokenness on misordered files. */
380 /* Reset the parser */
383 /* Note: can't use buf[], file might point at it. (Lame...) */
384 while (fgets(readbuf
, sizeof(readbuf
), inf
)) {
386 * The input buffer is long enough to handle anything
387 * that's supposed to be in the output buffer, so if
388 * we get a partial line, complain.
390 sp
= strchr(readbuf
, '\n');
392 printf("file is corrupt: long lines.\n");
398 if (restore_parseline(readbuf
)) {
405 warnx("%s: read error", file
);
411 name_list
[num_play
] = "done";
413 if (play
== NULL
|| cur_p
== NULL
|| num_play
< 2) {
414 printf("save file is incomplete.\n");
419 * We could at this point crosscheck the following:
420 * - there are only two GOJF cards floating around
421 * - total number of houses and hotels does not exceed maximums
422 * - no props are both built and mortgaged
423 * but for now we don't.
426 strcpy(xbuf
, ctime(&sbuf
.st_mtime
));
427 for (sp
= xbuf
; *sp
!= '\n'; sp
++)
430 printf("[%s]\n", xbuf
);
435 * State of the restore parser
437 static int restore_version
;
444 static int restore_itemnum
;
447 * Reset the restore parser
452 restore_version
= -1;
453 restore_item
= RI_NONE
;
454 restore_itemnum
= -1;
458 * Handle one line of the save file
461 restore_parseline(char *txt
)
466 if (restore_version
< 0) {
467 /* Haven't seen the header yet. Demand it right away. */
468 if (!strncmp(txt
, "NetBSD monop format v", 21)) {
469 return getnum("format version", txt
+21,
474 printf("file is not a monop save file.\n");
478 /* Check for lines that are right braces. */
479 if (!strcmp(txt
, "}")) {
480 if (restore_item
== RI_NONE
) {
481 printf("mismatched close brace.\n");
484 restore_item
= RI_NONE
;
485 restore_itemnum
= -1;
489 /* Any other line must begin with a word, which is the attribute. */
494 s
= strchr(attribute
, ' ');
496 printf("file is corrupt: attribute %s lacks value.\n",
503 /* keep the remaining text for further handling */
506 switch (restore_item
) {
508 /* toplevel attributes */
509 return restore_toplevel_attr(attribute
, txt
);
512 /* player attributes */
513 return restore_player_attr(attribute
, txt
);
516 /* deck attributes */
517 return restore_deck_attr(attribute
, txt
);
520 /* board square attributes */
521 return restore_square_attr(attribute
, txt
);
524 printf("internal logic error\n");
529 restore_toplevel_attr(const char *attribute
, char *txt
)
531 if (!strcmp(attribute
, "time")) {
533 } else if (!strcmp(attribute
, "numplayers")) {
534 if (getnum("numplayers", txt
, 2, MAX_PL
, &num_play
) < 0) {
538 printf("numplayers: multiple settings\n");
541 play
= calloc((size_t)num_play
, sizeof(play
[0]));
545 } else if (!strcmp(attribute
, "currentplayer")) {
546 if (getnum("currentplayer", txt
, 0, num_play
-1, &player
) < 0) {
550 printf("currentplayer: before numplayers\n");
553 cur_p
= &play
[player
];
554 } else if (!strcmp(attribute
, "doubles")) {
555 if (getnum("doubles", txt
, 0, 2, &num_doub
) < 0) {
558 } else if (!strcmp(attribute
, "player")) {
559 if (getnum_withbrace("player", txt
, 0, num_play
-1,
560 &restore_itemnum
) < 0) {
563 restore_item
= RI_PLAYER
;
564 } else if (!strcmp(attribute
, "deck")) {
565 if (getnum_withbrace("deck", txt
, 0, 1,
566 &restore_itemnum
) < 0) {
569 restore_item
= RI_DECK
;
570 } else if (!strcmp(attribute
, "square")) {
571 if (getnum_withbrace("square", txt
, 0, N_SQRS
-1,
572 &restore_itemnum
) < 0) {
575 restore_item
= RI_SQUARE
;
577 printf("unknown attribute %s\n", attribute
);
584 restore_player_attr(const char *attribute
, char *txt
)
590 printf("player came before numplayers.\n");
593 pp
= &play
[restore_itemnum
];
595 if (!strcmp(attribute
, "name")) {
596 if (pp
->name
!= NULL
) {
597 printf("player has multiple names.\n");
600 /* XXX should really systematize the max name length */
601 if (strlen(txt
) > 256) {
604 pp
->name
= strdup(txt
);
605 if (pp
->name
== NULL
)
607 name_list
[restore_itemnum
] = pp
->name
;
608 } else if (!strcmp(attribute
, "money")) {
609 if (getnum(attribute
, txt
, 0, INT_MAX
, &pp
->money
) < 0) {
612 } else if (!strcmp(attribute
, "loc")) {
613 /* note: not N_SQRS-1 */
614 if (getnum(attribute
, txt
, 0, N_SQRS
, &tmp
) < 0) {
618 } else if (!strcmp(attribute
, "num_gojf")) {
619 if (getnum(attribute
, txt
, 0, 2, &tmp
) < 0) {
623 } else if (!strcmp(attribute
, "in_jail")) {
624 if (getnum(attribute
, txt
, 0, 3, &tmp
) < 0) {
628 if (pp
->in_jail
> 0 && pp
->loc
!= JAIL
) {
629 printf("player escaped from jail?\n");
633 printf("unknown attribute %s\n", attribute
);
640 restore_deck_attr(const char *attribute
, char *txt
)
646 dp
= &deck
[restore_itemnum
];
648 if (!strcmp(attribute
, "numcards")) {
649 if (getnum(attribute
, txt
, dp
->num_cards
, dp
->num_cards
,
653 } else if (!strcmp(attribute
, "topcard")) {
654 if (getnum(attribute
, txt
, 0, dp
->num_cards
,
655 &dp
->top_card
) < 0) {
658 } else if (!strcmp(attribute
, "gojf_used")) {
659 if (getnum(attribute
, txt
, 0, 1, &tmp
) < 0) {
663 } else if (!strcmp(attribute
, "cards")) {
666 for (j
= 0; j
<dp
->num_cards
; j
++) {
667 tmp
= strtol(s
, &s
, 10);
668 if (tmp
< 0 || tmp
>= dp
->num_cards
) {
669 printf("cards: out of range value\n");
675 printf("cards: invalid values\n");
679 printf("unknown attribute %s\n", attribute
);
686 restore_square_attr(const char *attribute
, char *txt
)
688 SQUARE
*sp
= &board
[restore_itemnum
];
691 if (!strcmp(attribute
, "owner")) {
692 if (getnum(attribute
, txt
, -1, num_play
-1, &tmp
) < 0) {
697 add_list(tmp
, &play
[tmp
].own_list
, restore_itemnum
);
698 } else if (!strcmp(attribute
, "morg")) {
699 if (sp
->type
!= PRPTY
&& sp
->type
!= RR
&& sp
->type
!= UTIL
) {
700 printf("unownable property is mortgaged.\n");
703 if (getnum(attribute
, txt
, 0, 1, &tmp
) < 0) {
706 sp
->desc
->morg
= tmp
;
707 } else if (!strcmp(attribute
, "houses")) {
708 if (sp
->type
!= PRPTY
) {
709 printf("unbuildable property has houses.\n");
712 if (getnum(attribute
, txt
, 0, 5, &tmp
) < 0) {
715 sp
->desc
->houses
= tmp
;
717 printf("unknown attribute %s\n", attribute
);
724 getnum(const char *what
, char *txt
, int min
, int max
, int *ret
)
730 l
= strtol(txt
, &s
, 10);
731 if (errno
|| strlen(s
)>0) {
732 printf("%s: not a number.\n", what
);
735 if (l
< min
|| l
> max
) {
736 printf("%s: out of range.\n", what
);
743 getnum_withbrace(const char *what
, char *txt
, int min
, int max
, int *ret
)
746 s
= strchr(txt
, ' ');
748 printf("%s: expected open brace\n", what
);
755 printf("%s: expected open brace\n", what
);
759 printf("%s: garbage after open brace\n", what
);
762 return getnum(what
, txt
, min
, max
, ret
);