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