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.3 2003/11/12 14:53:54 eirikn 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(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 } 324