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