worm.c revision 1.6 1 /* $NetBSD: worm.c,v 1.6 1995/04/24 12:26:16 cgd 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 #ifndef lint
37 static char copyright[] =
38 "@(#) 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 static char rcsid[] = "$NetBSD: worm.c,v 1.6 1995/04/24 12:26:16 cgd 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 <signal.h>
58 #include <stdlib.h>
59 #include <termios.h>
60
61 #define newlink() (struct body *) malloc(sizeof (struct body));
62 #define HEAD '@'
63 #define BODY 'o'
64 #define LENGTH 7
65 #define RUNLEN 8
66 #define CNTRL(p) (p-'A'+1)
67 #ifndef baudrate
68 # define baudrate() _tty.sg_ospeed
69 #endif
70
71 WINDOW *tv;
72 WINDOW *stw;
73 struct body {
74 int x;
75 int y;
76 struct body *prev;
77 struct body *next;
78 } *head, *tail, goody;
79 int growing = 0;
80 int running = 0;
81 int slow = 0;
82 int score = 0;
83 int start_len = LENGTH;
84 char lastch;
85 char outbuf[BUFSIZ];
86
87 void leave(), wake(), suspend();
88
89 main(argc, argv)
90 int argc;
91 char **argv;
92 {
93 char ch;
94
95 if (argc == 2)
96 start_len = atoi(argv[1]);
97 if ((start_len <= 0) || (start_len > 500))
98 start_len = LENGTH;
99 setbuf(stdout, outbuf);
100 srand(getpid());
101 signal(SIGALRM, wake);
102 signal(SIGINT, leave);
103 signal(SIGQUIT, leave);
104 signal(SIGTSTP, suspend); /* process control signal */
105 initscr();
106 crmode();
107 noecho();
108 slow = (baudrate() <= 1200);
109 clear();
110 stw = newwin(1, COLS-1, 0, 0);
111 tv = newwin(LINES-1, COLS-1, 1, 0);
112 box(tv, '*', '*');
113 scrollok(tv, FALSE);
114 scrollok(stw, FALSE);
115 wmove(stw, 0, 0);
116 wprintw(stw, " Worm");
117 refresh();
118 wrefresh(stw);
119 wrefresh(tv);
120 life(); /* Create the worm */
121 prize(); /* Put up a goal */
122 while(1)
123 {
124 if (running)
125 {
126 running--;
127 process(lastch);
128 }
129 else
130 {
131 fflush(stdout);
132 if (read(0, &ch, 1) >= 0)
133 process(ch);
134 }
135 }
136 }
137
138 life()
139 {
140 register struct body *bp, *np;
141 register int i;
142
143 head = newlink();
144 head->x = start_len+2;
145 head->y = 12;
146 head->next = NULL;
147 display(head, HEAD);
148 for (i = 0, bp = head; i < start_len; i++, bp = np) {
149 np = newlink();
150 np->next = bp;
151 bp->prev = np;
152 np->x = bp->x - 1;
153 np->y = bp->y;
154 display(np, BODY);
155 }
156 tail = np;
157 tail->prev = NULL;
158 }
159
160 display(pos, chr)
161 struct body *pos;
162 char chr;
163 {
164 wmove(tv, pos->y, pos->x);
165 waddch(tv, chr);
166 }
167
168 void
169 leave()
170 {
171 endwin();
172 exit(0);
173 }
174
175 void
176 wake()
177 {
178 signal(SIGALRM, wake);
179 fflush(stdout);
180 process(lastch);
181 }
182
183 rnd(range)
184 {
185 return abs((rand()>>5)+(rand()>>5)) % range;
186 }
187
188 newpos(bp)
189 struct body * bp;
190 {
191 do {
192 bp->y = rnd(LINES-3)+ 2;
193 bp->x = rnd(COLS-3) + 1;
194 wmove(tv, bp->y, bp->x);
195 } while(winch(tv) != ' ');
196 }
197
198 prize()
199 {
200 int value;
201
202 value = rnd(9) + 1;
203 newpos(&goody);
204 waddch(tv, value+'0');
205 wrefresh(tv);
206 }
207
208 process(ch)
209 char ch;
210 {
211 register int x,y;
212 struct body *nh;
213
214 alarm(0);
215 x = head->x;
216 y = head->y;
217 switch(ch)
218 {
219 case 'h': x--; break;
220 case 'j': y++; break;
221 case 'k': y--; break;
222 case 'l': x++; break;
223 case 'H': x--; running = RUNLEN; ch = tolower(ch); break;
224 case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break;
225 case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break;
226 case 'L': x++; running = RUNLEN; ch = tolower(ch); break;
227 case '\f': setup(); return;
228 case CNTRL('Z'): suspend(); return;
229 case CNTRL('C'): crash(); return;
230 case CNTRL('D'): crash(); return;
231 default: if (! running) alarm(1);
232 return;
233 }
234 lastch = ch;
235 if (growing == 0)
236 {
237 display(tail, ' ');
238 tail->next->prev = NULL;
239 nh = tail->next;
240 free(tail);
241 tail = nh;
242 }
243 else growing--;
244 display(head, BODY);
245 wmove(tv, y, x);
246 if (isdigit(ch = winch(tv)))
247 {
248 growing += ch-'0';
249 prize();
250 score += growing;
251 running = 0;
252 wmove(stw, 0, 68);
253 wprintw(stw, "Score: %3d", score);
254 wrefresh(stw);
255 }
256 else if(ch != ' ') crash();
257 nh = newlink();
258 nh->next = NULL;
259 nh->prev = head;
260 head->next = nh;
261 nh->y = y;
262 nh->x = x;
263 display(nh, HEAD);
264 head = nh;
265 if (!(slow && running))
266 wrefresh(tv);
267 if (!running)
268 alarm(1);
269 }
270
271 crash()
272 {
273 sleep(2);
274 clear();
275 move(23, 0);
276 refresh();
277 printf("Well, you ran into something and the game is over.\n");
278 printf("Your final score was %d\n", score);
279 leave();
280 }
281
282 void
283 suspend()
284 {
285 char *sh;
286
287 move(LINES-1, 0);
288 refresh();
289 endwin();
290 fflush(stdout);
291 kill(getpid(), SIGTSTP);
292 signal(SIGTSTP, suspend);
293 crmode();
294 noecho();
295 setup();
296 }
297
298 setup()
299 {
300 clear();
301 refresh();
302 touchwin(stw);
303 wrefresh(stw);
304 touchwin(tv);
305 wrefresh(tv);
306 alarm(1);
307 }
308