xref: /netbsd/games/monop/cards.c (revision 5b4f06a6)
1 /*	$NetBSD: cards.c,v 1.27 2014/12/29 10:38:52 jnemeth 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.27 2014/12/29 10:38:52 jnemeth 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 owner 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
init_decks(void)193 init_decks(void)
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
set_up(DECK * dp)207 set_up(DECK *dp)
208 {
209 	int r1, r2;
210 	int i;
211 
212 	dp->cards = calloc((size_t)dp->num_cards, sizeof(dp->cards[0]));
213 	if (dp->cards == NULL)
214 		errx(1, "out of memory");
215 
216 	for (i = 0; i < dp->num_cards; i++)
217 		dp->cards[i] = i;
218 
219 	dp->top_card = 0;
220 	dp->gojf_used = FALSE;
221 
222 	for (i = 0; i < dp->num_cards; i++) {
223 		int temp;
224 
225 		r1 = roll(1, dp->num_cards) - 1;
226 		r2 = roll(1, dp->num_cards) - 1;
227 		temp = dp->cards[r2];
228 		dp->cards[r2] = dp->cards[r1];
229 		dp->cards[r1] = temp;
230 	}
231 }
232 
233 /*
234  *	This routine draws a card from the given deck
235  */
236 void
get_card(DECK * dp)237 get_card(DECK *dp)
238 {
239 	char type_maj, type_min;
240 	int num;
241 	int i, per_h, per_H, num_h, num_H;
242 	OWN *op;
243 	const struct cardinfo *thiscard;
244 
245 	do {
246 		thiscard = &dp->info[dp->top_card];
247 		type_maj = thiscard->actioncode[0];
248 		dp->top_card = (dp->top_card + 1) % dp->num_cards;
249 	} while (dp->gojf_used && type_maj == GOJF);
250 	type_min = thiscard->actioncode[1];
251 	num = atoi(thiscard->actioncode+2);
252 
253 	printmes(thiscard->text);
254 	switch (type_maj) {
255 	  case '+':		/* get money		*/
256 		if (type_min == 'A') {
257 			for (i = 0; i < num_play; i++)
258 				if (i != player)
259 					play[i].money -= num;
260 			num = num * (num_play - 1);
261 		}
262 		cur_p->money += num;
263 		break;
264 	  case '-':		/* lose money		*/
265 		if (type_min == 'A') {
266 			for (i = 0; i < num_play; i++)
267 				if (i != player)
268 					play[i].money += num;
269 			num = num * (num_play - 1);
270 		}
271 		cur_p->money -= num;
272 		break;
273 	  case 'M':		/* move somewhere	*/
274 		switch (type_min) {
275 		  case 'F':		/* move forward	*/
276 			num -= cur_p->loc;
277 			if (num < 0)
278 				num += 40;
279 			break;
280 		  case 'J':		/* move to jail	*/
281 			goto_jail();
282 			return;
283 		  case 'R':		/* move to railroad	*/
284 			spec = TRUE;
285 			num = (int)((cur_p->loc + 5)/10)*10 + 5 - cur_p->loc;
286 			break;
287 		  case 'U':		/* move to utility	*/
288 			spec = TRUE;
289 			if (cur_p->loc >= 12 && cur_p->loc < 28)
290 				num = 28 - cur_p->loc;
291 			else {
292 				num = 12 - cur_p->loc;
293 				if (num < 0)
294 					num += 40;
295 			}
296 			break;
297 		  case 'B':
298 			num = -num;
299 			break;
300 		}
301 		move(num);
302 		break;
303 	  case 'T':			/* tax			*/
304 		if (dp == &CC_D) {
305 			per_h = 40;
306 			per_H = 115;
307 		}
308 		else {
309 			per_h = 25;
310 			per_H = 100;
311 		}
312 		num_h = num_H = 0;
313 		for (op = cur_p->own_list; op; op = op->next)
314 			if (op->sqr->type == PRPTY) {
315 				if (op->sqr->desc->houses == 5)
316 					++num_H;
317 				else
318 					num_h += op->sqr->desc->houses;
319 			}
320 		num = per_h * num_h + per_H * num_H;
321 		printf(
322 		    "You had %d Houses and %d Hotels, so that cost you $%d\n",
323 		    num_h, num_H, num);
324 		if (num == 0)
325 			lucky("");
326 		else
327 			cur_p->money -= num;
328 		break;
329 	  case GOJF:		/* get-out-of-jail-free card	*/
330 		cur_p->num_gojf++;
331 		dp->gojf_used = TRUE;
332 		break;
333 	}
334 	spec = FALSE;
335 }
336 
337 /*
338  *	This routine prints out the message on the card
339  */
340 static void
printmes(const char * text)341 printmes(const char *text)
342 {
343 	int i;
344 
345 	printline();
346 	fflush(stdout);
347 	for (i = 0; text[i] != '\0'; i++)
348 		putchar(text[i]);
349 	printline();
350 	fflush(stdout);
351 }
352 
353 /*
354  *	This routine returns the players get-out-of-jail-free card
355  * to the bottom of a deck.  XXX currently does not return to the correct
356  * deck.
357  */
358 void
ret_card(PLAY * plr)359 ret_card(PLAY *plr)
360 {
361 	char type_maj;
362 	int gojfpos, last_card;
363 	int i;
364 	DECK *dp;
365 	int temp;
366 
367 	plr->num_gojf--;
368 	if (CC_D.gojf_used)
369 		dp = &CC_D;
370 	else
371 		dp = &CH_D;
372 	dp->gojf_used = FALSE;
373 
374 	/* Put at bottom of deck (top_card - 1) and remove it from wherever else
375 	 * it used to be.
376 	 */
377 	last_card = dp->top_card - 1;
378 	if (last_card < 0)
379 		last_card += dp->num_cards;
380 	gojfpos = dp->top_card;
381 	do {
382 		gojfpos = (gojfpos + 1) % dp->num_cards;
383 		type_maj = dp->info[gojfpos].actioncode[0];
384 	} while (type_maj != GOJF);
385 	temp = dp->cards[gojfpos];
386 	/* Only one of the next two loops does anything */
387 	for (i = gojfpos - 1; i > last_card; i--)
388 		dp->cards[i + 1] = dp->cards[i];
389 	for (i = gojfpos; i < last_card; i++)
390 		dp->cards[i] = dp->cards[i + 1];
391 	if (gojfpos > last_card) {
392 		dp->cards[dp->top_card] = temp;
393 		dp->top_card++;
394 		dp->top_card %= dp->num_cards;
395 	} else
396 		dp->cards[last_card] = temp;
397 }
398