src/games WARNS 6 cleanups.
[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.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 }