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