diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 559a0e0c6..d97471009 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -560,6 +560,7 @@ ./usr/games/factor minix-sys ./usr/games/fortune minix-sys ./usr/games/hide minix-sys +./usr/games/monop minix-sys ./usr/games/morse minix-sys ./usr/games/number minix-sys ./usr/games/pig minix-sys @@ -4758,6 +4759,7 @@ ./usr/man/man6/bcd.6 minix-sys ./usr/man/man6/factor.6 minix-sys ./usr/man/man6/fortune.6 minix-sys +./usr/man/man6/monop.6 minix-sys ./usr/man/man6/morse.6 minix-sys ./usr/man/man6/number.6 minix-sys ./usr/man/man6/pig.6 minix-sys diff --git a/games/Makefile b/games/Makefile index 75d15e425..0f02325da 100644 --- a/games/Makefile +++ b/games/Makefile @@ -11,7 +11,7 @@ SUBDIR= adventure \ bcd \ \ factor fortune \ - morse number \ + monop morse number \ pig ppt primes .if !defined(__MINIX) diff --git a/games/monop/Makefile b/games/monop/Makefile new file mode 100644 index 000000000..45eea382d --- /dev/null +++ b/games/monop/Makefile @@ -0,0 +1,12 @@ +# $NetBSD: Makefile,v 1.30 2008/02/24 02:43:18 dholland Exp $ +# @(#)Makefile 8.1 (Berkeley) 5/31/93 + +.include + +PROG= monop +SRCS= monop.c cards.c execute.c getinp.c houses.c jail.c misc.c \ + morg.c print.c prop.c rent.c roll.c spec.c trade.c +MAN= monop.6 +HIDEGAME=hidegame + +.include diff --git a/games/monop/cards.c b/games/monop/cards.c new file mode 100644 index 000000000..bae1de8e1 --- /dev/null +++ b/games/monop/cards.c @@ -0,0 +1,397 @@ +/* $NetBSD: cards.c,v 1.25 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)cards.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: cards.c,v 1.25 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include "monop.h" +#include "deck.h" + +/* + * These routine deal with the card decks + */ + +static void set_up(DECK *); +static void printmes(const char *text); + +#define GOJF 'F' /* char for get-out-of-jail-free cards */ + +struct cardinfo { + const char *actioncode; + const char *text; +}; + +static const struct cardinfo cc_cards[] = { + { "FF", + ">> GET OUT OF JAIL FREE <<\n" + "Keep this card until needed or sold\n" + }, + { "++25", + "Receive for Services $25.\n" + }, + { "++200", + "Bank Error in Your Favor.\n" + "Collect $200.\n" + }, + { "++20", + "Income Tax Refund.\n" + "Collect $20.\n" + }, + { "--100", + "Pay Hospital $100\n" + }, + { "++100", + "Life Insurance Matures.\n" + "Collect $100\n" + }, + { "++45", + "From sale of Stock You get $45.\n" + }, + { "TX", + "You are Assessed for street repairs.\n" + "\t$40 per House\n" + "\t$115 per Hotel\n" + }, + { "++100", + "X-mas Fund Matures.\n" + "Collect $100.\n" + }, + { "++11", + "You have won Second Prize in a Beauty Contest\n" + "Collect $11\n" + }, + { "MF0", + "Advance to GO\n" + "(Collect $200)\n" + }, + { "++100", + "You inherit $100\n" + }, + { "--150", + "Pay School Tax of $150.\n" + }, + { "MJ", + "\t\t>> GO TO JAIL <<\n" + "Go Directly to Jail. Do not pass GO Do not collect $200.\n" + }, + { "+A50", + "\t\t>> GRAND OPERA OPENING <<\n" + "Collect $50 from each player for opening night seats.\n" + }, + { "--50", + "Doctor's Fee: Pay $50.\n" + } +}; + +static const struct cardinfo ch_cards[] = { + { "FF", + ">> GET OUT OF JAIL FREE <<\n" + "Keep this card until needed or sold\n" + }, + { "MR", + "Advance to the nearest Railroad, and pay owner\n" + "Twice the rental to which he is otherwise entitled.\n" + "If Railroad is unowned you may buy it from the bank\n" + }, + { "MU", + "Advance to the nearest Utility.\n" + "If unowned, you may buy it from the bank.\n" + "If owned, throw dice and pay oner a total of ten times\n" + "the amount thrown.\n" + }, + { "MB3", + "Go Back 3 Spaces\n" + }, + { "MR", + "Advance to the nearest Railroad, and pay owner\n" + "Twice the rental to which he is otherwise entitled.\n" + "If Railroad is unowned you may buy it from the bank\n" + }, + { "MJ", + " >> GO DIRECTLY TO JAIL <<\n" + "Do not pass GO, Do not Collect $200.\n" + }, + { "MF5", + "Take a Ride on the Reading.\n" + "If you pass GO, collect $200.\n" + }, + { "MF39", + "Take a Walk on the Board Walk.\n" + " (Advance To Board Walk)\n" + }, + { "MF24", + "Advance to Illinois Ave.\n" + }, + { "MF0", + "Advance to Go\n" + }, + { "MF11", + "Advance to St. Charles Place.\n" + "If you pass GO, collect $200.\n" + }, + { "TX", + "Make general repairs on all of your Property.\n" + "For Each House pay $25.\n" + "For Each Hotel pay $100.\n" + }, + { "-A50", + "You have been elected Chairman of the Board.\n" + "Pay each player $50.\n" + }, + { "--15", + "Pay Poor Tax of $15\n" + }, + { "++50", + "Bank pays you Dividend of $50.\n" + }, + { "++150", + "Your Building and Loan Matures.\n" + "Collect $150.\n" + } +}; + +/* + * This routine initializes the decks from the data above. + */ +void +init_decks(void) +{ + CC_D.info = cc_cards; + CC_D.num_cards = sizeof(cc_cards) / sizeof(cc_cards[0]); + CH_D.info = ch_cards; + CH_D.num_cards = sizeof(ch_cards) / sizeof(ch_cards[0]); + set_up(&CC_D); + set_up(&CH_D); +} + +/* + * This routine sets up the offset pointers for the given deck. + */ +static void +set_up(DECK *dp) +{ + int r1, r2; + int i; + + dp->cards = calloc((size_t)dp->num_cards, sizeof(dp->cards[0])); + if (dp->cards == NULL) + errx(1, "out of memory"); + + for (i = 0; i < dp->num_cards; i++) + dp->cards[i] = i; + + dp->top_card = 0; + dp->gojf_used = FALSE; + + for (i = 0; i < dp->num_cards; i++) { + int temp; + + r1 = roll(1, dp->num_cards) - 1; + r2 = roll(1, dp->num_cards) - 1; + temp = dp->cards[r2]; + dp->cards[r2] = dp->cards[r1]; + dp->cards[r1] = temp; + } +} + +/* + * This routine draws a card from the given deck + */ +void +get_card(DECK *dp) +{ + char type_maj, type_min; + int num; + int i, per_h, per_H, num_h, num_H; + OWN *op; + const struct cardinfo *thiscard; + + do { + thiscard = &dp->info[dp->top_card]; + type_maj = thiscard->actioncode[0]; + dp->top_card = (dp->top_card + 1) % dp->num_cards; + } while (dp->gojf_used && type_maj == GOJF); + type_min = thiscard->actioncode[1]; + num = atoi(thiscard->actioncode+2); + + printmes(thiscard->text); + switch (type_maj) { + case '+': /* get money */ + if (type_min == 'A') { + for (i = 0; i < num_play; i++) + if (i != player) + play[i].money -= num; + num = num * (num_play - 1); + } + cur_p->money += num; + break; + case '-': /* lose money */ + if (type_min == 'A') { + for (i = 0; i < num_play; i++) + if (i != player) + play[i].money += num; + num = num * (num_play - 1); + } + cur_p->money -= num; + break; + case 'M': /* move somewhere */ + switch (type_min) { + case 'F': /* move forward */ + num -= cur_p->loc; + if (num < 0) + num += 40; + break; + case 'J': /* move to jail */ + goto_jail(); + return; + case 'R': /* move to railroad */ + spec = TRUE; + num = (int)((cur_p->loc + 5)/10)*10 + 5 - cur_p->loc; + break; + case 'U': /* move to utility */ + spec = TRUE; + if (cur_p->loc >= 12 && cur_p->loc < 28) + num = 28 - cur_p->loc; + else { + num = 12 - cur_p->loc; + if (num < 0) + num += 40; + } + break; + case 'B': + num = -num; + break; + } + move(num); + break; + case 'T': /* tax */ + if (dp == &CC_D) { + per_h = 40; + per_H = 115; + } + else { + per_h = 25; + per_H = 100; + } + num_h = num_H = 0; + for (op = cur_p->own_list; op; op = op->next) + if (op->sqr->type == PRPTY) { + if (op->sqr->desc->houses == 5) + ++num_H; + else + num_h += op->sqr->desc->houses; + } + num = per_h * num_h + per_H * num_H; + printf( + "You had %d Houses and %d Hotels, so that cost you $%d\n", + num_h, num_H, num); + if (num == 0) + lucky(""); + else + cur_p->money -= num; + break; + case GOJF: /* get-out-of-jail-free card */ + cur_p->num_gojf++; + dp->gojf_used = TRUE; + break; + } + spec = FALSE; +} + +/* + * This routine prints out the message on the card + */ +static void +printmes(const char *text) +{ + int i; + + printline(); + fflush(stdout); + for (i = 0; text[i] != '\0'; i++) + putchar(text[i]); + printline(); + fflush(stdout); +} + +/* + * This routine returns the players get-out-of-jail-free card + * to the bottom of a deck. XXX currently does not return to the correct + * deck. + */ +void +ret_card(PLAY *plr) +{ + char type_maj; + int gojfpos, last_card; + int i; + DECK *dp; + int temp; + + plr->num_gojf--; + if (CC_D.gojf_used) + dp = &CC_D; + else + dp = &CH_D; + dp->gojf_used = FALSE; + + /* Put at bottom of deck (top_card - 1) and remove it from wherever else + * it used to be. + */ + last_card = dp->top_card - 1; + if (last_card < 0) + last_card += dp->num_cards; + gojfpos = dp->top_card; + do { + gojfpos = (gojfpos + 1) % dp->num_cards; + type_maj = dp->info[gojfpos].actioncode[0]; + } while (type_maj != GOJF); + temp = dp->cards[gojfpos]; + /* Only one of the next two loops does anything */ + for (i = gojfpos - 1; i > last_card; i--) + dp->cards[i + 1] = dp->cards[i]; + for (i = gojfpos; i < last_card; i++) + dp->cards[i] = dp->cards[i + 1]; + if (gojfpos > last_card) { + dp->cards[dp->top_card] = temp; + dp->top_card++; + dp->top_card %= dp->num_cards; + } else + dp->cards[last_card] = temp; +} diff --git a/games/monop/deck.h b/games/monop/deck.h new file mode 100644 index 000000000..7e3f19158 --- /dev/null +++ b/games/monop/deck.h @@ -0,0 +1,58 @@ +/* $NetBSD: deck.h,v 1.9 2008/02/24 02:43:18 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)deck.h 8.1 (Berkeley) 5/31/93 + */ + +#include + +#define bool char + +struct cardinfo; /* private to cards.c */ + +#define CC_D deck[0] +#define CH_D deck[1] + +struct dk_st { /* deck description structure */ + int num_cards; /* number of cards in deck */ + int top_card; /* number of last card picked */ + bool gojf_used; /* set if gojf card out of deck */ + int *cards; /* which cards (indexes info[]) */ + const struct cardinfo *info; /* the static card data */ +}; + +typedef struct dk_st DECK; + +extern DECK deck[2]; + +/* cards.c */ +void init_decks(void); +void get_card(DECK *); + diff --git a/games/monop/execute.c b/games/monop/execute.c new file mode 100644 index 000000000..3466c7ec1 --- /dev/null +++ b/games/monop/execute.c @@ -0,0 +1,761 @@ +/* $NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)execute.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: execute.c,v 1.22 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "deck.h" +#include "monop.h" + +#define MIN_FORMAT_VERSION 1 +#define CUR_FORMAT_VERSION 1 +#define MAX_FORMAT_VERSION 1 + +typedef struct stat STAT; +typedef struct tm TIME; + +static char buf[257]; + +static bool new_play; /* set if move on to new player */ + +static void show_move(void); + +static void restore_reset(void); +static int restore_parseline(char *txt); +static int restore_toplevel_attr(const char *attribute, char *txt); +static int restore_player_attr(const char *attribute, char *txt); +static int restore_deck_attr(const char *attribute, char *txt); +static int restore_square_attr(const char *attribute, char *txt); +static int getnum(const char *what, char *txt, int min, int max, int *ret); +static int getnum_withbrace(const char *what, char *txt, int min, int max, + int *ret); + +/* + * This routine executes the given command by index number + */ +void +execute(int com_num) +{ + new_play = FALSE; /* new_play is true if fixing */ + (*func[com_num])(); + notify(); + force_morg(); + if (new_play) + next_play(); + else if (num_doub) + printf("%s rolled doubles. Goes again\n", cur_p->name); +} + +/* + * This routine moves a piece around. + */ +void +do_move(void) +{ + int r1, r2; + bool was_jail; + + new_play = was_jail = FALSE; + printf("roll is %d, %d\n", r1=roll(1, 6), r2=roll(1, 6)); + if (cur_p->loc == JAIL) { + was_jail++; + if (!move_jail(r1, r2)) { + new_play++; + goto ret; + } + } + else { + if (r1 == r2 && ++num_doub == 3) { + printf("That's 3 doubles. You go to jail\n"); + goto_jail(); + new_play++; + goto ret; + } + move(r1+r2); + } + if (r1 != r2 || was_jail) + new_play++; +ret: + return; +} + +/* + * This routine moves a normal move + */ +void +move(int rl) +{ + int old_loc; + + old_loc = cur_p->loc; + cur_p->loc = (cur_p->loc + rl) % N_SQRS; + if (cur_p->loc < old_loc && rl > 0) { + cur_p->money += 200; + printf("You pass %s and get $200\n", board[0].name); + } + show_move(); +} + +/* + * This routine shows the results of a move + */ +static void +show_move(void) +{ + SQUARE *sqp; + + sqp = &board[cur_p->loc]; + printf("That puts you on %s\n", sqp->name); + switch (sqp->type) { + case SAFE: + printf("That is a safe place\n"); + break; + case CC: + cc(); + break; + case CHANCE: + chance(); + break; + case INC_TAX: + inc_tax(); + break; + case GOTO_J: + goto_jail(); + break; + case LUX_TAX: + lux_tax(); + break; + case PRPTY: + case RR: + case UTIL: + if (sqp->owner < 0) { + printf("That would cost $%d\n", sqp->cost); + if (getyn("Do you want to buy? ") == 0) { + buy(player, sqp); + cur_p->money -= sqp->cost; + } + else if (num_play > 2) + bid(); + } + else if (sqp->owner == player) + printf("You own it.\n"); + else + rent(sqp); + } +} + +/* + * Reset the game state. + */ +static void +reset_game(void) +{ + int i; + + for (i = 0; i < N_SQRS; i++) { + board[i].owner = -1; + if (board[i].type == PRPTY) { + board[i].desc->morg = 0; + board[i].desc->houses = 0; + } else if (board[i].type == RR || board[i].type == UTIL) { + board[i].desc->morg = 0; + } + } + + for (i = 0; i < 2; i++) { + deck[i].top_card = 0; + deck[i].gojf_used = FALSE; + } + + if (play) { + for (i = 0; i < num_play; i++) { + free(play[i].name); + play[i].name = NULL; + } + free(play); + play = NULL; + } + + for (i = 0; i < MAX_PL+2; i++) { + name_list[i] = NULL; + } + + cur_p = NULL; + num_play = 0; + player = 0; + num_doub = 0; + fixing = FALSE; + trading = FALSE; + told_em = FALSE; + spec = FALSE; +} + + +/* + * This routine saves the current game for use at a later date + */ +void +save(void) +{ + char *sp; + FILE *outf; + time_t t; + struct stat sb; + int i, j; + + printf("Which file do you wish to save it in? "); + fgets(buf, sizeof(buf), stdin); + if (feof(stdin)) + return; + sp = strchr(buf, '\n'); + if (sp) + *sp = '\0'; + + /* + * check for existing files, and confirm overwrite if needed + */ + + if (stat(buf, &sb) == 0 + && getyn("File exists. Do you wish to overwrite? ") > 0) + return; + + outf = fopen(buf, "w"); + if (outf == NULL) { + warn("%s", buf); + return; + } + printf("\"%s\" ", buf); + time(&t); /* get current time */ + + /* Header */ + fprintf(outf, "NetBSD monop format v%d\n", CUR_FORMAT_VERSION); + fprintf(outf, "time %s", ctime(&t)); /* ctime includes a \n */ + fprintf(outf, "numplayers %d\n", num_play); + fprintf(outf, "currentplayer %d\n", player); + fprintf(outf, "doubles %d\n", num_doub); + + /* Players */ + for (i = 0; i < num_play; i++) { + fprintf(outf, "player %d {\n", i); + fprintf(outf, " name %s\n", name_list[i]); + fprintf(outf, " money %d\n", play[i].money); + fprintf(outf, " loc %d\n", play[i].loc); + fprintf(outf, " num_gojf %d\n", play[i].num_gojf); + fprintf(outf, " in_jail %d\n", play[i].in_jail); + fprintf(outf, "}\n"); + } + + /* Decks */ + for (i = 0; i < 2; i++) { + fprintf(outf, "deck %d {\n", i); + fprintf(outf, " numcards %d\n", deck[i].num_cards); + fprintf(outf, " topcard %d\n", deck[i].top_card); + fprintf(outf, " gojf_used %d\n", deck[i].gojf_used); + fprintf(outf, " cards"); + for (j = 0; j < deck[i].num_cards; j++) + fprintf(outf, " %d", deck[i].cards[j]); + fprintf(outf, "\n"); + fprintf(outf, "}\n"); + } + + /* Board */ + for (i = 0; i < N_SQRS; i++) { + fprintf(outf, "square %d {\n", i); + fprintf(outf, "owner %d\n", board[i].owner); + if (board[i].owner < 0) { + /* nothing */ + } else if (board[i].type == PRPTY) { + fprintf(outf, "morg %d\n", board[i].desc->morg); + fprintf(outf, "houses %d\n", board[i].desc->houses); + } else if (board[i].type == RR || board[i].type == UTIL) { + fprintf(outf, "morg %d\n", board[i].desc->morg); + } + fprintf(outf, "}\n"); + } + if (ferror(outf) || fflush(outf)) + warnx("write error"); + fclose(outf); + + strcpy(buf, ctime(&t)); + for (sp = buf; *sp != '\n'; sp++) + continue; + *sp = '\0'; + printf("[%s]\n", buf); +} + +/* + * This routine restores an old game from a file + */ +void +restore(void) +{ + char *sp; + + for (;;) { + printf("Which file do you wish to restore from? "); + fgets(buf, sizeof(buf), stdin); + if (feof(stdin)) + return; + sp = strchr(buf, '\n'); + if (sp) + *sp = '\0'; + if (rest_f(buf) == 0) + break; + } +} + +/* + * This does the actual restoring. It returns zero on success, + * and -1 on failure. + */ +int +rest_f(const char *file) +{ + char *sp; + FILE *inf; + char xbuf[80]; + STAT sbuf; + char readbuf[512]; + int ret = 0; + + inf = fopen(file, "r"); + if (inf == NULL) { + warn("%s", file); + return -1; + } + printf("\"%s\" ", file); + if (fstat(fileno(inf), &sbuf) < 0) { + err(1, "%s: fstat", file); + } + + /* Clear the game state to prevent brokenness on misordered files. */ + reset_game(); + + /* Reset the parser */ + restore_reset(); + + /* Note: can't use buf[], file might point at it. (Lame...) */ + while (fgets(readbuf, sizeof(readbuf), inf)) { + /* + * The input buffer is long enough to handle anything + * that's supposed to be in the output buffer, so if + * we get a partial line, complain. + */ + sp = strchr(readbuf, '\n'); + if (sp == NULL) { + printf("file is corrupt: long lines.\n"); + ret = -1; + break; + } + *sp = '\0'; + + if (restore_parseline(readbuf)) { + ret = -1; + break; + } + } + + if (ferror(inf)) + warnx("%s: read error", file); + fclose(inf); + + if (ret < 0) + return -1; + + name_list[num_play] = "done"; + + if (play == NULL || cur_p == NULL || num_play < 2) { + printf("save file is incomplete.\n"); + return -1; + } + + /* + * We could at this point crosscheck the following: + * - there are only two GOJF cards floating around + * - total number of houses and hotels does not exceed maximums + * - no props are both built and mortgaged + * but for now we don't. + */ + + strcpy(xbuf, ctime(&sbuf.st_mtime)); + for (sp = xbuf; *sp != '\n'; sp++) + continue; + *sp = '\0'; + printf("[%s]\n", xbuf); + return 0; +} + +/* + * State of the restore parser + */ +static int restore_version; +static enum { + RI_NONE, + RI_PLAYER, + RI_DECK, + RI_SQUARE +} restore_item; +static int restore_itemnum; + +/* + * Reset the restore parser + */ +static void +restore_reset(void) +{ + restore_version = -1; + restore_item = RI_NONE; + restore_itemnum = -1; +} + +/* + * Handle one line of the save file + */ +static int +restore_parseline(char *txt) +{ + char *attribute; + char *s; + + if (restore_version < 0) { + /* Haven't seen the header yet. Demand it right away. */ + if (!strncmp(txt, "NetBSD monop format v", 21)) { + return getnum("format version", txt+21, + MIN_FORMAT_VERSION, + MAX_FORMAT_VERSION, + &restore_version); + } + printf("file is not a monop save file.\n"); + return -1; + } + + /* Check for lines that are right braces. */ + if (!strcmp(txt, "}")) { + if (restore_item == RI_NONE) { + printf("mismatched close brace.\n"); + return -1; + } + restore_item = RI_NONE; + restore_itemnum = -1; + return 0; + } + + /* Any other line must begin with a word, which is the attribute. */ + s = txt; + while (*s==' ') + s++; + attribute = s; + s = strchr(attribute, ' '); + if (s == NULL) { + printf("file is corrupt: attribute %s lacks value.\n", + attribute); + return -1; + } + *(s++) = '\0'; + while (*s==' ') + s++; + /* keep the remaining text for further handling */ + txt = s; + + switch (restore_item) { + case RI_NONE: + /* toplevel attributes */ + return restore_toplevel_attr(attribute, txt); + + case RI_PLAYER: + /* player attributes */ + return restore_player_attr(attribute, txt); + + case RI_DECK: + /* deck attributes */ + return restore_deck_attr(attribute, txt); + + case RI_SQUARE: + /* board square attributes */ + return restore_square_attr(attribute, txt); + } + /* NOTREACHED */ + printf("internal logic error\n"); + return -1; +} + +static int +restore_toplevel_attr(const char *attribute, char *txt) +{ + if (!strcmp(attribute, "time")) { + /* nothing */ + } else if (!strcmp(attribute, "numplayers")) { + if (getnum("numplayers", txt, 2, MAX_PL, &num_play) < 0) { + return -1; + } + if (play != NULL) { + printf("numplayers: multiple settings\n"); + return -1; + } + play = calloc((size_t)num_play, sizeof(play[0])); + if (play == NULL) { + err(1, "calloc"); + } + } else if (!strcmp(attribute, "currentplayer")) { + if (getnum("currentplayer", txt, 0, num_play-1, &player) < 0) { + return -1; + } + if (play == NULL) { + printf("currentplayer: before numplayers\n"); + return -1; + } + cur_p = &play[player]; + } else if (!strcmp(attribute, "doubles")) { + if (getnum("doubles", txt, 0, 2, &num_doub) < 0) { + return -1; + } + } else if (!strcmp(attribute, "player")) { + if (getnum_withbrace("player", txt, 0, num_play-1, + &restore_itemnum) < 0) { + return -1; + } + restore_item = RI_PLAYER; + } else if (!strcmp(attribute, "deck")) { + if (getnum_withbrace("deck", txt, 0, 1, + &restore_itemnum) < 0) { + return -1; + } + restore_item = RI_DECK; + } else if (!strcmp(attribute, "square")) { + if (getnum_withbrace("square", txt, 0, N_SQRS-1, + &restore_itemnum) < 0) { + return -1; + } + restore_item = RI_SQUARE; + } else { + printf("unknown attribute %s\n", attribute); + return -1; + } + return 0; +} + +static int +restore_player_attr(const char *attribute, char *txt) +{ + PLAY *pp; + int tmp; + + if (play == NULL) { + printf("player came before numplayers.\n"); + return -1; + } + pp = &play[restore_itemnum]; + + if (!strcmp(attribute, "name")) { + if (pp->name != NULL) { + printf("player has multiple names.\n"); + return -1; + } + /* XXX should really systematize the max name length */ + if (strlen(txt) > 256) { + txt[256] = 0; + } + pp->name = strdup(txt); + if (pp->name == NULL) + err(1, "strdup"); + name_list[restore_itemnum] = pp->name; + } else if (!strcmp(attribute, "money")) { + if (getnum(attribute, txt, 0, INT_MAX, &pp->money) < 0) { + return -1; + } + } else if (!strcmp(attribute, "loc")) { + /* note: not N_SQRS-1 */ + if (getnum(attribute, txt, 0, N_SQRS, &tmp) < 0) { + return -1; + } + pp->loc = tmp; + } else if (!strcmp(attribute, "num_gojf")) { + if (getnum(attribute, txt, 0, 2, &tmp) < 0) { + return -1; + } + pp->num_gojf = tmp; + } else if (!strcmp(attribute, "in_jail")) { + if (getnum(attribute, txt, 0, 3, &tmp) < 0) { + return -1; + } + pp->in_jail = tmp; + if (pp->in_jail > 0 && pp->loc != JAIL) { + printf("player escaped from jail?\n"); + return -1; + } + } else { + printf("unknown attribute %s\n", attribute); + return -1; + } + return 0; +} + +static int +restore_deck_attr(const char *attribute, char *txt) +{ + int tmp, j; + char *s; + DECK *dp; + + dp = &deck[restore_itemnum]; + + if (!strcmp(attribute, "numcards")) { + if (getnum(attribute, txt, dp->num_cards, dp->num_cards, + &tmp) < 0) { + return -1; + } + } else if (!strcmp(attribute, "topcard")) { + if (getnum(attribute, txt, 0, dp->num_cards, + &dp->top_card) < 0) { + return -1; + } + } else if (!strcmp(attribute, "gojf_used")) { + if (getnum(attribute, txt, 0, 1, &tmp) < 0) { + return -1; + } + dp->gojf_used = tmp; + } else if (!strcmp(attribute, "cards")) { + errno = 0; + s = txt; + for (j = 0; jnum_cards; j++) { + tmp = strtol(s, &s, 10); + if (tmp < 0 || tmp >= dp->num_cards) { + printf("cards: out of range value\n"); + return -1; + } + dp->cards[j] = tmp; + } + if (errno) { + printf("cards: invalid values\n"); + return -1; + } + } else { + printf("unknown attribute %s\n", attribute); + return -1; + } + return 0; +} + +static int +restore_square_attr(const char *attribute, char *txt) +{ + SQUARE *sp = &board[restore_itemnum]; + int tmp; + + if (!strcmp(attribute, "owner")) { + if (getnum(attribute, txt, -1, num_play-1, &tmp) < 0) { + return -1; + } + sp->owner = tmp; + if (tmp >= 0) + add_list(tmp, &play[tmp].own_list, restore_itemnum); + } else if (!strcmp(attribute, "morg")) { + if (sp->type != PRPTY && sp->type != RR && sp->type != UTIL) { + printf("unownable property is mortgaged.\n"); + return -1; + } + if (getnum(attribute, txt, 0, 1, &tmp) < 0) { + return -1; + } + sp->desc->morg = tmp; + } else if (!strcmp(attribute, "houses")) { + if (sp->type != PRPTY) { + printf("unbuildable property has houses.\n"); + return -1; + } + if (getnum(attribute, txt, 0, 5, &tmp) < 0) { + return -1; + } + sp->desc->houses = tmp; + } else { + printf("unknown attribute %s\n", attribute); + return -1; + } + return 0; +} + +static int +getnum(const char *what, char *txt, int min, int max, int *ret) +{ + char *s; + long l; + + errno = 0; + l = strtol(txt, &s, 10); + if (errno || strlen(s)>0) { + printf("%s: not a number.\n", what); + return -1; + } + if (l < min || l > max) { + printf("%s: out of range.\n", what); + } + *ret = l; + return 0; +} + +static int +getnum_withbrace(const char *what, char *txt, int min, int max, int *ret) +{ + char *s; + s = strchr(txt, ' '); + if (s == NULL) { + printf("%s: expected open brace\n", what); + return -1; + } + *(s++) = '\0'; + while (*s == ' ') + s++; + if (*s != '{') { + printf("%s: expected open brace\n", what); + return -1; + } + if (s[1] != 0) { + printf("%s: garbage after open brace\n", what); + return -1; + } + return getnum(what, txt, min, max, ret); +} diff --git a/games/monop/getinp.c b/games/monop/getinp.c new file mode 100644 index 000000000..3d0dc637f --- /dev/null +++ b/games/monop/getinp.c @@ -0,0 +1,119 @@ +/* $NetBSD: getinp.c,v 1.19 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)getinp.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: getinp.c,v 1.19 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include + +#include "monop.h" + +#define LINE 70 + +static char buf[257]; + +static int comp(const char *); + +int +getinp(const char *prompt, const char *const lst []) +{ + int i, n_match, match = 0; + char *sp; + + for (;;) { + printf("%s", prompt); + fgets(buf, sizeof(buf), stdin); + if (feof(stdin)) { + return 0; + } + if (buf[0] == '?' && buf[1] == '\n') { + printf("Valid inputs are: "); + for (i = 0, match = 18; lst[i]; i++) { + if ((match+=(n_match=strlen(lst[i]))) > LINE) { + printf("\n\t"); + match = n_match + 8; + } + if (*lst[i] == '\0') { + match += 8; + printf(""); + } + else + printf("%s", lst[i]); + if (lst[i+1]) + printf(", "); + else + putchar('\n'); + match += 2; + } + continue; + } + if ((sp = strchr(buf, '\n')) != NULL) + *sp = '\0'; + for (sp = buf; *sp; sp++) + *sp = tolower((unsigned char)*sp); + for (i = n_match = 0; lst[i]; i++) + if (comp(lst[i])) { + n_match++; + match = i; + } + if (n_match == 1) + return match; + else if (buf[0] != '\0') + printf("Illegal response: \"%s\". " + "Use '?' to get list of valid answers\n", buf); + } +} + +static int +comp(const char *s1) +{ + const char *sp, *tsp; + char c; + + if (buf[0] != '\0') + for (sp = buf, tsp = s1; *sp; ) { + c = tolower((unsigned char)*tsp); + tsp++; + if (c != *sp++) + return 0; + } + else if (*s1 != '\0') + return 0; + return 1; +} diff --git a/games/monop/houses.c b/games/monop/houses.c new file mode 100644 index 000000000..ce313cc3f --- /dev/null +++ b/games/monop/houses.c @@ -0,0 +1,387 @@ +/* $NetBSD: houses.c,v 1.15 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)houses.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: houses.c,v 1.15 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include "monop.h" + +static const char *names[N_MON+2]; +static char cur_prop[80]; + +static MON *monops[N_MON]; + +static void buy_h(MON *); +static void sell_h(MON *); +static void list_cur(MON *); +static int get_avail_houses(void); +static int get_avail_hotels(void); +static bool ready_for_hotels(MON *); + +/* + * These routines deal with buying and selling houses + */ +void +buy_houses(void) +{ + int num_mon; + MON *mp; + OWN *op; + bool good, got_morg; + int i,p; + +over: + num_mon = 0; + good = TRUE; + got_morg = FALSE; + for (op = cur_p->own_list; op && op->sqr->type != PRPTY; op = op->next) + continue; + while (op) + if (op->sqr->desc->monop) { + mp = op->sqr->desc->mon_desc; + names[num_mon] = (monops[num_mon]=mp)->name; + num_mon++; + got_morg = good = FALSE; + for (i = 0; i < mp->num_in; i++) { + if (op->sqr->desc->morg) + got_morg = TRUE; + if (op->sqr->desc->houses != 5) + good = TRUE; + op = op->next; + } + if (!good || got_morg) + --num_mon; + } + else + op = op->next; + if (num_mon == 0) { + if (got_morg) + printf("You can't build on mortgaged monopolies.\n"); + else if (!good) + printf("You can't build any more.\n"); + else + printf("But you don't have any monopolies!!\n"); + return; + } + if (num_mon == 1) + buy_h(monops[0]); + else { + names[num_mon++] = "done"; + names[num_mon--] = 0; + if ((p = getinp( + "Which property do you wish to buy houses for? ", + names)) == num_mon) + return; + buy_h(monops[p]); + goto over; + } +} + +static void +buy_h(MON *mnp) +{ + int i; + MON *mp; + int price; + short input[3], result[3]; + int wanted_houses, wanted_hotels; + int total_purchase; + PROP *pp; + int avail_houses, avail_hotels; + bool buying_hotels; + + mp = mnp; + price = mp->h_cost * 50; + + avail_houses = get_avail_houses(); + avail_hotels = get_avail_hotels(); + buying_hotels = ready_for_hotels(mnp); + + if (avail_houses == 0 && !buying_hotels) { + printf("Building shortage: no houses available."); + return; + } + if (avail_hotels == 0 && buying_hotels) { + printf("Building shortage: no hotels available."); + return; + } + +blew_it: + list_cur(mp); + printf("Houses will cost $%d\n", price); + printf("How many houses do you wish to buy for\n"); + for (i = 0; i < mp->num_in; i++) { + pp = mp->sq[i]->desc; +over: + if (pp->houses == 5) { + printf("%s (H):\n", mp->sq[i]->name); + input[i] = 0; + result[i] = 5; + continue; + } + (void)snprintf(cur_prop, sizeof(cur_prop), "%s (%d): ", + mp->sq[i]->name, pp->houses); + input[i] = get_int(cur_prop); + result[i] = input[i] + pp->houses; + if (result[i] > 5 || result[i] < 0) { + printf("That's too many. The most you can buy is %d\n", + 5 - pp->houses); + goto over; + } + } + if (mp->num_in == 3 && + (abs(result[0] - result[1]) > 1 || + abs(result[0] - result[2]) > 1 || + abs(result[1] - result[2]) > 1)) { +err: printf("That makes the spread too wide. Try again\n"); + goto blew_it; + } + else if (mp->num_in == 2 && abs(result[0] - result[1]) > 1) + goto err; + + wanted_houses = 0; + wanted_hotels = 0; + total_purchase = 0; + + for (i = 0; i < mp->num_in; i++) { + wanted_houses += input[i]; + total_purchase += input[i]; + if (result[i] == 5 && input[i] > 0) { + wanted_hotels++; + wanted_houses--; + } + } + if (wanted_houses > avail_houses) { + printf("You have asked for %d %s but only %d are available. " + "Try again\n", + wanted_houses, wanted_houses == 1 ? "house" : "houses", + avail_houses); + goto blew_it; + } else if (wanted_hotels > avail_hotels) { + printf("You have asked for %d %s but only %d are available. " + "Try again\n", + wanted_hotels, wanted_hotels == 1 ? "hotel" : "hotels", + avail_hotels); + goto blew_it; + } + + if (total_purchase) { + printf("You asked for %d %s and %d %s for $%d\n", + wanted_houses, wanted_houses == 1 ? "house" : "houses", + wanted_hotels, wanted_hotels == 1 ? "hotel" : "hotels", + total_purchase * price); + if (getyn("Is that ok? ") == 0) { + cur_p->money -= total_purchase * price; + for (i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->houses = result[i]; + } + } +} + +/* + * This routine sells houses. + */ +void +sell_houses(void) +{ + int num_mon; + MON *mp; + OWN *op; + bool good; + int p; + +over: + num_mon = 0; + good = TRUE; + for (op = cur_p->own_list; op;) + if (op->sqr->type == PRPTY && op->sqr->desc->monop) { + mp = op->sqr->desc->mon_desc; + names[num_mon] = (monops[num_mon]=mp)->name; + num_mon++; + good = 0; + do + if (!good && op->sqr->desc->houses != 0) + good = TRUE; + while (op->next && op->sqr->desc->mon_desc == mp + && (op = op->next)); + if (!good) + --num_mon; + } else + op = op->next; + if (num_mon == 0) { + printf("You don't have any houses to sell!!\n"); + return; + } + if (num_mon == 1) + sell_h(monops[0]); + else { + names[num_mon++] = "done"; + names[num_mon--] = 0; + if ((p = getinp( + "Which property do you wish to sell houses from? ", + names)) == num_mon) + return; + sell_h(monops[p]); + notify(); + goto over; + } +} + +static void +sell_h(MON *mnp) +{ + int i; + MON *mp; + int price; + short input[3],temp[3]; + int tot; + PROP *pp; + + mp = mnp; + price = mp->h_cost * 25; +blew_it: + printf("Houses will get you $%d apiece\n", price); + list_cur(mp); + printf("How many houses do you wish to sell from\n"); + for (i = 0; i < mp->num_in; i++) { + pp = mp->sq[i]->desc; +over: + if (pp->houses == 0) { + printf("%s (0):\n", mp->sq[i]->name); + input[i] = temp[i] = 0; + continue; + } + if (pp->houses < 5) + (void)snprintf(cur_prop, sizeof(cur_prop), "%s (%d): ", + mp->sq[i]->name,pp->houses); + else + (void)snprintf(cur_prop, sizeof(cur_prop), "%s (H): ", + mp->sq[i]->name); + input[i] = get_int(cur_prop); + temp[i] = pp->houses - input[i]; + if (temp[i] < 0) { + printf( + "That's too many. The most you can sell is %d\n", + pp->houses); + goto over; + } + } + if (mp->num_in == 3 && (abs(temp[0] - temp[1]) > 1 || + abs(temp[0] - temp[2]) > 1 || abs(temp[1] - temp[2]) > 1)) { +err: printf("That makes the spread too wide. Try again\n"); + goto blew_it; + } + else if (mp->num_in == 2 && abs(temp[0] - temp[1]) > 1) + goto err; + for (tot = i = 0; i < mp->num_in; i++) + tot += input[i]; + if (tot) { + printf("You asked to sell %d house%s for $%d\n", tot, + tot == 1 ? "" : "s", tot * price); + if (getyn("Is that ok? ") == 0) { + cur_p->money += tot * price; + for (tot = i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->houses = temp[i]; + } + } +} + +static void +list_cur(MON *mp) +{ + int i; + SQUARE *sqp; + + for (i = 0; i < mp->num_in; i++) { + sqp = mp->sq[i]; + if (sqp->desc->houses == 5) + printf("%s (H) ", sqp->name); + else + printf("%s (%d) ", sqp->name, sqp->desc->houses); + } + putchar('\n'); +} + +static int +get_avail_houses(void) +{ + int i, c; + SQUARE *sqp; + + c = 0; + for (i = 0; i < N_SQRS; i++) { + sqp = &board[i]; + if (sqp->type == PRPTY && sqp->owner >= 0 && sqp->desc->monop) { + if (sqp->desc->houses < 5 && sqp->desc->houses > 0) + c += sqp->desc->houses; + } + } + return(N_HOUSE - c); +} + +static int +get_avail_hotels(void) +{ + int i, c; + SQUARE *sqp; + + c = 0; + for (i = 0; i < N_SQRS; i++) { + sqp = &board[i]; + if (sqp->type == PRPTY && sqp->owner >= 0 && sqp->desc->monop) { + if (sqp->desc->houses == 5) + c++; + } + } + return(N_HOTEL - c); +} + +/* + * If we can put a hotel on, we can't put any houses on, and if we can + * put houses on, then we can't put a hotel on yet. + */ +static bool +ready_for_hotels(MON *mp) +{ + int i; + + for (i = 0; i < mp->num_in; i++) { + if (mp->sq[i]->desc->houses < 4) + return(FALSE); + } + return(TRUE); +} diff --git a/games/monop/jail.c b/games/monop/jail.c new file mode 100644 index 000000000..62b9ea0b3 --- /dev/null +++ b/games/monop/jail.c @@ -0,0 +1,123 @@ +/* $NetBSD: jail.c,v 1.10 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)jail.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: jail.c,v 1.10 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include "monop.h" + +/* + * This routine uses a get-out-of-jail-free card to get the + * player out of jail. + */ +void +card(void) +{ + if (cur_p->loc != JAIL) { + printf("But you're not IN Jail\n"); + return; + } + if (cur_p->num_gojf == 0) { + printf("But you don't HAVE a get out of jail free card\n"); + return; + } + ret_card(cur_p); + cur_p->loc = 10; /* just visiting */ + cur_p->in_jail = 0; +} + +/* + * This routine deals with paying your way out of jail. + */ +void +pay(void) +{ + if (cur_p->loc != JAIL) { + printf("But you're not IN Jail\n"); + return; + } + cur_p->loc = 10; + cur_p->money -= 50; + cur_p->in_jail = 0; + printf("That cost you $50\n"); +} + +/* + * This routine deals with a move in jail + */ +int +move_jail(int r1, int r2) +{ + if (r1 != r2) { + printf("Sorry, that doesn't get you out\n"); + if (++(cur_p->in_jail) == 3) { + printf("It's your third turn and you didn't roll " + "doubles. You have to pay $50\n"); + cur_p->money -= 50; +moveit: + cur_p->loc = 10; + cur_p->in_jail = 0; + move(r1+r2); + r1 = r2 - 1; /* kludge: stop new roll w/doub */ + return TRUE; + } + return FALSE; + } else { + printf("Double roll gets you out.\n"); + goto moveit; + } +} + +void +printturn(void) +{ + if (cur_p->loc != JAIL) + return; + printf("(This is your "); + switch (cur_p->in_jail) { + case 0: + printf("1st"); + break; + case 1: + printf("2nd"); + break; + case 2: + printf("3rd (and final)"); + break; + } + printf(" turn in JAIL)\n"); +} diff --git a/games/monop/misc.c b/games/monop/misc.c new file mode 100644 index 000000000..aaa9eb3d5 --- /dev/null +++ b/games/monop/misc.c @@ -0,0 +1,299 @@ +/* $NetBSD: misc.c,v 1.23 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: misc.c,v 1.23 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include +#include + +#include "monop.h" + +static void is_monop(MON *, int); + +/* + * This routine executes a truncated set of commands until a + * "yes or "no" answer is gotten. + */ +int +getyn(const char *prompt) +{ + int com; + + for (;;) + if ((com=getinp(prompt, yncoms)) < 2) + return com; + else + (*func[com-2])(); +} + +/* + * This routine tells the player if he's out of money. + */ +void +notify(void) +{ + if (cur_p->money < 0) + printf("That leaves you $%d in debt\n", -cur_p->money); + else if (cur_p->money == 0) + printf("that leaves you broke\n"); + else if (fixing && !told_em && cur_p->money > 0) { + printf("-- You are now Solvent ---\n"); + told_em = TRUE; + } +} + +/* + * This routine switches to the next player + */ +void +next_play(void) +{ + player = (player + 1) % num_play; + cur_p = &play[player]; + num_doub = 0; +} + +/* + * This routine gets an integer from the keyboard after the + * given prompt. + */ +int +get_int(const char *prompt) +{ + long num; + char *sp; + char buf[257]; + + for (;;) { + printf("%s", prompt); + fgets(buf, sizeof(buf), stdin); + /* if stdin is closed we cant really play anymore */ + if (feof(stdin)) + quit(); + sp = strchr(buf, '\n'); + if (sp) + *sp = '\0'; + errno = 0; + num = strtol(buf, &sp, 10); + if (errno || strlen(sp) > 0 || num < 0 || num >= INT_MAX) { + printf("I can't understand that\n"); + continue; + } + return num; + } +} + +/* + * This routine sets the monopoly flag from the list given. + */ +void +set_ownlist(int pl) +{ + int num; /* general counter */ + MON *orig; /* remember starting monop ptr */ + OWN *op; /* current owned prop */ + OWN *orig_op; /* original prop before loop */ + + op = play[pl].own_list; +#ifdef DEBUG + printf("op [%p] = play[pl [%d] ].own_list;\n", op, pl); +#endif + while (op) { +#ifdef DEBUG + printf("op->sqr->type = %d\n", op->sqr->type); +#endif + switch (op->sqr->type) { + case UTIL: +#ifdef DEBUG + printf(" case UTIL:\n"); +#endif + for (num = 0; op && op->sqr->type == UTIL; + op = op->next) + num++; + play[pl].num_util = num; +#ifdef DEBUG + printf("play[pl].num_util = num [%d];\n", num); +#endif + break; + case RR: +#ifdef DEBUG + printf(" case RR:\n"); +#endif + for (num = 0; op && op->sqr->type == RR; + op = op->next) { +#ifdef DEBUG + printf("iter: %d\n", num); + printf("op = %p, op->sqr = %p, " + "op->sqr->type = %d\n", op, op->sqr, + op->sqr->type); +#endif + num++; + } + play[pl].num_rr = num; +#ifdef DEBUG + printf("play[pl].num_rr = num [%d];\n", num); +#endif + break; + case PRPTY: +#ifdef DEBUG + printf(" case PRPTY:\n"); +#endif + orig = op->sqr->desc->mon_desc; + orig_op = op; + num = 0; + while (op && op->sqr->desc->mon_desc == orig) { +#ifdef DEBUG + printf("iter: %d\n", num); +#endif + num++; +#ifdef DEBUG + printf("op = op->next "); +#endif + op = op->next; +#ifdef DEBUG + printf("[%p];\n", op); +#endif + } +#ifdef DEBUG + printf("num = %d\n", num); +#endif + if (orig == NULL) { + printf("panic: bad monopoly descriptor: " + "orig = %p\n", orig); + printf("player # %d\n", pl+1); + printhold(pl); + printf("orig_op = %p\n", orig_op); + if (orig_op) { + printf("orig_op->sqr->type = %d (PRPTY)\n", + orig_op->sqr->type); + printf("orig_op->next = %p\n", + orig_op->next); + printf("orig_op->sqr->desc = %p\n", + orig_op->sqr->desc); + } + printf("op = %p\n", op); + if (op) { + printf("op->sqr->type = %d (PRPTY)\n", + op->sqr->type); + printf("op->next = %p\n", op->next); + printf("op->sqr->desc = %p\n", + op->sqr->desc); + } + printf("num = %d\n", num); + exit(1); + } +#ifdef DEBUG + printf("orig->num_in = %d\n", orig->num_in); +#endif + if (num == orig->num_in) + is_monop(orig, pl); + else + is_not_monop(orig); + break; + } + } +} + +/* + * This routine sets things up as if it is a new monopoly + */ +static void +is_monop(MON *mp, int pl) +{ + int i; + + mp->owner = pl; + mp->num_own = mp->num_in; + for (i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->monop = TRUE; + mp->name = mp->mon_n; +} + +/* + * This routine sets things up as if it is no longer a monopoly + */ +void +is_not_monop(MON *mp) +{ + int i; + + mp->owner = -1; + for (i = 0; i < mp->num_in; i++) + mp->sq[i]->desc->monop = FALSE; + mp->name = mp->not_m; +} + +/* + * This routine gives a list of the current player's routine + */ +void +list(void) +{ + printhold(player); +} + +/* + * This routine gives a list of a given players holdings + */ +void +list_all(void) +{ + int pl; + + while ((pl = getinp("Whose holdings do you want to see? ", name_list)) + < num_play) + printhold(pl); +} + +/* + * This routine gives the players a chance before it exits. + */ +void +quit(void) +{ + putchar('\n'); + + /* We dont even have a chance to input y/n if stdin is closed */ + if (feof(stdin)) + exit(0); + + if (getyn("Do you all really want to quit? ") == 0) + exit(0); +} diff --git a/games/monop/monop.6 b/games/monop/monop.6 new file mode 100644 index 000000000..ee8bf2aeb --- /dev/null +++ b/games/monop/monop.6 @@ -0,0 +1,178 @@ +.\" $NetBSD: monop.6,v 1.19 2008/02/24 03:50:07 dholland Exp $ +.\" +.\" Copyright (c) 1980 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)monop.6 6.5 (Berkeley) 3/25/93 +.\" +.Dd February 23, 2008 +.Dt MONOP 6 +.Os +.Sh NAME +.Nm monop +.Nd Monopoly game +.Sh SYNOPSIS +.Nm +.Op Ar file +.Sh DESCRIPTION +.Nm +is reminiscent of the Parker Brother's game Monopoly, and +monitors a game between 2 to 9 users. +It is assumed that the rules of Monopoly are known. +The game follows the standard rules, with the exception that, +if a property goes up for auction and there are only two solvent players, +no auction is held and the property remains unowned. +.Pp +The game, in effect, lends the player money, +so it is possible to buy something which you cannot afford. +However, as soon as a person goes into debt, he must +.Dq fix the problem , +i.e., make himself solvent, before play can continue. +If this is not possible, the player's property reverts to his debtee, +either a player or the bank. +A player can resign at any time to any person or the bank, +which puts the property back on the board, unowned. +.Pp +Any time that the response to a question is a +.Em string , +e.g., a name, place or person, you can type +.Sq Ic \&? +to get a list of valid answers. +It is not possible to input a negative number, nor is it ever necessary. +.Pp +.Em A Summary of Commands : +.Bl -tag -width item +.It Ic quit +quit game: This allows you to quit the game. +It asks you if you're sure. +.It Ic print +print board: This prints out the current board. +The columns have the following meanings (column headings are the same for the +.Ic where , +.Ic own holdings , +and +.Ic holdings +commands): +.Pp +.Bl -tag -width indent -compact +.It Name +The first ten characters of the name of the square. +.It Own +The +.Em number +of the owner of the property. +.It Price +The cost of the property (if any). +.It Mg +This field has a +.Sq * +in it if the property is mortgaged. +.It \&# +If the property is a Utility or Railroad, this is the number +of such owned by the owner. +If the property is land, this is the number of houses on it. +.It Rent +Current rent on the property. +If it is not owned, there is no rent. +.El +.It Ic where +where players are: Tells you where all the players are. +A +.Sq * +indicates the current player. +.It Ic own holdings +List your own holdings, +i.e., money, get-out-of-jail-free cards, and property. +.It Ic holdings +holdings list: Look at anyone's holdings. +It will ask you whose holdings you wish to look at. +When you are finished, type +.Sq Ic done . +.It Ic mortgage +mortgage property: +Sets up a list of mortgageable property, and asks which you wish to mortgage. +.It Ic unmortgage +unmortgage property: +Unmortgage mortgaged property. +.It Ic buy +buy houses: +Sets up a list of monopolies on which you can buy houses. +If there is more than one, it asks you which you want to buy for. +It then asks you how many for each piece of property, +giving the current amount in parentheses after the property name. +If you build in an unbalanced manner +(a disparity of more than one house within the same monopoly), +it asks you to re-input things. +.It Ic sell +sell houses: +Sets up a list of monopolies from which you can sell houses. +It operates in an analogous manner to +.Ic buy . +.It Ic card +card for jail: +Use a get-out-of-jail-free card to get out of jail. +If you're not in jail, or you don't have one, it tells you so. +.It Ic pay +pay for jail: +Pay $50 to get out of jail, from whence you are put on Just Visiting. +Difficult to do if you're not there. +.It Ic trade +This allows you to trade with another player. +It asks you whom you wish to trade with, +and then asks you what each wishes to give up. +You can get a summary at the end, and, in all cases, +it asks for confirmation of the trade before doing it. +.It Ic resign +Resign to another player or the bank. +If you resign to the bank, all property reverts to its virgin state, +and get-out-of-jail-free cards revert to the deck. +.It Ic save +save game: +Save the current game in a file for later play. +You can continue play after saving, +either by adding the file in which you saved the game after the +.Nm +command, or by using the +.Ic restore +command (see below). +It will ask you which file you wish to save it in, +and, if the file exists, confirm that you wish to overwrite it. +.It Ic restore +restore game: +Read in a previously saved game from a file. +It leaves the file intact. +.It Ic roll +Roll the dice and move forward to your new location. +If you simply hit the +.Aq RETURN +key instead of a command, it is the same as typing +.Ic roll . +.El +.Sh AUTHORS +.An Ken Arnold +.Sh BUGS +No command can be given an argument instead of a response to a query. diff --git a/games/monop/monop.c b/games/monop/monop.c new file mode 100644 index 000000000..7da1c301b --- /dev/null +++ b/games/monop/monop.c @@ -0,0 +1,360 @@ +/* $NetBSD: monop.c,v 1.27 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1980, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)monop.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: monop.c,v 1.27 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include "deck.h" +#include "monop.h" + +int main(int, char *[]); +static void getplayers(void); +static void init_players(void); +static void init_monops(void); +static void do_quit(int); + + +bool fixing, /* set if fixing up debt */ + trading, /* set if in process of trading */ + told_em, /* set if told user he's out of debt */ + spec; /* set if moving by card to RR or UTIL */ + +const char *name_list[MAX_PL+2]; /* list of players' names */ +static const char *const comlist[] = { /* list of normal commands */ + "quit", /* 0 */ "print", /* 1 */ + "where", /* 2 */ "own holdings", /* 3 */ + "holdings", /* 4 */ "mortgage", /* 5 */ + "unmortgage", /* 6 */ "buy houses", /* 7 */ + "sell houses", /* 8 */ "card", /* 9 */ + "pay", /* 10 */ "trade", /* 11 */ + "resign", /* 12 */ "save", /* 13 */ + "restore", /* 14 */ "roll", /* 15 */ + "", /* 16 */ + 0 +}; +const char *const yncoms[] = { /* list of commands for yes/no answers */ + "yes", /* 0 */ "no", /* 1 */ + "quit", /* 2 */ "print", /* 3 */ + "where", /* 4 */ "own holdings", /* 5 */ + "holdings", /* 6 */ + 0 +}; +const char *const lucky_mes[] = { /* "got lucky" messages */ + "You lucky stiff", "You got lucky", + "What a lucky person!", "You must have a 4-leaf clover", + "My, my! Aren't we lucky!", "Luck smiles upon you", + "You got lucky this time", "Lucky person!", + "Your karma must certainly be together", + "How beautifully Cosmic", "Wow, you must be really with it" + /* "I want your autograph", -- Save for later */ +}; + +int player, /* current player number */ + num_play, /* current number of players */ + num_doub, /* # of doubles current player rolled */ + /* # of "got lucky" messages */ + num_luck = sizeof lucky_mes / sizeof (char *); + +/* list of command functions */ +void (*const func[])(void) = { /* array of function calls for commands */ + quit, /* quit game |* 0 *| */ + printboard, /* print board |* 1 *| */ + where, /* where players are |* 2 *| */ + list, /* own holdings |* 3 *| */ + list_all, /* holdings list |* 4 *| */ + mortgage, /* mortgage property |* 5 *| */ + unmortgage, /* unmortgage property |* 6 *| */ + buy_houses, /* buy houses |* 7 *| */ + sell_houses, /* sell houses |* 8 *| */ + card, /* card for jail |* 9 *| */ + pay, /* pay for jail |* 10 *| */ + trade, /* trade |* 11 *| */ + resign, /* resign |* 12 *| */ + save, /* save game |* 13 *| */ + restore, /* restore game |* 14 *| */ + do_move, /* roll |* 15 *| */ + do_move /* "" |* 16 *| */ + }; + +DECK deck[2]; /* Chance and Community Chest */ + +PLAY *play, /* player structure array ("calloc"ed) */ + *cur_p; /* pointer to current player's struct */ + +static RR_S rr[N_RR]; /* railroad descriptions */ + +static UTIL_S util[2]; /* utility descriptions */ + +#define MONINIT(num_in, h_cost, not_m, mon_n, sq1,sq2,sq3) \ + {0, -1, num_in, 0, h_cost, not_m, mon_n, {sq1,sq2,sq3}, {0,0,0}} +/* name owner num_own sq */ + +static MON mon[N_MON] = { /* monopoly descriptions */ +/* num_in h_cost not_m mon_n sqnums */ +MONINIT(2, 1, "Purple", "PURPLE", 1,3, 0), +MONINIT(3, 1, "Lt. Blue", "LT. BLUE", 6,8,9), +MONINIT(3, 2, "Violet", "VIOLET", 11,13,14), +MONINIT(3, 2, "Orange", "ORANGE", 16,18,19), +MONINIT(3, 3, "Red", "RED", 21,23,24), +MONINIT(3, 3, "Yellow", "YELLOW", 26,27,29), +MONINIT(3, 4, "Green", "GREEN", 31,32,34), +MONINIT(2, 4, "Dk. Blue", "DK. BLUE", 37,39, 0), +}; +#undef MONINIT + +PROP prop[N_PROP] = { /* typical properties */ +/* morg monop square houses mon_desc rent */ +{0, 0, 1, 0, &mon[0], { 2, 10, 30, 90, 160, 250} }, +{0, 0, 3, 0, &mon[0], { 4, 20, 60, 180, 320, 450} }, +{0, 0, 6, 0, &mon[1], { 6, 30, 90, 270, 400, 550} }, +{0, 0, 7, 0, &mon[1], { 6, 30, 90, 270, 400, 550} }, +{0, 0, 9, 0, &mon[1], { 8, 40,100, 300, 450, 600} }, +{0, 0, 11, 0, &mon[2], {10, 50,150, 450, 625, 750} }, +{0, 0, 13, 0, &mon[2], {10, 50,150, 450, 625, 750} }, +{0, 0, 14, 0, &mon[2], {12, 60,180, 500, 700, 900} }, +{0, 0, 16, 0, &mon[3], {14, 70,200, 550, 750, 950} }, +{0, 0, 17, 0, &mon[3], {14, 70,200, 550, 750, 950} }, +{0, 0, 19, 0, &mon[3], {16, 80,220, 600, 800,1000} }, +{0, 0, 21, 0, &mon[4], {18, 90,250, 700, 875,1050} }, +{0, 0, 23, 0, &mon[4], {18, 90,250, 700, 875,1050} }, +{0, 0, 24, 0, &mon[4], {20,100,300, 750, 925,1100} }, +{0, 0, 26, 0, &mon[5], {22,110,330, 800, 975,1150} }, +{0, 0, 27, 0, &mon[5], {22,110,330, 800, 975,1150} }, +{0, 0, 29, 0, &mon[5], {24,120,360, 850,1025,1200} }, +{0, 0, 31, 0, &mon[6], {26,130,390, 900,1100,1275} }, +{0, 0, 32, 0, &mon[6], {26,130,390, 900,1100,1275} }, +{0, 0, 34, 0, &mon[6], {28,150,450,1000,1200,1400} }, +{0, 0, 37, 0, &mon[7], {35,175,500,1100,1300,1500} }, +{0, 0, 39, 0, &mon[7], {50,200,600,1400,1700,2000} } +}; + +SQUARE board[N_SQRS+1] = { /* board itself (+1 for Jail) */ +/* name (COLOR) owner type desc cost */ + +{"=== GO ===", -1, SAFE, NULL, 0 }, +{"Mediterranean Ave. (P)", -1, PRPTY, &prop[0], 60 }, +{"Community Chest i", -1, CC, NULL, 0 }, +{"Baltic Ave. (P)", -1, PRPTY, &prop[1], 60 }, +{"Income Tax", -1, INC_TAX, NULL, 0 }, +{"Reading RR", -1, RR, &rr[0], 200 }, +{"Oriental Ave. (L)", -1, PRPTY, &prop[2], 100 }, +{"Chance i", -1, CHANCE, NULL, 0 }, +{"Vermont Ave. (L)", -1, PRPTY, &prop[3], 100 }, +{"Connecticut Ave. (L)", -1, PRPTY, &prop[4], 120 }, +{"Just Visiting", -1, SAFE, NULL, 0 }, +{"St. Charles Pl. (V)", -1, PRPTY, &prop[5], 140 }, +{"Electric Co.", -1, UTIL, &util[0], 150 }, +{"States Ave. (V)", -1, PRPTY, &prop[6], 140 }, +{"Virginia Ave. (V)", -1, PRPTY, &prop[7], 160 }, +{"Pennsylvania RR", -1, RR, &rr[1], 200 }, +{"St. James Pl. (O)", -1, PRPTY, &prop[8], 180 }, +{"Community Chest ii", -1, CC, NULL, 0 }, +{"Tennessee Ave. (O)", -1, PRPTY, &prop[9], 180 }, +{"New York Ave. (O)", -1, PRPTY, &prop[10], 200 }, +{"Free Parking", -1, SAFE, NULL, 0 }, +{"Kentucky Ave. (R)", -1, PRPTY, &prop[11], 220 }, +{"Chance ii", -1, CHANCE, NULL, 0 }, +{"Indiana Ave. (R)", -1, PRPTY, &prop[12], 220 }, +{"Illinois Ave. (R)", -1, PRPTY, &prop[13], 240 }, +{"B&O RR", -1, RR, &rr[2], 200 }, +{"Atlantic Ave. (Y)", -1, PRPTY, &prop[14], 260 }, +{"Ventnor Ave. (Y)", -1, PRPTY, &prop[15], 260 }, +{"Water Works", -1, UTIL, &util[1], 150 }, +{"Marvin Gardens (Y)", -1, PRPTY, &prop[16], 280 }, +{"GO TO JAIL", -1, GOTO_J, NULL, 0 }, +{"Pacific Ave. (G)", -1, PRPTY, &prop[17], 300 }, +{"N. Carolina Ave. (G)", -1, PRPTY, &prop[18], 300 }, +{"Community Chest iii", -1, CC, NULL, 0 }, +{"Pennsylvania Ave. (G)", -1, PRPTY, &prop[19], 320 }, +{"Short Line RR", -1, RR, &rr[3], 200 }, +{"Chance iii", -1, CHANCE, NULL, 0 }, +{"Park Place (D)", -1, PRPTY, &prop[20], 350 }, +{"Luxury Tax", -1, LUX_TAX, NULL, 0 }, +{"Boardwalk (D)", -1, PRPTY, &prop[21], 400 }, +{"JAIL", -1, IN_JAIL, NULL, 0 } +}; + + +/* + * This program implements a monopoly game + */ +int +main(int ac, char *av[]) +{ + /* Revoke setgid privileges */ + setgid(getgid()); + + srandom((unsigned long)time(NULL)); + num_luck = sizeof lucky_mes / sizeof (char *); + init_decks(); + init_monops(); + if (ac > 1) { + if (rest_f(av[1]) < 0) + restore(); + } + else { + getplayers(); + init_players(); + } + signal(SIGINT, do_quit); + for (;;) { + printf("\n%s (%d) (cash $%d) on %s\n", cur_p->name, player + 1, + cur_p->money, board[cur_p->loc].name); + printturn(); + force_morg(); + execute(getinp("-- Command: ", comlist)); + } +} + +/*ARGSUSED*/ +static void +do_quit(int n __unused) +{ + quit(); +} + +/* + * This routine gets the names of the players + */ +static void +getplayers(void) +{ + int i, j; + char buf[257]; + +blew_it: + for (;;) { + if ((num_play = get_int("How many players? ")) <= 1 || + num_play > MAX_PL) + printf("Sorry. Number must range from 2 to %d\n", + MAX_PL); + else + break; + } + cur_p = play = calloc((size_t)num_play, sizeof (PLAY)); + if (play == NULL) + err(1, NULL); + for (i = 0; i < num_play; i++) { + do { + printf("Player %d's name: ", i + 1); + fgets(buf, sizeof(buf), stdin); + if (feof(stdin)) { + quit(); + } + buf[strcspn(buf, "\n")] = '\0'; + } while (strlen(buf) == 0); + name_list[i] = play[i].name = strdup(buf); + if (name_list[i] == NULL) + err(1, NULL); + play[i].money = 1500; + } + name_list[i++] = "done"; + name_list[i] = 0; + for (i = 0; i < num_play; i++) + for (j = i + 1; j <= num_play; j++) + if (strcasecmp(name_list[i], name_list[j]) == 0) { + if (j != num_play) + printf("Hey!!! Some of those are " + "IDENTICAL!! Let's try that " + "again...\n"); + else + printf("\"done\" is a reserved word. " + "Please try again\n"); + for (i = 0; i < num_play; i++) + free(play[i].name); + free(play); + goto blew_it; + } +} + +/* + * This routine figures out who goes first + */ +static void +init_players(void) +{ + int i, rl, cur_max; + bool over = 0; + int max_pl = 0; + +again: + putchar('\n'); + for (cur_max = i = 0; i < num_play; i++) { + printf("%s (%d) rolls %d\n", play[i].name, i+1, rl=roll(2, 6)); + if (rl > cur_max) { + over = FALSE; + cur_max = rl; + max_pl = i; + } + else if (rl == cur_max) + over++; + } + if (over) { + printf("%d people rolled the same thing, so we'll try again\n", + over + 1); + goto again; + } + player = max_pl; + cur_p = &play[max_pl]; + printf("%s (%d) goes first\n", cur_p->name, max_pl + 1); +} + +/* + * This routine initializes the monopoly structures. + */ +static void +init_monops(void) +{ + MON *mp; + int i; + + for (mp = mon; mp < &mon[N_MON]; mp++) { + mp->name = mp->not_m; + for (i = 0; i < mp->num_in; i++) + mp->sq[i] = &board[mp->sqnums[i]]; + } +} diff --git a/games/monop/monop.h b/games/monop/monop.h new file mode 100644 index 000000000..ecc74204d --- /dev/null +++ b/games/monop/monop.h @@ -0,0 +1,221 @@ +/* $NetBSD: monop.h,v 1.19 2009/08/12 08:10:49 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)monop.h 8.1 (Berkeley) 5/31/93 + */ + +#include +#include +#include +#include + +#define bool char + +#define TRUE (1) +#define FALSE (0) + +#define N_MON 8 /* number of monopolies */ +#define N_PROP 22 /* number of normal property squares */ +#define N_RR 4 /* number of railroads */ +#define N_UTIL 2 /* number of utilities */ +#define N_SQRS 40 /* number of squares on board */ +#define MAX_PL 9 /* maximum number of players */ +#define MAX_PRP (N_PROP+N_RR+N_UTIL) /* max # ownable property */ +#define N_HOUSE 32 /* total number of houses available */ +#define N_HOTEL 12 /* total number of hotels available */ + + /* square type numbers */ +#define PRPTY 0 /* normal property */ +#define RR 1 /* railroad */ +#define UTIL 2 /* water works - electric co */ +#define SAFE 3 /* safe spot */ +#define CC 4 /* community chest */ +#define CHANCE 5 /* chance (surprise!!!) */ +#define INC_TAX 6 /* Income tax */ +#define GOTO_J 7 /* Go To Jail! */ +#define LUX_TAX 8 /* Luxury tax */ +#define IN_JAIL 9 /* In jail */ + +#define JAIL 40 /* JAIL square number */ + +#define lucky(str) printf("%s%s\n",str,lucky_mes[roll(1,num_luck)-1]) +#define printline() printf("------------------------------\n") +#define sqnum(sqp) ((short)(sqp - board)) + +struct sqr_st { /* structure for square */ + const char *name; /* place name */ + short owner; /* owner number */ + short type; /* place type */ + struct prp_st *desc; /* description struct */ + int cost; /* cost */ +}; + +typedef struct sqr_st SQUARE; + +struct mon_st { /* monopoly description structure */ + const char *name; /* monop. name (color) */ + short owner; /* owner of monopoly */ + short num_in; /* # in monopoly */ + short num_own; /* # owned (-1: not poss. monop)*/ + short h_cost; /* price of houses */ + const char *not_m; /* name if not monopoly */ + const char *mon_n; /* name if a monopoly */ + unsigned char sqnums[3]; /* Square numbers (used to init)*/ + SQUARE *sq[3]; /* list of squares in monop */ +}; + +typedef struct mon_st MON; + +/* + * This struct describes a property. For railroads and utilities, only + * the "morg" member is used. + */ +struct prp_st { /* property description structure */ + bool morg; /* set if mortgaged */ + bool monop; /* set if monopoly */ + short square; /* square description */ + short houses; /* number of houses */ + MON *mon_desc; /* name of color */ + int rent[6]; /* rents */ +}; + +struct own_st { /* element in list owned things */ + SQUARE *sqr; /* pointer to square */ + struct own_st *next; /* next in list */ +}; + +typedef struct own_st OWN; + +struct plr_st { /* player description structure */ + char *name; /* owner name */ + short num_gojf; /* # of get-out-of-jail-free's */ + short num_rr; /* # of railroads owned */ + short num_util; /* # of water works/elec. co. */ + short loc; /* location on board */ + short in_jail; /* count of turns in jail */ + int money; /* amount of money */ + OWN *own_list; /* start of property list */ +}; + +typedef struct plr_st PLAY; +typedef struct prp_st PROP; +typedef struct prp_st RR_S; +typedef struct prp_st UTIL_S; + +extern bool trading, spec, fixing, told_em; + +extern const char *const yncoms[], *name_list[], *const lucky_mes[]; + +extern int num_play, player, num_doub, num_luck; + +extern void (*const func[])(void); + +/*extern MON mon[N_MON];*/ + +extern PLAY *play, *cur_p; + +extern PROP prop[N_PROP]; + +/*extern RR_S rr[N_RR];*/ + +extern SQUARE board[N_SQRS + 1]; + +/*extern UTIL_S util[2];*/ + + +/* cards.c */ +void ret_card(PLAY *); + +/* execute.c */ +void execute(int); +void do_move(void); +void move(int); +void save(void); +void restore(void); +int rest_f(const char *); + +/* getinp.c */ +int getinp(const char *, const char *const []); + +/* houses.c */ +void buy_houses(void); +void sell_houses(void); + +/* jail.c */ +void card(void); +void pay(void); +int move_jail(int, int ); +void printturn(void); + +/* misc.c */ +int getyn(const char *); +void notify(void); +void next_play(void); +int get_int(const char *); +void set_ownlist(int); +void is_not_monop(MON *); +void list(void); +void list_all(void); +void quit(void); + +/* morg.c */ +void mortgage(void); +void unmortgage(void); +void force_morg(void); + +/* print.c */ +void printboard(void); +void where(void); +void printsq(int, bool); +void printhold(int); + +/* prop.c */ +void buy(int, SQUARE *); +void add_list(int, OWN **, int); +void del_list(int, OWN **, short); +void bid(void); +int prop_worth(PLAY *); + +/* rent.c */ +void rent(SQUARE *); + +/* roll.c */ +int roll(int, int); + +/* spec.c */ +void inc_tax(void); +void goto_jail(void); +void lux_tax(void); +void cc(void); +void chance(void); + +/* trade.c */ +void trade(void); +void resign(void); diff --git a/games/monop/morg.c b/games/monop/morg.c new file mode 100644 index 000000000..74da5151d --- /dev/null +++ b/games/monop/morg.c @@ -0,0 +1,229 @@ +/* $NetBSD: morg.c,v 1.19 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)morg.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: morg.c,v 1.19 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include "monop.h" + +/* + * These routines deal with mortgaging. + */ + +static const char *names[MAX_PRP+2], + *const morg_coms[] = { + "quit", /* 0 */ + "print", /* 1 */ + "where", /* 2 */ + "own holdings", /* 3 */ + "holdings", /* 4 */ + "mortgage", /* 5 */ + "unmortgage", /* 6 */ + "buy", /* 7 */ + "sell", /* 8 */ + "card", /* 9 */ + "pay", /* 10 */ + "trade", /* 11 */ + "resign", /* 12 */ + "save game", /* 13 */ + "restore game", /* 14 */ + 0 + }; + +static short square[MAX_PRP+2]; + +static int num_good, got_houses; + + +static int set_mlist(void); +static void m(int); +static int set_umlist(void); +static void unm(int); + +/* + * This routine is the command level response the mortgage command. + * it gets the list of mortgageable property and asks which are to + * be mortgaged. + */ +void +mortgage(void) +{ + int propnum; + + for (;;) { + if (set_mlist() == 0) { + if (got_houses) + printf("You can't mortgage property with " + "houses on it.\n"); + else + printf("You don't have any un-mortgaged " + "property.\n"); + return; + } + if (num_good == 1) { + printf("Your only mortgageable property is %s\n", + names[0]); + if (getyn("Do you want to mortgage it? ") == 0) + m(square[0]); + return; + } + propnum = getinp("Which property do you want to mortgage? ", + names); + if (propnum == num_good) + return; + m(square[propnum]); + notify(); + } +} + +/* + * This routine sets up the list of mortgageable property + */ +static int +set_mlist(void) +{ + OWN *op; + + num_good = 0; + for (op = cur_p->own_list; op; op = op->next) + if (!op->sqr->desc->morg) { + if (op->sqr->type == PRPTY && op->sqr->desc->houses) + got_houses++; + else { + names[num_good] = op->sqr->name; + square[num_good++] = sqnum(op->sqr); + } + } + names[num_good++] = "done"; + names[num_good--] = 0; + return num_good; +} + +/* + * This routine actually mortgages the property. + */ +static void +m(int propnum) +{ + int price; + + price = board[propnum].cost/2; + board[propnum].desc->morg = TRUE; + printf("That got you $%d\n",price); + cur_p->money += price; +} + +/* + * This routine is the command level repsponse to the unmortgage + * command. It gets the list of mortgaged property and asks which are + * to be unmortgaged. + */ +void +unmortgage(void) +{ + int propnum; + + for (;;) { + if (set_umlist() == 0) { + printf("You don't have any mortgaged property.\n"); + return; + } + if (num_good == 1) { + printf("Your only mortgaged property is %s\n", + names[0]); + if (getyn("Do you want to unmortgage it? ") == 0) + unm(square[0]); + return; + } + propnum = getinp("Which property do you want to unmortgage? ", + names); + if (propnum == num_good) + return; + unm(square[propnum]); + } +} + +/* + * This routine sets up the list of mortgaged property + */ +static int +set_umlist(void) +{ + OWN *op; + + num_good = 0; + for (op = cur_p->own_list; op; op = op->next) + if (op->sqr->desc->morg) { + names[num_good] = op->sqr->name; + square[num_good++] = sqnum(op->sqr); + } + names[num_good++] = "done"; + names[num_good--] = 0; + return num_good; +} + +/* + * This routine actually unmortgages the property + */ +static void +unm(int propnum) +{ + int price; + + price = board[propnum].cost/2; + board[propnum].desc->morg = FALSE; + price += price/10; + printf("That cost you $%d\n",price); + cur_p->money -= price; + (void)set_umlist(); +} + +/* + * This routine forces the indebted player to fix his + * financial woes. It is fine to have $0 but not to be in debt. + */ +void +force_morg(void) +{ + told_em = fixing = TRUE; + while (cur_p->money < 0) { + told_em = FALSE; + (*func[(getinp("How are you going to fix it up? ", morg_coms))])(); + notify(); + } + fixing = FALSE; +} diff --git a/games/monop/print.c b/games/monop/print.c new file mode 100644 index 000000000..4b7b662dc --- /dev/null +++ b/games/monop/print.c @@ -0,0 +1,197 @@ +/* $NetBSD: print.c,v 1.13 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: print.c,v 1.13 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include "monop.h" + +static const char *header = "Name Own Price Mg # Rent"; + +static void printmorg(const SQUARE *); + +/* + * This routine prints out the current board + */ +void +printboard(void) +{ + int i; + + printf("%s\t%s\n", header, header); + for (i = 0; i < N_SQRS/2; i++) { + printsq(i, FALSE); + putchar('\t'); + printsq(i+N_SQRS/2, TRUE); + } +} + +/* + * This routine lists where each player is. + */ +void +where(void) +{ + int i; + + printf("%s Player\n", header); + for (i = 0; i < num_play; i++) { + printsq(play[i].loc, FALSE); + printf(" %s (%d)", play[i].name, i+1); + if (cur_p == &play[i]) + printf(" *"); + putchar('\n'); + } +} + +/* + * This routine prints out an individual square + */ +void +printsq(int sqn, bool eoln) +{ + int rnt; + PROP *pp; + SQUARE *sqp; + + sqp = &board[sqn]; + printf("%-10.10s", sqp->name); + switch (sqp->type) { + case SAFE: + case CC: + case CHANCE: + case INC_TAX: + case GOTO_J: + case LUX_TAX: + case IN_JAIL: + if (!eoln) + printf(" "); + break; + case PRPTY: + pp = sqp->desc; + if (sqp->owner < 0) { + printf(" - %-8.8s %3d", pp->mon_desc->name, sqp->cost); + if (!eoln) + printf(" "); + break; + } + printf(" %d %-8.8s %3d", sqp->owner+1, pp->mon_desc->name, + sqp->cost); + printmorg(sqp); + if (pp->monop) { + if (pp->houses < 5) + if (pp->houses > 0) + printf("%d %4d", pp->houses, + pp->rent[pp->houses]); + else + printf("0 %4d", pp->rent[0] * 2); + else + printf("H %4d", pp->rent[5]); + } else + printf(" %4d", pp->rent[0]); + break; + case UTIL: + if (sqp->owner < 0) { + printf(" - 150"); + if (!eoln) + printf(" "); + break; + } + printf(" %d 150", sqp->owner+1); + printmorg(sqp); + printf("%d", play[sqp->owner].num_util); + if (!eoln) + printf(" "); + break; + case RR: + if (sqp->owner < 0) { + printf(" - Railroad 200"); + if (!eoln) + printf(" "); + break; + } + printf(" %d Railroad 200", sqp->owner+1); + printmorg(sqp); + rnt = 25; + rnt <<= play[sqp->owner].num_rr - 1; + printf("%d %4d", play[sqp->owner].num_rr, + 25 << (play[sqp->owner].num_rr - 1)); + break; + } + if (eoln) + putchar('\n'); +} + +/* + * This routine prints out the mortgage flag. + */ +static void +printmorg(const SQUARE *sqp) +{ + if (sqp->desc->morg) + printf(" * "); + else + printf(" "); +} + +/* + * This routine lists the holdings of the player given + */ +void +printhold(int pl) +{ + OWN *op; + PLAY *pp; + + pp = &play[pl]; + printf("%s's (%d) holdings (Total worth: $%d):\n", name_list[pl], + pl + 1, pp->money + prop_worth(pp)); + printf("\t$%d", pp->money); + if (pp->num_gojf) { + printf(", %d get-out-of-jail-free card", pp->num_gojf); + if (pp->num_gojf > 1) + putchar('s'); + } + putchar('\n'); + if (pp->own_list) { + printf("\t%s\n", header); + for (op = pp->own_list; op; op = op->next) { + putchar('\t'); + printsq(sqnum(op->sqr), TRUE); + } + } +} diff --git a/games/monop/prop.c b/games/monop/prop.c new file mode 100644 index 000000000..0b6bef81d --- /dev/null +++ b/games/monop/prop.c @@ -0,0 +1,224 @@ +/* $NetBSD: prop.c,v 1.20 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)prop.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: prop.c,v 1.20 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include + +#include "monop.h" + +static int value(SQUARE *); + +/* + * This routine deals with buying property, setting all the + * appropriate flags. + */ +void +buy(int playernum, SQUARE *sqrp) +{ + trading = FALSE; + sqrp->owner = playernum; + add_list(playernum, &(play[playernum].own_list), cur_p->loc); +} + +/* + * This routine adds an item to the list. + */ +void +add_list(int plr, OWN **head, int op_sqr) +{ + int val; + OWN *tp, *last_tp; + OWN *op; + + op = calloc(1, sizeof (OWN)); + if (op == NULL) + errx(1, "out of memory"); + op->sqr = &board[op_sqr]; + val = value(op->sqr); + last_tp = NULL; + for (tp = *head; tp && value(tp->sqr) < val; tp = tp->next) + if (val == value(tp->sqr)) { + free(op); + return; + } + else + last_tp = tp; + op->next = tp; + if (last_tp != NULL) + last_tp->next = op; + else + *head = op; + if (!trading) + set_ownlist(plr); +} + +/* + * This routine deletes property from the list. + */ +void +del_list(int plr, OWN **head, short op_sqr) +{ + OWN *op, *last_op; + + switch (board[op_sqr].type) { + case PRPTY: + board[op_sqr].desc->mon_desc->num_own--; + break; + case RR: + play[plr].num_rr--; + break; + case UTIL: + play[plr].num_util--; + break; + } + last_op = NULL; + for (op = *head; op; op = op->next) + if (op->sqr == &board[op_sqr]) + break; + else + last_op = op; + if (op == NULL) + return; + if (last_op == NULL) + *head = op->next; + else { + last_op->next = op->next; + free(op); + } +} + +/* + * This routine calculates the value for sorting of the + * given square. + */ +static int +value(SQUARE *sqp) +{ + int sqr; + + sqr = sqnum(sqp); + switch (sqp->type) { + case SAFE: + return 0; + default: /* Specials, etc */ + return 1; + case UTIL: + if (sqr == 12) + return 2; + else + return 3; + case RR: + return 4 + sqr/10; + case PRPTY: + return 8 + (sqp->desc) - prop; + } +} + +/* + * This routine accepts bids for the current piece of property. + */ +void +bid(void) +{ + static bool in[MAX_PL]; + int i, num_in, cur_max; + char buf[257]; + int cur_bid; + + printf("\nSo it goes up for auction. Type your bid after your name\n"); + for (i = 0; i < num_play; i++) + in[i] = TRUE; + i = -1; + cur_max = 0; + num_in = num_play; + while (num_in > 1 || (cur_max == 0 && num_in > 0)) { + i = (i + 1) % num_play; + if (in[i]) { + do { + (void)snprintf(buf, sizeof(buf), "%s: ", + name_list[i]); + cur_bid = get_int(buf); + if (cur_bid == 0) { + in[i] = FALSE; + if (--num_in == 0) + break; + } else if (cur_bid <= cur_max) { + printf("You must bid higher than %d " + "to stay in\n", cur_max); + printf("(bid of 0 drops you out)\n"); + } else if (cur_bid > play[i].money) { + printf("You can't bid more than your cash ($%d)\n", + play[i].money); + cur_bid = -1; + } + } while (cur_bid != 0 && cur_bid <= cur_max); + cur_max = (cur_bid ? cur_bid : cur_max); + } + } + if (cur_max != 0) { + while (!in[i]) + i = (i + 1) % num_play; + printf("It goes to %s (%d) for $%d\n",play[i].name,i+1,cur_max); + buy(i, &board[cur_p->loc]); + play[i].money -= cur_max; + } + else + printf("Nobody seems to want it, so we'll leave it for " + "later\n"); +} + +/* + * This routine calculates the value of the property + * of given player. + */ +int +prop_worth(PLAY *plp) +{ + OWN *op; + int worth; + + worth = 0; + for (op = plp->own_list; op; op = op->next) { + if (op->sqr->type == PRPTY && op->sqr->desc->monop) + worth += op->sqr->desc->mon_desc->h_cost * 50 * + op->sqr->desc->houses; + worth += op->sqr->cost; + } + return worth; +} diff --git a/games/monop/rent.c b/games/monop/rent.c new file mode 100644 index 000000000..55f131ff1 --- /dev/null +++ b/games/monop/rent.c @@ -0,0 +1,96 @@ +/* $NetBSD: rent.c,v 1.9 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)rent.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: rent.c,v 1.9 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include "monop.h" + +/* + * This routine has the player pay rent + */ +void +rent(SQUARE *sqp) +{ + int rnt = 0; + PROP *pp; + PLAY *plp; + + plp = &play[sqp->owner]; + printf("Owned by %s\n", plp->name); + if (sqp->desc->morg) { + lucky("The thing is mortgaged. "); + return; + } + switch (sqp->type) { + case PRPTY: + pp = sqp->desc; + if (pp->monop) + if (pp->houses == 0) + printf("rent is %d\n", rnt=pp->rent[0] * 2); + else if (pp->houses < 5) + printf("with %d house%s, rent is %d\n", + pp->houses, pp->houses == 1 ? "" : "s", + rnt=pp->rent[pp->houses]); + else + printf("with a hotel, rent is %d\n", + rnt=pp->rent[pp->houses]); + else + printf("rent is %d\n", rnt = pp->rent[0]); + break; + case RR: + rnt = 25; + rnt <<= (plp->num_rr - 1); + if (spec) + rnt <<= 1; + printf("rent is %d\n", rnt); + break; + case UTIL: + rnt = roll(2, 6); + if (plp->num_util == 2 || spec) { + printf("rent is 10 * roll (%d) = %d\n", rnt, rnt * 10); + rnt *= 10; + } + else { + printf("rent is 4 * roll (%d) = %d\n", rnt, rnt * 4); + rnt *= 4; + } + break; + } + cur_p->money -= rnt; + plp->money += rnt; +} diff --git a/games/monop/roll.c b/games/monop/roll.c new file mode 100644 index 000000000..373fc7331 --- /dev/null +++ b/games/monop/roll.c @@ -0,0 +1,58 @@ +/* $NetBSD: roll.c,v 1.14 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)roll.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: roll.c,v 1.14 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include + +#include "monop.h" + +/* + * This routine rolls ndie nside-sided dice. + */ + +int +roll(int ndie, int nsides) +{ + long tot; + + tot = 0; + while (ndie--) + tot += (random() % nsides) + 1; + return (int)tot; +} diff --git a/games/monop/spec.c b/games/monop/spec.c new file mode 100644 index 000000000..801aa769e --- /dev/null +++ b/games/monop/spec.c @@ -0,0 +1,115 @@ +/* $NetBSD: spec.c,v 1.11 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: spec.c,v 1.11 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include "monop.h" +#include "deck.h" + +static const char *const perc[] = { + "10%", "ten percent", "%", "$200", "200", 0 + }; + +/* + * collect income tax + */ +void +inc_tax(void) +{ + int worth, com_num; + + com_num = getinp("Do you wish to lose 10% of your total worth or " + "$200? ", perc); + worth = cur_p->money + prop_worth(cur_p); + printf("You were worth $%d", worth); + worth /= 10; + if (com_num > 2) { + if (worth < 200) + printf(". Good try, but not quite.\n"); + else if (worth > 200) + lucky(".\nGood guess. "); + cur_p->money -= 200; + } + else { + printf(", so you pay $%d", worth); + if (worth > 200) + printf(" OUCH!!!!.\n"); + else if (worth < 200) + lucky("\nGood guess. "); + cur_p->money -= worth; + } + if (worth == 200) + lucky("\nIt makes no difference! "); +} + +/* + * move player to jail + */ +void +goto_jail(void) +{ + cur_p->loc = JAIL; +} + +/* + * landing on luxury tax + */ +void +lux_tax(void) +{ + printf("You lose $75\n"); + cur_p->money -= 75; +} + +/* + * draw community chest card + */ +void +cc(void) +{ + get_card(&CC_D); +} + +/* + * draw chance card + */ +void +chance(void) +{ + get_card(&CH_D); +} diff --git a/games/monop/trade.c b/games/monop/trade.c new file mode 100644 index 000000000..63d2e8a9b --- /dev/null +++ b/games/monop/trade.c @@ -0,0 +1,329 @@ +/* $NetBSD: trade.c,v 1.16 2012/06/19 05:35:32 dholland Exp $ */ + +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)trade.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: trade.c,v 1.16 2012/06/19 05:35:32 dholland Exp $"); +#endif +#endif /* not lint */ + +#include "monop.h" + +struct trd_st { /* how much to give to other player */ + int trader; /* trader number */ + int cash; /* amount of cash */ + int gojf; /* # get-out-of-jail-free cards */ + OWN *prop_list; /* property list */ +}; + +typedef struct trd_st TRADE; + +static const char *plist[MAX_PRP+2]; + +static int used[MAX_PRP]; + +static TRADE trades[2]; + +static void get_list(int, int ); +static int set_list(OWN *); +static void summate(void); +static void do_trade(void); +static void move_em(TRADE *, TRADE *); + +void +trade(void) +{ + int tradee, i; + + trading = TRUE; + for (i = 0; i < 2; i++) { + trades[i].cash = 0; + trades[i].gojf = FALSE; + trades[i].prop_list = NULL; + } +over: + if (num_play == 1) { + printf("There ain't no-one around to trade WITH!!\n"); + return; + } + if (num_play > 2) { + tradee = getinp("Which player do you wish to trade with? ", + name_list); + if (tradee == num_play) + return; + if (tradee == player) { + printf("You can't trade with yourself!\n"); + goto over; + } + } + else + tradee = 1 - player; + get_list(0, player); + get_list(1, tradee); + if (getyn("Do you wish a summary? ") == 0) + summate(); + if (getyn("Is the trade ok? ") == 0) + do_trade(); +} + +/* + * This routine gets the list of things to be trader for the + * player, and puts in the structure given. + */ +static void +get_list(int struct_no, int play_no) +{ + int sn, pn; + PLAY *pp; + int numin, propnum, num_prp; + OWN *op; + TRADE *tp; + + for (numin = 0; numin < MAX_PRP; numin++) + used[numin] = FALSE; + sn = struct_no, pn = play_no; + pp = &play[pn]; + tp = &trades[sn]; + tp->trader = pn; + printf("player %s (%d):\n", pp->name, pn+1); + if (pp->own_list) { + numin = set_list(pp->own_list); + for (num_prp = numin; num_prp; ) { + propnum=getinp("Which property do you wish to trade? ", + plist); + if (propnum == numin) + break; + else if (used[propnum]) + printf("You've already allocated that.\n"); + else { + num_prp--; + used[propnum] = TRUE; + for (op = pp->own_list; propnum--; op = op->next) + continue; + add_list(pn, &(tp->prop_list), sqnum(op->sqr)); + } + } + } + if (pp->money > 0) { + printf("You have $%d. ", pp->money); + tp->cash = get_int("How much are you trading? "); + } + if (pp->num_gojf > 0) { +once_more: + printf("You have %d get-out-of-jail-free cards. ",pp->num_gojf); + tp->gojf = get_int("How many are you trading? "); + if (tp->gojf > pp->num_gojf) { + printf("You don't have that many. Try again.\n"); + goto once_more; + } + } +} + +/* + * This routine sets up the list of tradable property. + */ +static int +set_list(OWN *the_list) +{ + int i; + OWN *op; + + i = 0; + for (op = the_list; op; op = op->next) + if (!used[i]) + plist[i++] = op->sqr->name; + plist[i++] = "done"; + plist[i--] = 0; + return i; +} + +/* + * This routine summates the trade. + */ +static void +summate(void) +{ + bool some; + int i; + TRADE *tp; + OWN *op; + + for (i = 0; i < 2; i++) { + tp = &trades[i]; + some = FALSE; + printf("Player %s (%d) gives:\n", play[tp->trader].name, + tp->trader+1); + if (tp->cash > 0) + printf("\t$%d\n", tp->cash), some++; + if (tp->gojf > 0) + printf("\t%d get-out-of-jail-free card(s)\n", tp->gojf), + some++; + if (tp->prop_list) { + for (op = tp->prop_list; op; op = op->next) + putchar('\t'), printsq(sqnum(op->sqr), TRUE); + some++; + } + if (!some) + printf("\t-- Nothing --\n"); + } +} + +/* + * This routine actually executes the trade. + */ +static void +do_trade(void) +{ + move_em(&trades[0], &trades[1]); + move_em(&trades[1], &trades[0]); +} + +/* + * This routine does a switch from one player to another + */ +static void +move_em(TRADE *from, TRADE *to) +{ + PLAY *pl_fr, *pl_to; + OWN *op; + + pl_fr = &play[from->trader]; + pl_to = &play[to->trader]; + + pl_fr->money -= from->cash; + pl_to->money += from->cash; + pl_fr->num_gojf -= from->gojf; + pl_to->num_gojf += from->gojf; + for (op = from->prop_list; op; op = op->next) { + add_list(to->trader, &(pl_to->own_list), sqnum(op->sqr)); + op->sqr->owner = to->trader; + del_list(from->trader, &(pl_fr->own_list), sqnum(op->sqr)); + } + set_ownlist(to->trader); +} + +/* + * This routine lets a player resign + */ +void +resign(void) +{ + int i, new_own; + OWN *op; + SQUARE *sqp; + + if (cur_p->money <= 0) { + switch (board[cur_p->loc].type) { + case UTIL: + case RR: + case PRPTY: + new_own = board[cur_p->loc].owner; + /* If you ran out of money by buying current location */ + if (new_own == player) + new_own = num_play; + break; + default: /* Chance, taxes, etc */ + new_own = num_play; + break; + } + if (new_own == num_play) + printf("You would resign to the bank\n"); + else + printf("You would resign to %s\n", name_list[new_own]); + } + else if (num_play == 1) { + new_own = num_play; + printf("You would resign to the bank\n"); + } + else { + name_list[num_play] = "bank"; + do { + new_own = getinp("Who do you wish to resign to? ", + name_list); + if (new_own == player) + printf("You can't resign to yourself!!\n"); + } while (new_own == player); + name_list[num_play] = "done"; + } + if (getyn("Do you really want to resign? ") != 0) + return; + if (num_play == 1) { + printf("Then NOBODY wins (not even YOU!)\n"); + exit(0); + } + if (new_own < num_play) { /* resign to player */ + printf("resigning to player\n"); + trades[0].trader = new_own; + trades[0].cash = trades[0].gojf = 0; + trades[0].prop_list = NULL; + trades[1].trader = player; + trades[1].cash = cur_p->money > 0 ? cur_p->money : 0; + trades[1].gojf = cur_p->num_gojf; + trades[1].prop_list = cur_p->own_list; + do_trade(); + } + else { /* resign to bank */ + printf("resigning to bank\n"); + for (op = cur_p->own_list; op; op = op->next) { + sqp = op->sqr; + sqp->owner = -1; + sqp->desc->morg = FALSE; + if (sqp->type == PRPTY) { + is_not_monop(sqp->desc->mon_desc); + sqp->desc->houses = 0; + } + } + if (cur_p->num_gojf) + ret_card(cur_p); + } + free(play[player].name); + for (i = player; i < num_play; i++) { + name_list[i] = name_list[i+1]; + if (i + 1 < num_play) + play[i] = play[i+1]; + } + name_list[num_play--] = NULL; + for (i = 0; i < N_SQRS; i++) + if (board[i].owner > player) + --board[i].owner; + player = player == 0 ? num_play - 1 : player - 1; + next_play(); + if (num_play < 2) { + printf("\nThen %s WINS!!!!!\n", play[0].name); + printhold(0); + printf("That's a grand worth of $%d.\n", + play[0].money+prop_worth(&play[0])); + exit(0); + } +} diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 8691ba3e3..1f9545eb5 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -74,6 +74,7 @@ 2013/12/1 12:00:00,games/fortune 2013/12/1 12:00:00,games/Makefile 2013/12/1 12:00:00,games/Makefile.inc +2013/12/1 12:00:00,games/monop 2013/12/1 12:00:00,games/morse 2013/12/1 12:00:00,games/number 2013/12/1 12:00:00,games/pig