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