xref: /dragonfly/games/monop/cards.c (revision 631c21f2)
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  *	@(#)cards.c	8.1 (Berkeley) 5/31/93
32  */
33 
34 #include <sys/types.h>
35 #include <sys/endian.h>
36 #include "monop.h"
37 #include "deck.h"
38 
39 /*
40  *	These routine deal with the card decks
41  */
42 
43 static void set_up(DECK *);
44 static void printmes(const char *text);
45 
46 #define	GOJF	'F'	/* char for get-out-of-jail-free cards	*/
47 
48 struct cardinfo {
49 	const char *actioncode;
50 	const char *text;
51 };
52 
53 static const struct cardinfo cc_cards[] = {
54 	{ "FF",
55 		">> GET OUT OF JAIL FREE <<\n"
56 		"Keep this card until needed or sold\n"
57 	},
58 	{ "++25",
59 		"Receive for Services $25.\n"
60 	},
61 	{ "++200",
62 		"Bank Error in Your Favor.\n"
63 		"Collect $200.\n"
64 	},
65 	{ "++20",
66 		"Income Tax Refund.\n"
67 		"Collect $20.\n"
68 	},
69 	{ "--100",
70 		"Pay Hospital $100\n"
71 	},
72 	{ "++100",
73 		"Life Insurance Matures.\n"
74 		"Collect $100\n"
75 	},
76 	{ "++45",
77 		"From sale of Stock You get $45.\n"
78 	},
79 	{ "TX",
80 		"You are Assessed for street repairs.\n"
81 		"\t$40 per House\n"
82 		"\t$115 per Hotel\n"
83 	},
84 	{ "++100",
85 		"X-mas Fund Matures.\n"
86 	  	"Collect $100.\n"
87 	},
88 	{ "++11",
89 		"You have won Second Prize in a Beauty Contest\n"
90 		"Collect $11\n"
91 	},
92 	{ "MF0",
93 		"Advance to GO\n"
94 		"(Collect $200)\n"
95 	},
96 	{ "++100",
97 		"You inherit $100\n"
98 	},
99 	{ "--150",
100 		"Pay School Tax of $150.\n"
101 	},
102 	{ "MJ",
103 		"\t\t>> GO TO JAIL <<\n"
104 	  	"Go Directly to Jail. Do not pass GO  Do not collect $200.\n"
105 	},
106 	{ "+A50",
107 		"\t\t>> GRAND OPERA OPENING <<\n"
108 		"Collect $50 from each player for opening night seats.\n"
109 	},
110 	{ "--50",
111 		"Doctor's Fee:  Pay $50.\n"
112 	}
113 };
114 
115 static const struct cardinfo ch_cards[] = {
116 	{ "FF",
117 		">> GET OUT OF JAIL FREE <<\n"
118 		"Keep this card until needed or sold\n"
119 	},
120 	{ "MR",
121 		"Advance to the nearest Railroad, and pay owner\n"
122 		"Twice the rental to which he is otherwise entitled.\n"
123 		"If Railroad is unowned you may buy it from the bank\n"
124 	},
125 	{ "MU",
126 		"Advance to the nearest Utility.\n"
127 		"If unowned, you may buy it from the bank.\n"
128 		"If owned, throw dice and pay owner a total of ten times\n"
129 		"the amount thrown.\n"
130 	},
131 	{ "MB3",
132 		"Go Back 3 Spaces\n"
133 	},
134 	{ "MR",
135 		"Advance to the nearest Railroad, and pay owner\n"
136 		"Twice the rental to which he is otherwise entitled.\n"
137 		"If Railroad is unowned you may buy it from the bank\n"
138 	},
139 	{ "MJ",
140 		"    >> GO DIRECTLY TO JAIL <<\n"
141 		"Do not pass GO, Do not Collect $200.\n"
142 	},
143 	{ "MF5",
144 		"Take a Ride on the Reading.\n"
145 		"If you pass GO, collect $200.\n"
146 	},
147 	{ "MF39",
148 		"Take a Walk on the Board Walk.\n"
149 		"    (Advance To Board Walk)\n"
150 	},
151 	{ "MF24",
152 		"Advance to Illinois Ave.\n"
153 	},
154 	{ "MF0",
155 		"Advance to Go\n"
156 	},
157 	{ "MF11",
158 		"Advance to St. Charles Place.\n"
159 		"If you pass GO, collect $200.\n"
160 	},
161 	{ "TX",
162 		"Make general repairs on all of your Property.\n"
163 		"For Each House pay $25.\n"
164 		"For Each Hotel pay $100.\n"
165 	},
166 	{ "-A50",
167 		"You have been elected Chairman of the Board.\n"
168 		"Pay each player $50.\n"
169 	},
170 	{ "--15",
171 		"Pay Poor Tax of $15\n"
172 	},
173 	{ "++50",
174 		"Bank pays you Dividend of $50.\n"
175 	},
176 	{ "++150",
177 		"Your Building and Loan Matures.\n"
178 		"Collect $150.\n"
179 	}
180 };
181 
182 /*
183  * This routine initializes the decks from the data above.
184  */
185 void
186 init_decks(void)
187 {
188 	CC_D.info = cc_cards;
189 	CC_D.num_cards = sizeof(cc_cards) / sizeof(cc_cards[0]);
190 	CH_D.info = ch_cards;
191 	CH_D.num_cards = sizeof(ch_cards) / sizeof(ch_cards[0]);
192 	set_up(&CC_D);
193 	set_up(&CH_D);
194 }
195 
196 /*
197  *	This routine sets up the offset pointers for the given deck.
198  */
199 static void
200 set_up(DECK *dp)
201 {
202 	int r1, r2;
203 	int i;
204 
205 	dp->cards = calloc((size_t)dp->num_cards, sizeof(dp->cards[0]));
206 	if (dp->cards == NULL)
207 		errx(1, "out of memory");
208 
209 	for (i = 0; i < dp->num_cards; i++)
210 		dp->cards[i] = i;
211 
212 	dp->top_card = 0;
213 	dp->gojf_used = FALSE;
214 
215 	for (i = 0; i < dp->num_cards; i++) {
216 		int temp;
217 
218 		r1 = roll(1, dp->num_cards) - 1;
219 		r2 = roll(1, dp->num_cards) - 1;
220 		temp = dp->cards[r2];
221 		dp->cards[r2] = dp->cards[r1];
222 		dp->cards[r1] = temp;
223 	}
224 }
225 
226 /*
227  *	This routine draws a card from the given deck
228  */
229 void
230 get_card(DECK *dp)
231 {
232 	char type_maj, type_min;
233 	int num;
234 	int i, per_h, per_H, num_h, num_H;
235 	OWN *op;
236 	const struct cardinfo *thiscard;
237 
238 	do {
239 		thiscard = &dp->info[dp->top_card];
240 		type_maj = thiscard->actioncode[0];
241 		dp->top_card = (dp->top_card + 1) % dp->num_cards;
242 	} while (dp->gojf_used && type_maj == GOJF);
243 	type_min = thiscard->actioncode[1];
244 	num = atoi(thiscard->actioncode+2);
245 
246 	printmes(thiscard->text);
247 	switch (type_maj) {
248 	  case '+':		/* get money		*/
249 		if (type_min == 'A') {
250 			for (i = 0; i < num_play; i++)
251 				if (i != player)
252 					play[i].money -= num;
253 			num = num * (num_play - 1);
254 		}
255 		cur_p->money += num;
256 		break;
257 	  case '-':		/* lose 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 'M':		/* move somewhere	*/
267 		switch (type_min) {
268 		  case 'F':		/* move forward	*/
269 			num -= cur_p->loc;
270 			if (num < 0)
271 				num += 40;
272 			break;
273 		  case 'J':		/* move to jail	*/
274 			goto_jail();
275 			return;
276 		  case 'R':		/* move to railroad	*/
277 			spec = TRUE;
278 			num = (int)((cur_p->loc + 5)/10)*10 + 5 - cur_p->loc;
279 			break;
280 		  case 'U':		/* move to utility	*/
281 			spec = TRUE;
282 			if (cur_p->loc >= 12 && cur_p->loc < 28)
283 				num = 28 - cur_p->loc;
284 			else {
285 				num = 12 - cur_p->loc;
286 				if (num < 0)
287 					num += 40;
288 			}
289 			break;
290 		  case 'B':
291 			num = -num;
292 			break;
293 		}
294 		move(num);
295 		break;
296 	  case 'T':			/* tax			*/
297 		if (dp == &CC_D) {
298 			per_h = 40;
299 			per_H = 115;
300 		}
301 		else {
302 			per_h = 25;
303 			per_H = 100;
304 		}
305 		num_h = num_H = 0;
306 		for (op = cur_p->own_list; op; op = op->next)
307 			if (op->sqr->type == PRPTY) {
308 				if (op->sqr->desc->houses == 5)
309 					++num_H;
310 				else
311 					num_h += op->sqr->desc->houses;
312 			}
313 		num = per_h * num_h + per_H * num_H;
314 		printf(
315 		    "You had %d Houses and %d Hotels, so that cost you $%d\n",
316 		    num_h, num_H, num);
317 		if (num == 0)
318 			lucky("");
319 		else
320 			cur_p->money -= num;
321 		break;
322 	  case GOJF:		/* get-out-of-jail-free card	*/
323 		cur_p->num_gojf++;
324 		dp->gojf_used = TRUE;
325 		break;
326 	}
327 	spec = FALSE;
328 }
329 
330 /*
331  *	This routine prints out the message on the card
332  */
333 static void
334 printmes(const char *text)
335 {
336 	int i;
337 
338 	printline();
339 	fflush(stdout);
340 	for (i = 0; text[i] != '\0'; i++)
341 		putchar(text[i]);
342 	printline();
343 	fflush(stdout);
344 }
345 
346 /*
347  *	This routine returns the players get-out-of-jail-free card
348  * to the bottom of a deck.  XXX currently does not return to the correct
349  * deck.
350  */
351 void
352 ret_card(PLAY *plr)
353 {
354 	char type_maj;
355 	int gojfpos, last_card;
356 	int i;
357 	DECK *dp;
358 	int temp;
359 
360 	plr->num_gojf--;
361 	if (CC_D.gojf_used)
362 		dp = &CC_D;
363 	else
364 		dp = &CH_D;
365 	dp->gojf_used = FALSE;
366 
367 	/* Put at bottom of deck (top_card - 1) and remove it from wherever else
368 	 * it used to be.
369 	 */
370 	last_card = dp->top_card - 1;
371 	if (last_card < 0)
372 		last_card += dp->num_cards;
373 	gojfpos = dp->top_card;
374 	do {
375 		gojfpos = (gojfpos + 1) % dp->num_cards;
376 		type_maj = dp->info[gojfpos].actioncode[0];
377 	} while (type_maj != GOJF);
378 	temp = dp->cards[gojfpos];
379 	/* Only one of the next two loops does anything */
380 	for (i = gojfpos - 1; i > last_card; i--)
381 		dp->cards[i + 1] = dp->cards[i];
382 	for (i = gojfpos; i < last_card; i++)
383 		dp->cards[i] = dp->cards[i + 1];
384 	if (gojfpos > last_card) {
385 		dp->cards[dp->top_card] = temp;
386 		dp->top_card++;
387 		dp->top_card %= dp->num_cards;
388 	} else
389 		dp->cards[last_card] = temp;
390 }
391