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