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