xref: /openbsd/games/monop/cards.c (revision 404b540a)
1 /*	$OpenBSD: cards.c,v 1.8 2003/06/03 03:01:40 millert Exp $	*/
2 /*	$NetBSD: cards.c,v 1.3 1995/03/23 08:34:35 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1980, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)cards.c	8.1 (Berkeley) 5/31/93";
36 #else
37 static const char rcsid[] = "$OpenBSD: cards.c,v 1.8 2003/06/03 03:01:40 millert Exp $";
38 #endif
39 #endif /* not lint */
40 
41 #include	<err.h>
42 #include	"monop.ext"
43 #include	"pathnames.h"
44 
45 /*
46  *	These routine deal with the card decks
47  */
48 
49 #define	GOJF	'F'	/* char for get-out-of-jail-free cards	*/
50 
51 static char	*cardfile	= _PATH_CARDS;
52 
53 static FILE	*deckf;
54 
55 static void set_up(DECK *);
56 static void printmes(void);
57 
58 /*
59  *	This routine initializes the decks from the data file,
60  * which it opens.
61  */
62 void
63 init_decks()
64 {
65 	if ((deckf = fopen(cardfile, "r")) == NULL)
66 file_err:
67 		err(1, "%s", cardfile);
68 	if (fread(&deck[0].num_cards, sizeof(deck[0].num_cards), 1, deckf) != 1)
69 		goto file_err;
70 	if (fread(&deck[0].top_card, sizeof(deck[0].top_card), 1, deckf) != 1)
71 		goto file_err;
72 	if (fread(&deck[0].gojf_used, sizeof(deck[0].gojf_used), 1, deckf) != 1)
73 		goto file_err;
74 	deck[0].num_cards = ntohs(deck[0].num_cards);
75 	deck[0].top_card = ntohs(deck[0].top_card);
76 
77 	if (fread(&deck[1].num_cards, sizeof(deck[1].num_cards), 1, deckf) != 1)
78 		goto file_err;
79 	if (fread(&deck[1].top_card, sizeof(deck[1].top_card), 1, deckf) != 1)
80 		goto file_err;
81 	if (fread(&deck[1].gojf_used, sizeof(deck[1].gojf_used), 1, deckf) != 1)
82 		goto file_err;
83 	deck[1].num_cards = ntohs(deck[1].num_cards);
84 	deck[1].top_card = ntohs(deck[1].top_card);
85 
86 	set_up(&CC_D);
87 	set_up(&CH_D);
88 }
89 /*
90  *	This routine sets up the offset pointers for the given deck.
91  */
92 static void
93 set_up(dp)
94 	DECK	*dp;
95 {
96 	int	r1, r2;
97 	int	i;
98 
99 	if ((dp->offsets = (int32_t *) calloc(dp->num_cards, sizeof (int32_t))) == NULL)
100 		err(1, NULL);
101 	for (i = 0 ; i < dp->num_cards ; i++) {
102 		if (fread(&dp->offsets[i], sizeof(dp->offsets[i]), 1, deckf) != 1)
103 			err(1, "%s", cardfile);
104 		dp->offsets[i] = ntohl(dp->offsets[i]);
105 	}
106 	dp->top_card = 0;
107 	dp->gojf_used = FALSE;
108 	for (i = 0; i < dp->num_cards; i++) {
109 		long	temp;
110 
111 		r1 = roll(1, dp->num_cards) - 1;
112 		r2 = roll(1, dp->num_cards) - 1;
113 		temp = dp->offsets[r2];
114 		dp->offsets[r2] = dp->offsets[r1];
115 		dp->offsets[r1] = temp;
116 	}
117 }
118 /*
119  *	This routine draws a card from the given deck
120  */
121 void
122 get_card(dp)
123 	DECK	*dp;
124 {
125 	char	type_maj, type_min;
126 	int16_t	num;
127 	int	i, per_h, per_H, num_h, num_H;
128 	OWN	*op;
129 
130 	do {
131 		fseek(deckf, dp->offsets[dp->top_card], SEEK_SET);
132 		dp->top_card = ++(dp->top_card) % dp->num_cards;
133 		type_maj = getc(deckf);
134 	} while (dp->gojf_used && type_maj == GOJF);
135 	type_min = getc(deckf);
136 	fread(&num, sizeof(num), 1, deckf);
137 	num = ntohs(num);
138 	printmes();
139 	switch (type_maj) {
140 	  case '+':		/* get money		*/
141 		if (type_min == 'A') {
142 			for (i = 0; i < num_play; i++)
143 				if (i != player)
144 					play[i].money -= num;
145 			num = num * (num_play - 1);
146 		}
147 		cur_p->money += num;
148 		break;
149 	  case '-':		/* lose money		*/
150 		if (type_min == 'A') {
151 			for (i = 0; i < num_play; i++)
152 				if (i != player)
153 					play[i].money += num;
154 			num = num * (num_play - 1);
155 		}
156 		cur_p->money -= num;
157 		break;
158 	  case 'M':		/* move somewhere	*/
159 		switch (type_min) {
160 		  case 'F':		/* move forward	*/
161 			num -= cur_p->loc;
162 			if (num < 0)
163 				num += 40;
164 			break;
165 		  case 'J':		/* move to jail	*/
166 			goto_jail();
167 			return;
168 		  case 'R':		/* move to railroad	*/
169 			spec = TRUE;
170 			num = (int)((cur_p->loc + 5)/10)*10 + 5 - cur_p->loc;
171 			break;
172 		  case 'U':		/* move to utility	*/
173 			spec = TRUE;
174 			if (cur_p->loc >= 12 && cur_p->loc < 28)
175 				num = 28 - cur_p->loc;
176 			else {
177 				num = 12 - cur_p->loc;
178 				if (num < 0)
179 					num += 40;
180 			}
181 			break;
182 		  case 'B':
183 			num = -num;
184 			break;
185 		}
186 		move(num);
187 		break;
188 	  case 'T':			/* tax			*/
189 		if (dp == &CC_D) {
190 			per_h = 40;
191 			per_H = 115;
192 		}
193 		else {
194 			per_h = 25;
195 			per_H = 100;
196 		}
197 		num_h = num_H = 0;
198 		for (op = cur_p->own_list; op; op = op->next)
199 			if (op->sqr->type == PRPTY) {
200 				if (op->sqr->desc->houses == 5)
201 					++num_H;
202 				else
203 					num_h += op->sqr->desc->houses;
204 			}
205 		num = per_h * num_h + per_H * num_H;
206 		printf("You had %d Houses and %d Hotels, so that cost you $%d\n", num_h, num_H, num);
207 		if (num == 0)
208 			lucky("");
209 		else
210 			cur_p->money -= num;
211 		break;
212 	  case GOJF:		/* get-out-of-jail-free card	*/
213 		cur_p->num_gojf++;
214 		dp->gojf_used = TRUE;
215 		break;
216 	}
217 	spec = FALSE;
218 }
219 
220 /*
221  *	This routine prints out the message on the card
222  */
223 static void
224 printmes()
225 {
226 	char	c;
227 
228 	printline();
229 	fflush(stdout);
230 	while ((c = getc(deckf)) != '\0')
231 		putchar(c);
232 	printline();
233 	fflush(stdout);
234 }
235 
236 /*
237  *	This routine returns the players get-out-of-jail-free card
238  * to the bottom of a deck.  XXX currently does not return to the correct
239  * deck.
240  */
241 void
242 ret_card(plr)
243 	PLAY	*plr;
244 {
245 	char	type_maj;
246 	int16_t	gojfpos, last_card;
247 	int	i;
248 	DECK *dp;
249 	int32_t temp;
250 
251 	plr->num_gojf--;
252 	if (CC_D.gojf_used)
253 		dp = &CC_D;
254 	else
255 		dp = &CH_D;
256 	dp->gojf_used = FALSE;
257 
258 	/* Put at bottom of deck (top_card - 1) and remove it from wherever else
259 	 * it used to be.
260 	 */
261 	last_card = dp->top_card - 1;
262 	if (last_card < 0)
263 		last_card += dp->num_cards;
264 	gojfpos = dp->top_card;
265 	do {
266 		gojfpos = (gojfpos + 1) % dp->num_cards;
267 		fseek(deckf, dp->offsets[gojfpos], SEEK_SET);
268 		type_maj = getc(deckf);
269 	} while (type_maj != GOJF);
270 	temp = dp->offsets[gojfpos];
271 	/* Only one of the next two loops does anything */
272 	for (i = gojfpos - 1; i > last_card; i--)
273 		dp->offsets[i + 1] = dp->offsets[i];
274 	for (i = gojfpos; i < last_card; i++)
275 		dp->offsets[i] = dp->offsets[i + 1];
276 	if (gojfpos > last_card) {
277 		dp->offsets[dp->top_card] = temp;
278 		dp->top_card++;
279 		dp->top_card %= dp->num_cards;
280 	} else
281 		dp->offsets[last_card] = temp;
282 }
283