]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - worm/worm.c
Check for screen sizes that are too small. Fix off-by-one error in
[bsdgames-darwin.git] / worm / worm.c
1 /* $NetBSD: worm.c,v 1.21 2001/08/30 10:49:50 jsm 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. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. 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 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)worm.c 8.1 (Berkeley) 5/31/93";
45 #else
46 __RCSID("$NetBSD: worm.c,v 1.21 2001/08/30 10:49:50 jsm Exp $");
47 #endif
48 #endif /* not lint */
49
50 /*
51 * Worm. Written by Michael Toy
52 * UCSC
53 */
54
55 #include <ctype.h>
56 #include <curses.h>
57 #include <err.h>
58 #include <signal.h>
59 #include <stdlib.h>
60 #include <termios.h>
61 #include <unistd.h>
62
63 #define newlink() (struct body *) malloc(sizeof (struct body));
64 #define HEAD '@'
65 #define BODY 'o'
66 #define LENGTH 7
67 #define RUNLEN 8
68 #define CNTRL(p) (p-'A'+1)
69
70 WINDOW *tv;
71 WINDOW *stw;
72 struct body {
73 int x;
74 int y;
75 struct body *prev;
76 struct body *next;
77 } *head, *tail, goody;
78 int growing = 0;
79 int running = 0;
80 int slow = 0;
81 int score = 0;
82 int start_len = LENGTH;
83 int lastch;
84 char outbuf[BUFSIZ];
85
86 void crash __P((void)) __attribute__((__noreturn__));
87 void display __P((const struct body *, char));
88 int main __P((int, char **));
89 void leave __P((int)) __attribute__((__noreturn__));
90 void life __P((void));
91 void newpos __P((struct body *));
92 void process __P((int));
93 void prize __P((void));
94 int rnd __P((int));
95 void setup __P((void));
96 void wake __P((int));
97
98 int
99 main(argc, argv)
100 int argc;
101 char **argv;
102 {
103
104 /* Revoke setgid privileges */
105 setgid(getgid());
106
107 setbuf(stdout, outbuf);
108 srand(getpid());
109 signal(SIGALRM, wake);
110 signal(SIGINT, leave);
111 signal(SIGQUIT, leave);
112 initscr();
113 crmode();
114 noecho();
115 #ifdef KEY_LEFT
116 keypad(stdscr, TRUE);
117 #endif
118 slow = (baudrate() <= 1200);
119 clear();
120 if (COLS < 18 || LINES < 5) {
121 /*
122 * Insufficient room for the line with " Worm" and the
123 * score if fewer than 18 columns; insufficient room for
124 * anything much if fewer than 5 lines.
125 */
126 endwin();
127 errx(1, "screen too small");
128 }
129 if (argc == 2)
130 start_len = atoi(argv[1]);
131 if ((start_len <= 0) || (start_len > ((LINES-3) * (COLS-2)) / 3))
132 start_len = LENGTH;
133 stw = newwin(1, COLS-1, 0, 0);
134 tv = newwin(LINES-1, COLS-1, 1, 0);
135 box(tv, '*', '*');
136 scrollok(tv, FALSE);
137 scrollok(stw, FALSE);
138 wmove(stw, 0, 0);
139 wprintw(stw, " Worm");
140 refresh();
141 wrefresh(stw);
142 wrefresh(tv);
143 life(); /* Create the worm */
144 prize(); /* Put up a goal */
145 while(1)
146 {
147 if (running)
148 {
149 running--;
150 process(lastch);
151 }
152 else
153 {
154 fflush(stdout);
155 process(getch());
156 }
157 }
158 }
159
160 void
161 life()
162 {
163 struct body *bp, *np;
164 int i, j = 1;
165
166 np = NULL;
167 head = newlink();
168 if (head == NULL)
169 err(1, NULL);
170 head->x = start_len % (COLS-5) + 2;
171 head->y = LINES / 2;
172 head->next = NULL;
173 display(head, HEAD);
174 for (i = 0, bp = head; i < start_len; i++, bp = np) {
175 np = newlink();
176 if (np == NULL)
177 err(1, NULL);
178 np->next = bp;
179 bp->prev = np;
180 if (((bp->x <= 2) && (j == 1)) || ((bp->x >= COLS-4) && (j == -1))) {
181 j *= -1;
182 np->x = bp->x;
183 np->y = bp->y + 1;
184 } else {
185 np->x = bp->x - j;
186 np->y = bp->y;
187 }
188 display(np, BODY);
189 }
190 tail = np;
191 tail->prev = NULL;
192 }
193
194 void
195 display(pos, chr)
196 const struct body *pos;
197 char chr;
198 {
199 wmove(tv, pos->y, pos->x);
200 waddch(tv, chr);
201 }
202
203 void
204 leave(dummy)
205 int dummy;
206 {
207 endwin();
208
209 if (dummy == 0){ /* called via crash() */
210 printf("\nWell, you ran into something and the game is over.\n");
211 printf("Your final score was %d\n\n", score);
212 }
213 exit(0);
214 }
215
216 void
217 wake(dummy)
218 int dummy __attribute__((__unused__));
219 {
220 signal(SIGALRM, wake);
221 fflush(stdout);
222 process(lastch);
223 }
224
225 int
226 rnd(range)
227 int range;
228 {
229 return abs((rand()>>5)+(rand()>>5)) % range;
230 }
231
232 void
233 newpos(bp)
234 struct body * bp;
235 {
236 do {
237 bp->y = rnd(LINES-3)+ 1;
238 bp->x = rnd(COLS-3) + 1;
239 wmove(tv, bp->y, bp->x);
240 } while(winch(tv) != ' ');
241 }
242
243 void
244 prize()
245 {
246 int value;
247
248 value = rnd(9) + 1;
249 newpos(&goody);
250 waddch(tv, value+'0');
251 wrefresh(tv);
252 }
253
254 void
255 process(ch)
256 int ch;
257 {
258 int x,y;
259 struct body *nh;
260
261 alarm(0);
262 x = head->x;
263 y = head->y;
264 switch(ch)
265 {
266 #ifdef KEY_LEFT
267 case KEY_LEFT:
268 #endif
269 case 'h':
270 x--; break;
271
272 #ifdef KEY_DOWN
273 case KEY_DOWN:
274 #endif
275 case 'j':
276 y++; break;
277
278 #ifdef KEY_UP
279 case KEY_UP:
280 #endif
281 case 'k':
282 y--; break;
283
284 #ifdef KEY_RIGHT
285 case KEY_RIGHT:
286 #endif
287 case 'l':
288 x++; break;
289
290 case 'H': x--; running = RUNLEN; ch = tolower(ch); break;
291 case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break;
292 case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break;
293 case 'L': x++; running = RUNLEN; ch = tolower(ch); break;
294 case '\f': setup(); return;
295
296 case ERR:
297 case CNTRL('C'):
298 case CNTRL('D'):
299 crash();
300 return;
301
302 default: if (! running) alarm(1);
303 return;
304 }
305 lastch = ch;
306 if (growing == 0)
307 {
308 display(tail, ' ');
309 tail->next->prev = NULL;
310 nh = tail->next;
311 free(tail);
312 tail = nh;
313 }
314 else growing--;
315 display(head, BODY);
316 wmove(tv, y, x);
317 if (isdigit(ch = winch(tv)))
318 {
319 growing += ch-'0';
320 prize();
321 score += growing;
322 running = 0;
323 wmove(stw, 0, COLS - 12);
324 wprintw(stw, "Score: %3d", score);
325 wrefresh(stw);
326 }
327 else if(ch != ' ') crash();
328 nh = newlink();
329 if (nh == NULL)
330 err(1, NULL);
331 nh->next = NULL;
332 nh->prev = head;
333 head->next = nh;
334 nh->y = y;
335 nh->x = x;
336 display(nh, HEAD);
337 head = nh;
338 if (!(slow && running))
339 {
340 wmove(tv, head->y, head->x);
341 wrefresh(tv);
342 }
343 if (!running)
344 alarm(1);
345 }
346
347 void
348 crash()
349 {
350 leave(0);
351 }
352
353 void
354 setup()
355 {
356 clear();
357 refresh();
358 touchwin(stw);
359 wrefresh(stw);
360 touchwin(tv);
361 wrefresh(tv);
362 alarm(1);
363 }