xref: /openbsd/games/mille/misc.c (revision 4bdff4be)
1 /*	$OpenBSD: misc.c,v 1.14 2023/10/10 09:42:56 tb Exp $	*/
2 /*	$NetBSD: misc.c,v 1.4 1995/03/24 05:01:54 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 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 #include <ctype.h>
34 #include <unistd.h>
35 
36 #include "mille.h"
37 
38 /*
39  * @(#)misc.c	1.2 (Berkeley) 3/28/83
40  */
41 
42 #define	NUMSAFE	4
43 
44 bool
45 error(char *str, ...)
46 {
47 	va_list ap;
48 
49 	va_start(ap, str);
50 	wmove(Score, ERR_Y, ERR_X);
51 	vw_printw(Score, str, ap);
52 	wclrtoeol(Score);
53 	beep();
54 	refresh();
55 	va_end(ap);
56 	return FALSE;
57 }
58 
59 CARD
60 getcard(void)
61 {
62 	int	c, c1;
63 
64 	for (;;) {
65 		while ((c = readch()) == '\n' || c == '\r' || c == ' ')
66 			continue;
67 		if (islower(c))
68 			c = toupper(c);
69 		if (c == killchar() || c == erasechar())
70 			return -1;
71 		addstr(unctrl(c));
72 		clrtoeol();
73 		switch (c) {
74 		  case '1':	case '2':	case '3':
75 		  case '4':	case '5':	case '6':
76 			c -= '0';
77 			break;
78 		  case '0':	case 'P':	case 'p':
79 			c = 0;
80 			break;
81 		  default:
82 			beep();
83 			addch('\b');
84 			if (!isprint(c))
85 				addch('\b');
86 			c = -1;
87 			break;
88 		}
89 		refresh();
90 		if (c >= 0) {
91 			while ((c1 = readch()) != '\r' && c1 != '\n' && c1 != ' ')
92 				if (c1 == killchar())
93 					return -1;
94 				else if (c1 == erasechar()) {
95 					addch('\b');
96 					clrtoeol();
97 					refresh();
98 					goto cont;
99 				}
100 				else
101 					beep();
102 			return c;
103 		}
104 cont:		;
105 	}
106 }
107 
108 int
109 check_ext(bool forcomp)
110 {
111 	if (End == 700) {
112 		if (Play == PLAYER) {
113 			if (getyn(EXTENSIONPROMPT)) {
114 extend:
115 				if (!forcomp)
116 					End = 1000;
117 				return TRUE;
118 			} else {
119 done:
120 				if (!forcomp)
121 					Finished = TRUE;
122 				return FALSE;
123 			}
124 		} else {
125 			PLAY	*pp, *op;
126 			int	i, safe, miles;
127 
128 			pp = &Player[COMP];
129 			op = &Player[PLAYER];
130 			for (safe = 0, i = 0; i < NUMSAFE; i++)
131 				if (pp->safety[i] != S_UNKNOWN)
132 					safe++;
133 			if (safe < 2)
134 				goto done;
135 			if (op->mileage == 0 || onecard(op)
136 			    || (op->can_go && op->mileage >= 500))
137 				goto done;
138 			for (miles = 0, i = 0; i < NUMSAFE; i++)
139 				if (op->safety[i] != S_PLAYED
140 				    && pp->safety[i] == S_UNKNOWN)
141 					miles++;
142 			if (miles + safe == NUMSAFE)
143 				goto extend;
144 			for (miles = 0, i = 0; i < HAND_SZ; i++)
145 				if ((safe = pp->hand[i]) <= C_200)
146 					miles += Value[safe];
147 			if (miles + (Topcard - Deck) * 3 > 1000)
148 				goto extend;
149 			goto done;
150 		}
151 	} else
152 		goto done;
153 }
154 
155 /*
156  *	Get a yes or no answer to the given question.  Saves are
157  * also allowed.  Return TRUE if the answer was yes, FALSE if no.
158  */
159 int
160 getyn(int promptno)
161 {
162 	char	c;
163 
164 	Saved = FALSE;
165 	for (;;) {
166 		leaveok(Board, FALSE);
167 		prompt(promptno);
168 		clrtoeol();
169 		refresh();
170 		switch (c = readch()) {
171 		  case 'n':	case 'N':
172 			addch('N');
173 			refresh();
174 			leaveok(Board, TRUE);
175 			return FALSE;
176 		  case 'y':	case 'Y':
177 			addch('Y');
178 			refresh();
179 			leaveok(Board, TRUE);
180 			return TRUE;
181 		  case 's':	case 'S':
182 			addch('S');
183 			refresh();
184 			Saved = save();
185 			continue;
186 		  case CTRL('L'):
187 			wrefresh(curscr);
188 			break;
189 		  default:
190 			addstr(unctrl(c));
191 			refresh();
192 			beep();
193 			break;
194 		}
195 	}
196 }
197 
198 /*
199  *	Check to see if more games are desired.  If not, and game
200  * came from a saved file, make sure that they don't want to restore
201  * it.  Exit appropriately.
202  */
203 void
204 check_more(void)
205 {
206 	On_exit = TRUE;
207 	if (Player[PLAYER].total >= 5000 || Player[COMP].total >= 5000) {
208 		if (getyn(ANOTHERGAMEPROMPT))
209 			return;
210 		else {
211 			/*
212 			 * must do accounting normally done in main()
213 			 */
214 			if (Player[PLAYER].total > Player[COMP].total)
215 				Player[PLAYER].games++;
216 			else if (Player[PLAYER].total < Player[COMP].total)
217 				Player[COMP].games++;
218 			Player[COMP].total = 0;
219 			Player[PLAYER].total = 0;
220 		}
221 	} else
222 		if (getyn(ANOTHERHANDPROMPT))
223 			return;
224 	if (!Saved && getyn(SAVEGAMEPROMPT))
225 		if (!save())
226 			return;
227 	die(0);
228 }
229 
230 int
231 readch(void)
232 {
233 	int	cnt;
234 	static char	c;
235 
236 	for (cnt = 0; read(STDIN_FILENO, &c, 1) <= 0; cnt++)
237 		if (cnt > 100)
238 			die(1);
239 	return c;
240 }
241