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 
104 SimSprite *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 
136 void 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 
225  case SPRITE_HELICOPTER:
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 
355 SimSprite *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 
375 short 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 
396 short 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 
431 bool 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 
477 short 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 
525 int 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 
571  case SPRITE_HELICOPTER:
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 &&
1223  (s->type == SPRITE_AIRPLANE || s->type == SPRITE_HELICOPTER
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 &&
1278  (s->type == SPRITE_AIRPLANE || s->type == SPRITE_HELICOPTER
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 
1626 int 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:
1670  sendMessage(MESSAGE_PLANE_CRASHED, x, y, true);
1671  break;
1672 
1673  case SPRITE_SHIP:
1674  sendMessage(MESSAGE_SHIP_CRASHED, x, y, true);
1675  break;
1676 
1677  case SPRITE_TRAIN:
1678  sendMessage(MESSAGE_TRAIN_CRASHED, x, y, true);
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 
1698 bool 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 
1714 void 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 
1764 void 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 
1805 void 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 
1836 void Micropolis::generateTrain(int x, int y)
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 
1849 void 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 
1905 void Micropolis::makeShipHere(int x, int y)
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 
1956 void Micropolis::makeMonsterAt(int x, int y)
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 
2010  makeSprite(SPRITE_TORNADO, x, y);
2011  sendMessage(MESSAGE_TORNADO_SIGHTED, (x >>4) + 3, (y >>4) + 2, true, true);
2012 }
2013 
2014 
2020 void Micropolis::makeExplosion(int x, int y)
2021 {
2022  if (testBounds(x, y)) {
2023  makeExplosionAt((x << 4) + 8, (y << 4) + 8);
2024  }
2025 }
2026 
2027 
2033 void Micropolis::makeExplosionAt( int x, int y)
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.
Definition: micropolis.h:2213
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.
Definition: micropolis.h:2338
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.
Definition: micropolis.h:2231
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.
Definition: micropolis.h:2048
void moveObjects()
Definition: sprite.cpp:553
bool doAnimation
Definition: micropolis.h:1887
int getRandom16()
Definition: random.cpp:130
bool enableDisasters
Enable disasters.
Definition: micropolis.h:2346
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.
Definition: micropolis.h:2047
void doShipSprite(SimSprite *sprite)
Definition: sprite.cpp:867
void doExplosionSprite(SimSprite *sprite)
Definition: sprite.cpp:1306
void generateShip()
Definition: sprite.cpp:1858
MapValue randomFire()
Definition: micropolis.h:2139
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
Definition: micropolis.h:1004
unsigned short * map[WORLD_W]
Definition: micropolis.h:1120
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.
Definition: micropolis.h:1245
static bool testBounds(int wx, int wy)
Definition: micropolis.h:2378
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
Definition: micropolis.h:1290
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:891
int destX
Destination X coordinate of the sprite.
Definition: micropolis.h:901
int yHot
Offset of the hot-spot relative to SimSprite::y?
Definition: micropolis.h:898
int type
Type of the sprite (TRA – BUS).
Definition: micropolis.h:889
int destY
Destination Y coordinate of the sprite.
Definition: micropolis.h:902
SimSprite * next
Pointer to next SimSprite object in the list.
Definition: micropolis.h:887
std::string name
Name of the sprite.
Definition: micropolis.h:888
int y
Y coordinate of the sprite in pixels?
Definition: micropolis.h:892
int frame
Frame (0 means non-active sprite)
Definition: micropolis.h:890
int xHot
Offset of the hot-spot relative to SimSprite::x?
Definition: micropolis.h:897
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:701
@ 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:808
static T absoluteValue(const T val)
Definition: micropolis.h:825
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