]> cvs.zerfleddert.de Git - micropolis/blob - src/sim/w_sprite.c
705bf28085b5950e0b9531bfa7f01daccb567c32
[micropolis] / src / sim / w_sprite.c
1 /* w_sprite.c
2 *
3 * Micropolis, Unix Version. This game was released for the Unix platform
4 * in or about 1990 and has been modified for inclusion in the One Laptop
5 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6 * you need assistance with this program, you may contact:
7 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. You should have received a
18 * copy of the GNU General Public License along with this program. If
19 * not, see <http://www.gnu.org/licenses/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
23 * No trademark or publicity rights are granted. This license does NOT
24 * give you any right, title or interest in the trademark SimCity or any
25 * other Electronic Arts trademark. You may not distribute any
26 * modification of this program using the trademark SimCity or claim any
27 * affliation or association with Electronic Arts Inc. or its employees.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
32 * If you convey this program (or any modifications of it) and assume
33 * contractual liability for the program to recipients of it, you agree
34 * to indemnify Electronic Arts for any liability that those contractual
35 * assumptions impose on Electronic Arts.
36 *
37 * You may not misrepresent the origins of this program; modified
38 * versions of the program must be marked as such and not identified as
39 * the original program.
40 *
41 * This disclaimer supplements the one included in the General Public
42 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60 * NOT APPLY TO YOU.
61 */
62 #include "sim.h"
63
64
65 Tcl_HashTable SpriteCmds;
66 short CrashX, CrashY;
67 int absDist;
68 short Cycle;
69
70 SimSprite *GlobalSprites[OBJN];
71
72 SimSprite *NewSprite(char *name, int type, int x, int y);
73 void MonsterHere(int x, int y);
74 void MakeShipHere(int x, int y);
75 void StartFire(int x, int y);
76 void OFireZone(int Xloc, int Yloc, int ch);
77 void Destroy(int ox, int oy);
78 void ExplodeSprite(SimSprite *sprite);
79 int CanDriveOn(int x, int y);
80 void DoBusSprite(SimSprite *sprite);
81 void DoExplosionSprite(SimSprite *sprite);
82 void DoTornadoSprite(SimSprite *sprite);
83 void DoMonsterSprite(SimSprite *sprite);
84 void DoShipSprite(SimSprite *sprite);
85 void DoAirplaneSprite(SimSprite *sprite);
86 void DoCopterSprite(SimSprite *sprite);
87 void DoTrainSprite(SimSprite *sprite);
88 void DrawSprite(SimView *view, SimSprite *sprite);
89 void InitSprite(SimSprite *sprite, int x, int y);
90
91
92 #define TRA_GROOVE_X -39
93 #define TRA_GROOVE_Y 6
94 #define BUS_GROOVE_X -39
95 #define BUS_GROOVE_Y 6
96
97 #define SPRITECMD_ACCESS_INT(var) \
98 int SpriteCmd##var(SPRITE_ARGS) { \
99 int val; \
100 if ((argc != 2) && (argc != 3)) return (TCL_ERROR); \
101 if (argc == 3) { \
102 if (Tcl_GetInt(interp, argv[2], &val) != TCL_OK) return (TCL_ERROR); \
103 sprite->var = val; \
104 } \
105 sprintf(interp->result, "%d", sprite->var); \
106 return (TCL_OK); \
107 }
108
109
110 #define SPRITECMD_GET_STR(var) \
111 int SpriteCmd##var(SPRITE_ARGS) { \
112 sprintf(interp->result, "%s", sprite->var); \
113 return (TCL_OK); \
114 }
115
116
117 int
118 DoSpriteCmd(CLIENT_ARGS)
119 {
120 SimSprite *sprite = (SimSprite *) clientData;
121 Tcl_HashEntry *ent;
122 int result = TCL_OK;
123 int (*cmd)();
124
125 if (argc < 2) {
126 return TCL_ERROR;
127 }
128
129 if ((ent = Tcl_FindHashEntry(&SpriteCmds, argv[1]))) {
130 cmd = (int (*)())ent->clientData;
131 Tk_Preserve((ClientData) sprite);
132 result = cmd(sprite, interp, argc, argv);
133 Tk_Release((ClientData) sprite);
134 } else {
135 Tcl_AppendResult(interp, "unknown command name: \"",
136 argv[0], " ", argv[1], "\".", (char *) NULL);
137 result = TCL_ERROR;
138 }
139 return result;
140 }
141
142
143 int
144 SpriteCmd(CLIENT_ARGS)
145 {
146 SimSprite *sprite;
147 int type;
148
149 if ((argc != 3) ||
150 (Tcl_GetInt(interp, argv[2], &type) != TCL_OK) ||
151 (type < 1) || (type >= OBJN)) {
152 return TCL_ERROR;
153 }
154
155 sprite = NewSprite(argv[1], type, 0, 0);
156 sprite->frame = 0;
157
158 Tcl_CreateCommand(interp, sprite->name,
159 DoSpriteCmd, (ClientData) sprite, (void (*)()) NULL);
160
161 interp->result = sprite->name;
162 return TCL_OK;
163 }
164
165
166 SPRITECMD_GET_STR(name)
167 SPRITECMD_ACCESS_INT(type)
168 SPRITECMD_ACCESS_INT(frame)
169 SPRITECMD_ACCESS_INT(x)
170 SPRITECMD_ACCESS_INT(y)
171 SPRITECMD_ACCESS_INT(width)
172 SPRITECMD_ACCESS_INT(height)
173 SPRITECMD_ACCESS_INT(x_offset)
174 SPRITECMD_ACCESS_INT(y_offset)
175 SPRITECMD_ACCESS_INT(x_hot)
176 SPRITECMD_ACCESS_INT(y_hot)
177 SPRITECMD_ACCESS_INT(orig_x)
178 SPRITECMD_ACCESS_INT(orig_y)
179 SPRITECMD_ACCESS_INT(dest_x)
180 SPRITECMD_ACCESS_INT(dest_y)
181 SPRITECMD_ACCESS_INT(count)
182 SPRITECMD_ACCESS_INT(sound_count)
183 SPRITECMD_ACCESS_INT(dir)
184 SPRITECMD_ACCESS_INT(new_dir)
185 SPRITECMD_ACCESS_INT(step)
186 SPRITECMD_ACCESS_INT(flag)
187 SPRITECMD_ACCESS_INT(control)
188 SPRITECMD_ACCESS_INT(turn)
189 SPRITECMD_ACCESS_INT(accel)
190 SPRITECMD_ACCESS_INT(speed)
191
192
193 int SpriteCmdExplode(SPRITE_ARGS)
194 {
195 ExplodeSprite(sprite);
196 return TCL_OK;
197 }
198
199
200 int SpriteCmdInit(SPRITE_ARGS)
201 {
202 int x, y;
203
204 if (argc != 4) {
205 return (TCL_ERROR);
206 }
207 if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK) ||
208 (x < 0) || (x >= (WORLD_X <<4)) ||
209 (Tcl_GetInt(interp, argv[3], &y) != TCL_OK) ||
210 (y < 0) || (y >= (WORLD_Y <<4))) {
211 return (TCL_ERROR);
212 }
213 InitSprite(sprite, x, y);
214 return TCL_OK;
215 }
216
217
218 void
219 sprite_command_init(void)
220 {
221 int i;
222
223 Tcl_CreateCommand(tk_mainInterp, "sprite", SpriteCmd,
224 (ClientData)NULL, (void (*)()) NULL);
225
226 Tcl_InitHashTable(&SpriteCmds, TCL_STRING_KEYS);
227
228 #define SPRITE_CMD(cmd) HASHED_CMD(Sprite, cmd)
229
230 SPRITE_CMD(name);
231 SPRITE_CMD(type);
232 SPRITE_CMD(frame);
233 SPRITE_CMD(x);
234 SPRITE_CMD(y);
235 SPRITE_CMD(width);
236 SPRITE_CMD(height);
237 SPRITE_CMD(x_offset);
238 SPRITE_CMD(y_offset);
239 SPRITE_CMD(x_hot);
240 SPRITE_CMD(y_hot);
241 SPRITE_CMD(orig_x);
242 SPRITE_CMD(orig_y);
243 SPRITE_CMD(dest_x);
244 SPRITE_CMD(dest_y);
245 SPRITE_CMD(count);
246 SPRITE_CMD(sound_count);
247 SPRITE_CMD(dir);
248 SPRITE_CMD(new_dir);
249 SPRITE_CMD(step);
250 SPRITE_CMD(flag);
251 SPRITE_CMD(control);
252 SPRITE_CMD(turn);
253 SPRITE_CMD(accel);
254 SPRITE_CMD(speed);
255 SPRITE_CMD(Explode);
256 SPRITE_CMD(Init);
257
258 for (i = 0; i < OBJN; i++) {
259 GlobalSprites[i] = NULL;
260 }
261 }
262
263
264 SimSprite *FreeSprites = NULL;
265
266 SimSprite *
267 NewSprite(char *name, int type, int x, int y)
268 {
269 SimSprite *sprite;
270
271 if (FreeSprites) {
272 sprite = FreeSprites;
273 FreeSprites = sprite->next;
274 } else {
275 sprite = (SimSprite *)ckalloc(sizeof (SimSprite));
276 }
277
278 sprite->name = (char *)ckalloc(strlen(name) + 1);
279 strcpy(sprite->name, name);
280 sprite->type = type;
281
282 InitSprite(sprite, x, y);
283
284 sim->sprites++; sprite->next = sim->sprite; sim->sprite = sprite;
285
286 return sprite;
287 }
288
289
290 void
291 InitSprite(SimSprite *sprite, int x, int y)
292 {
293 sprite->x = x; sprite->y = y;
294 sprite->frame = 0;
295 sprite->orig_x = sprite->orig_y = 0;
296 sprite->dest_x = sprite->dest_y = 0;
297 sprite->count = sprite->sound_count = 0;
298 sprite->dir = sprite->new_dir = 0;
299 sprite->step = sprite->flag = 0;
300 sprite->control = -1;
301 sprite->turn = 0;
302 sprite->accel = 0;
303 sprite->speed = 100;
304
305 if (GlobalSprites[sprite->type] == NULL) {
306 GlobalSprites[sprite->type] = sprite;
307 }
308
309 switch (sprite->type) {
310
311 case TRA:
312 sprite->width = sprite->height = 32;
313 sprite->x_offset = 32; sprite->y_offset = -16;
314 sprite->x_hot = 40; sprite->y_hot = -8;
315 sprite->frame = 1;
316 sprite->dir = 4;
317 break;
318
319 case SHI:
320 sprite->width = sprite->height = 48;
321 sprite->x_offset = 32; sprite->y_offset = -16;
322 sprite->x_hot = 48; sprite->y_hot = 0;
323 if (x < (4 <<4)) sprite->frame = 3;
324 else if (x >= ((WORLD_X - 4) <<4)) sprite->frame = 7;
325 else if (y < (4 <<4)) sprite->frame = 5;
326 else if (y >= ((WORLD_Y - 4) <<4)) sprite->frame = 1;
327 else sprite->frame = 3;
328 sprite->new_dir = sprite->frame;
329 sprite->dir = 10;
330 sprite->count = 1;
331 break;
332
333 case GOD:
334 sprite->width = sprite->height = 48;
335 sprite->x_offset = 24; sprite->y_offset = 0;
336 sprite->x_hot = 40; sprite->y_hot = 16;
337 if (x > ((WORLD_X <<4) / 2)) {
338 if (y > ((WORLD_Y <<4) / 2)) sprite->frame = 10;
339 else sprite->frame = 7;
340 } else if (y > ((WORLD_Y <<4) / 2)) sprite->frame = 1;
341 else sprite->frame = 4;
342 sprite->count = 1000;
343 sprite->dest_x = PolMaxX <<4;
344 sprite->dest_y = PolMaxY <<4;
345 sprite->orig_x = sprite->x;
346 sprite->orig_y = sprite->y;
347 break;
348
349 case COP:
350 sprite->width = sprite->height = 32;
351 sprite->x_offset = 32; sprite->y_offset = -16;
352 sprite->x_hot = 40; sprite->y_hot = -8;
353 sprite->frame = 5;
354 sprite->count = 1500;
355 sprite->dest_x = Rand((WORLD_X <<4) - 1);
356 sprite->dest_y = Rand((WORLD_Y <<4) - 1);
357 sprite->orig_x = x - 30;
358 sprite->orig_y = y;
359 break;
360
361 case AIR:
362 sprite->width = sprite->height = 48;
363 sprite->x_offset = 24; sprite->y_offset = 0;
364 sprite->x_hot = 48; sprite->y_hot = 16;
365 if (x > ((WORLD_X - 20) <<4)) {
366 sprite->x -= 100 + 48;
367 sprite->dest_x = sprite->x - 200;
368 sprite->frame = 7;
369 } else {
370 sprite->dest_x = sprite->x + 200;
371 sprite->frame = 11;
372 }
373 sprite->dest_y = sprite->y;
374 break;
375
376 case TOR:
377 sprite->width = sprite->height = 48;
378 sprite->x_offset = 24; sprite->y_offset = 0;
379 sprite->x_hot = 40; sprite->y_hot = 36;
380 sprite->frame = 1;
381 sprite->count = 200;
382 break;
383
384 case EXP:
385 sprite->width = sprite->height = 48;
386 sprite->x_offset = 24; sprite->y_offset = 0;
387 sprite->x_hot = 40; sprite->y_hot = 16;
388 sprite->frame = 1;
389 break;
390
391 case BUS:
392 sprite->width = sprite->height = 32;
393 sprite->x_offset = 30; sprite->y_offset = -18;
394 sprite->x_hot = 40; sprite->y_hot = -8;
395 sprite->frame = 1;
396 sprite->dir = 1;
397 break;
398
399 }
400 }
401
402
403 void
404 DestroyAllSprites(void)
405 {
406 SimSprite *sprite;
407
408 for (sprite = sim->sprite; sprite != NULL; sprite = sprite->next) {
409 sprite->frame = 0;
410 }
411 }
412
413
414 void
415 DestroySprite(SimSprite *sprite)
416 {
417 SimView *view;
418 SimSprite **sp;
419
420 for (view = sim->editor; view != NULL; view = view->next)
421 if (view->follow == sprite)
422 view->follow = NULL;
423
424 if (GlobalSprites[sprite->type] == sprite) {
425 GlobalSprites[sprite->type] = (SimSprite *)NULL;
426 }
427
428 if (sprite->name != NULL) {
429 ckfree(sprite->name);
430 sprite->name = NULL;
431 }
432
433 for (sp = &sim->sprite; *sp != NULL; sp = &((*sp)->next)) {
434 if (sprite == (*sp)) {
435 *sp = sprite->next;
436 break;
437 }
438 }
439
440 sprite->next = FreeSprites;
441 FreeSprites = sprite;
442 }
443
444
445 SimSprite *
446 GetSprite(int type)
447 {
448 SimSprite *sprite;
449
450 if (((sprite = GlobalSprites[type]) == NULL) ||
451 (sprite->frame == 0))
452 return (SimSprite *)NULL;
453 else
454 return sprite;
455 }
456
457
458 SimSprite *
459 MakeSprite(int type, int x, int y)
460 {
461 SimSprite *sprite;
462
463 if ((sprite = GlobalSprites[type]) == NULL) {
464 sprite = NewSprite("", type, x, y);
465 } else {
466 InitSprite(sprite, x, y);
467 }
468 return sprite;
469 }
470
471
472 SimSprite *
473 MakeNewSprite(int type, int x, int y)
474 {
475 SimSprite *sprite;
476
477 sprite = NewSprite("", type, x, y);
478 return sprite;
479 }
480
481
482 void
483 DrawObjects(SimView *view)
484 {
485 SimSprite *sprite;
486
487 /* XXX: sort these by layer */
488 /*
489 if (z = Oframe[TRA]) DrawTrain(view, z);
490 if (z = Oframe[SHI]) DrawBoat(view, z);
491 if (z = Oframe[GOD]) DrawMonster(view, z);
492 if (z = Oframe[COP]) DrawCopter(view, z);
493 if (z = Oframe[AIR]) DrawPlane(view, z);
494 if (z = Oframe[TOR]) DrawTor(view, z);
495 if (z = Oframe[EXP]) DrawExp(view, z);
496 */
497
498 for (sprite = sim->sprite; sprite != NULL; sprite = sprite->next) {
499 DrawSprite(view, sprite);
500 }
501 }
502
503
504 void
505 DrawSprite(SimView *view, SimSprite *sprite)
506 {
507 Pixmap pict, mask;
508 int x, y, i;
509
510 if (sprite->frame == 0)
511 return;
512
513 i = (sprite->frame - 1) * 2;
514 pict = view->x->objects[sprite->type][i];
515 mask = view->x->objects[sprite->type][i + 1];
516
517 x = sprite->x
518 - ((view->tile_x <<4) - view->screen_x)
519 + sprite->x_offset;
520 y = sprite->y
521 - ((view->tile_y <<4) - view->screen_y)
522 + sprite->y_offset;
523
524 XSetClipMask(view->x->dpy, view->x->gc, mask);
525 XSetClipOrigin(view->x->dpy, view->x->gc, x, y);
526 XCopyArea(view->x->dpy, pict, view->pixmap2, view->x->gc,
527 0, 0, sprite->width, sprite->height, x, y);
528 XSetClipMask(view->x->dpy, view->x->gc, None);
529 XSetClipOrigin(view->x->dpy, view->x->gc, 0, 0);
530 }
531
532
533 short GetChar(int x, int y)
534 {
535 x >>= 4;
536 y >>= 4;
537 if (!TestBounds(x, y))
538 return(-1);
539 else
540 return(Map[x][y] & LOMASK);
541 }
542
543
544 short TurnTo(int p, int d)
545 {
546 if (p == d) return(p);
547 if (p < d)
548 if ((d - p) < 4) p++;
549 else p--;
550 else
551 if ((p - d) < 4) p--;
552 else p++;
553 if (p > 8) p = 1;
554 if (p < 1) p = 8;
555 return(p);
556 }
557
558
559 int
560 TryOther(int Tpoo, int Told, int Tnew)
561 {
562 register short z;
563
564 z = Told + 4;
565 if (z > 8) z -= 8;
566 if (Tnew != z) return(0);
567 if ((Tpoo == POWERBASE) || (Tpoo == POWERBASE + 1) ||
568 (Tpoo == RAILBASE) || (Tpoo == RAILBASE + 1))
569 return(1);
570 return(0);
571 }
572
573
574 short SpriteNotInBounds(SimSprite *sprite)
575 {
576 int x = sprite->x + sprite->x_hot;
577 int y = sprite->y + sprite->y_hot;
578
579 if ((x < 0) || (y < 0) ||
580 (x >= (WORLD_X <<4)) ||
581 (y >= (WORLD_Y <<4))) {
582 return (1);
583 }
584 return (0);
585 }
586
587
588 short GetDir(int orgX, int orgY, int desX, int desY)
589 {
590 static short Gdtab[13] = { 0, 3, 2, 1, 3, 4, 5, 7, 6, 5, 7, 8, 1 };
591 int dispX, dispY, z;
592
593 dispX = desX - orgX;
594 dispY = desY - orgY;
595 if (dispX < 0)
596 if (dispY < 0) z = 11;
597 else z = 8;
598 else
599 if (dispY < 0) z = 2;
600 else z = 5;
601 if (dispX < 0) dispX = -dispX;
602 if (dispY < 0) dispY = -dispY;
603
604 absDist = dispX + dispY;
605
606 if ((dispX <<1) < dispY) z++;
607 else if ((dispY <<1) < dispY) z--;
608
609 if ((z < 0) || (z > 12)) z = 0;
610
611 return (Gdtab[z]);
612 }
613
614
615 int
616 GetDis(int x1, int y1, int x2, int y2)
617 {
618 register short dispX, dispY;
619
620 if (x1 > x2) dispX = x1 - x2;
621 else dispX = x2 - x1;
622 if (y1 > y2) dispY = y1 - y2;
623 else dispY = y2 - y1;
624
625 return (dispX + dispY);
626 }
627
628
629 int CheckSpriteCollision(SimSprite *s1, SimSprite *s2)
630 {
631 if ((s1->frame != 0) && (s2->frame != 0) &&
632 GetDis(s1->x + s1->x_hot, s1->y + s1->y_hot,
633 s2->x + s2->x_hot, s2->y + s2->y_hot) < 30)
634 return(1);
635 return(0);
636 }
637
638
639 void MoveObjects(void)
640 {
641 SimSprite *sprite;
642
643 if (!SimSpeed) return;
644 Cycle++;
645
646 for (sprite = sim->sprite; sprite != NULL;) {
647 if (sprite->frame) {
648 switch (sprite->type) {
649 case TRA:
650 DoTrainSprite(sprite);
651 break;
652 case COP:
653 DoCopterSprite(sprite);
654 break;
655 case AIR:
656 DoAirplaneSprite(sprite);
657 break;
658 case SHI:
659 DoShipSprite(sprite);
660 break;
661 case GOD:
662 DoMonsterSprite(sprite);
663 break;
664 case TOR:
665 DoTornadoSprite(sprite);
666 break;
667 case EXP:
668 DoExplosionSprite(sprite);
669 break;
670 case BUS:
671 DoBusSprite(sprite);
672 break;
673 }
674 sprite = sprite->next;
675 } else {
676 if (sprite->name[0] == '\0') {
677 SimSprite *s = sprite;
678 sprite = sprite->next;
679 DestroySprite(s);
680 } else {
681 sprite = sprite->next;
682 }
683 }
684 }
685 }
686
687
688 void
689 DoTrainSprite(SimSprite *sprite)
690 {
691 static short Cx[4] = { 0, 16, 0, -16 };
692 static short Cy[4] = { -16, 0, 16, 0 };
693 static short Dx[5] = { 0, 4, 0, -4, 0 };
694 static short Dy[5] = { -4, 0, 4, 0, 0 };
695 static short TrainPic2[5] = { 1, 2, 1, 2, 5 };
696 register short z, dir, dir2;
697 short c;
698
699 if ((sprite->frame == 3) || (sprite->frame == 4))
700 sprite->frame = TrainPic2[sprite->dir];
701 sprite->x += Dx[sprite->dir];
702 sprite->y += Dy[sprite->dir];
703 if (!(Cycle & 3)) {
704 dir = Rand16() & 3;
705 for (z = dir; z < (dir + 4); z++) {
706 dir2 = z & 3;
707 if (sprite->dir != 4) {
708 if (dir2 == ((sprite->dir + 2) & 3)) continue;
709 }
710 c = GetChar(sprite->x + Cx[dir2] + 48,
711 sprite->y + Cy[dir2]);
712 if (((c >= RAILBASE) && (c <= LASTRAIL)) || /* track? */
713 (c == RAILVPOWERH) ||
714 (c == RAILHPOWERV)) {
715 if ((sprite->dir != dir2) &&
716 (sprite->dir != 4)) {
717 if ((sprite->dir + dir2) == 3)
718 sprite->frame = 3;
719 else
720 sprite->frame = 4;
721 } else
722 sprite->frame = TrainPic2[dir2];
723
724 if ((c == RAILBASE) || (c == (RAILBASE + 1)))
725 sprite->frame = 5;
726 sprite->dir = dir2;
727 return;
728 }
729 }
730 if (sprite->dir == 4) {
731 sprite->frame = 0;
732 return;
733 }
734 sprite->dir = 4;
735 }
736 }
737
738
739 void
740 DoCopterSprite(SimSprite *sprite)
741 {
742 static short CDx[9] = { 0, 0, 3, 5, 3, 0, -3, -5, -3 };
743 static short CDy[9] = { 0, -5, -3, 0, 3, 5, 3, 0, -3 };
744 register short z, d, x, y;
745
746 if (sprite->sound_count > 0) sprite->sound_count--;
747
748 if (sprite->control < 0) {
749
750 if (sprite->count > 0) sprite->count--;
751
752 if (!sprite->count) {
753 /* Attract copter to monster and tornado so it blows up more often */
754 SimSprite *s = GetSprite(GOD);
755 if (s != NULL) {
756 sprite->dest_x = s->x;
757 sprite->dest_y = s->y;
758 } else {
759 s = GetSprite(TOR);
760 if (s != NULL) {
761 sprite->dest_x = s->x;
762 sprite->dest_y = s->y;
763 } else {
764 sprite->dest_x = sprite->orig_x;
765 sprite->dest_y = sprite->orig_y;
766 }
767 }
768 }
769 if (!sprite->count) { /* land */
770 GetDir(sprite->x, sprite->y, sprite->orig_x, sprite->orig_y);
771 if (absDist < 30) {
772 sprite->frame = 0;
773 return;
774 }
775 }
776 } else {
777 GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
778 if (absDist < 16) {
779 sprite->dest_x = sprite->orig_x;
780 sprite->dest_y = sprite->orig_y;
781 sprite->control = -1;
782 }
783 }
784
785 if (!sprite->sound_count) { /* send report */
786 x = (sprite->x + 48) >>5;
787 y = sprite->y >>5;
788 if ((x >= 0) &&
789 (x < (WORLD_X >>1)) &&
790 (y >= 0) &&
791 (y < (WORLD_Y >>1))) {
792 /* Don changed from 160 to 170 to shut the #$%#$% thing up! */
793 if ((TrfDensity[x][y] > 170) && ((Rand16() & 7) == 0)) {
794 SendMesAt(-41, (x <<1) + 1, (y <<1) + 1);
795 MakeSound("city", "HeavyTraffic"); /* chopper */
796 sprite->sound_count = 200;
797 }
798 }
799 }
800 z = sprite->frame;
801 if (!(Cycle & 3)) {
802 d = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
803 z = TurnTo(z, d);
804 sprite->frame = z;
805 }
806
807 sprite->x += CDx[z];
808 sprite->y += CDy[z];
809 }
810
811
812 void
813 DoAirplaneSprite(SimSprite *sprite)
814 {
815 static short CDx[12] = { 0, 0, 6, 8, 6, 0, -6, -8, -6, 8, 8, 8 };
816 static short CDy[12] = { 0, -8, -6, 0, 6, 8, 6, 0, -6, 0, 0, 0 };
817
818 register short z, d;
819
820 z = sprite->frame;
821
822 if (!(Cycle % 5)) {
823 if (z > 8) { /* TakeOff */
824 z--;
825 if (z < 9) z = 3;
826 sprite->frame = z;
827 } else { /* goto destination */
828 d = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
829 z = TurnTo(z, d);
830 sprite->frame = z;
831 }
832 }
833
834 if (absDist < 50) { /* at destination */
835 sprite->dest_x = Rand((WORLD_X * 16) + 100) - 50;
836 sprite->dest_y = Rand((WORLD_Y * 16) + 100) - 50;
837 }
838
839 /* deh added test for !Disasters */
840 if (!NoDisasters) {
841 SimSprite *s;
842 int explode = 0;
843
844 for (s = sim->sprite; s != NULL; s = s->next) {
845 if ((s->frame != 0) &&
846 ((s->type == COP) ||
847 ((sprite != s) &&
848 (s->type == AIR))) &&
849 CheckSpriteCollision(sprite, s)) {
850 ExplodeSprite(s);
851 explode = 1;
852 }
853 }
854 if (explode)
855 ExplodeSprite(sprite);
856 }
857
858 sprite->x += CDx[z];
859 sprite->y += CDy[z];
860 if (SpriteNotInBounds(sprite)) sprite->frame = 0;
861 }
862
863
864 void
865 DoShipSprite(SimSprite *sprite)
866 {
867 static short BDx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
868 static short BDy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
869 static short BPx[9] = { 0, 0, 2, 2, 2, 0, -2, -2, -2 };
870 static short BPy[9] = { 0, -2, -2, 0, 2, 2, 2, 0, -2 };
871 static short BtClrTab[8] = { RIVER, CHANNEL, POWERBASE, POWERBASE + 1,
872 RAILBASE, RAILBASE + 1, BRWH, BRWV };
873 register short x, y, z, t = RIVER;
874 short tem, pem;
875
876 if (sprite->sound_count > 0) sprite->sound_count--;
877 if (!sprite->sound_count) {
878 if ((Rand16() & 3) == 1) {
879 if ((ScenarioID == 2) && /* San Francisco */
880 (Rand(10) < 5)) {
881 MakeSound("city", "HonkHonk-Low");
882 } else {
883 MakeSound("city", "HonkHonk-Low");
884 }
885 }
886 sprite->sound_count = 200;
887 }
888
889 if (sprite->count > 0) sprite->count--;
890 if (!sprite->count) {
891 sprite->count = 9;
892 if (sprite->frame != sprite->new_dir) {
893 sprite->frame = TurnTo(sprite->frame, sprite->new_dir);
894 return;
895 }
896 tem = Rand16() & 7;
897 for (pem = tem; pem < (tem + 8); pem++) {
898 z = (pem & 7) + 1;
899
900 if (z == sprite->dir) continue;
901 x = ((sprite->x + (48 - 1)) >>4) + BDx[z];
902 y = (sprite->y >>4) + BDy[z];
903 if (TestBounds(x, y)) {
904 t = Map[x][y] & LOMASK;
905 if ((t == CHANNEL) || (t == BRWH) || (t == BRWV) ||
906 TryOther(t, sprite->dir, z)) {
907 sprite->new_dir = z;
908 sprite->frame = TurnTo(sprite->frame, sprite->new_dir);
909 sprite->dir = z + 4;
910 if (sprite->dir > 8) sprite->dir -= 8;
911 break;
912 }
913 }
914 }
915 if (pem == (tem + 8)) {
916 sprite->dir = 10;
917 sprite->new_dir = (Rand16() & 7) + 1;
918 }
919 } else {
920 z = sprite->frame;
921 if (z == sprite->new_dir) {
922 sprite->x += BPx[z];
923 sprite->y += BPy[z];
924 }
925 }
926 if (SpriteNotInBounds(sprite)) {
927 sprite->frame = 0;
928 return;
929 }
930 if (!NoDisasters) {
931 for (z = 0; z < 8; z++) {
932 if (t == BtClrTab[z]) break;
933 if (z == 7) {
934 ExplodeSprite(sprite);
935 Destroy(sprite->x + 48, sprite->y);
936 }
937 }
938 }
939 }
940
941
942 void
943 DoMonsterSprite(SimSprite *sprite)
944 {
945 static short Gx[5] = { 2, 2, -2, -2, 0 };
946 static short Gy[5] = { -2, 2, 2, -2, 0 };
947 static short ND1[4] = { 0, 1, 2, 3 };
948 static short ND2[4] = { 1, 2, 3, 0 };
949 static short nn1[4] = { 2, 5, 8, 11 };
950 static short nn2[4] = { 11, 2, 5, 8 };
951 register short d, z, c;
952
953 if (sprite->sound_count > 0) sprite->sound_count--;
954
955 if (sprite->control < 0) {
956 /* business as usual */
957
958 if (sprite->control == -2) {
959 d = (sprite->frame - 1) / 3;
960 z = (sprite->frame - 1) % 3;
961 if (z == 2) sprite->step = 0;
962 if (z == 0) sprite->step = 1;
963 if (sprite->step) z++;
964 else z--;
965 c = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
966 if (absDist < 18) {
967 sprite->control = -1;
968 sprite->count = 1000;
969 sprite->flag = 1;
970 sprite->dest_x = sprite->orig_x;
971 sprite->dest_y = sprite->orig_y;
972 } else {
973 c = (c - 1) / 2;
974 if (((c != d) && (!Rand(5))) ||
975 (!Rand(20))) {
976 int diff = (c - d) & 3;
977 if ((diff == 1) || (diff == 3)) {
978 d = c;
979 } else {
980 if (Rand16() & 1) d++; else d--;
981 d &= 3;
982 }
983 } else {
984 if (!Rand(20)) {
985 if (Rand16() & 1) d++; else d--;
986 d &= 3;
987 }
988 }
989 }
990 } else {
991
992 d = (sprite->frame - 1) / 3;
993
994 if (d < 4) { /* turn n s e w */
995 z = (sprite->frame - 1) % 3;
996 if (z == 2) sprite->step = 0;
997 if (z == 0) sprite->step = 1;
998 if (sprite->step) z++;
999 else z--;
1000 GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
1001 if (absDist < 60) {
1002 if (sprite->flag == 0) {
1003 sprite->flag = 1;
1004 sprite->dest_x = sprite->orig_x;
1005 sprite->dest_y = sprite->orig_y;
1006 } else {
1007 sprite->frame = 0;
1008 return;
1009 }
1010 }
1011 c = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
1012 c = (c - 1) / 2;
1013 if ((c != d) && (!Rand(10))) {
1014 if (Rand16() & 1) z = ND1[d];
1015 else z = ND2[d];
1016 d = 4;
1017 if (!sprite->sound_count) {
1018 MakeSound("city", "Monster"); /* monster */
1019 sprite->sound_count = 50 + Rand(100);
1020 }
1021 }
1022 } else {
1023 d = 4;
1024 c = sprite->frame;
1025 z = (c - 13) & 3;
1026 if (!(Rand16() & 3)) {
1027 if (Rand16() & 1) z = nn1[z];
1028 else z = nn2[z];
1029 d = (z - 1) / 3;
1030 z = (z - 1) % 3;
1031 }
1032 }
1033 }
1034 } else {
1035 /* somebody's taken control of the monster */
1036
1037 d = sprite->control;
1038 z = (sprite->frame - 1) % 3;
1039
1040 if (z == 2) sprite->step = 0;
1041 if (z == 0) sprite->step = 1;
1042 if (sprite->step) z++;
1043 else z--;
1044 }
1045
1046 z = (((d * 3) + z) + 1);
1047 if (z > 16) z = 16;
1048 sprite->frame = z;
1049
1050 sprite->x += Gx[d];
1051 sprite->y += Gy[d];
1052
1053 if (sprite->count > 0) sprite->count--;
1054 c = GetChar(sprite->x + sprite->x_hot, sprite->y + sprite->y_hot);
1055 if ((c == -1) ||
1056 ((c == RIVER) &&
1057 (sprite->count != 0) &&
1058 (sprite->count < 900) &&
1059 (sprite->control == -1))) {
1060 sprite->frame = 0; /* kill zilla */
1061 }
1062
1063 { SimSprite *s;
1064 for (s = sim->sprite; s != NULL; s = s->next) {
1065 if ((s->frame != 0) &&
1066 ((s->type == AIR) ||
1067 (s->type == COP) ||
1068 (s->type == SHI) ||
1069 (s->type == TRA)) &&
1070 CheckSpriteCollision(sprite, s)) {
1071 ExplodeSprite(s);
1072 }
1073 }
1074 }
1075
1076 Destroy(sprite->x + 48, sprite->y + 16);
1077 }
1078
1079
1080 void
1081 DoTornadoSprite(SimSprite *sprite)
1082 {
1083 static short CDx[9] = { 2, 3, 2, 0, -2, -3 };
1084 static short CDy[9] = { -2, 0, 2, 3, 2, 0 };
1085 register short z;
1086
1087 z = sprite->frame;
1088
1089 if (z == 2) /* cycle animation... post Rel */
1090 if (sprite->flag)
1091 z = 3;
1092 else
1093 z = 1;
1094 else {
1095 if (z == 1)
1096 sprite->flag = 1;
1097 else
1098 sprite->flag = 0;
1099 z = 2;
1100 }
1101
1102 if (sprite->count > 0) sprite->count--;
1103
1104 sprite->frame = z;
1105
1106 { SimSprite *s;
1107 for (s = sim->sprite; s != NULL; s = s->next) {
1108 if ((s->frame != 0) &&
1109 ((s->type == AIR) ||
1110 (s->type == COP) ||
1111 (s->type == SHI) ||
1112 (s->type == TRA)) &&
1113 CheckSpriteCollision(sprite, s)) {
1114 ExplodeSprite(s);
1115 }
1116 }
1117 }
1118
1119 z = Rand(5);
1120 sprite->x += CDx[z];
1121 sprite->y += CDy[z];
1122 if (SpriteNotInBounds(sprite)) sprite->frame = 0;
1123
1124 if ((sprite->count != 0) &&
1125 (!Rand(500)))
1126 sprite->frame = 0;
1127
1128 Destroy(sprite->x + 48, sprite->y + 40);
1129 }
1130
1131
1132 void
1133 DoExplosionSprite(SimSprite *sprite)
1134 {
1135 short x, y;
1136
1137 if (!(Cycle & 1)) {
1138 if (sprite->frame == 1) {
1139 MakeSound("city", "Explosion-High"); /* explosion */
1140 x = (sprite->x >>4) + 3;
1141 y = (sprite->y >>4);
1142 SendMesAt(32, x, y);
1143 }
1144 sprite->frame++;
1145 }
1146
1147 if (sprite->frame > 6) {
1148 sprite->frame = 0;
1149
1150 StartFire(sprite->x + 48 - 8, sprite->y + 16);
1151 StartFire(sprite->x + 48 - 24, sprite->y);
1152 StartFire(sprite->x + 48 + 8, sprite->y);
1153 StartFire(sprite->x + 48 - 24, sprite->y + 32);
1154 StartFire(sprite->x + 48 + 8, sprite->y + 32);
1155 return;
1156 }
1157 }
1158
1159
1160 void
1161 DoBusSprite(SimSprite *sprite)
1162 {
1163 static short Dx[5] = { 0, 1, 0, -1, 0 };
1164 static short Dy[5] = { -1, 0, 1, 0, 0 };
1165 static short Dir2Frame[4] = { 1, 2, 1, 2 };
1166 int dx, dy, tx, ty, otx, oty;
1167 int turned = 0;
1168 int speed = 0, z;
1169
1170 #ifdef DEBUGBUS
1171 printf("Bus dir %d turn %d frame %d\n",
1172 sprite->dir, sprite->turn, sprite->frame);
1173 #endif
1174
1175 if (sprite->turn) {
1176 if (sprite->turn < 0) { /* ccw */
1177 if (sprite->dir & 1) { /* up or down */
1178 sprite->frame = 4;
1179 } else { /* left or right */
1180 sprite->frame = 3;
1181 }
1182 sprite->turn++;
1183 sprite->dir = (sprite->dir - 1) & 3;
1184 } else { /* cw */
1185 if (sprite->dir & 1) { /* up or down */
1186 sprite->frame = 3;
1187 } else { /* left or right */
1188 sprite->frame = 4;
1189 }
1190 sprite->turn--;
1191 sprite->dir = (sprite->dir + 1) & 3;
1192 }
1193 turned = 1;
1194 } else {
1195 /* finish turn */
1196 if ((sprite->frame == 3) || (sprite->frame == 4)) {
1197 turned = 1;
1198 sprite->frame = Dir2Frame[sprite->dir];
1199 }
1200 }
1201
1202 if (sprite->speed == 0) {
1203 /* brake */
1204 dx = 0; dy = 0;
1205 } else { /* cruise at traffic speed */
1206
1207 tx = (sprite->x + sprite->x_hot) >>5;
1208 ty = (sprite->y + sprite->y_hot) >>5;
1209 if ((tx >= 0) &&
1210 (tx < (WORLD_X >>1)) &&
1211 (ty >= 0) &&
1212 (ty < (WORLD_Y >>1))) {
1213 z = TrfDensity[tx][ty] >>6;
1214 if (z > 1) z--;
1215 } else z = 0;
1216
1217 switch (z) {
1218 case 0:
1219 speed = 8;
1220 break;
1221 case 1:
1222 speed = 4;
1223 break;
1224 case 2:
1225 speed = 1;
1226 break;
1227 }
1228
1229 /* govern speed */
1230 if (speed > sprite->speed)
1231 speed = sprite->speed;
1232
1233 if (turned) {
1234 #ifdef DEBUGBUS
1235 printf("turned\n");
1236 #endif
1237 if (speed > 1) speed = 1;
1238 dx = Dx[sprite->dir] * speed;
1239 dy = Dy[sprite->dir] * speed;
1240 } else {
1241 dx = Dx[sprite->dir] * speed;
1242 dy = Dy[sprite->dir] * speed;
1243
1244 tx = (sprite->x + sprite->x_hot) >>4;
1245 ty = (sprite->y + sprite->y_hot) >>4;
1246
1247 /* drift into the right lane */
1248 switch (sprite->dir) {
1249 case 0: /* up */
1250 z = ((tx <<4) + 4) - (sprite->x + sprite->x_hot);
1251 if (z < 0) dx = -1;
1252 else if (z > 0) dx = 1;
1253 #ifdef DEBUGBUS
1254 printf("moving up x %x z %d dx %d\n", sprite->x + sprite->x_hot, z, dx);
1255 #endif
1256 break;
1257 case 1: /* right */
1258 z = ((ty <<4) + 4) - (sprite->y + sprite->y_hot);
1259 if (z < 0) dy = -1;
1260 else if (z > 0) dy = 1;
1261 #ifdef DEBUGBUS
1262 printf("moving right y %x z %d dy %d\n", sprite->y + sprite->y_hot, z, dy);
1263 #endif
1264 break;
1265 case 2: /* down */
1266 z = ((tx <<4)) - (sprite->x + sprite->x_hot);
1267 if (z < 0) dx = -1;
1268 else if (z > 0) dx = 1;
1269 #ifdef DEBUGBUS
1270 printf("moving down x %x z %d dx %d\n", sprite->x + sprite->x_hot, z, dx);
1271 #endif
1272 break;
1273 case 3: /* left */
1274 z = ((ty <<4)) - (sprite->y + sprite->y_hot);
1275 if (z < 0) dy = -1;
1276 else if (z > 0) dy = 1;
1277 #ifdef DEBUGBUS
1278 printf("moving left y %x z %d dy %d\n", sprite->y + sprite->y_hot, z, dy);
1279 #endif
1280 break;
1281 }
1282 }
1283 }
1284 #ifdef DEBUGBUS
1285 printf("speed dx %d dy %d\n", dx, dy);
1286 #endif
1287
1288 #define AHEAD 8
1289
1290 otx = (sprite->x + sprite->x_hot + (Dx[sprite->dir] * AHEAD)) >>4;
1291 oty = (sprite->y + sprite->y_hot + (Dy[sprite->dir] * AHEAD)) >>4;
1292 if (otx < 0) otx = 0; else if (otx >= WORLD_X) otx = WORLD_X - 1;
1293 if (oty < 0) oty = 0; else if (oty >= WORLD_Y) oty = WORLD_Y - 1;
1294
1295 tx = (sprite->x + sprite->x_hot + dx + (Dx[sprite->dir] * AHEAD)) >>4;
1296 ty = (sprite->y + sprite->y_hot + dy + (Dy[sprite->dir] * AHEAD)) >>4;
1297 if (tx < 0) tx = 0; else if (tx >= WORLD_X) tx = WORLD_X - 1;
1298 if (ty < 0) ty = 0; else if (ty >= WORLD_Y) ty = WORLD_Y - 1;
1299
1300 if ((tx != otx) || (ty != oty)) {
1301 #ifdef DEBUGBUS
1302 printf("drive from tile %d %d to %d %d\n",
1303 otx, oty, tx, ty);
1304 #endif
1305 z = CanDriveOn(tx, ty);
1306 if (z == 0) {
1307 /* can't drive forward into a new tile */
1308 if (speed == 8) {
1309 bulldozer_tool(NULL, tx, ty);
1310 } else {
1311 }
1312 } else {
1313 /* drive forward into a new tile */
1314 if (z > 0) {
1315 /* smooth */
1316 } else {
1317 /* bumpy */
1318 dx /= 2;
1319 dy /= 2;
1320 }
1321 }
1322 }
1323
1324 tx = (sprite->x + sprite->x_hot + dx) >>4;
1325 ty = (sprite->y + sprite->y_hot + dy) >>4;
1326 z = CanDriveOn(tx, ty);
1327 if (z > 0) {
1328 /* cool, cruise along */
1329 } else {
1330 if (z < 0) {
1331 /* bumpy */
1332 } else {
1333 /* something in the way */
1334 }
1335 }
1336
1337 sprite->x += dx;
1338 sprite->y += dy;
1339
1340 if (!NoDisasters) {
1341 SimSprite *s;
1342 int explode = 0;
1343
1344 for (s = sim->sprite; s != NULL; s = s->next) {
1345 if ((sprite != s) &&
1346 (s->frame != 0) &&
1347 ((s->type == BUS) ||
1348 ((s->type == TRA) &&
1349 (s->frame != 5))) &&
1350 CheckSpriteCollision(sprite, s)) {
1351 ExplodeSprite(s);
1352 explode = 1;
1353 }
1354 }
1355 if (explode)
1356 ExplodeSprite(sprite);
1357 }
1358 }
1359
1360
1361 int
1362 CanDriveOn(int x, int y)
1363 {
1364 int tile;
1365
1366 if (!TestBounds(x, y))
1367 return 0;
1368
1369 tile = Map[x][y] & LOMASK;
1370
1371 if (((tile >= ROADBASE) &&
1372 (tile <= LASTROAD) &&
1373 (tile != BRWH) &&
1374 (tile != BRWV)) ||
1375 (tile == HRAILROAD) ||
1376 (tile == VRAILROAD))
1377 return 1;
1378
1379 if ((tile == DIRT) || tally(tile))
1380 return -1;
1381
1382 return 0;
1383 }
1384
1385
1386 void
1387 ExplodeSprite(SimSprite *sprite)
1388 {
1389 int x, y;
1390
1391 sprite->frame = 0;
1392
1393 x = sprite->x + sprite->x_hot;
1394 y = sprite->y + sprite->y_hot;
1395 MakeExplosionAt(x, y);
1396
1397 x = (x >>4);
1398 y = (y >>4);
1399
1400 switch (sprite->type) {
1401 case AIR:
1402 CrashX = x;
1403 CrashY = y;
1404 SendMesAt(-24, x, y);
1405 break;
1406 case SHI:
1407 CrashX = x;
1408 CrashY = y;
1409 SendMesAt(-25, x, y);
1410 break;
1411 case TRA:
1412 CrashX = x;
1413 CrashY = y;
1414 SendMesAt(-26, x, y);
1415 break;
1416 case COP:
1417 CrashX = x;
1418 CrashY = y;
1419 SendMesAt(-27, x, y);
1420 break;
1421 case BUS:
1422 CrashX = x;
1423 CrashY = y;
1424 SendMesAt(-26, x, y); /* XXX for now */
1425 break;
1426 }
1427 MakeSound("city", "Explosion-High"); /* explosion */
1428 return;
1429 }
1430
1431
1432 int checkWet(int x)
1433 {
1434 if ((x == POWERBASE) || (x == POWERBASE + 1) ||
1435 (x == RAILBASE) || (x == RAILBASE + 1) ||
1436 (x == BRWH) || (x == BRWV))
1437 return(1);
1438 else
1439 return(0);
1440 }
1441
1442
1443 void
1444 Destroy(int ox, int oy)
1445 {
1446 short t, z, x, y;
1447
1448 x = ox >>4;
1449 y = oy >>4;
1450 if (!TestBounds(x, y))
1451 return;
1452 z = Map[x][y];
1453 t = z & LOMASK;
1454 if (t >= TREEBASE) {
1455 /* TILE_IS_BRIDGE(t) */
1456 if (!(z & BURNBIT)) {
1457 if ((t >= ROADBASE) && (t <= LASTROAD))
1458 Map[x][y] = RIVER;
1459 return;
1460 }
1461 if (z & ZONEBIT) {
1462 OFireZone(x, y, z);
1463 if (t > RZB) {
1464 MakeExplosionAt(ox, oy);
1465 }
1466 }
1467 if (checkWet(t))
1468 Map[x][y] = RIVER;
1469 else
1470 Map[x][y] = (DoAnimation
1471 ? TINYEXP
1472 : (LASTTINYEXP - 3)) | BULLBIT | ANIMBIT;
1473 }
1474 }
1475
1476
1477 void
1478 OFireZone(int Xloc, int Yloc, int ch)
1479 {
1480 register short Xtem, Ytem;
1481 short x, y, XYmax;
1482
1483 RateOGMem[Xloc >>3][Yloc >>3] -= 20;
1484
1485 ch &= LOMASK;
1486 if (ch < PORTBASE)
1487 XYmax = 2;
1488 else
1489 if (ch == AIRPORT) XYmax = 5;
1490 else XYmax = 4;
1491
1492 for (x = -1; x < XYmax; x++)
1493 for (y = -1; y < XYmax; y++) {
1494 Xtem = Xloc + x;
1495 Ytem = Yloc + y;
1496 if ((Map[Xtem][Ytem] & LOMASK) >= ROADBASE)
1497 Map[Xtem][Ytem] |= BULLBIT;
1498 }
1499 }
1500
1501
1502 void
1503 StartFire(int x, int y)
1504 {
1505 register int t, z;
1506
1507 x >>= 4;
1508 y >>= 4;
1509 if ((x >= WORLD_X) ||
1510 (y >= WORLD_Y) ||
1511 (x < 0) || (y < 0))
1512 return;
1513 z = Map[x][y];
1514 t = z & LOMASK;
1515 if ((!(z & BURNBIT)) && (t != 0)) return;
1516 if (z & ZONEBIT) return;
1517 Map[x][y] = FIRE + (Rand16() & 3) + ANIMBIT;
1518 }
1519
1520
1521 void
1522 GenerateTrain(int x, int y)
1523 {
1524 if ((TotalPop > 20) &&
1525 (GetSprite(TRA) == NULL) &&
1526 (!Rand(25))) {
1527 MakeSprite(TRA, (x <<4) + TRA_GROOVE_X, (y <<4) + TRA_GROOVE_Y);
1528 }
1529 }
1530
1531
1532 void
1533 GenerateBus(int x, int y)
1534 {
1535 if ((GetSprite(BUS) == NULL) &&
1536 (!Rand(25))) {
1537 MakeSprite(BUS, (x <<4) + BUS_GROOVE_X, (y <<4) + BUS_GROOVE_Y);
1538 }
1539 }
1540
1541
1542 void
1543 GenerateShip(void)
1544 {
1545 register short x, y;
1546
1547 if (!(Rand16() & 3))
1548 for (x = 4; x < WORLD_X - 2; x++)
1549 if (Map[x][0] == CHANNEL) {
1550 MakeShipHere(x, 0);
1551 return;
1552 }
1553 if (!(Rand16() & 3))
1554 for (y = 1; y < WORLD_Y - 2; y++)
1555 if (Map[0][y] == CHANNEL) {
1556 MakeShipHere(0, y);
1557 return;
1558 }
1559 if (!(Rand16() & 3))
1560 for (x = 4; x < WORLD_X - 2; x++)
1561 if (Map[x][WORLD_Y - 1] == CHANNEL) {
1562 MakeShipHere(x, WORLD_Y - 1);
1563 return;
1564 }
1565 if (!(Rand16() & 3))
1566 for (y = 1; y < WORLD_Y - 2; y++)
1567 if (Map[WORLD_X - 1][y] == CHANNEL) {
1568 MakeShipHere(WORLD_X - 1, y);
1569 return;
1570 }
1571 }
1572
1573
1574 void
1575 MakeShipHere(int x, int y)
1576 {
1577 MakeSprite(SHI, (x <<4) - (48 - 1), (y <<4));
1578 }
1579
1580
1581 void
1582 MakeMonster(void)
1583 {
1584 register int x, y, z, done = 0;
1585 SimSprite *sprite;
1586
1587 if ((sprite = GetSprite(GOD)) != NULL) {
1588 sprite->sound_count = 1;
1589 sprite->count = 1000;
1590 sprite->dest_x = PolMaxX <<4;
1591 sprite->dest_y = PolMaxY <<4;
1592 return;
1593 }
1594
1595 for (z = 0; z < 300; z++) {
1596 x = Rand(WORLD_X - 20) + 10;
1597 y = Rand(WORLD_Y - 10) + 5;
1598 if ((Map[x][y] == RIVER) || (Map[x][y] == RIVER + BULLBIT)) {
1599 MonsterHere(x, y);
1600 done = 1;
1601 break;
1602 }
1603 }
1604 if (!done == 0)
1605 MonsterHere(60, 50);
1606 }
1607
1608
1609 void
1610 MonsterHere(int x, int y)
1611 {
1612 MakeSprite(GOD, (x <<4) + 48, (y <<4));
1613 ClearMes();
1614 SendMesAt(-21, x + 5, y);
1615 }
1616
1617
1618 void
1619 GenerateCopter(int x, int y)
1620 {
1621 if (GetSprite(COP) != NULL) return;
1622
1623 MakeSprite(COP, (x <<4), (y <<4) + 30);
1624 }
1625
1626
1627 void
1628 GeneratePlane(int x, int y)
1629 {
1630 if (GetSprite(AIR) != NULL) return;
1631
1632 MakeSprite(AIR, (x <<4) + 48, (y <<4) + 12);
1633 }
1634
1635
1636 void
1637 MakeAirCrash(void)
1638 {
1639 #ifndef NO_AIRCRASH
1640 if (GetSprite(AIR) == NULL) {
1641 short x, y;
1642
1643 x = Rand(WORLD_X - 20) + 10;
1644 y = Rand(WORLD_Y - 10) + 5;
1645
1646 GeneratePlane(x, y);
1647 }
1648
1649 ExplodeSprite(GetSprite(AIR));
1650 #endif
1651 }
1652
1653
1654 void
1655 MakeTornado(void)
1656 {
1657 short x, y;
1658 SimSprite *sprite;
1659
1660 if ((sprite = GetSprite(TOR)) != NULL) {
1661 sprite->count = 200;
1662 return;
1663 }
1664
1665 x = Rand((WORLD_X <<4) - 800) + 400;
1666 y = Rand((WORLD_Y <<4) - 200) + 100;
1667 MakeSprite(TOR, x, y);
1668 ClearMes();
1669 SendMesAt(-22, (x >>4) + 3, (y >>4) + 2);
1670 }
1671
1672
1673 void
1674 MakeExplosion(int x, int y)
1675 {
1676 if ((x >= 0) && (x < WORLD_X) &&
1677 (y >= 0) && (y < WORLD_Y)) {
1678 MakeExplosionAt((x << 4) + 8, (y << 4) + 8);
1679 }
1680 }
1681
1682
1683 void
1684 MakeExplosionAt(int x, int y)
1685 {
1686 MakeNewSprite(EXP, x - 40, y - 16);
1687 }
1688
Impressum, Datenschutz