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