xref: /openbsd/games/atc/graphics.c (revision 79af1000)
1 /*	$OpenBSD: graphics.c,v 1.12 2016/08/27 02:02:44 guenther Exp $	*/
2 /*	$NetBSD: graphics.c,v 1.3 1995/03/21 15:04:04 cgd Exp $	*/
3 
4 /*-
5  * Copyright (c) 1990, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Ed James.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 /*
37  * Copyright (c) 1987 by Ed James, UC Berkeley.  All rights reserved.
38  *
39  * Copy permission is hereby granted provided that this notice is
40  * retained on all partial or complete copies.
41  *
42  * For more info on this and all of my stuff, mail edjames@berkeley.edu.
43  */
44 
45 #include <sys/time.h>
46 #include <curses.h>
47 #include <err.h>
48 #include <stdlib.h>
49 
50 #include "def.h"
51 #include "extern.h"
52 
53 #define C_TOPBOTTOM		'-'
54 #define C_LEFTRIGHT		'|'
55 #define C_AIRPORT		'='
56 #define C_LINE			'+'
57 #define C_BACKROUND		'.'
58 #define C_BEACON		'*'
59 #define C_CREDIT		'*'
60 
61 WINDOW	*radar, *cleanradar, *credit, *input, *planes;
62 
63 int
getAChar(void)64 getAChar(void)
65 {
66 	int c;
67 
68 	if ((c = getchar()) == EOF && feof(stdin))
69 		quit(0);
70 	return (c);
71 }
72 
73 void
erase_all(void)74 erase_all(void)
75 {
76 	PLANE	*pp;
77 
78 	for (pp = air.head; pp != NULL; pp = pp->next) {
79 		wmove(cleanradar, pp->ypos, pp->xpos * 2);
80 		wmove(radar, pp->ypos, pp->xpos * 2);
81 		waddch(radar, winch(cleanradar));
82 		wmove(cleanradar, pp->ypos, pp->xpos * 2 + 1);
83 		wmove(radar, pp->ypos, pp->xpos * 2 + 1);
84 		waddch(radar, winch(cleanradar));
85 	}
86 }
87 
88 void
draw_all(void)89 draw_all(void)
90 {
91 	PLANE	*pp;
92 
93 	for (pp = air.head; pp != NULL; pp = pp->next) {
94 		if (pp->status == S_MARKED)
95 			wstandout(radar);
96 		wmove(radar, pp->ypos, pp->xpos * 2);
97 		waddch(radar, name(pp));
98 		waddch(radar, '0' + pp->altitude);
99 		if (pp->status == S_MARKED)
100 			wstandend(radar);
101 	}
102 	wrefresh(radar);
103 	planewin();
104 	wrefresh(input);		/* return cursor */
105 	fflush(stdout);
106 }
107 
108 void
setup_screen(const C_SCREEN * scp)109 setup_screen(const C_SCREEN *scp)
110 {
111 	static char	buffer[BUFSIZ];
112 	int	i, j;
113 	char	str[3];
114 	const char *airstr;
115 
116 	initscr();
117 	/* size of screen depends on chosen game, but we need at least 80
118 	 * columns for "Information area" to work. */
119 	if (LINES < (INPUT_LINES + scp->height) ||
120 	    COLS < (PLANE_COLS + 2 * scp->width) ||
121 	    COLS < 80) {
122 		endwin();
123 		errx(1, "screen too small.");
124 	}
125 	setvbuf(stdout, buffer, _IOFBF, sizeof buffer);
126 	input = newwin(INPUT_LINES, COLS - PLANE_COLS, LINES - INPUT_LINES, 0);
127 	credit = newwin(INPUT_LINES, PLANE_COLS, LINES - INPUT_LINES,
128 		COLS - PLANE_COLS);
129 	planes = newwin(LINES - INPUT_LINES, PLANE_COLS, 0, COLS - PLANE_COLS);
130 
131 	str[2] = '\0';
132 
133 	if (radar != NULL)
134 		delwin(radar);
135 	radar = newwin(scp->height, scp->width * 2, 0, 0);
136 
137 	if (cleanradar != NULL)
138 		delwin(cleanradar);
139 	cleanradar = newwin(scp->height, scp->width * 2, 0, 0);
140 
141 	/* minus one here to prevent a scroll */
142 	for (i = 0; i < PLANE_COLS - 1; i++) {
143 		wmove(credit, 0, i);
144 		waddch(credit, C_CREDIT);
145 		wmove(credit, INPUT_LINES - 1, i);
146 		waddch(credit, C_CREDIT);
147 	}
148 	wmove(credit, INPUT_LINES / 2, 1);
149 	waddstr(credit, AUTHOR_STR);
150 
151 	for (i = 1; i < scp->height - 1; i++) {
152 		for (j = 1; j < scp->width - 1; j++) {
153 			wmove(radar, i, j * 2);
154 			waddch(radar, C_BACKROUND);
155 		}
156 	}
157 
158 	/*
159 	 * Draw the lines first, since people like to draw lines
160 	 * through beacons and exit points.
161 	 */
162 	str[0] = C_LINE;
163 	for (i = 0; i < scp->num_lines; i++) {
164 		str[1] = ' ';
165 		draw_line(radar, scp->line[i].p1.x, scp->line[i].p1.y,
166 			scp->line[i].p2.x, scp->line[i].p2.y, str);
167 	}
168 
169 	str[0] = C_TOPBOTTOM;
170 	str[1] = C_TOPBOTTOM;
171 	wmove(radar, 0, 0);
172 	for (i = 0; i < scp->width - 1; i++)
173 		waddstr(radar, str);
174 	waddch(radar, C_TOPBOTTOM);
175 
176 	str[0] = C_TOPBOTTOM;
177 	str[1] = C_TOPBOTTOM;
178 	wmove(radar, scp->height - 1, 0);
179 	for (i = 0; i < scp->width - 1; i++)
180 		waddstr(radar, str);
181 	waddch(radar, C_TOPBOTTOM);
182 
183 	for (i = 1; i < scp->height - 1; i++) {
184 		wmove(radar, i, 0);
185 		waddch(radar, C_LEFTRIGHT);
186 		wmove(radar, i, (scp->width - 1) * 2);
187 		waddch(radar, C_LEFTRIGHT);
188 	}
189 
190 	str[0] = C_BEACON;
191 	for (i = 0; i < scp->num_beacons; i++) {
192 		str[1] = '0' + i;
193 		wmove(radar, scp->beacon[i].y, scp->beacon[i].x * 2);
194 		waddstr(radar, str);
195 	}
196 
197 	for (i = 0; i < scp->num_exits; i++) {
198 		wmove(radar, scp->exit[i].y, scp->exit[i].x * 2);
199 		waddch(radar, '0' + i);
200 	}
201 
202 	airstr = "^?>?v?<?";
203 	for (i = 0; i < scp->num_airports; i++) {
204 		str[0] = airstr[scp->airport[i].dir];
205 		str[1] = '0' + i;
206 		wmove(radar, scp->airport[i].y, scp->airport[i].x * 2);
207 		waddstr(radar, str);
208 	}
209 
210 	overwrite(radar, cleanradar);
211 	wrefresh(radar);
212 	wrefresh(credit);
213 	fflush(stdout);
214 }
215 
216 void
draw_line(WINDOW * w,int x,int y,int lx,int ly,const char * s)217 draw_line(WINDOW *w, int x, int y, int lx, int ly, const char *s)
218 {
219 	int	dx, dy;
220 
221 	dx = SGN(lx - x);
222 	dy = SGN(ly - y);
223 	for (;;) {
224 		wmove(w, y, x * 2);
225 		waddstr(w, s);
226 		if (x == lx && y == ly)
227 			break;
228 		x += dx;
229 		y += dy;
230 	}
231 }
232 
233 void
ioclrtoeol(int pos)234 ioclrtoeol(int pos)
235 {
236 	wmove(input, 0, pos);
237 	wclrtoeol(input);
238 	wrefresh(input);
239 	fflush(stdout);
240 }
241 
242 void
iomove(int pos)243 iomove(int pos)
244 {
245 	wmove(input, 0, pos);
246 	wrefresh(input);
247 	fflush(stdout);
248 }
249 
250 void
ioaddstr(int pos,const char * str)251 ioaddstr(int pos, const char *str)
252 {
253 	wmove(input, 0, pos);
254 	waddstr(input, str);
255 	wrefresh(input);
256 	fflush(stdout);
257 }
258 
259 void
ioclrtobot(void)260 ioclrtobot(void)
261 {
262 	wclrtobot(input);
263 	wrefresh(input);
264 	fflush(stdout);
265 }
266 
267 void
ioerror(int pos,int len,const char * str)268 ioerror(int pos, int len, const char *str)
269 {
270 	int	i;
271 
272 	wmove(input, 1, pos);
273 	for (i = 0; i < len; i++)
274 		waddch(input, '^');
275 	wmove(input, 2, 0);
276 	waddstr(input, str);
277 	wrefresh(input);
278 	fflush(stdout);
279 }
280 
281 void
quit(int dummy)282 quit(int dummy)
283 {
284 	int			c, y, x;
285 	struct itimerval	itv;
286 
287 	getyx(input, y, x);
288 	wmove(input, 2, 0);
289 	waddstr(input, "Really quit? (y/n) ");
290 	wclrtobot(input);
291 	wrefresh(input);
292 	fflush(stdout);
293 
294 	c = getchar();
295 	if (c == EOF || c == 'y') {
296 		/* disable timer */
297 		itv.it_value.tv_sec = 0;
298 		itv.it_value.tv_usec = 0;
299 		setitimer(ITIMER_REAL, &itv, NULL);
300 		fflush(stdout);
301 		clear();
302 		refresh();
303 		endwin();
304 		log_score(0);
305 		exit(0);
306 	}
307 	wmove(input, 2, 0);
308 	wclrtobot(input);
309 	wmove(input, y, x);
310 	wrefresh(input);
311 	fflush(stdout);
312 }
313 
314 void
planewin(void)315 planewin(void)
316 {
317 	PLANE	*pp;
318 	int	warning = 0;
319 
320 	wclear(planes);
321 
322 	wmove(planes, 0,0);
323 
324 	wprintw(planes, "Time: %-4d Safe: %d", clck, safe_planes);
325 	wmove(planes, 2, 0);
326 
327 	waddstr(planes, "pl dt  comm");
328 	for (pp = air.head; pp != NULL; pp = pp->next) {
329 		if (waddch(planes, '\n') == ERR) {
330 			warning++;
331 			break;
332 		}
333 		waddstr(planes, command(pp));
334 	}
335 	waddch(planes, '\n');
336 	for (pp = ground.head; pp != NULL; pp = pp->next) {
337 		if (waddch(planes, '\n') == ERR) {
338 			warning++;
339 			break;
340 		}
341 		waddstr(planes, command(pp));
342 	}
343 	if (warning) {
344 		wmove(planes, LINES - INPUT_LINES - 1, 0);
345 		waddstr(planes, "---- more ----");
346 		wclrtoeol(planes);
347 	}
348 	wrefresh(planes);
349 	fflush(stdout);
350 }
351 
352 void
loser(const PLANE * p,const char * s)353 loser(const PLANE *p, const char *s)
354 {
355 	int			c;
356 	struct itimerval	itv;
357 
358 	/* disable timer */
359 	itv.it_value.tv_sec = 0;
360 	itv.it_value.tv_usec = 0;
361 	setitimer(ITIMER_REAL, &itv, NULL);
362 
363 	wmove(input, 0, 0);
364 	wclrtobot(input);
365 	if (p == NULL)
366 		wprintw(input, "%s\n\nHit space for top players list...", s);
367 	else
368 		wprintw(input, "Plane '%c' %s\n\nHit space for top players list...",
369 			name(p), s);
370 	wrefresh(input);
371 	fflush(stdout);
372 	while ((c = getchar()) != EOF && c != ' ')
373 		;
374 	clear();	/* move to top of screen */
375 	refresh();
376 	endwin();
377 	log_score(0);
378 	exit(0);
379 }
380 
381 void
redraw(void)382 redraw(void)
383 {
384 	clear();
385 	refresh();
386 
387 	touchwin(radar);
388 	wrefresh(radar);
389 	touchwin(planes);
390 	wrefresh(planes);
391 	touchwin(credit);
392 	wrefresh(credit);
393 
394 	/* refresh input last to get cursor in right place */
395 	touchwin(input);
396 	wrefresh(input);
397 	fflush(stdout);
398 }
399 
400 void
done_screen(void)401 done_screen(void)
402 {
403 	clear();
404 	refresh();
405 	endwin();	  /* clean up curses */
406 }
407