xref: /netbsd-src/games/monop/cards.c (revision 63d4abf06d37aace2f9e41a494102a64fe3abddb)
1 /*	$NetBSD: cards.c,v 1.23 2008/02/24 03:56:48 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)cards.c	8.1 (Berkeley) 5/31/93";
36 #else
37 __RCSID("$NetBSD: cards.c,v 1.23 2008/02/24 03:56:48 christos Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/types.h>
42 #include <sys/endian.h>
43 #include "monop.h"
44 #include "deck.h"
45 
46 /*
47  *	These routine deal with the card decks
48  */
49 
50 static void set_up(DECK *);
51 static void printmes(const char *text);
52 
53 #define	GOJF	'F'	/* char for get-out-of-jail-free cards	*/
54 
55 struct cardinfo {
56 	const char *actioncode;
57 	const char *text;
58 };
59 
60 static const struct cardinfo cc_cards[] = {
61 	{ "FF",
62 		">> GET OUT OF JAIL FREE <<\n"
63 		"Keep this card until needed or sold\n"
64 	},
65 	{ "++25",
66 		"Receive for Services $25.\n"
67 	},
68 	{ "++200",
69 		"Bank Error in Your Favor.\n"
70 		"Collect $200.\n"
71 	},
72 	{ "++20",
73 		"Income Tax Refund.\n"
74 		"Collect $20.\n"
75 	},
76 	{ "--100",
77 		"Pay Hospital $100\n"
78 	},
79 	{ "++100",
80 		"Life Insurance Matures.\n"
81 		"Collect $100\n"
82 	},
83 	{ "++45",
84 		"From sale of Stock You get $45.\n"
85 	},
86 	{ "TX",
87 		"You are Assessed for street repairs.\n"
88 		"\t$40 per House\n"
89 		"\t$115 per Hotel\n"
90 	},
91 	{ "++100",
92 		"X-mas Fund Matures.\n"
93 	  	"Collect $100.\n"
94 	},
95 	{ "++11",
96 		"You have won Second Prize in a Beauty Contest\n"
97 		"Collect $11\n"
98 	},
99 	{ "MF0",
100 		"Advance to GO\n"
101 		"(Collect $200)\n"
102 	},
103 	{ "++100",
104 		"You inherit $100\n"
105 	},
106 	{ "--150",
107 		"Pay School Tax of $150.\n"
108 	},
109 	{ "MJ",
110 		"\t\t>> GO TO JAIL <<\n"
111 	  	"Go Directly to Jail. Do not pass GO  Do not collect $200.\n"
112 	},
113 	{ "+A50",
114 		"\t\t>> GRAND OPERA OPENING <<\n"
115 		"Collect $50 from each player for opening night seats.\n"
116 	},
117 	{ "--50",
118 		"Doctor's Fee:  Pay $50.\n"
119 	}
120 };
121 
122 static const struct cardinfo ch_cards[] = {
123 	{ "FF",
124 		">> GET OUT OF JAIL FREE <<\n"
125 		"Keep this card until needed or sold\n"
126 	},
127 	{ "MR",
128 		"Advance to the nearest Railroad, and pay owner\n"
129 		"Twice the rental to which he is otherwise entitled.\n"
130 		"If Railroad is unowned you may buy it from the bank\n"
131 	},
132 	{ "MU",
133 		"Advance to the nearest Utility.\n"
134 		"If unowned, you may buy it from the bank.\n"
135 		"If owned, throw dice and pay oner a total of ten times\n"
136 		"the amount thrown.\n"
137 	},
138 	{ "MB3",
139 		"Go Back 3 Spaces\n"
140 	},
141 	{ "MR",
142 		"Advance to the nearest Railroad, and pay owner\n"
143 		"Twice the rental to which he is otherwise entitled.\n"
144 		"If Railroad is unowned you may buy it from the bank\n"
145 	},
146 	{ "MJ",
147 		"    >> GO DIRECTLY TO JAIL <<\n"
148 		"Do not pass GO, Do not Collect $200.\n"
149 	},
150 	{ "MF5",
151 		"Take a Ride on the Reading.\n"
152 		"If you pass GO, collect $200.\n"
153 	},
154 	{ "MF39",
155 		"Take a Walk on the Board Walk.\n"
156 		"    (Advance To Board Walk)\n"
157 	},
158 	{ "MF24",
159 		"Advance to Illinois Ave.\n"
160 	},
161 	{ "MF0",
162 		"Advance to Go\n"
163 	},
164 	{ "MF11",
165 		"Advance to St. Charles Place.\n"
166 		"If you pass GO, collect $200.\n"
167 	},
168 	{ "TX",
169 		"Make general repairs on all of your Property.\n"
170 		"For Each House pay $25.\n"
171 		"For Each Hotel pay $100.\n"
172 	},
173 	{ "-A50",
174 		"You have been elected Chairman of the Board.\n"
175 		"Pay each player $50.\n"
176 	},
177 	{ "--15",
178 		"Pay Poor Tax of $15\n"
179 	},
180 	{ "++50",
181 		"Bank pays you Dividend of $50.\n"
182 	},
183 	{ "++150",
184 		"Your Building and Loan Matures.\n"
185 		"Collect $150.\n"
186 	}
187 };
188 
189 /*
190  * This routine initializes the decks from the data above.
191  */
192 void
193 init_decks()
194 {
195 	CC_D.info = cc_cards;
196 	CC_D.num_cards = sizeof(cc_cards) / sizeof(cc_cards[0]);
197 	CH_D.info = ch_cards;
198 	CH_D.num_cards = sizeof(ch_cards) / sizeof(ch_cards[0]);
199 	set_up(&CC_D);
200 	set_up(&CH_D);
201 }
202 
203 /*
204  *	This routine sets up the offset pointers for the given deck.
205  */
206 static void
207 set_up(dp)
208 	DECK *dp;
209 {
210 	int r1, r2;
211 	int i;
212 
213 	dp->cards = calloc((size_t)dp->num_cards, sizeof(dp->cards[0]));
214 	if (dp->cards == NULL)
215 		errx(1, "out of memory");
216 
217 	for (i = 0; i < dp->num_cards; i++)
218 		dp->cards[i] = i;
219 
220 	dp->top_card = 0;
221 	dp->gojf_used = FALSE;
222 
223 	for (i = 0; i < dp->num_cards; i++) {
224 		int temp;
225 
226 		r1 = roll(1, dp->num_cards) - 1;
227 		r2 = roll(1, dp->num_cards) - 1;
228 		temp = dp->cards[r2];
229 		dp->cards[r2] = dp->cards[r1];
230 		dp->cards[r1] = temp;
231 	}
232 }
233 
234 /*
235  *	This routine draws a card from the given deck
236  */
237 void
238 get_card(dp)
239 	DECK *dp;
240 {
241 	char type_maj, type_min;
242 	int num;
243 	int i, per_h, per_H, num_h, num_H;
244 	OWN *op;
245 	const struct cardinfo *thiscard;
246 
247 	do {
248 		thiscard = &dp->info[dp->top_card];
249 		type_maj = thiscard->actioncode[0];
250 		dp->top_card = ++(dp->top_card) % dp->num_cards;
251 	} while (dp->gojf_used && type_maj == GOJF);
252 	type_min = thiscard->actioncode[1];
253 	num = atoi(thiscard->actioncode+2);
254 
255 	printmes(thiscard->text);
256 	switch (type_maj) {
257 	  case '+':		/* get money		*/
258 		if (type_min == 'A') {
259 			for (i = 0; i < num_play; i++)
260 				if (i != player)
261 					play[i].money -= num;
262 			num = num * (num_play - 1);
263 		}
264 		cur_p->money += num;
265 		break;
266 	  case '-':		/* lose money		*/
267 		if (type_min == 'A') {
268 			for (i = 0; i < num_play; i++)
269 				if (i != player)
270 					play[i].money += num;
271 			num = num * (num_play - 1);
272 		}
273 		cur_p->money -= num;
274 		break;
275 	  case 'M':		/* move somewhere	*/
276 		switch (type_min) {
277 		  case 'F':		/* move forward	*/
278 			num -= cur_p->loc;
279 			if (num < 0)
280 				num += 40;
281 			break;
282 		  case 'J':		/* move to jail	*/
283 			goto_jail();
284 			return;
285 		  case 'R':		/* move to railroad	*/
286 			spec = TRUE;
287 			num = (int)((cur_p->loc + 5)/10)*10 + 5 - cur_p->loc;
288 			break;
289 		  case 'U':		/* move to utility	*/
290 			spec = TRUE;
291 			if (cur_p->loc >= 12 && cur_p->loc < 28)
292 				num = 28 - cur_p->loc;
293 			else {
294 				num = 12 - cur_p->loc;
295 				if (num < 0)
296 					num += 40;
297 			}
298 			break;
299 		  case 'B':
300 			num = -num;
301 			break;
302 		}
303 		move(num);
304 		break;
305 	  case 'T':			/* tax			*/
306 		if (dp == &CC_D) {
307 			per_h = 40;
308 			per_H = 115;
309 		}
310 		else {
311 			per_h = 25;
312 			per_H = 100;
313 		}
314 		num_h = num_H = 0;
315 		for (op = cur_p->own_list; op; op = op->next)
316 			if (op->sqr->type == PRPTY) {
317 				if (op->sqr->desc->houses == 5)
318 					++num_H;
319 				else
320 					num_h += op->sqr->desc->houses;
321 			}
322 		num = per_h * num_h + per_H * num_H;
323 		printf(
324 		    "You had %d Houses and %d Hotels, so that cost you $%d\n",
325 		    num_h, num_H, num);
326 		if (num == 0)
327 			lucky("");
328 		else
329 			cur_p->money -= num;
330 		break;
331 	  case GOJF:		/* get-out-of-jail-free card	*/
332 		cur_p->num_gojf++;
333 		dp->gojf_used = TRUE;
334 		break;
335 	}
336 	spec = FALSE;
337 }
338 
339 /*
340  *	This routine prints out the message on the card
341  */
342 static void
343 printmes(const char *text)
344 {
345 	int i;
346 
347 	printline();
348 	fflush(stdout);
349 	for (i = 0; text[i] != '\0'; i++)
350 		putchar(text[i]);
351 	printline();
352 	fflush(stdout);
353 }
354 
355 /*
356  *	This routine returns the players get-out-of-jail-free card
357  * to the bottom of a deck.  XXX currently does not return to the correct
358  * deck.
359  */
360 void
361 ret_card(plr)
362 	PLAY *plr;
363 {
364 	char type_maj;
365 	int gojfpos, last_card;
366 	int i;
367 	DECK *dp;
368 	int temp;
369 
370 	plr->num_gojf--;
371 	if (CC_D.gojf_used)
372 		dp = &CC_D;
373 	else
374 		dp = &CH_D;
375 	dp->gojf_used = FALSE;
376 
377 	/* Put at bottom of deck (top_card - 1) and remove it from wherever else
378 	 * it used to be.
379 	 */
380 	last_card = dp->top_card - 1;
381 	if (last_card < 0)
382 		last_card += dp->num_cards;
383 	gojfpos = dp->top_card;
384 	do {
385 		gojfpos = (gojfpos + 1) % dp->num_cards;
386 		type_maj = dp->info[gojfpos].actioncode[0];
387 	} while (type_maj != GOJF);
388 	temp = dp->cards[gojfpos];
389 	/* Only one of the next two loops does anything */
390 	for (i = gojfpos - 1; i > last_card; i--)
391 		dp->cards[i + 1] = dp->cards[i];
392 	for (i = gojfpos; i < last_card; i++)
393 		dp->cards[i] = dp->cards[i + 1];
394 	if (gojfpos > last_card) {
395 		dp->cards[dp->top_card] = temp;
396 		dp->top_card++;
397 		dp->top_card %= dp->num_cards;
398 	} else
399 		dp->cards[last_card] = temp;
400 }
401