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