1 /* $NetBSD: worm.c,v 1.23 2001/12/06 12:24:00 blymn Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)worm.c 8.1 (Berkeley) 5/31/93"; 45 #else 46 __RCSID("$NetBSD: worm.c,v 1.23 2001/12/06 12:24:00 blymn Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 /* 51 * Worm. Written by Michael Toy 52 * UCSC 53 */ 54 55 #include <ctype.h> 56 #include <curses.h> 57 #include <err.h> 58 #include <signal.h> 59 #include <stdlib.h> 60 #include <termios.h> 61 #include <unistd.h> 62 63 #define newlink() (struct body *) malloc(sizeof (struct body)); 64 #define HEAD '@' 65 #define BODY 'o' 66 #define LENGTH 7 67 #define RUNLEN 8 68 #define CNTRL(p) (p-'A'+1) 69 70 WINDOW *tv; 71 WINDOW *stw; 72 struct body { 73 int x; 74 int y; 75 struct body *prev; 76 struct body *next; 77 } *head, *tail, goody; 78 int growing = 0; 79 int running = 0; 80 int slow = 0; 81 int score = 0; 82 int start_len = LENGTH; 83 int visible_len; 84 int lastch; 85 char outbuf[BUFSIZ]; 86 87 void crash __P((void)) __attribute__((__noreturn__)); 88 void display __P((const struct body *, char)); 89 int main __P((int, char **)); 90 void leave __P((int)) __attribute__((__noreturn__)); 91 void life __P((void)); 92 void newpos __P((struct body *)); 93 void process __P((int)); 94 void prize __P((void)); 95 int rnd __P((int)); 96 void setup __P((void)); 97 void wake __P((int)); 98 99 int 100 main(argc, argv) 101 int argc; 102 char **argv; 103 { 104 105 /* Revoke setgid privileges */ 106 setgid(getgid()); 107 108 setbuf(stdout, outbuf); 109 srand(getpid()); 110 signal(SIGALRM, wake); 111 signal(SIGINT, leave); 112 signal(SIGQUIT, leave); 113 initscr(); 114 cbreak(); 115 noecho(); 116 #ifdef KEY_LEFT 117 keypad(stdscr, TRUE); 118 #endif 119 slow = (baudrate() <= 1200); 120 clear(); 121 if (COLS < 18 || LINES < 5) { 122 /* 123 * Insufficient room for the line with " Worm" and the 124 * score if fewer than 18 columns; insufficient room for 125 * anything much if fewer than 5 lines. 126 */ 127 endwin(); 128 errx(1, "screen too small"); 129 } 130 if (argc == 2) 131 start_len = atoi(argv[1]); 132 if ((start_len <= 0) || (start_len > ((LINES-3) * (COLS-2)) / 3)) 133 start_len = LENGTH; 134 stw = newwin(1, COLS-1, 0, 0); 135 tv = newwin(LINES-1, COLS-1, 1, 0); 136 box(tv, '*', '*'); 137 scrollok(tv, FALSE); 138 scrollok(stw, FALSE); 139 wmove(stw, 0, 0); 140 wprintw(stw, " Worm"); 141 refresh(); 142 wrefresh(stw); 143 wrefresh(tv); 144 life(); /* Create the worm */ 145 prize(); /* Put up a goal */ 146 while(1) 147 { 148 if (running) 149 { 150 running--; 151 process(lastch); 152 } 153 else 154 { 155 fflush(stdout); 156 process(getch()); 157 } 158 } 159 } 160 161 void 162 life() 163 { 164 struct body *bp, *np; 165 int i, j = 1; 166 167 np = NULL; 168 head = newlink(); 169 if (head == NULL) 170 err(1, NULL); 171 head->x = start_len % (COLS-5) + 2; 172 head->y = LINES / 2; 173 head->next = NULL; 174 display(head, HEAD); 175 for (i = 0, bp = head; i < start_len; i++, bp = np) { 176 np = newlink(); 177 if (np == NULL) 178 err(1, NULL); 179 np->next = bp; 180 bp->prev = np; 181 if (((bp->x <= 2) && (j == 1)) || ((bp->x >= COLS-4) && (j == -1))) { 182 j *= -1; 183 np->x = bp->x; 184 np->y = bp->y + 1; 185 } else { 186 np->x = bp->x - j; 187 np->y = bp->y; 188 } 189 display(np, BODY); 190 } 191 tail = np; 192 tail->prev = NULL; 193 visible_len = start_len + 1; 194 } 195 196 void 197 display(pos, chr) 198 const struct body *pos; 199 char chr; 200 { 201 wmove(tv, pos->y, pos->x); 202 waddch(tv, chr); 203 } 204 205 void 206 leave(dummy) 207 int dummy; 208 { 209 endwin(); 210 211 if (dummy == 0){ /* called via crash() */ 212 printf("\nWell, you ran into something and the game is over.\n"); 213 printf("Your final score was %d\n\n", score); 214 } 215 exit(0); 216 } 217 218 void 219 wake(dummy) 220 int dummy __attribute__((__unused__)); 221 { 222 signal(SIGALRM, wake); 223 fflush(stdout); 224 process(lastch); 225 } 226 227 int 228 rnd(range) 229 int range; 230 { 231 return abs((rand()>>5)+(rand()>>5)) % range; 232 } 233 234 void 235 newpos(bp) 236 struct body * bp; 237 { 238 if (visible_len == (LINES-3) * (COLS-3) - 1) { 239 endwin(); 240 241 printf("\nYou won!\n"); 242 printf("Your final score was %d\n\n", score); 243 exit(0); 244 } 245 do { 246 bp->y = rnd(LINES-3)+ 1; 247 bp->x = rnd(COLS-3) + 1; 248 wmove(tv, bp->y, bp->x); 249 } while(winch(tv) != ' '); 250 } 251 252 void 253 prize() 254 { 255 int value; 256 257 value = rnd(9) + 1; 258 newpos(&goody); 259 waddch(tv, value+'0'); 260 wrefresh(tv); 261 } 262 263 void 264 process(ch) 265 int ch; 266 { 267 int x,y; 268 struct body *nh; 269 270 alarm(0); 271 x = head->x; 272 y = head->y; 273 switch(ch) 274 { 275 #ifdef KEY_LEFT 276 case KEY_LEFT: 277 #endif 278 case 'h': 279 x--; break; 280 281 #ifdef KEY_DOWN 282 case KEY_DOWN: 283 #endif 284 case 'j': 285 y++; break; 286 287 #ifdef KEY_UP 288 case KEY_UP: 289 #endif 290 case 'k': 291 y--; break; 292 293 #ifdef KEY_RIGHT 294 case KEY_RIGHT: 295 #endif 296 case 'l': 297 x++; break; 298 299 case 'H': x--; running = RUNLEN; ch = tolower(ch); break; 300 case 'J': y++; running = RUNLEN/2; ch = tolower(ch); break; 301 case 'K': y--; running = RUNLEN/2; ch = tolower(ch); break; 302 case 'L': x++; running = RUNLEN; ch = tolower(ch); break; 303 case '\f': setup(); return; 304 305 case ERR: 306 case CNTRL('C'): 307 case CNTRL('D'): 308 crash(); 309 return; 310 311 default: if (! running) alarm(1); 312 return; 313 } 314 lastch = ch; 315 if (growing == 0) 316 { 317 display(tail, ' '); 318 tail->next->prev = NULL; 319 nh = tail->next; 320 free(tail); 321 tail = nh; 322 visible_len--; 323 } 324 else growing--; 325 display(head, BODY); 326 wmove(tv, y, x); 327 if (isdigit(ch = winch(tv))) 328 { 329 growing += ch-'0'; 330 prize(); 331 score += growing; 332 running = 0; 333 wmove(stw, 0, COLS - 12); 334 wprintw(stw, "Score: %3d", score); 335 wrefresh(stw); 336 } 337 else if(ch != ' ') crash(); 338 nh = newlink(); 339 if (nh == NULL) 340 err(1, NULL); 341 nh->next = NULL; 342 nh->prev = head; 343 head->next = nh; 344 nh->y = y; 345 nh->x = x; 346 display(nh, HEAD); 347 head = nh; 348 visible_len++; 349 if (!(slow && running)) 350 { 351 wmove(tv, head->y, head->x); 352 wrefresh(tv); 353 } 354 if (!running) 355 alarm(1); 356 } 357 358 void 359 crash() 360 { 361 leave(0); 362 } 363 364 void 365 setup() 366 { 367 clear(); 368 refresh(); 369 touchwin(stw); 370 wrefresh(stw); 371 touchwin(tv); 372 wrefresh(tv); 373 alarm(1); 374 } 375