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