Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / games / worm / worm.c
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 }