xref: /dragonfly/games/worm/worm.c (revision 8164c1fe)
1 /*
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#) Copyright (c) 1980, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)worm.c	8.1 (Berkeley) 5/31/93
35  * $FreeBSD: src/games/worm/worm.c,v 1.9 1999/12/07 02:01:27 billf Exp $
36  * $DragonFly: src/games/worm/worm.c,v 1.4 2005/03/15 20:53:40 dillon Exp $
37  */
38 
39 /*
40  * Worm.  Written by Michael Toy
41  * UCSC
42  */
43 
44 #include <ctype.h>
45 #include <curses.h>
46 #include <signal.h>
47 #include <stdlib.h>
48 #include <termios.h>
49 #include <unistd.h>
50 
51 #define newlink() (struct body *) malloc(sizeof (struct body));
52 #define HEAD '@'
53 #define BODY 'o'
54 #define LENGTH 7
55 #define RUNLEN 8
56 #define CNTRL(p) (p-'A'+1)
57 #if 0
58 #ifndef baudrate
59 # define	baudrate()	_tty.sg_ospeed
60 #endif
61 #endif
62 
63 WINDOW *tv;
64 WINDOW *stw;
65 struct body {
66 	int x;
67 	int y;
68 	struct body *prev;
69 	struct body *next;
70 } *head, *tail, goody;
71 int growing = 0;
72 int running = 0;
73 int slow = 0;
74 int score = 0;
75 int start_len = LENGTH;
76 char lastch;
77 char outbuf[BUFSIZ];
78 
79 void crash (void);
80 void display (struct body *, char);
81 void leave (int);
82 void life (void);
83 void newpos (struct body *);
84 void prize (void);
85 void process (char);
86 long rnd (int);
87 void setup (void);
88 void suspend (int);
89 void wake (int);
90 
91 int
92 main(int argc, char **argv)
93 {
94 	char ch;
95 
96 	/* revoke */
97 	setgid(getgid());
98 
99 	if (argc == 2)
100 		start_len = atoi(argv[1]);
101 	if ((start_len <= 0) || (start_len > 500))
102 		start_len = LENGTH;
103 	setbuf(stdout, outbuf);
104 	srandomdev();
105 	signal(SIGALRM, wake);
106 	signal(SIGINT, leave);
107 	signal(SIGQUIT, leave);
108 	signal(SIGTSTP, suspend);	/* process control signal */
109 	initscr();
110 	crmode();
111 	noecho();
112 	slow = (baudrate() <= B1200);
113 	clear();
114 	stw = newwin(1, COLS-1, 0, 0);
115 	tv = newwin(LINES-1, COLS-1, 1, 0);
116 	box(tv, '*', '*');
117 	scrollok(tv, FALSE);
118 	scrollok(stw, FALSE);
119 	wmove(stw, 0, 0);
120 	wprintw(stw, " Worm");
121 	refresh();
122 	wrefresh(stw);
123 	wrefresh(tv);
124 	life();			/* Create the worm */
125 	prize();		/* Put up a goal */
126 	while(1)
127 	{
128 		if (running)
129 		{
130 			running--;
131 			process(lastch);
132 		}
133 		else
134 		{
135 		    fflush(stdout);
136 		    if (read(0, &ch, 1) >= 0)
137 			process(ch);
138 		}
139 	}
140 }
141 
142 void
143 life()
144 {
145 	struct body *bp, *np;
146 	int i;
147 
148 	np = NULL;
149 	head = newlink();
150 	head->x = start_len+2;
151 	head->y = 12;
152 	head->next = NULL;
153 	display(head, HEAD);
154 	for (i = 0, bp = head; i < start_len; i++, bp = np) {
155 		np = newlink();
156 		np->next = bp;
157 		bp->prev = np;
158 		np->x = bp->x - 1;
159 		np->y = bp->y;
160 		display(np, BODY);
161 	}
162 	tail = np;
163 	tail->prev = NULL;
164 }
165 
166 void
167 display(pos, chr)
168 struct body *pos;
169 char chr;
170 {
171 	wmove(tv, pos->y, pos->x);
172 	waddch(tv, chr);
173 }
174 
175 void
176 leave(__unused int sig)
177 {
178 	endwin();
179 	exit(0);
180 }
181 
182 void
183 wake(__unused int sig)
184 {
185 	signal(SIGALRM, wake);
186 	fflush(stdout);
187 	process(lastch);
188 }
189 
190 long
191 rnd(int range)
192 {
193 	return random() % range;
194 }
195 
196 void
197 newpos(bp)
198 struct body * bp;
199 {
200 	do {
201 		bp->y = rnd(LINES-3)+ 2;
202 		bp->x = rnd(COLS-3) + 1;
203 		wmove(tv, bp->y, bp->x);
204 	} while(winch(tv) != ' ');
205 }
206 
207 void
208 prize()
209 {
210 	int value;
211 
212 	value = rnd(9) + 1;
213 	newpos(&goody);
214 	waddch(tv, value+'0');
215 	wrefresh(tv);
216 }
217 
218 void
219 process(ch)
220 char ch;
221 {
222 	int x,y;
223 	struct body *nh;
224 
225 	alarm(0);
226 	x = head->x;
227 	y = head->y;
228 	switch(ch)
229 	{
230 		case 'h': x--; break;
231 		case 'j': y++; break;
232 		case 'k': y--; break;
233 		case 'l': x++; break;
234 		case 'H': x--; running = RUNLEN; ch = tolower(ch); break;
235 		case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break;
236 		case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break;
237 		case 'L': x++; running = RUNLEN; ch = tolower(ch); break;
238 		case '\f': setup(); return;
239 		case CNTRL('Z'): suspend(0); return;
240 		case CNTRL('C'): crash(); return;
241 		case CNTRL('D'): crash(); return;
242 		default: if (! running) alarm(1);
243 			   return;
244 	}
245 	lastch = ch;
246 	if (growing == 0)
247 	{
248 		display(tail, ' ');
249 		tail->next->prev = NULL;
250 		nh = tail->next;
251 		free(tail);
252 		tail = nh;
253 	}
254 	else growing--;
255 	display(head, BODY);
256 	wmove(tv, y, x);
257 	if (isdigit(ch = winch(tv)))
258 	{
259 		growing += ch-'0';
260 		prize();
261 		score += growing;
262 		running = 0;
263 		wmove(stw, 0, 68);
264 		wprintw(stw, "Score: %3d", score);
265 		wrefresh(stw);
266 	}
267 	else if(ch != ' ') crash();
268 	nh = newlink();
269 	nh->next = NULL;
270 	nh->prev = head;
271 	head->next = nh;
272 	nh->y = y;
273 	nh->x = x;
274 	display(nh, HEAD);
275 	head = nh;
276 	if (!(slow && running))
277 		wrefresh(tv);
278 	if (!running)
279 		alarm(1);
280 }
281 
282 void
283 crash(void)
284 {
285 	sleep(2);
286 	clear();
287 	move(23, 0);
288 	refresh();
289 	printf("Well, you ran into something and the game is over.\n");
290 	printf("Your final score was %d\n", score);
291 	leave(0);
292 }
293 
294 void
295 suspend(__unused int sig)
296 {
297 	move(LINES-1, 0);
298 	refresh();
299 	endwin();
300 	fflush(stdout);
301 	kill(getpid(), SIGTSTP);
302 	signal(SIGTSTP, suspend);
303 	crmode();
304 	noecho();
305 	setup();
306 }
307 
308 void
309 setup(void)
310 {
311 	clear();
312 	refresh();
313 	touchwin(stw);
314 	wrefresh(stw);
315 	touchwin(tv);
316 	wrefresh(tv);
317 	alarm(1);
318 }
319