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 } 319