Micropolis
sprite.cpp
Go to the documentation of this file.
1/* sprite.cpp
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
78
79
80#include "micropolis.h"
81#include "text.h"
82
83
85
86
87#define TRA_GROOVE_X -39
88#define TRA_GROOVE_Y 6
89#define BUS_GROOVE_X -39
90#define BUS_GROOVE_Y 6
91
92
94
95
104SimSprite *Micropolis::newSprite(const std::string &name, int type, int x, int y)
105{
106 SimSprite *sprite;
107
108 // If a sprite is available at the pool, use one.
109 // else, allocate a new one.
110 if (freeSprites) {
111 sprite = freeSprites;
112 freeSprites = sprite->next;
113 } else {
114 sprite = (SimSprite *)newPtr(sizeof (SimSprite));
115 }
116
117 sprite->name = name;
118 sprite->type = type;
119
120 initSprite(sprite, x, y);
121
122 sprite->next = spriteList;
123 spriteList = sprite;
124
125 return sprite;
126}
127
128
136void Micropolis::initSprite(SimSprite *sprite, int x, int y)
137{
138 sprite->x = x;
139 sprite->y = y;
140 sprite->frame = 0;
141 sprite->origX = 0;
142 sprite->origY = 0;
143 sprite->destX = 0;
144 sprite->destY = 0;
145 sprite->count = 0;
146 sprite->soundCount = 0;
147 sprite->dir = 0;
148 sprite->newDir = 0;
149 sprite->step = 0;
150 sprite->flag = 0;
151 sprite->control = -1;
152 sprite->turn = 0;
153 sprite->accel = 0;
154 sprite->speed = 100;
155
156 if (globalSprites[sprite->type] == NULL) {
157 globalSprites[sprite->type] = sprite;
158 }
159
160 switch (sprite->type) {
161
162 case SPRITE_TRAIN:
163 sprite->width = 32;
164 sprite->height = 32;
165 sprite->xOffset = 32;
166 sprite->yOffset = -16;
167 sprite->xHot = 40;
168 sprite->yHot = -8;
169 sprite->frame = 1;
170 sprite->dir = 4;
171 break;
172
173 case SPRITE_SHIP:
174 sprite->width = 48;
175 sprite->height = 48;
176 sprite->xOffset = 32;
177 sprite->yOffset = -16;
178 sprite->xHot = 48;
179 sprite->yHot = 0;
180
181 if (x < (4 <<4)) {
182 sprite->frame = 3;
183 } else if (x >= ((WORLD_W - 4) <<4)) {
184 sprite->frame = 7;
185 } else if (y < (4 <<4)) {
186 sprite->frame = 5;
187 } else if (y >= ((WORLD_H - 4) <<4)) {
188 sprite->frame = 1;
189 } else {
190 sprite->frame = 3;
191 }
192
193 sprite->newDir = sprite->frame;
194 sprite->dir = 10;
195 sprite->count = 1;
196 break;
197
198 case SPRITE_MONSTER:
199 sprite->width = 48;
200 sprite->height = 48;
201 sprite->xOffset = 24;
202 sprite->yOffset = 0;
203 sprite->xHot = 40;
204 sprite->yHot = 16;
205
206 if (x > ((WORLD_W <<4) / 2)) {
207 if (y > ((WORLD_H <<4) / 2)) {
208 sprite->frame = 10;
209 } else {
210 sprite->frame = 7;
211 }
212 } else if (y > ((WORLD_H <<4) / 2)) {
213 sprite->frame = 1;
214 } else {
215 sprite->frame = 4;
216 }
217
218 sprite->count = 1000;
219 sprite->destX = pollutionMaxX <<4;
220 sprite->destY = pollutionMaxY <<4;
221 sprite->origX = sprite->x;
222 sprite->origY = sprite->y;
223 break;
224
226 sprite->width = 32;
227 sprite->height = 32;
228 sprite->xOffset = 32;
229 sprite->yOffset = -16;
230 sprite->xHot = 40;
231 sprite->yHot = -8;
232 sprite->frame = 5;
233 sprite->count = 1500;
234 sprite->destX = getRandom((WORLD_W <<4) - 1);
235 sprite->destY = getRandom((WORLD_H <<4) - 1);
236 sprite->origX = x - 30;
237 sprite->origY = y;
238 break;
239
240 case SPRITE_AIRPLANE:
241 sprite->width = 48;
242 sprite->height = 48;
243 sprite->xOffset = 24;
244 sprite->yOffset = 0;
245 sprite->xHot = 48;
246 sprite->yHot = 16;
247 if (x > ((WORLD_W - 20) <<4)) {
248 sprite->x -= 100 + 48;
249 sprite->destX = sprite->x - 200;
250 sprite->frame = 7;
251 } else {
252 sprite->destX = sprite->x + 200;
253 sprite->frame = 11;
254 }
255 sprite->destY = sprite->y;
256 break;
257
258 case SPRITE_TORNADO:
259 sprite->width = 48;
260 sprite->height = 48;
261 sprite->xOffset = 24;
262 sprite->yOffset = 0;
263 sprite->xHot = 40;
264 sprite->yHot = 36;
265 sprite->frame = 1;
266 sprite->count = 200;
267 break;
268
269 case SPRITE_EXPLOSION:
270 sprite->width = 48;
271 sprite->height = 48;
272 sprite->xOffset = 24;
273 sprite->yOffset = 0;
274 sprite->xHot = 40;
275 sprite->yHot = 16;
276 sprite->frame = 1;
277 break;
278
279 case SPRITE_BUS:
280 sprite->width = 32;
281 sprite->height = 32;
282 sprite->xOffset = 30;
283 sprite->yOffset = -18;
284 sprite->xHot = 40;
285 sprite->yHot = -8;
286 sprite->frame = 1;
287 sprite->dir = 1;
288 break;
289
290 }
291}
292
293
299{
300 SimSprite *sprite;
301
302 for (sprite = spriteList; sprite != NULL; sprite = sprite->next) {
303 sprite->frame = 0;
304 }
305}
306
307
314{
315 SimSprite **sp;
316
317 if (globalSprites[sprite->type] == sprite) {
318 globalSprites[sprite->type] = (SimSprite *)NULL;
319 }
320
321 for (sp = &spriteList; *sp != NULL; sp = &((*sp)->next)) {
322 if (sprite == (*sp)) {
323 *sp = sprite->next;
324 break;
325 }
326 }
327
328 sprite->next = freeSprites;
329 freeSprites = sprite;
330}
331
332
339{
340 SimSprite *sprite = globalSprites[type];
341 if (sprite == NULL || sprite->frame == 0) {
342 return (SimSprite *)NULL;
343 } else {
344 return sprite;
345 }
346}
347
348
355SimSprite *Micropolis::makeSprite(int type, int x, int y)
356{
357 SimSprite *sprite;
358
359 sprite = globalSprites[type];
360 if (sprite == NULL) {
361 sprite = newSprite("", type, x, y);
362 } else {
363 initSprite(sprite, x, y);
364 }
365 return sprite;
366}
367
368
375short Micropolis::getChar(int x, int y)
376{
377 // Convert sprite coordinates to tile coordinates.
378 x >>= 4;
379 y >>= 4;
380
381 if (!testBounds(x, y)) {
382 return -1;
383 } else {
384 return map[x][y] & LOMASK;
385 }
386}
387
388
396short Micropolis::turnTo(int p, int d)
397{
398 if (p == d) {
399 return p;
400 }
401
402 if (p < d) {
403 if (d - p < 4) {
404 p++;
405 } else {
406 p--;
407 }
408 } else {
409 if (p - d < 4) {
410 p--;
411 } else {
412 p++;
413 }
414 }
415
416 if (p > 8) {
417 p = 1;
418 }
419
420 if (p < 1) {
421 p = 8;
422 }
423
424 return p;
425}
426
431bool Micropolis::tryOther(int Tpoo, int Told, int Tnew)
432{
433 short z;
434
435 z = Told + 4;
436
437 if (z > 8) {
438 z -= 8;
439 }
440
441 if (Tnew != z) {
442 return false;
443 }
444
445 if (Tpoo == POWERBASE || Tpoo == POWERBASE + 1
446 || Tpoo == RAILBASE || Tpoo == RAILBASE + 1) {
447 return true;
448 }
449
450 return false;
451}
452
453
460{
461 int x = sprite->x + sprite->xHot;
462 int y = sprite->y + sprite->yHot;
463
464 return x < 0 || y < 0 || x >= (WORLD_W <<4) || y >= (WORLD_H <<4);
465}
466
477short Micropolis::getDir(int orgX, int orgY, int desX, int desY)
478{
479 static const short Gdtab[13] = { 0, 3, 2, 1, 3, 4, 5, 7, 6, 5, 7, 8, 1 };
480 int dispX, dispY, z;
481
482 dispX = desX - orgX;
483 dispY = desY - orgY;
484
485 if (dispX < 0) {
486 if (dispY < 0) {
487 z = 11;
488 } else {
489 z = 8;
490 }
491 } else {
492 if (dispY < 0) {
493 z = 2;
494 } else {
495 z = 5;
496 }
497 }
498
499 dispX = absoluteValue(dispX);
500 dispY = absoluteValue(dispY);
501 absDist = dispX + dispY;
502
503 if (dispX * 2 < dispY) {
504 z++;
505 } else if (dispY * 2 < dispY) { // XXX This never holds!!
506 z--;
507 }
508
509 if (z < 0 || z > 12) {
510 z = 0;
511 }
512
513 return Gdtab[z];
514}
515
516
525int Micropolis::getDistance(int x1, int y1, int x2, int y2)
526{
527 return absoluteValue(x1 - x2) + absoluteValue(y1 - y2);
528}
529
530
538{
539 return s1->frame != 0 && s2->frame != 0 &&
540 getDistance(s1->x + s1->xHot, s1->y + s1->yHot,
541 s2->x + s2->xHot, s2->y + s2->yHot) < 30;
542}
543
544
554{
555 SimSprite *sprite;
556
557 if (!simSpeed) {
558 return;
559 }
560
561 spriteCycle++;
562
563 for (sprite = spriteList; sprite != NULL;) {
564 if (sprite->frame > 0) {
565 switch (sprite->type) {
566
567 case SPRITE_TRAIN:
568 doTrainSprite(sprite);
569 break;
570
572 doCopterSprite(sprite);
573 break;
574
575 case SPRITE_AIRPLANE:
576 doAirplaneSprite(sprite);
577 break;
578
579 case SPRITE_SHIP:
580 doShipSprite(sprite);
581 break;
582
583 case SPRITE_MONSTER:
584 doMonsterSprite(sprite);
585 break;
586
587 case SPRITE_TORNADO:
588 doTornadoSprite(sprite);
589 break;
590
591 case SPRITE_EXPLOSION:
592 doExplosionSprite(sprite);
593 break;
594
595 case SPRITE_BUS:
596 doBusSprite(sprite);
597 break;
598
599 }
600
601 sprite = sprite->next;
602
603 } else {
604
605 if (sprite->name[0] == '\0') {
606 SimSprite *s = sprite;
607 sprite = sprite->next;
608 destroySprite(s);
609 } else {
610 sprite = sprite->next;
611 }
612
613 }
614 }
615}
616
617
624{
625 /* Offset in pixels of sprite x and y to map tile */
626 static const short Cx[4] = { 0, 16, 0, -16 };
627 static const short Cy[4] = { -16, 0, 16, 0 };
628 /* X and Y movement of the sprite in pixels */
629 static const short Dx[5] = { 0, 4, 0, -4, 0 };
630 static const short Dy[5] = { -4, 0, 4, 0, 0 };
631
632 static const short TrainPic2[5] = { 1, 2, 1, 2, 5 };
633 short z, dir, dir2;
634 short c;
635
636 if (sprite->frame == 3 || sprite->frame == 4) {
637 sprite->frame = TrainPic2[sprite->dir];
638 }
639
640 sprite->x += Dx[sprite->dir];
641 sprite->y += Dy[sprite->dir];
642
643 if ((spriteCycle & 3) == 0) {
644
645 dir = getRandom16() & 3;
646 for (z = dir; z < dir + 4; z++) {
647 dir2 = z & 3;
648
649 if (sprite->dir != 4) {
650 if (dir2 == ((sprite->dir + 2) & 3)) {
651 continue;
652 }
653 }
654
655 c = getChar(sprite->x + Cx[dir2] + 48, sprite->y + Cy[dir2]);
656
657 if ((c >= RAILBASE && c <= LASTRAIL) /* track? */
658 || c == RAILVPOWERH || c == RAILHPOWERV) {
659
660 if (sprite->dir != dir2 && sprite->dir != 4) {
661
662 if (sprite->dir + dir2 == 3) {
663 sprite->frame = 3;
664 } else {
665 sprite->frame = 4;
666 }
667
668 } else {
669 sprite->frame = TrainPic2[dir2];
670 }
671
672 if (c == HRAIL || c == VRAIL) {
673 sprite->frame = 5;
674 }
675
676 sprite->dir = dir2;
677 return;
678 }
679 }
680
681 if (sprite->dir == 4) {
682 sprite->frame = 0;
683 return;
684 }
685
686 sprite->dir = 4;
687 }
688}
689
696 SimSprite *sprite)
697{
698 static const short CDx[9] = { 0, 0, 3, 5, 3, 0, -3, -5, -3 };
699 static const short CDy[9] = { 0, -5, -3, 0, 3, 5, 3, 0, -3 };
700
701 if (sprite->soundCount > 0) {
702 sprite->soundCount--;
703 }
704
705 if (sprite->control < 0) {
706
707 if (sprite->count > 0) {
708 sprite->count--;
709 }
710
711 if (sprite->count == 0) {
712
713 /* Attract copter to monster so it blows up more often */
715
716 if (s != NULL) {
717 sprite->destX = s->x;
718 sprite->destY = s->y;
719 } else {
720
721 /* Attract copter to tornado so it blows up more often */
723
724 if (s != NULL) {
725 sprite->destX = s->x;
726 sprite->destY = s->y;
727 } else {
728 sprite->destX = sprite->origX;
729 sprite->destY = sprite->origY;
730 }
731
732 }
733 }
734
735 if (sprite->count == 0) { /* land */
736 getDir(sprite->x, sprite->y, sprite->origX, sprite->origY);
737
738 if (absDist < 30) {
739 sprite->frame = 0;
740 return;
741 }
742
743 }
744
745 } else {
746
747 getDir(sprite->x, sprite->y, sprite->destX, sprite->destY);
748
749 if (absDist < 16) {
750 sprite->destX = sprite->origX;
751 sprite->destY = sprite->origY;
752 sprite->control = -1;
753 }
754
755 }
756
757 if (sprite->soundCount == 0) { /* send report */
758
759 // Convert sprite coordinates to world coordinates.
760 short x = (sprite->x + 48) / 16;
761 short y = sprite->y / 16;
762
763 if (x >= 0 && x < WORLD_W && y >= 0 && y < WORLD_H) {
764
765 /* Don changed from 160 to 170 to shut the #$%#$% thing up! */
766
767 int chopperX = x + 1;
768 int chopperY = y + 1;
769 if (trafficDensityMap.worldGet(x, y) > 170 && (getRandom16() & 7) == 0) {
770 sendMessage(MESSAGE_HEAVY_TRAFFIC, chopperX, chopperY, true);
771 makeSound("city", "HeavyTraffic", chopperX, chopperY); /* chopper */
772 sprite->soundCount = 200;
773 }
774
775 }
776
777 }
778
779 short z = sprite->frame;
780
781 if ((spriteCycle & 3) == 0) {
782 short d = getDir(sprite->x, sprite->y, sprite->destX, sprite->destY);
783 z = turnTo(z, d);
784 sprite->frame = z;
785 }
786
787 sprite->x += CDx[z];
788 sprite->y += CDy[z];
789}
790
791
801 SimSprite *sprite)
802{
803 static const short CDx[12] = { 0, 0, 6, 8, 6, 0, -6, -8, -6, 8, 8, 8 };
804 static const short CDy[12] = { 0, -8, -6, 0, 6, 8, 6, 0, -6, 0, 0, 0 };
805
806 short z = sprite->frame;
807
808 if ((spriteCycle % 5) == 0) {
809
810 if (z > 8) { /* TakeOff */
811 z--;
812 if (z < 9) {
813 z = 3;
814 }
815 sprite->frame = z;
816 } else { /* goto destination */
817 short d = getDir(sprite->x, sprite->y, sprite->destX, sprite->destY);
818 z = turnTo(z, d);
819 sprite->frame = z;
820 }
821
822 }
823
824 if (absDist < 50) { /* at destination */
825 sprite->destX = getRandom((WORLD_W * 16) + 100) - 50;
826 sprite->destY = getRandom((WORLD_H * 16) + 100) - 50;
827 }
828
829 /* deh added test for enableDisasters */
830 if (enableDisasters) {
831 SimSprite *s;
832 bool explode = false;
833
834 /* Check whether another sprite is near enough to collide with */
835 for (s = spriteList; s != NULL; s = s->next) {
836 if (s->frame == 0 || s == sprite) {
837 /* Non-active sprite, or self: skip */
838 continue;
839 }
840
841 if ((s->type == SPRITE_HELICOPTER || s->type == SPRITE_AIRPLANE)
842 && checkSpriteCollision(sprite, s)) {
843 explodeSprite(s);
844 explode = true;
845 }
846 }
847
848 if (explode) {
849 explodeSprite(sprite);
850 }
851 }
852
853 sprite->x += CDx[z];
854 sprite->y += CDy[z];
855
856 if (spriteNotInBounds(sprite)) {
857 sprite->frame = 0;
858 }
859}
860
861
868{
869 static const short BDx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
870 static const short BDy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
871 static const short BPx[9] = { 0, 0, 2, 2, 2, 0, -2, -2, -2 };
872 static const short BPy[9] = { 0, -2, -2, 0, 2, 2, 2, 0, -2 };
873 static const short BtClrTab[8] = { RIVER, CHANNEL, POWERBASE, POWERBASE + 1,
874 RAILBASE, RAILBASE + 1, BRWH, BRWV };
875 short x, y, z, t = RIVER;
876 short tem, pem;
877
878 if (sprite->soundCount > 0) {
879 sprite->soundCount--;
880 }
881
882 if (!sprite->soundCount) {
883
884 if ((getRandom16() & 3) == 1) {
885
886 // Convert sprite coordinates to tile coordinates.
887 int shipX = sprite->x >>4;
888 int shipY = sprite->y >>4;
889
890 if (scenario == SC_SAN_FRANCISCO && getRandom(10) < 5) {
891 makeSound("city", "FogHornLow", shipX, shipY);
892 } else {
893 makeSound("city", "HonkHonkLow", shipX, shipY);
894 }
895
896 }
897
898 sprite->soundCount = 200;
899 }
900
901 if (sprite->count > 0) {
902 sprite->count--;
903 }
904
905 if (sprite->count == 0) {
906
907 sprite->count = 9;
908
909 if (sprite->frame != sprite->newDir) {
910 sprite->frame = turnTo(sprite->frame, sprite->newDir);
911 return;
912 }
913
914 tem = getRandom16() & 7;
915
916 for (pem = tem; pem < (tem + 8); pem++) {
917
918 z = (pem & 7) + 1;
919
920 if (z == sprite->dir) {
921 continue;
922 }
923
924 x = ((sprite->x + (48 - 1)) >>4) + BDx[z];
925 y = (sprite->y >>4) + BDy[z];
926
927 if (testBounds(x, y)) {
928
929 t = map[x][y] & LOMASK;
930
931 if (t == CHANNEL || t == BRWH || t == BRWV
932 || tryOther(t, sprite->dir, z)) {
933
934 sprite->newDir = z;
935 sprite->frame = turnTo(sprite->frame, sprite->newDir);
936 sprite->dir = z + 4;
937
938 if (sprite->dir > 8) {
939 sprite->dir -= 8;
940 }
941
942 break;
943 }
944 }
945 }
946
947 if (pem == (tem + 8)) {
948 sprite->dir = 10;
949 sprite->newDir = (getRandom16() & 7) + 1;
950 }
951
952 } else {
953
954 z = sprite->frame;
955
956 if (z == sprite->newDir) {
957 sprite->x += BPx[z];
958 sprite->y += BPy[z];
959 }
960 }
961
962 if (spriteNotInBounds(sprite)) {
963 sprite->frame = 0;
964 return;
965 }
966
967 for (z = 0; z < 8; z++) {
968
969 if (t == BtClrTab[z]) {
970 break;
971 }
972
973 if (z == 7) {
974 explodeSprite(sprite);
975 destroyMapTile(sprite->x + 48, sprite->y);
976 }
977
978 }
979}
980
981
1008{
1009 static const short Gx[5] = { 2, 2, -2, -2, 0 };
1010 static const short Gy[5] = { -2, 2, 2, -2, 0 };
1011 static const short ND1[4] = { 0, 1, 2, 3 };
1012 static const short ND2[4] = { 1, 2, 3, 0 };
1013 static const short nn1[4] = { 2, 5, 8, 11 };
1014 static const short nn2[4] = { 11, 2, 5, 8 };
1015 short d, z, c;
1016
1017 if (sprite->soundCount > 0) {
1018 sprite->soundCount--;
1019 }
1020
1021 if (sprite->control < 0) {
1022 /* business as usual */
1023
1024 if (sprite->control == -2) {
1025
1026 d = (sprite->frame - 1) / 3;
1027 z = (sprite->frame - 1) % 3;
1028
1029 if (z == 2) {
1030 sprite->step = 0;
1031 }
1032
1033 if (z == 0) {
1034 sprite->step = 1;
1035 }
1036
1037 if (sprite->step) {
1038 z++;
1039 } else {
1040 z--;
1041 }
1042
1043 c = getDir(sprite->x, sprite->y, sprite->destX, sprite->destY);
1044
1045 if (absDist < 18) {
1046
1047 sprite->control = -1;
1048 sprite->count = 1000;
1049 sprite->flag = 1;
1050 sprite->destX = sprite->origX;
1051 sprite->destY = sprite->origY;
1052
1053 } else {
1054
1055 c = (c - 1) / 2;
1056
1057 if ((c != d && getRandom(5) == 0) || getRandom(20) == 0) {
1058
1059 int diff = (c - d) & 3;
1060
1061 if (diff == 1 || diff == 3) {
1062 d = c;
1063 } else {
1064
1065 if (getRandom16() & 1) {
1066 d++;
1067 } else {
1068 d--;
1069 }
1070
1071 d &= 3;
1072 }
1073 } else {
1074
1075 if (getRandom(20) == 0) {
1076
1077 if (getRandom16() & 1) {
1078 d++;
1079 } else {
1080 d--;
1081 }
1082
1083 d &= 3;
1084 }
1085 }
1086 }
1087 } else {
1088
1089 d = (sprite->frame - 1) / 3;
1090
1091 if (d < 4) { /* turn n s e w */
1092
1093 z = (sprite->frame - 1) % 3;
1094
1095 if (z == 2) {
1096 sprite->step = 0;
1097 }
1098
1099 if (z == 0) {
1100 sprite->step = 1;
1101 }
1102
1103 if (sprite->step) {
1104 z++;
1105 } else {
1106 z--;
1107 }
1108
1109 getDir(sprite->x, sprite->y, sprite->destX, sprite->destY);
1110
1111 if (absDist < 60) {
1112
1113 if (sprite->flag == 0) {
1114
1115 sprite->flag = 1;
1116 sprite->destX = sprite->origX;
1117 sprite->destY = sprite->origY;
1118
1119 } else {
1120
1121 sprite->frame = 0;
1122 return;
1123
1124 }
1125
1126 }
1127
1128 c = getDir(sprite->x, sprite->y, sprite->destX, sprite->destY);
1129 c = (c - 1) / 2;
1130
1131 if ((c != d) && (!getRandom(10))) {
1132
1133 if (getRandom16() & 1) {
1134 z = ND1[d];
1135 } else {
1136 z = ND2[d];
1137 }
1138
1139 d = 4;
1140
1141 if (!sprite->soundCount) {
1142 // Convert sprite coordinates to tile coordinates.
1143 int monsterX = sprite->x >>4;
1144 int monsterY = sprite->y >>4;
1145 makeSound("city", "Monster", monsterX, monsterY); /* monster */
1146 sprite->soundCount = 50 + getRandom(100);
1147 }
1148
1149 }
1150
1151 } else {
1152
1153 d = 4;
1154 c = sprite->frame;
1155 z = (c - 13) & 3;
1156
1157 if (!(getRandom16() & 3)) {
1158
1159 if (getRandom16() & 1) {
1160 z = nn1[z];
1161 } else {
1162 z = nn2[z];
1163 }
1164
1165 d = (z - 1) / 3;
1166 z = (z - 1) % 3;
1167
1168 }
1169
1170 }
1171
1172 }
1173
1174 } else {
1175
1176 /* somebody's taken control of the monster */
1177
1178 d = sprite->control;
1179 z = (sprite->frame - 1) % 3;
1180
1181 if (z == 2) {
1182 sprite->step = 0;
1183 }
1184
1185 if (z == 0) {
1186 sprite->step = 1;
1187 }
1188
1189 if (sprite->step) {
1190 z++;
1191 } else {
1192 z--;
1193 }
1194
1195 }
1196
1197 z = d * 3 + z + 1;
1198
1199 if (z > 16) {
1200 z = 16;
1201 }
1202
1203 sprite->frame = z;
1204
1205 sprite->x += Gx[d];
1206 sprite->y += Gy[d];
1207
1208 if (sprite->count > 0) {
1209 sprite->count--;
1210 }
1211
1212 c = getChar(sprite->x + sprite->xHot, sprite->y + sprite->yHot);
1213
1214 if (c == -1
1215 || (c == RIVER && sprite->count != 0 && sprite->control == -1)) {
1216 sprite->frame = 0; /* kill scary monster */
1217 }
1218
1219 {
1220 SimSprite *s;
1221 for (s = spriteList; s != NULL; s = s->next) {
1222 if (s->frame != 0 &&
1224 || s->type == SPRITE_SHIP || s->type == SPRITE_TRAIN) &&
1225 checkSpriteCollision(sprite, s)) {
1226 explodeSprite(s);
1227 }
1228 }
1229 }
1230
1231 destroyMapTile(sprite->x + 48, sprite->y + 16);
1232}
1233
1240{
1241 static const short CDx[9] = { 2, 3, 2, 0, -2, -3 };
1242 static const short CDy[9] = { -2, 0, 2, 3, 2, 0 };
1243 short z;
1244
1245 z = sprite->frame;
1246
1247 if (z == 2) {
1248
1249 /* cycle animation... post Rel */
1250
1251 if (sprite->flag) {
1252 z = 3;
1253 } else {
1254 z = 1;
1255 }
1256
1257 } else {
1258
1259 if (z == 1) {
1260 sprite->flag = 1;
1261 } else {
1262 sprite->flag = 0;
1263 }
1264
1265 z = 2;
1266 }
1267
1268 if (sprite->count > 0) {
1269 sprite->count--;
1270 }
1271
1272 sprite->frame = z;
1273
1274 {
1275 SimSprite *s;
1276 for (s = spriteList; s != NULL; s = s->next) {
1277 if (s->frame != 0 &&
1279 || s->type == SPRITE_SHIP || s->type == SPRITE_TRAIN) &&
1280 checkSpriteCollision(sprite, s)) {
1281 explodeSprite(s);
1282 }
1283 }
1284 }
1285
1286 z = getRandom(5);
1287 sprite->x += CDx[z];
1288 sprite->y += CDy[z];
1289
1290 if (spriteNotInBounds(sprite)) {
1291 sprite->frame = 0;
1292 }
1293
1294 if (sprite->count != 0 && getRandom(500) == 0) {
1295 sprite->frame = 0;
1296 }
1297
1298 destroyMapTile(sprite->x + 48, sprite->y + 40);
1299}
1300
1301
1307{
1308 short x, y;
1309
1310 if ((spriteCycle & 1) == 0) {
1311
1312 if (sprite->frame == 1) {
1313 // Convert sprite coordinates to tile coordinates.
1314 int explosionX = sprite->x >>4;
1315 int explosionY = sprite->y >>4;
1316 makeSound("city", "ExplosionHigh", explosionX, explosionY); /* explosion */
1317 x = (sprite->x >>4) + 3;
1318 y = (sprite->y >>4);
1320 }
1321
1322 sprite->frame++;
1323 }
1324
1325 if (sprite->frame > 6) {
1326 sprite->frame = 0;
1327
1328 startFire(sprite->x + 48 - 8, sprite->y + 16);
1329 startFire(sprite->x + 48 - 24, sprite->y);
1330 startFire(sprite->x + 48 + 8, sprite->y);
1331 startFire(sprite->x + 48 - 24, sprite->y + 32);
1332 startFire(sprite->x + 48 + 8, sprite->y + 32);
1333 }
1334}
1335
1336
1343{
1344 static const short Dx[5] = { 0, 1, 0, -1, 0 };
1345 static const short Dy[5] = { -1, 0, 1, 0, 0 };
1346 static const short Dir2Frame[4] = { 1, 2, 1, 2 };
1347 int dx, dy, tx, ty, otx, oty;
1348 int turned = 0;
1349 int speed = 0;
1350 int z;
1351
1352#ifdef DEBUGBUS
1353 printf("Bus dir %d turn %d frame %d\n",
1354 sprite->dir, sprite->turn, sprite->frame);
1355#endif
1356
1357 if (sprite->turn) {
1358
1359 if (sprite->turn < 0) { /* ccw */
1360
1361 if (sprite->dir & 1) { /* up or down */
1362 sprite->frame = 4;
1363 } else { /* left or right */
1364 sprite->frame = 3;
1365 }
1366
1367 sprite->turn++;
1368 sprite->dir = (sprite->dir - 1) & 3;
1369
1370 } else { /* cw */
1371
1372 if (sprite->dir & 1) { /* up or down */
1373 sprite->frame = 3;
1374 } else { /* left or right */
1375 sprite->frame = 4;
1376 }
1377
1378 sprite->turn--;
1379 sprite->dir = (sprite->dir + 1) & 3;
1380
1381 }
1382
1383 turned = 1;
1384
1385 } else {
1386
1387 /* finish turn */
1388 if ((sprite->frame == 3) ||
1389 (sprite->frame == 4)) {
1390 turned = 1;
1391 sprite->frame = Dir2Frame[sprite->dir];
1392 }
1393 }
1394
1395 if (sprite->speed == 0) {
1396
1397 /* brake */
1398 dx = 0; dy = 0;
1399
1400 } else { /* cruise at traffic speed */
1401
1402 tx = (sprite->x + sprite->xHot) >>5;
1403 ty = (sprite->y + sprite->yHot) >>5;
1404
1405 if (tx >= 0 && tx < WORLD_W_2 && ty >= 0 && ty < WORLD_H_2) {
1406
1407 z = trafficDensityMap.worldGet(tx << 1, ty << 1) >>6;
1408
1409 if (z > 1) {
1410 z--;
1411 }
1412
1413 } else {
1414
1415 z = 0;
1416
1417 }
1418
1419 switch (z) {
1420
1421 case 0:
1422 speed = 8;
1423 break;
1424
1425 case 1:
1426 speed = 4;
1427 break;
1428
1429 case 2:
1430 speed = 1;
1431 break;
1432
1433 }
1434
1435 /* govern speed */
1436 if (speed > sprite->speed) {
1437 speed = sprite->speed;
1438 }
1439
1440 if (turned) {
1441
1442#ifdef DEBUGBUS
1443 printf("turned\n");
1444#endif
1445
1446 if (speed > 1) {
1447 speed = 1;
1448 }
1449
1450 dx = Dx[sprite->dir] * speed;
1451 dy = Dy[sprite->dir] * speed;
1452
1453 } else {
1454
1455 dx = Dx[sprite->dir] * speed;
1456 dy = Dy[sprite->dir] * speed;
1457
1458 tx = (sprite->x + sprite->xHot) >>4;
1459 ty = (sprite->y + sprite->yHot) >>4;
1460
1461 /* drift into the right lane */
1462 switch (sprite->dir) {
1463
1464 case 0: /* up */
1465
1466 z = ((tx <<4) + 4) - (sprite->x + sprite->xHot);
1467
1468 if (z < 0) {
1469 dx = -1;
1470 } else if (z > 0) {
1471 dx = 1;
1472 }
1473
1474#ifdef DEBUGBUS
1475 printf("moving up x %x z %d dx %d\n", sprite->x + sprite->xHot, z, dx);
1476#endif
1477
1478 break;
1479
1480 case 1: /* right */
1481
1482 z = ((ty <<4) + 4) - (sprite->y + sprite->yHot);
1483
1484 if (z < 0) {
1485 dy = -1;
1486 } else if (z > 0) {
1487 dy = 1;
1488 }
1489
1490#ifdef DEBUGBUS
1491 printf("moving right y %x z %d dy %d\n", sprite->y + sprite->yHot, z, dy);
1492#endif
1493
1494 break;
1495
1496 case 2: /* down */
1497
1498 z = (tx <<4) - (sprite->x + sprite->xHot);
1499
1500 if (z < 0) {
1501 dx = -1;
1502 } else if (z > 0) {
1503 dx = 1;
1504 }
1505
1506#ifdef DEBUGBUS
1507 printf("moving down x %x z %d dx %d\n", sprite->x + sprite->xHot, z, dx);
1508#endif
1509
1510 break;
1511
1512 case 3: /* left */
1513
1514 z = (ty <<4) - (sprite->y + sprite->yHot);
1515
1516 if (z < 0) {
1517 dy = -1;
1518 } else if (z > 0) {
1519 dy = 1;
1520 }
1521
1522#ifdef DEBUGBUS
1523 printf("moving left y %x z %d dy %d\n", sprite->y + sprite->yHot, z, dy);
1524#endif
1525
1526 break;
1527 }
1528 }
1529 }
1530
1531#ifdef DEBUGBUS
1532 printf("speed dx %d dy %d\n", dx, dy);
1533#endif
1534
1535#define AHEAD 8
1536
1537 otx = (sprite->x + sprite->xHot + (Dx[sprite->dir] * AHEAD)) >>4;
1538 oty = (sprite->y + sprite->yHot + (Dy[sprite->dir] * AHEAD)) >>4;
1539
1540 otx = clamp(otx, 0, WORLD_W - 1);
1541 oty = clamp(oty, 0, WORLD_H - 1);
1542
1543 tx = (sprite->x + sprite->xHot + dx + (Dx[sprite->dir] * AHEAD)) >>4;
1544 ty = (sprite->y + sprite->yHot + dy + (Dy[sprite->dir] * AHEAD)) >>4;
1545
1546 tx = clamp(tx, 0, WORLD_W - 1);
1547 ty = clamp(ty, 0, WORLD_H - 1);
1548
1549 if (tx != otx || ty != oty) {
1550
1551#ifdef DEBUGBUS
1552 printf("drive from tile %d %d to %d %d\n",
1553 otx, oty, tx, ty);
1554#endif
1555
1556 z = canDriveOn(tx, ty);
1557
1558 if (z == 0) {
1559
1560 /* can't drive forward into a new tile */
1561 if (speed == 8) {
1562 bulldozerTool(tx, ty);
1563 } else {
1564 }
1565
1566 } else {
1567
1568 /* drive forward into a new tile */
1569 if (z > 0) {
1570 /* smooth */
1571 } else {
1572 /* bumpy */
1573 dx /= 2;
1574 dy /= 2;
1575 }
1576
1577 }
1578 }
1579
1580 tx = (sprite->x + sprite->xHot + dx) >>4;
1581 ty = (sprite->y + sprite->yHot + dy) >>4;
1582
1583 z = canDriveOn(tx, ty);
1584
1585 if (z > 0) {
1586 /* cool, cruise along */
1587 } else {
1588 if (z < 0) {
1589 /* bumpy */
1590 } else {
1591 /* something in the way */
1592 }
1593 }
1594
1595 sprite->x += dx;
1596 sprite->y += dy;
1597
1598 if (enableDisasters) {
1599 SimSprite *s;
1600 int explode = 0;
1601
1602 for (s = spriteList; s != NULL; s = s->next) {
1603 if (sprite != s && s->frame != 0
1604 && (s->type == SPRITE_BUS
1605 || (s->type == SPRITE_TRAIN && s->frame != 5))
1606 && checkSpriteCollision(sprite, s)) {
1607 explodeSprite(s);
1608 explode = 1;
1609 }
1610 }
1611
1612 if (explode) {
1613 explodeSprite(sprite);
1614 }
1615
1616 }
1617}
1618
1619
1626int Micropolis::canDriveOn(int x, int y)
1627{
1628 int tile;
1629
1630 if (!testBounds(x, y)) {
1631 return 0;
1632 }
1633
1634 tile = map[x][y] & LOMASK;
1635
1636 if ((tile >= ROADBASE && tile <= LASTROAD && tile != BRWH && tile != BRWV)
1637 || tile == HRAILROAD || tile == VRAILROAD) {
1638 return 1;
1639 }
1640
1641 if (tile == DIRT || tally(tile)) {
1642 return -1;
1643 }
1644
1645 return 0;
1646}
1647
1648
1655{
1656 int x, y;
1657
1658 sprite->frame = 0;
1659
1660 x = sprite->x + sprite->xHot;
1661 y = sprite->y + sprite->yHot;
1662 makeExplosionAt(x, y);
1663
1664 x = (x >>4);
1665 y = (y >>4);
1666
1667 switch (sprite->type) {
1668
1669 case SPRITE_AIRPLANE:
1671 break;
1672
1673 case SPRITE_SHIP:
1674 sendMessage(MESSAGE_SHIP_CRASHED, x, y, true);
1675 break;
1676
1677 case SPRITE_TRAIN:
1679 break;
1680
1681 case SPRITE_HELICOPTER:
1683 break;
1684
1685 case SPRITE_BUS:
1686 sendMessage(MESSAGE_TRAIN_CRASHED, x, y, true); /* XXX for now */
1687 break;
1688
1689 }
1690
1691 // Convert sprite coordinates to tile coordinates.
1692 makeSound("city", "ExplosionHigh", x, y); /* explosion */
1693
1694 return;
1695}
1696
1697
1698bool Micropolis::checkWet(int x)
1699{
1700 if (x == HPOWER || x == VPOWER || x == HRAIL || x == VRAIL
1701 || x == BRWH || x == BRWV) {
1702 return true;
1703 } else {
1704 return false;
1705 }
1706}
1707
1708
1714void Micropolis::destroyMapTile(int ox, int oy)
1715{
1716 short t, z, x, y;
1717
1718 x = ox >>4;
1719 y = oy >>4;
1720
1721 if (!testBounds(x, y)) {
1722 return;
1723 }
1724
1725 z = map[x][y];
1726 t = z & LOMASK;
1727
1728 if (t >= TREEBASE) {
1729 if (!(z & BURNBIT)) {
1730
1731 if (t >= ROADBASE && t <= LASTROAD) {
1732 map[x][y] = RIVER;
1733 }
1734
1735 return;
1736 }
1737
1738 if (z & ZONEBIT) {
1739
1740 startFireInZone(x, y, z);
1741
1742 if (t > RZB) {
1743 makeExplosionAt(ox, oy);
1744 }
1745
1746 }
1747
1748 if (checkWet(t)) {
1749 map[x][y] = RIVER;
1750 } else {
1751 map[x][y] = (doAnimation ? TINYEXP : (LASTTINYEXP - 3))
1752 | BULLBIT | ANIMBIT;
1753 }
1754 }
1755}
1756
1757
1764void Micropolis::startFireInZone(int Xloc, int Yloc, int ch)
1765{
1766 short Xtem, Ytem;
1767 short x, y, XYmax;
1768
1769 int value = rateOfGrowthMap.worldGet(Xloc, Yloc);
1770 value = clamp(value - 20, -200, 200);
1771 rateOfGrowthMap.worldSet(Xloc, Yloc, value);
1772
1773 ch &= LOMASK;
1774
1775 if (ch < PORTBASE) {
1776 XYmax = 2;
1777 } else {
1778 if (ch == AIRPORT) {
1779 XYmax = 5;
1780 } else {
1781 XYmax = 4;
1782 }
1783 }
1784
1785 for (x = -1; x < XYmax; x++) {
1786 for (y = -1; y < XYmax; y++) {
1787
1788 Xtem = Xloc + x;
1789 Ytem = Yloc + y;
1790
1791 if (testBounds(Xtem, Ytem) && (map[Xtem][Ytem] & LOMASK) >= ROADBASE) {
1792 map[Xtem][Ytem] |= BULLBIT;
1793 }
1794
1795 }
1796 }
1797}
1798
1799
1805void Micropolis::startFire(int x, int y)
1806{
1807 int t, z;
1808
1809 x >>= 4;
1810 y >>= 4;
1811
1812 if (!testBounds(x, y)) {
1813 return;
1814 }
1815
1816 z = map[x][y];
1817 t = z & LOMASK;
1818
1819 if (!(z & BURNBIT) && t != DIRT) {
1820 return;
1821 }
1822
1823 if (z & ZONEBIT) {
1824 return;
1825 }
1826
1827 map[x][y] = randomFire();
1828}
1829
1830
1837{
1838 if (totalPop > 20 && getSprite(SPRITE_TRAIN) == NULL && getRandom(25) == 0) {
1839 makeSprite(SPRITE_TRAIN, (x <<4) + TRA_GROOVE_X, (y <<4) + TRA_GROOVE_Y);
1840 }
1841}
1842
1843
1849void Micropolis::generateBus(int x, int y)
1850{
1851 if (getSprite(SPRITE_BUS) == NULL && getRandom(25) == 0) {
1852 makeSprite(SPRITE_BUS, (x <<4) + BUS_GROOVE_X, (y <<4) + BUS_GROOVE_Y);
1853 }
1854}
1855
1856
1859{
1860 short x, y;
1861
1862 if (!(getRandom16() & 3)) {
1863 for (x = 4; x < WORLD_W - 2; x++) {
1864 if (map[x][0] == CHANNEL) {
1865 makeShipHere(x, 0);
1866 return;
1867 }
1868 }
1869 }
1870
1871 if (!(getRandom16() & 3)) {
1872 for (y = 1; y < WORLD_H - 2; y++) {
1873 if (map[0][y] == CHANNEL) {
1874 makeShipHere(0, y);
1875 return;
1876 }
1877 }
1878 }
1879
1880 if (!(getRandom16() & 3)) {
1881 for (x = 4; x < WORLD_W - 2; x++) {
1882 if (map[x][WORLD_H - 1] == CHANNEL) {
1883 makeShipHere(x, WORLD_H - 1);
1884 return;
1885 }
1886 }
1887 }
1888
1889 if (!(getRandom16() & 3)) {
1890 for (y = 1; y < WORLD_H - 2; y++) {
1891 if (map[WORLD_W - 1][y] == CHANNEL) {
1892 makeShipHere(WORLD_W - 1, y);
1893 return;
1894 }
1895 }
1896 }
1897}
1898
1899
1906{
1907 makeSprite(SPRITE_SHIP, (x <<4) - (48 - 1), (y <<4));
1908}
1909
1910
1918{
1919 int x, y, z, done = 0;
1920 SimSprite *sprite;
1921
1922 sprite = getSprite(SPRITE_MONSTER);
1923 if (sprite != NULL) {
1924 sprite->soundCount = 1;
1925 sprite->count = 1000;
1926 sprite->destX = pollutionMaxX <<4;
1927 sprite->destY = pollutionMaxY <<4;
1928 return;
1929 }
1930
1931 for (z = 0; z < 300; z++) {
1932
1933 x = getRandom(WORLD_W - 20) + 10;
1934 y = getRandom(WORLD_H - 10) + 5;
1935
1936 if (map[x][y] == RIVER || map[x][y] == RIVER + BULLBIT) {
1937 makeMonsterAt(x, y);
1938 done = 1;
1939 break;
1940 }
1941
1942 }
1943
1944 if (!done) {
1945 makeMonsterAt(60, 50);
1946 }
1947
1948}
1949
1950
1957{
1958 makeSprite(SPRITE_MONSTER, (x << 4) + 48, (y << 4));
1959 sendMessage(MESSAGE_MONSTER_SIGHTED, x + 5, y, true, true);
1960}
1961
1962
1970{
1971 if (getSprite(SPRITE_HELICOPTER) != NULL) {
1972 return;
1973 }
1974
1975 makeSprite(SPRITE_HELICOPTER, (pos.posX << 4), (pos.posY << 4) + 30);
1976}
1977
1978
1986{
1987 if (getSprite(SPRITE_AIRPLANE) != NULL) {
1988 return;
1989 }
1990
1991 makeSprite(SPRITE_AIRPLANE, (pos.posX <<4) + 48, (pos.posY <<4) + 12);
1992}
1993
1994
1997{
1998 short x, y;
1999 SimSprite *sprite;
2000
2001 sprite = getSprite(SPRITE_TORNADO);
2002 if (sprite != NULL) {
2003 sprite->count = 200;
2004 return;
2005 }
2006
2007 x = getRandom((WORLD_W <<4) - 800) + 400;
2008 y = getRandom((WORLD_H <<4) - 200) + 100;
2009
2011 sendMessage(MESSAGE_TORNADO_SIGHTED, (x >>4) + 3, (y >>4) + 2, true, true);
2012}
2013
2014
2021{
2022 if (testBounds(x, y)) {
2023 makeExplosionAt((x << 4) + 8, (y << 4) + 8);
2024 }
2025}
2026
2027
2034{
2035 newSprite("", SPRITE_EXPLOSION, x - 40, y - 16);
2036}
2037
2038
DATA worldGet(int x, int y) const
Definition map_type.h:316
void worldSet(int x, int y, DATA val)
Definition map_type.h:297
void doCopterSprite(SimSprite *sprite)
Definition sprite.cpp:695
SimSprite * spriteList
List of active sprites.
void generateCopter(const Position &pos)
Definition sprite.cpp:1969
void explodeSprite(SimSprite *sprite)
Definition sprite.cpp:1654
void doTornadoSprite(SimSprite *sprite)
Definition sprite.cpp:1239
void doAirplaneSprite(SimSprite *sprite)
Definition sprite.cpp:800
bool checkSpriteCollision(SimSprite *s1, SimSprite *s2)
Definition sprite.cpp:537
void startFireInZone(int Xloc, int Yloc, int ch)
Definition sprite.cpp:1764
short turnTo(int p, int d)
Definition sprite.cpp:396
bool tally(short tileValue)
Definition tool.cpp:535
void initSprite(SimSprite *sprite, int x, int y)
Definition sprite.cpp:136
Scenario scenario
Scenario being played.
void makeExplosion(int x, int y)
Definition sprite.cpp:2020
void destroySprite(SimSprite *sprite)
Definition sprite.cpp:313
SimSprite * freeSprites
Pool of free SimSprite objects.
short getDir(int orgX, int orgY, int desX, int desY)
Definition sprite.cpp:477
void makeMonster()
Definition sprite.cpp:1917
void makeMonsterAt(int x, int y)
Definition sprite.cpp:1956
void startFire(int x, int y)
Definition sprite.cpp:1805
short getRandom(short range)
Definition random.cpp:110
short pollutionMaxY
Y coordinate of most polluted area.
void moveObjects()
Definition sprite.cpp:553
bool doAnimation
int getRandom16()
Definition random.cpp:130
bool enableDisasters
Enable disasters.
void generatePlane(const Position &pos)
Definition sprite.cpp:1985
int canDriveOn(int x, int y)
Definition sprite.cpp:1626
short pollutionMaxX
X coordinate of most polluted area.
void doShipSprite(SimSprite *sprite)
Definition sprite.cpp:867
void doExplosionSprite(SimSprite *sprite)
Definition sprite.cpp:1306
void generateShip()
Definition sprite.cpp:1858
MapValue randomFire()
void doTrainSprite(SimSprite *sprite)
Definition sprite.cpp:623
SimSprite * getSprite(int type)
Definition sprite.cpp:338
bool tryOther(int Tpoo, int Told, int Tnew)
Definition sprite.cpp:431
int getDistance(int x1, int y1, int x2, int y2)
Definition sprite.cpp:525
short totalPop
unsigned short * map[WORLD_W]
void destroyAllSprites()
Definition sprite.cpp:298
void makeTornado()
Definition sprite.cpp:1996
void doBusSprite(SimSprite *sprite)
Definition sprite.cpp:1342
void generateTrain(int x, int y)
Definition sprite.cpp:1836
void sendMessage(short Mnum, short x=NOWHERE, short y=NOWHERE, bool picture=false, bool important=false)
Definition message.cpp:390
void makeSound(const std::string &channel, const std::string &sound, int x=-1, int y=-1)
short getChar(int x, int y)
Definition sprite.cpp:375
void generateBus(int x, int y)
Definition sprite.cpp:1849
SimSprite * newSprite(const std::string &name, int type, int x, int y)
Definition sprite.cpp:104
MapByte2 trafficDensityMap
Traffic density map.
static bool testBounds(int wx, int wy)
void doMonsterSprite(SimSprite *sprite)
Definition sprite.cpp:1007
void makeExplosionAt(int x, int y)
Definition sprite.cpp:2033
SimSprite * makeSprite(int type, int x, int y)
Definition sprite.cpp:355
Ptr newPtr(int size)
MapShort8 rateOfGrowthMap
void makeShipHere(int x, int y)
Definition sprite.cpp:1905
bool spriteNotInBounds(SimSprite *sprite)
Definition sprite.cpp:459
void destroyMapTile(int ox, int oy)
Definition sprite.cpp:1714
int posY
Vertical coordnate of the position.
Definition position.h:169
int posX
Horizontal coordinate of the position.
Definition position.h:168
int x
X coordinate of the sprite in pixels?
Definition micropolis.h:892
int destX
Destination X coordinate of the sprite.
Definition micropolis.h:902
int yHot
Offset of the hot-spot relative to SimSprite::y?
Definition micropolis.h:899
int type
Type of the sprite (TRA – BUS).
Definition micropolis.h:890
int destY
Destination Y coordinate of the sprite.
Definition micropolis.h:903
SimSprite * next
Pointer to next SimSprite object in the list.
Definition micropolis.h:888
std::string name
Name of the sprite.
Definition micropolis.h:889
int y
Y coordinate of the sprite in pixels?
Definition micropolis.h:893
int frame
Frame (0 means non-active sprite)
Definition micropolis.h:891
int xHot
Offset of the hot-spot relative to SimSprite::x?
Definition micropolis.h:898
static const int WORLD_H
Definition map_type.h:95
static const int WORLD_W
Definition map_type.h:90
Header file for Micropolis game engine.
@ SC_SAN_FRANCISCO
San francisco (earthquake)
Definition micropolis.h:702
@ RAILHPOWERV
Horizontal rail, vertical power.
Definition micropolis.h:477
@ PORTBASE
Top-left tile of the seaport.
Definition micropolis.h:567
@ DIRT
Clear tile.
Definition micropolis.h:382
@ RAILVPOWERH
Vertical rail, horizontal power.
Definition micropolis.h:478
static const int WORLD_H_2
Definition micropolis.h:157
@ SPRITE_AIRPLANE
Airplane sprite.
Definition micropolis.h:333
@ SPRITE_TORNADO
Tornado sprite.
Definition micropolis.h:336
@ SPRITE_MONSTER
Scary monster.
Definition micropolis.h:335
@ SPRITE_TRAIN
Train sprite.
Definition micropolis.h:331
@ SPRITE_HELICOPTER
Helicopter sprite.
Definition micropolis.h:332
@ SPRITE_BUS
Bus sprite.
Definition micropolis.h:338
@ SPRITE_SHIP
Ship.
Definition micropolis.h:334
@ SPRITE_EXPLOSION
Explosion sprite.
Definition micropolis.h:337
static T clamp(const T val, const T lower, const T upper)
Definition micropolis.h:809
static T absoluteValue(const T val)
Definition micropolis.h:826
Defines string identification numbers for texts used in the Micropolis game engine.
@ MESSAGE_SHIP_CRASHED
25: Shipwreck reported !
Definition text.h:137
@ MESSAGE_PLANE_CRASHED
A plane has crashed !
Definition text.h:136
@ MESSAGE_TRAIN_CRASHED
A train crashed !
Definition text.h:138
@ MESSAGE_HELICOPTER_CRASHED
A helicopter crashed !
Definition text.h:139
@ MESSAGE_MONSTER_SIGHTED
A Monster has been sighted !!
Definition text.h:133
@ MESSAGE_EXPLOSION_REPORTED
Explosion detected !
Definition text.h:144
@ MESSAGE_TORNADO_SIGHTED
Tornado reported !!
Definition text.h:134
@ MESSAGE_HEAVY_TRAFFIC
Heavy Traffic reported.
Definition text.h:153
@ BURNBIT
bit 13, tile can be lit.
Definition tool.h:122
@ LOMASK
Mask for the Tiles part of the tile.
Definition tool.h:129
@ ZONEBIT
bit 10, tile is the center tile of the zone.
Definition tool.h:125
@ BULLBIT
bit 12, tile is bulldozable.
Definition tool.h:123
@ ANIMBIT
bit 11, tile is animated.
Definition tool.h:124