Commit | Line | Data |
---|---|---|
e04f5cf8 KB |
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 | ||
516f5c21 KB |
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 | |
e04f5cf8 | 21 | static char sccsid[] = "@(#)update.c 5.4 (Berkeley) %G%"; |
516f5c21 KB |
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 | ||
0071b083 | 176 | (void)sprintf(buf, "collided with plane '%c'.", |
516f5c21 KB |
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; | |
ff3cd131 | 201 | char *index(); |
516f5c21 KB |
202 | |
203 | buf[0] = '\0'; | |
204 | bp = buf; | |
0071b083 | 205 | (void)sprintf(bp, "%c%d%c%c%d: ", name(pp), pp->altitude, |
516f5c21 KB |
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) | |
0071b083 | 211 | (void)sprintf(bp, "Holding @ A%d", pp->orig_no); |
516f5c21 KB |
212 | else if (pp->new_dir >= MAXDIR || pp->new_dir < 0) |
213 | strcpy(bp, "Circle"); | |
214 | else if (pp->new_dir != pp->dir) | |
0071b083 | 215 | (void)sprintf(bp, "%d", dir_deg(pp->new_dir)); |
516f5c21 KB |
216 | |
217 | bp = index(buf, '\0'); | |
218 | if (pp->delayd) | |
0071b083 | 219 | (void)sprintf(bp, " @ B%d", pp->delayd_no); |
516f5c21 KB |
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 | } |