1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ed James. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 /* 12 * Copyright (c) 1987 by Ed James, UC Berkeley. All rights reserved. 13 * 14 * Copy permission is hereby granted provided that this notice is 15 * retained on all partial or complete copies. 16 * 17 * For more info on this and all of my stuff, mail edjames@berkeley.edu. 18 */ 19 20 #ifndef lint 21 static char sccsid[] = "@(#)update.c 5.4 (Berkeley) 04/30/90"; 22 #endif not lint 23 24 #include "include.h" 25 26 update() 27 { 28 int i, dir_diff, mask, unclean; 29 PLANE *pp, *p1, *p2, *p; 30 31 #ifdef BSD 32 mask = sigblock(sigmask(SIGINT)); 33 #endif 34 #ifdef SYSV 35 alarm(0); 36 signal(SIGALRM, update); 37 #endif 38 39 clock++; 40 41 erase_all(); 42 43 /* put some planes in the air */ 44 do { 45 unclean = 0; 46 for (pp = ground.head; pp != NULL; pp = pp->next) { 47 if (pp->new_altitude > 0) { 48 delete(&ground, pp); 49 append(&air, pp); 50 unclean = 1; 51 break; 52 } 53 } 54 } while (unclean); 55 56 /* do altitude change and basic movement */ 57 for (pp = air.head; pp != NULL; pp = pp->next) { 58 /* type 0 only move every other turn */ 59 if (pp->plane_type == 0 && clock & 1) 60 continue; 61 62 pp->fuel--; 63 if (pp->fuel < 0) 64 loser(pp, "ran out of fuel."); 65 66 pp->altitude += SGN(pp->new_altitude - pp->altitude); 67 68 if (!pp->delayd) { 69 dir_diff = pp->new_dir - pp->dir; 70 /* 71 * Allow for circle commands 72 */ 73 if (pp->new_dir >= 0 && pp->new_dir < MAXDIR) { 74 if (dir_diff > MAXDIR/2) 75 dir_diff -= MAXDIR; 76 else if (dir_diff < -(MAXDIR/2)) 77 dir_diff += MAXDIR; 78 } 79 if (dir_diff > 2) 80 dir_diff = 2; 81 else if (dir_diff < -2) 82 dir_diff = -2; 83 pp->dir += dir_diff; 84 if (pp->dir >= MAXDIR) 85 pp->dir -= MAXDIR; 86 else if (pp->dir < 0) 87 pp->dir += MAXDIR; 88 } 89 pp->xpos += displacement[pp->dir].dx; 90 pp->ypos += displacement[pp->dir].dy; 91 92 if (pp->delayd && pp->xpos == sp->beacon[pp->delayd_no].x && 93 pp->ypos == sp->beacon[pp->delayd_no].y) { 94 pp->delayd = 0; 95 if (pp->status == S_UNMARKED) 96 pp->status = S_MARKED; 97 } 98 99 switch (pp->dest_type) { 100 case T_AIRPORT: 101 if (pp->xpos == sp->airport[pp->dest_no].x && 102 pp->ypos == sp->airport[pp->dest_no].y && 103 pp->altitude == 0) { 104 if (pp->dir != sp->airport[pp->dest_no].dir) 105 loser(pp, "landed in the wrong direction."); 106 else { 107 pp->status = S_GONE; 108 continue; 109 } 110 } 111 break; 112 case T_EXIT: 113 if (pp->xpos == sp->exit[pp->dest_no].x && 114 pp->ypos == sp->exit[pp->dest_no].y) { 115 if (pp->altitude != 9) 116 loser(pp, "exited at the wrong altitude."); 117 else { 118 pp->status = S_GONE; 119 continue; 120 } 121 } 122 break; 123 default: 124 loser(pp, "has a bizarre destination, get help!"); 125 } 126 if (pp->altitude > 9) 127 /* "this is impossible" */ 128 loser(pp, "exceded flight ceiling."); 129 if (pp->altitude <= 0) { 130 for (i = 0; i < sp->num_airports; i++) 131 if (pp->xpos == sp->airport[i].x && 132 pp->ypos == sp->airport[i].y) { 133 if (pp->dest_type == T_AIRPORT) 134 loser(pp, 135 "landed at the wrong airport."); 136 else 137 loser(pp, 138 "landed instead of exited."); 139 } 140 loser(pp, "crashed on the ground."); 141 } 142 if (pp->xpos < 1 || pp->xpos >= sp->width - 1 || 143 pp->ypos < 1 || pp->ypos >= sp->height - 1) { 144 for (i = 0; i < sp->num_exits; i++) 145 if (pp->xpos == sp->exit[i].x && 146 pp->ypos == sp->exit[i].y) { 147 if (pp->dest_type == T_EXIT) 148 loser(pp, 149 "exited via the wrong exit."); 150 else 151 loser(pp, 152 "exited instead of landed."); 153 } 154 loser(pp, "illegally left the flight arena."); 155 } 156 } 157 158 /* 159 * Traverse the list once, deleting the planes that are gone. 160 */ 161 for (pp = air.head; pp != NULL; pp = p2) { 162 p2 = pp->next; 163 if (pp->status == S_GONE) { 164 safe_planes++; 165 delete(&air, pp); 166 } 167 } 168 169 draw_all(); 170 171 for (p1 = air.head; p1 != NULL; p1 = p1->next) 172 for (p2 = p1->next; p2 != NULL; p2 = p2->next) 173 if (too_close(p1, p2, 1)) { 174 static char buf[80]; 175 176 (void)sprintf(buf, "collided with plane '%c'.", 177 name(p2)); 178 loser(p1, buf); 179 } 180 /* 181 * Check every other update. Actually, only add on even updates. 182 * Otherwise, prop jobs show up *on* entrance. Remember that 183 * we don't update props on odd updates. 184 */ 185 if ((rand() % sp->newplane_time) == 0) 186 addplane(); 187 188 #ifdef BSD 189 sigsetmask(mask); 190 #endif 191 #ifdef SYSV 192 alarm(sp->update_secs); 193 #endif 194 } 195 196 char * 197 command(pp) 198 PLANE *pp; 199 { 200 static char buf[50], *bp, *comm_start; 201 char *index(); 202 203 buf[0] = '\0'; 204 bp = buf; 205 (void)sprintf(bp, "%c%d%c%c%d: ", name(pp), pp->altitude, 206 (pp->fuel < LOWFUEL) ? '*' : ' ', 207 (pp->dest_type == T_AIRPORT) ? 'A' : 'E', pp->dest_no); 208 209 comm_start = bp = index(buf, '\0'); 210 if (pp->altitude == 0) 211 (void)sprintf(bp, "Holding @ A%d", pp->orig_no); 212 else if (pp->new_dir >= MAXDIR || pp->new_dir < 0) 213 strcpy(bp, "Circle"); 214 else if (pp->new_dir != pp->dir) 215 (void)sprintf(bp, "%d", dir_deg(pp->new_dir)); 216 217 bp = index(buf, '\0'); 218 if (pp->delayd) 219 (void)sprintf(bp, " @ B%d", pp->delayd_no); 220 221 bp = index(buf, '\0'); 222 if (*comm_start == '\0' && 223 (pp->status == S_UNMARKED || pp->status == S_IGNORED)) 224 strcpy(bp, "---------"); 225 return (buf); 226 } 227 228 /* char */ 229 name(p) 230 PLANE *p; 231 { 232 if (p->plane_type == 0) 233 return ('A' + p->plane_no); 234 else 235 return ('a' + p->plane_no); 236 } 237 238 number(l) 239 { 240 if (l < 'a' && l > 'z' && l < 'A' && l > 'Z') 241 return (-1); 242 else if (l >= 'a' && l <= 'z') 243 return (l - 'a'); 244 else 245 return (l - 'A'); 246 } 247 248 next_plane() 249 { 250 static int last_plane = -1; 251 PLANE *pp; 252 int found, start_plane = last_plane; 253 254 do { 255 found = 0; 256 last_plane++; 257 if (last_plane >= 26) 258 last_plane = 0; 259 for (pp = air.head; pp != NULL; pp = pp->next) 260 if (pp->plane_no == last_plane) { 261 found++; 262 break; 263 } 264 if (!found) 265 for (pp = ground.head; pp != NULL; pp = pp->next) 266 if (pp->plane_no == last_plane) { 267 found++; 268 break; 269 } 270 } while (found && last_plane != start_plane); 271 if (last_plane == start_plane) 272 return (-1); 273 return (last_plane); 274 } 275 276 addplane() 277 { 278 PLANE p, *pp, *p1; 279 int i, num_starts, close, rnd, rnd2, pnum; 280 281 bzero(&p, sizeof (p)); 282 283 p.status = S_MARKED; 284 p.plane_type = random() % 2; 285 286 num_starts = sp->num_exits + sp->num_airports; 287 rnd = random() % num_starts; 288 289 if (rnd < sp->num_exits) { 290 p.dest_type = T_EXIT; 291 p.dest_no = rnd; 292 } else { 293 p.dest_type = T_AIRPORT; 294 p.dest_no = rnd - sp->num_exits; 295 } 296 297 /* loop until we get a plane not near another */ 298 for (i = 0; i < num_starts; i++) { 299 /* loop till we get a different start point */ 300 while ((rnd2 = random() % num_starts) == rnd) 301 ; 302 if (rnd2 < sp->num_exits) { 303 p.orig_type = T_EXIT; 304 p.orig_no = rnd2; 305 p.xpos = sp->exit[rnd2].x; 306 p.ypos = sp->exit[rnd2].y; 307 p.new_dir = p.dir = sp->exit[rnd2].dir; 308 p.altitude = p.new_altitude = 7; 309 close = 0; 310 for (p1 = air.head; p1 != NULL; p1 = p1->next) 311 if (too_close(p1, &p, 4)) { 312 close++; 313 break; 314 } 315 if (close) 316 continue; 317 } else { 318 p.orig_type = T_AIRPORT; 319 p.orig_no = rnd2 - sp->num_exits; 320 p.xpos = sp->airport[p.orig_no].x; 321 p.ypos = sp->airport[p.orig_no].y; 322 p.new_dir = p.dir = sp->airport[p.orig_no].dir; 323 p.altitude = p.new_altitude = 0; 324 } 325 p.fuel = sp->width + sp->height; 326 break; 327 } 328 if (i >= num_starts) 329 return (-1); 330 pnum = next_plane(); 331 if (pnum < 0) 332 return (-1); 333 p.plane_no = pnum; 334 335 pp = newplane(); 336 bcopy(&p, pp, sizeof (p)); 337 338 if (pp->orig_type == T_AIRPORT) 339 append(&ground, pp); 340 else 341 append(&air, pp); 342 343 return (pp->dest_type); 344 } 345 346 PLANE * 347 findplane(n) 348 { 349 PLANE *pp; 350 351 for (pp = air.head; pp != NULL; pp = pp->next) 352 if (pp->plane_no == n) 353 return (pp); 354 for (pp = ground.head; pp != NULL; pp = pp->next) 355 if (pp->plane_no == n) 356 return (pp); 357 return (NULL); 358 } 359 360 too_close(p1, p2, dist) 361 PLANE *p1, *p2; 362 { 363 if (ABS(p1->altitude - p2->altitude) <= dist && 364 ABS(p1->xpos - p2->xpos) <= dist && ABS(p1->ypos - p2->ypos) <= dist) 365 return (1); 366 else 367 return (0); 368 } 369 370 dir_deg(d) 371 { 372 switch (d) { 373 case 0: return (0); 374 case 1: return (45); 375 case 2: return (90); 376 case 3: return (135); 377 case 4: return (180); 378 case 5: return (225); 379 case 6: return (270); 380 case 7: return (315); 381 default: 382 return (-1); 383 } 384 } 385