]> git.zerfleddert.de Git - micropolis/blob - src/sim/w_sprite.c
ff1e679cf150e24c96952b2937cecf855914b0f2
[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 -speed 80");
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 for (z = 0; z < 8; z++) {
902 if (t == BtClrTab[z]) break;
903 if (z == 7) {
904 ExplodeSprite(sprite);
905 Destroy(sprite->x + 48, sprite->y);
906 }
907 }
908 }
909
910
911 DoMonsterSprite(SimSprite *sprite)
912 {
913 static short Gx[5] = { 2, 2, -2, -2, 0 };
914 static short Gy[5] = { -2, 2, 2, -2, 0 };
915 static short ND1[4] = { 0, 1, 2, 3 };
916 static short ND2[4] = { 1, 2, 3, 0 };
917 static short nn1[4] = { 2, 5, 8, 11 };
918 static short nn2[4] = { 11, 2, 5, 8 };
919 register short d, z, c;
920
921 if (sprite->sound_count > 0) sprite->sound_count--;
922
923 if (sprite->control < 0) {
924 /* business as usual */
925
926 if (sprite->control == -2) {
927 d = (sprite->frame - 1) / 3;
928 z = (sprite->frame - 1) % 3;
929 if (z == 2) sprite->step = 0;
930 if (z == 0) sprite->step = 1;
931 if (sprite->step) z++;
932 else z--;
933 c = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
934 if (absDist < 18) {
935 sprite->control = -1;
936 sprite->count = 1000;
937 sprite->flag = 1;
938 sprite->dest_x = sprite->orig_x;
939 sprite->dest_y = sprite->orig_y;
940 } else {
941 c = (c - 1) / 2;
942 if (((c != d) && (!Rand(5))) ||
943 (!Rand(20))) {
944 int diff = (c - d) & 3;
945 if ((diff == 1) || (diff == 3)) {
946 d = c;
947 } else {
948 if (Rand16() & 1) d++; else d--;
949 d &= 3;
950 }
951 } else {
952 if (!Rand(20)) {
953 if (Rand16() & 1) d++; else d--;
954 d &= 3;
955 }
956 }
957 }
958 } else {
959
960 d = (sprite->frame - 1) / 3;
961
962 if (d < 4) { /* turn n s e w */
963 z = (sprite->frame - 1) % 3;
964 if (z == 2) sprite->step = 0;
965 if (z == 0) sprite->step = 1;
966 if (sprite->step) z++;
967 else z--;
968 GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
969 if (absDist < 60) {
970 if (sprite->flag == 0) {
971 sprite->flag = 1;
972 sprite->dest_x = sprite->orig_x;
973 sprite->dest_y = sprite->orig_y;
974 } else {
975 sprite->frame = 0;
976 return;
977 }
978 }
979 c = GetDir(sprite->x, sprite->y, sprite->dest_x, sprite->dest_y);
980 c = (c - 1) / 2;
981 if ((c != d) && (!Rand(10))) {
982 if (Rand16() & 1) z = ND1[d];
983 else z = ND2[d];
984 d = 4;
985 if (!sprite->sound_count) {
986 MakeSound("city", "Monster -speed [MonsterSpeed]"); /* monster */
987 sprite->sound_count = 50 + Rand(100);
988 }
989 }
990 } else {
991 d = 4;
992 c = sprite->frame;
993 z = (c - 13) & 3;
994 if (!(Rand16() & 3)) {
995 if (Rand16() & 1) z = nn1[z];
996 else z = nn2[z];
997 d = (z - 1) / 3;
998 z = (z - 1) % 3;
999 }
1000 }
1001 }
1002 } else {
1003 /* somebody's taken control of the monster */
1004
1005 d = sprite->control;
1006 z = (sprite->frame - 1) % 3;
1007
1008 if (z == 2) sprite->step = 0;
1009 if (z == 0) sprite->step = 1;
1010 if (sprite->step) z++;
1011 else z--;
1012 }
1013
1014 z = (((d * 3) + z) + 1);
1015 if (z > 16) z = 16;
1016 sprite->frame = z;
1017
1018 sprite->x += Gx[d];
1019 sprite->y += Gy[d];
1020
1021 if (sprite->count > 0) sprite->count--;
1022 c = GetChar(sprite->x + sprite->x_hot, sprite->y + sprite->y_hot);
1023 if ((c == -1) ||
1024 ((c == RIVER) &&
1025 (sprite->count != 0) &&
1026 (sprite->control == -1))) {
1027 sprite->frame = 0; /* kill zilla */
1028 }
1029
1030 { SimSprite *s;
1031 for (s = sim->sprite; s != NULL; s = s->next) {
1032 if ((s->frame != 0) &&
1033 ((s->type == AIR) ||
1034 (s->type == COP) ||
1035 (s->type == SHI) ||
1036 (s->type == TRA)) &&
1037 CheckSpriteCollision(sprite, s)) {
1038 ExplodeSprite(s);
1039 }
1040 }
1041 }
1042
1043 Destroy(sprite->x + 48, sprite->y + 16);
1044 }
1045
1046
1047 DoTornadoSprite(SimSprite *sprite)
1048 {
1049 static short CDx[9] = { 2, 3, 2, 0, -2, -3 };
1050 static short CDy[9] = { -2, 0, 2, 3, 2, 0 };
1051 register short z;
1052
1053 z = sprite->frame;
1054
1055 if (z == 2) /* cycle animation... post Rel */
1056 if (sprite->flag)
1057 z = 3;
1058 else
1059 z = 1;
1060 else {
1061 if (z == 1)
1062 sprite->flag = 1;
1063 else
1064 sprite->flag = 0;
1065 z = 2;
1066 }
1067
1068 if (sprite->count > 0) sprite->count--;
1069
1070 sprite->frame = z;
1071
1072 { SimSprite *s;
1073 for (s = sim->sprite; s != NULL; s = s->next) {
1074 if ((s->frame != 0) &&
1075 ((s->type == AIR) ||
1076 (s->type == COP) ||
1077 (s->type == SHI) ||
1078 (s->type == TRA)) &&
1079 CheckSpriteCollision(sprite, s)) {
1080 ExplodeSprite(s);
1081 }
1082 }
1083 }
1084
1085 z = Rand(5);
1086 sprite->x += CDx[z];
1087 sprite->y += CDy[z];
1088 if (SpriteNotInBounds(sprite)) sprite->frame = 0;
1089
1090 if ((sprite->count != 0) &&
1091 (!Rand(500)))
1092 sprite->frame = 0;
1093
1094 Destroy(sprite->x + 48, sprite->y + 40);
1095 }
1096
1097
1098 DoExplosionSprite(SimSprite *sprite)
1099 {
1100 short x, y;
1101
1102 if (!(Cycle & 1)) {
1103 if (sprite->frame == 1) {
1104 MakeSound("city", "Explosion-High"); /* explosion */
1105 x = (sprite->x >>4) + 3;
1106 y = (sprite->y >>4);
1107 SendMesAt(32, x, y);
1108 }
1109 sprite->frame++;
1110 }
1111
1112 if (sprite->frame > 6) {
1113 sprite->frame = 0;
1114
1115 StartFire(sprite->x + 48 - 8, sprite->y + 16);
1116 StartFire(sprite->x + 48 - 24, sprite->y);
1117 StartFire(sprite->x + 48 + 8, sprite->y);
1118 StartFire(sprite->x + 48 - 24, sprite->y + 32);
1119 StartFire(sprite->x + 48 + 8, sprite->y + 32);
1120 return;
1121 }
1122 }
1123
1124
1125 DoBusSprite(SimSprite *sprite)
1126 {
1127 static short Dx[5] = { 0, 1, 0, -1, 0 };
1128 static short Dy[5] = { -1, 0, 1, 0, 0 };
1129 static short Dir2Frame[4] = { 1, 2, 1, 2 };
1130 register int dir, dir2;
1131 int c, dx, dy, crossed, tx, ty, otx, oty;
1132 int turned = 0;
1133 int speed, z;
1134
1135 #ifdef DEBUGBUS
1136 printf("Bus dir %d turn %d frame %d\n",
1137 sprite->dir, sprite->turn, sprite->frame);
1138 #endif
1139
1140 if (sprite->turn) {
1141 if (sprite->turn < 0) { /* ccw */
1142 if (sprite->dir & 1) { /* up or down */
1143 sprite->frame = 4;
1144 } else { /* left or right */
1145 sprite->frame = 3;
1146 }
1147 sprite->turn++;
1148 sprite->dir = (sprite->dir - 1) & 3;
1149 } else { /* cw */
1150 if (sprite->dir & 1) { /* up or down */
1151 sprite->frame = 3;
1152 } else { /* left or right */
1153 sprite->frame = 4;
1154 }
1155 sprite->turn--;
1156 sprite->dir = (sprite->dir + 1) & 3;
1157 }
1158 turned = 1;
1159 } else {
1160 /* finish turn */
1161 if ((sprite->frame == 3) || (sprite->frame == 4)) {
1162 turned = 1;
1163 sprite->frame = Dir2Frame[sprite->dir];
1164 }
1165 }
1166
1167 if (sprite->speed == 0) {
1168 /* brake */
1169 dx = 0; dy = 0;
1170 } else { /* cruise at traffic speed */
1171
1172 tx = (sprite->x + sprite->x_hot) >>5;
1173 ty = (sprite->y + sprite->y_hot) >>5;
1174 if ((tx >= 0) &&
1175 (tx < (WORLD_X >>1)) &&
1176 (ty >= 0) &&
1177 (ty < (WORLD_Y >>1))) {
1178 z = TrfDensity[tx][ty] >>6;
1179 if (z > 1) z--;
1180 } else z = 0;
1181
1182 switch (z) {
1183 case 0:
1184 speed = 8;
1185 break;
1186 case 1:
1187 speed = 4;
1188 break;
1189 case 2:
1190 speed = 1;
1191 break;
1192 }
1193
1194 /* govern speed */
1195 if (speed > sprite->speed)
1196 speed = sprite->speed;
1197
1198 if (turned) {
1199 #ifdef DEBUGBUS
1200 printf("turned\n");
1201 #endif
1202 if (speed > 1) speed = 1;
1203 dx = Dx[sprite->dir] * speed;
1204 dy = Dy[sprite->dir] * speed;
1205 } else {
1206 dx = Dx[sprite->dir] * speed;
1207 dy = Dy[sprite->dir] * speed;
1208
1209 tx = (sprite->x + sprite->x_hot) >>4;
1210 ty = (sprite->y + sprite->y_hot) >>4;
1211
1212 /* drift into the right lane */
1213 switch (sprite->dir) {
1214 case 0: /* up */
1215 z = ((tx <<4) + 4) - (sprite->x + sprite->x_hot);
1216 if (z < 0) dx = -1;
1217 else if (z > 0) dx = 1;
1218 #ifdef DEBUGBUS
1219 printf("moving up x %x z %d dx %d\n", sprite->x + sprite->x_hot, z, dx);
1220 #endif
1221 break;
1222 case 1: /* right */
1223 z = ((ty <<4) + 4) - (sprite->y + sprite->y_hot);
1224 if (z < 0) dy = -1;
1225 else if (z > 0) dy = 1;
1226 #ifdef DEBUGBUS
1227 printf("moving right y %x z %d dy %d\n", sprite->y + sprite->y_hot, z, dy);
1228 #endif
1229 break;
1230 case 2: /* down */
1231 z = ((tx <<4)) - (sprite->x + sprite->x_hot);
1232 if (z < 0) dx = -1;
1233 else if (z > 0) dx = 1;
1234 #ifdef DEBUGBUS
1235 printf("moving down x %x z %d dx %d\n", sprite->x + sprite->x_hot, z, dx);
1236 #endif
1237 break;
1238 case 3: /* left */
1239 z = ((ty <<4)) - (sprite->y + sprite->y_hot);
1240 if (z < 0) dy = -1;
1241 else if (z > 0) dy = 1;
1242 #ifdef DEBUGBUS
1243 printf("moving left y %x z %d dy %d\n", sprite->y + sprite->y_hot, z, dy);
1244 #endif
1245 break;
1246 }
1247 }
1248 }
1249 #ifdef DEBUGBUS
1250 printf("speed dx %d dy %d\n", dx, dy);
1251 #endif
1252
1253 #define AHEAD 8
1254
1255 otx = (sprite->x + sprite->x_hot + (Dx[sprite->dir] * AHEAD)) >>4;
1256 oty = (sprite->y + sprite->y_hot + (Dy[sprite->dir] * AHEAD)) >>4;
1257 if (otx < 0) otx = 0; else if (otx >= WORLD_X) otx = WORLD_X - 1;
1258 if (oty < 0) oty = 0; else if (oty >= WORLD_Y) oty = WORLD_Y - 1;
1259
1260 tx = (sprite->x + sprite->x_hot + dx + (Dx[sprite->dir] * AHEAD)) >>4;
1261 ty = (sprite->y + sprite->y_hot + dy + (Dy[sprite->dir] * AHEAD)) >>4;
1262 if (tx < 0) tx = 0; else if (tx >= WORLD_X) tx = WORLD_X - 1;
1263 if (ty < 0) ty = 0; else if (ty >= WORLD_Y) ty = WORLD_Y - 1;
1264
1265 if ((tx != otx) || (ty != oty)) {
1266 #ifdef DEBUGBUS
1267 printf("drive from tile %d %d to %d %d\n",
1268 otx, oty, tx, ty);
1269 #endif
1270 z = CanDriveOn(tx, ty);
1271 if (z == 0) {
1272 /* can't drive forward into a new tile */
1273 if (speed == 8) {
1274 bulldozer_tool(NULL, tx, ty);
1275 } else {
1276 }
1277 } else {
1278 /* drive forward into a new tile */
1279 if (z > 0) {
1280 /* smooth */
1281 } else {
1282 /* bumpy */
1283 dx /= 2;
1284 dy /= 2;
1285 }
1286 }
1287 }
1288
1289 tx = (sprite->x + sprite->x_hot + dx) >>4;
1290 ty = (sprite->y + sprite->y_hot + dy) >>4;
1291 z = CanDriveOn(tx, ty);
1292 if (z > 0) {
1293 /* cool, cruise along */
1294 } else {
1295 if (z < 0) {
1296 /* bumpy */
1297 } else {
1298 /* something in the way */
1299 }
1300 }
1301
1302 sprite->x += dx;
1303 sprite->y += dy;
1304
1305 if (!NoDisasters) {
1306 SimSprite *s;
1307 int explode = 0;
1308
1309 for (s = sim->sprite; s != NULL; s = s->next) {
1310 if ((sprite != s) &&
1311 (s->frame != 0) &&
1312 ((s->type == BUS) ||
1313 ((s->type == TRA) &&
1314 (s->frame != 5))) &&
1315 CheckSpriteCollision(sprite, s)) {
1316 ExplodeSprite(s);
1317 explode = 1;
1318 }
1319 }
1320 if (explode)
1321 ExplodeSprite(sprite);
1322 }
1323 }
1324
1325
1326 int
1327 CanDriveOn(int x, int y)
1328 {
1329 int tile;
1330
1331 if (!TestBounds(x, y))
1332 return 0;
1333
1334 tile = Map[x][y] & LOMASK;
1335
1336 if (((tile >= ROADBASE) &&
1337 (tile <= LASTROAD) &&
1338 (tile != BRWH) &&
1339 (tile != BRWV)) ||
1340 (tile == HRAILROAD) ||
1341 (tile == VRAILROAD))
1342 return 1;
1343
1344 if ((tile == DIRT) || tally(tile))
1345 return -1;
1346
1347 return 0;
1348 }
1349
1350
1351 ExplodeSprite(SimSprite *sprite)
1352 {
1353 int x, y;
1354
1355 sprite->frame = 0;
1356
1357 x = sprite->x + sprite->x_hot;
1358 y = sprite->y + sprite->y_hot;
1359 MakeExplosionAt(x, y);
1360
1361 x = (x >>4);
1362 y = (y >>4);
1363
1364 switch (sprite->type) {
1365 case AIR:
1366 CrashX = x;
1367 CrashY = y;
1368 SendMesAt(-24, x, y);
1369 break;
1370 case SHI:
1371 CrashX = x;
1372 CrashY = y;
1373 SendMesAt(-25, x, y);
1374 break;
1375 case TRA:
1376 CrashX = x;
1377 CrashY = y;
1378 SendMesAt(-26, x, y);
1379 break;
1380 case COP:
1381 CrashX = x;
1382 CrashY = y;
1383 SendMesAt(-27, x, y);
1384 break;
1385 case BUS:
1386 CrashX = x;
1387 CrashY = y;
1388 SendMesAt(-26, x, y); /* XXX for now */
1389 break;
1390 }
1391 MakeSound("city", "Explosion-High"); /* explosion */
1392 return;
1393 }
1394
1395
1396 int checkWet(int x)
1397 {
1398 if ((x == POWERBASE) || (x == POWERBASE + 1) ||
1399 (x == RAILBASE) || (x == RAILBASE + 1) ||
1400 (x == BRWH) || (x == BRWV))
1401 return(1);
1402 else
1403 return(0);
1404 }
1405
1406
1407 Destroy(int ox, int oy)
1408 {
1409 short t, z, x, y;
1410
1411 x = ox >>4;
1412 y = oy >>4;
1413 if (!TestBounds(x, y))
1414 return;
1415 z = Map[x][y];
1416 t = z & LOMASK;
1417 if (t >= TREEBASE) {
1418 /* TILE_IS_BRIDGE(t) */
1419 if (!(z & BURNBIT)) {
1420 if ((t >= ROADBASE) && (t <= LASTROAD))
1421 Map[x][y] = RIVER;
1422 return;
1423 }
1424 if (z & ZONEBIT) {
1425 OFireZone(x, y, z);
1426 if (t > RZB) {
1427 MakeExplosionAt(ox, oy);
1428 }
1429 }
1430 if (checkWet(t))
1431 Map[x][y] = RIVER;
1432 else
1433 Map[x][y] = (DoAnimation
1434 ? TINYEXP
1435 : (LASTTINYEXP - 3)) | BULLBIT | ANIMBIT;
1436 }
1437 }
1438
1439
1440 OFireZone(int Xloc, int Yloc, int ch)
1441 {
1442 register short Xtem, Ytem;
1443 short x, y, XYmax;
1444
1445 RateOGMem[Xloc >>3][Yloc >>3] -= 20;
1446
1447 ch &= LOMASK;
1448 if (ch < PORTBASE)
1449 XYmax = 2;
1450 else
1451 if (ch == AIRPORT) XYmax = 5;
1452 else XYmax = 4;
1453
1454 for (x = -1; x < XYmax; x++)
1455 for (y = -1; y < XYmax; y++) {
1456 Xtem = Xloc + x;
1457 Ytem = Yloc + y;
1458 if ((Map[Xtem][Ytem] & LOMASK) >= ROADBASE)
1459 Map[Xtem][Ytem] |= BULLBIT;
1460 }
1461 }
1462
1463
1464 StartFire(int x, int y)
1465 {
1466 register t, z;
1467
1468 x >>= 4;
1469 y >>= 4;
1470 if ((x >= WORLD_X) ||
1471 (y >= WORLD_Y) ||
1472 (x < 0) || (y < 0))
1473 return;
1474 z = Map[x][y];
1475 t = z & LOMASK;
1476 if ((!(z & BURNBIT)) && (t != 0)) return;
1477 if (z & ZONEBIT) return;
1478 Map[x][y] = FIRE + (Rand16() & 3) + ANIMBIT;
1479 }
1480
1481
1482 GenerateTrain(int x, int y)
1483 {
1484 if ((TotalPop > 20) &&
1485 (GetSprite(TRA) == NULL) &&
1486 (!Rand(25))) {
1487 MakeSprite(TRA, (x <<4) + TRA_GROOVE_X, (y <<4) + TRA_GROOVE_Y);
1488 }
1489 }
1490
1491
1492 GenerateBus(int x, int y)
1493 {
1494 if ((GetSprite(BUS) == NULL) &&
1495 (!Rand(25))) {
1496 MakeSprite(BUS, (x <<4) + BUS_GROOVE_X, (y <<4) + BUS_GROOVE_Y);
1497 }
1498 }
1499
1500
1501 GenerateShip(void)
1502 {
1503 register short x, y;
1504
1505 if (!(Rand16() & 3))
1506 for (x = 4; x < WORLD_X - 2; x++)
1507 if (Map[x][0] == CHANNEL) {
1508 MakeShipHere(x, 0);
1509 return;
1510 }
1511 if (!(Rand16() & 3))
1512 for (y = 1; y < WORLD_Y - 2; y++)
1513 if (Map[0][y] == CHANNEL) {
1514 MakeShipHere(0, y);
1515 return;
1516 }
1517 if (!(Rand16() & 3))
1518 for (x = 4; x < WORLD_X - 2; x++)
1519 if (Map[x][WORLD_Y - 1] == CHANNEL) {
1520 MakeShipHere(x, WORLD_Y - 1);
1521 return;
1522 }
1523 if (!(Rand16() & 3))
1524 for (y = 1; y < WORLD_Y - 2; y++)
1525 if (Map[WORLD_X - 1][y] == CHANNEL) {
1526 MakeShipHere(WORLD_X - 1, y);
1527 return;
1528 }
1529 }
1530
1531
1532 MakeShipHere(int x, int y, int z)
1533 {
1534 MakeSprite(SHI, (x <<4) - (48 - 1), (y <<4));
1535 }
1536
1537
1538 MakeMonster(void)
1539 {
1540 register x, y, z, done = 0;
1541 SimSprite *sprite;
1542
1543 if ((sprite = GetSprite(GOD)) != NULL) {
1544 sprite->sound_count = 1;
1545 sprite->count = 1000;
1546 sprite->dest_x = PolMaxX <<4;
1547 sprite->dest_y = PolMaxY <<4;
1548 return;
1549 }
1550
1551 for (z = 0; z < 300; z++) {
1552 x = Rand(WORLD_X - 20) + 10;
1553 y = Rand(WORLD_Y - 10) + 5;
1554 if ((Map[x][y] == RIVER) || (Map[x][y] == RIVER + BULLBIT)) {
1555 MonsterHere(x, y);
1556 done = 1;
1557 break;
1558 }
1559 }
1560 if (!done == 0)
1561 MonsterHere(60, 50);
1562 }
1563
1564
1565 MonsterHere(int x, int y)
1566 {
1567 short z;
1568
1569 MakeSprite(GOD, (x <<4) + 48, (y <<4));
1570 ClearMes();
1571 SendMesAt(-21, x + 5, y);
1572 }
1573
1574
1575 GenerateCopter(int x, int y)
1576 {
1577 if (GetSprite(COP) != NULL) return;
1578
1579 MakeSprite(COP, (x <<4), (y <<4) + 30);
1580 }
1581
1582
1583 GeneratePlane(int x, int y)
1584 {
1585 if (GetSprite(AIR) != NULL) return;
1586
1587 MakeSprite(AIR, (x <<4) + 48, (y <<4) + 12);
1588 }
1589
1590
1591 MakeAirCrash(void)
1592 {
1593 #ifndef NO_AIRCRASH
1594 if (GetSprite(AIR) == NULL) {
1595 short x, y;
1596
1597 x = Rand(WORLD_X - 20) + 10;
1598 y = Rand(WORLD_Y - 10) + 5;
1599
1600 GeneratePlane(x, y);
1601 }
1602
1603 ExplodeSprite(GetSprite(AIR));
1604 #endif
1605 }
1606
1607
1608 MakeTornado(void)
1609 {
1610 short x, y;
1611 SimSprite *sprite;
1612
1613 if ((sprite = GetSprite(TOR)) != NULL) {
1614 sprite->count = 200;
1615 return;
1616 }
1617
1618 x = Rand((WORLD_X <<4) - 800) + 400;
1619 y = Rand((WORLD_Y <<4) - 200) + 100;
1620 MakeSprite(TOR, x, y);
1621 ClearMes();
1622 SendMesAt(-22, (x >>4) + 3, (y >>4) + 2);
1623 }
1624
1625
1626 MakeExplosion(int x, int y)
1627 {
1628 if ((x >= 0) && (x < WORLD_X) &&
1629 (y >= 0) && (y < WORLD_Y)) {
1630 MakeExplosionAt((x << 4) + 8, (y << 4) + 8);
1631 }
1632 }
1633
1634
1635 MakeExplosionAt(int x, int y)
1636 {
1637 MakeNewSprite(EXP, x - 40, y - 16);
1638 }
1639
Impressum, Datenschutz