Micropolis
simulate.cpp
Go to the documentation of this file.
1/* simulate.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
77
78
79#include "micropolis.h"
80#include "text.h"
81
82
84// Constants
85
90static const int CENSUS_FREQUENCY_10 = 4;
91
97
101static const int TAX_FREQUENCY = 48;
102
103
105
106
107/* comefrom: doEditWindow scoreDoer doMapInFront graphDoer doNilEvent */
108void Micropolis::simFrame()
109{
110
111 if (simSpeed == 0) {
112 return;
113 }
114
115 if (++speedCycle > 1023) {
116 speedCycle = 0;
117 }
118
119 if (simSpeed == 1 && (speedCycle % 5) != 0) {
120 return;
121 }
122
123 if (simSpeed == 2 && (speedCycle % 3) != 0) {
124 return;
125 }
126
127 simulate();
128}
129
130
131/* comefrom: simFrame */
132void Micropolis::simulate()
133{
134 static const short speedPowerScan[3] =
135 { 2, 4, 5 };
136 static const short SpeedPollutionTerrainLandValueScan[3] =
137 { 2, 7, 17 };
138 static const short speedCrimeScan[3] =
139 { 1, 8, 18 };
140 static const short speedPopulationDensityScan[3] =
141 { 1, 9, 19 };
142 static const short speedFireAnalysis[3] =
143 { 1, 10, 20 };
144
145 short speedIndex = clamp((short)(simSpeed - 1), (short)0, (short)2);
146
147 //printf("simulate phaseCycle=%d initSimLoad %d\n", phaseCycle, initSimLoad);
148
149 // The simulator has 16 different phases, which we cycle through
150 // according to phaseCycle, which is incremented and wrapped at
151 // the end of this switch.
152
153 if (initSimLoad) {
154 phaseCycle = 0;
155 } else {
156 phaseCycle &= 15;
157 }
158
159 switch (phaseCycle) {
160
161 case 0:
162
163 if (++simCycle > 1023) {
164 simCycle = 0; // This is cosmic!
165 }
166
167 if (doInitialEval) {
168 doInitialEval = false;
170 }
171
172 cityTime++;
173 cityTaxAverage += cityTax;
174
175 if (!(simCycle & 1)) {
176 setValves();
177 }
178
179 clearCensus();
180
181 break;
182
183 case 1:
184 case 2:
185 case 3:
186 case 4:
187 case 5:
188 case 6:
189 case 7:
190 case 8:
191
192 // Scan 1/8 of the map for each of the 8 phases 1..8:
193 mapScan((phaseCycle - 1) * WORLD_W / 8, phaseCycle * WORLD_W / 8);
194
195 break;
196
197 case 9:
198 if (cityTime % CENSUS_FREQUENCY_10 == 0) {
199 take10Census();
200 }
201
202 if (cityTime % CENSUS_FREQUENCY_120 == 0) {
203 take120Census();
204 }
205
206 if (cityTime % TAX_FREQUENCY == 0) {
207 collectTax();
209 }
210
211 break;
212
213 case 10:
214
215 if (!(simCycle % 5)) {
217 }
218
220
228
229 sendMessages();
230
231 break;
232
233 case 11:
234
235 if ((simCycle % speedPowerScan[speedIndex]) == 0) {
236 doPowerScan();
238 newPower = true; /* post-release change */
239 }
240
241 break;
242
243 case 12:
244
245 if ((simCycle % SpeedPollutionTerrainLandValueScan[speedIndex]) == 0) {
246 pollutionTerrainLandValueScan();
247 }
248
249 break;
250
251 case 13:
252
253 if ((simCycle % speedCrimeScan[speedIndex]) == 0) {
254 crimeScan();
255 }
256
257 break;
258
259 case 14:
260
261 if ((simCycle % speedPopulationDensityScan[speedIndex]) == 0) {
263 }
264
265 break;
266
267 case 15:
268
269 if ((simCycle % speedFireAnalysis[speedIndex]) == 0) {
270 fireAnalysis();
271 }
272
273 doDisasters();
274
275 break;
276
277 }
278
279 // Go on the the next phase.
280 phaseCycle = (phaseCycle + 1) & 15;
281}
282
283
289{
290 phaseCycle = 0;
291 simCycle = 0;
292
293 if (initSimLoad == 2) {
294 /* if new city */
295 initSimMemory();
296 }
297
298 if (initSimLoad == 1) {
299 /* if city just loaded */
300 simLoadInit();
301 }
302
303 setValves();
304 clearCensus();
305 mapScan(0, WORLD_W);
306 doPowerScan();
307 newPower = true; /* post rel */
308 pollutionTerrainLandValueScan();
309 crimeScan();
311 fireAnalysis();
312 newMap = 1;
313 censusChanged = true;
314 totalPop = 1;
315 doInitialEval = true;
316}
317
318
324{
325 short x, y;
326
327 for (x = 0; x < WORLD_W; x++) {
328 for (y = 0; y < WORLD_H; y++) {
329 MapValue z = map[x][y];
330 if (z & ZONEBIT) {
331 setZonePower(Position(x, y));
332 }
333 }
334 }
335}
336
337
340{
341 /* tends to empty trafficDensityMap */
342 short x, y, z;
343
344 for (x = 0; x < WORLD_W; x += trafficDensityMap.MAP_BLOCKSIZE) {
345 for (y = 0; y < WORLD_H; y += trafficDensityMap.MAP_BLOCKSIZE) {
346 z = trafficDensityMap.worldGet(x, y);
347 if (z == 0) {
348 continue;
349 }
350
351 if (z <= 24) {
353 continue;
354 }
355
356 if (z > 200) {
357 trafficDensityMap.worldSet(x, y, z - 34);
358 } else {
359 trafficDensityMap.worldSet(x, y, z - 24);
360 }
361 }
362 }
363}
364
365
372{
373 /* tends to empty rateOfGrowthMap */
374 short x, y, z;
375
376 for (x = 0; x < rateOfGrowthMap.MAP_W; x++) {
377 for (y = 0; y < rateOfGrowthMap.MAP_H; y++) {
378 z = rateOfGrowthMap.get(x, y);
379 if (z == 0) {
380 continue;
381 }
382
383 if (z > 0) {
384 z--;
385 z = clamp(z, (short)-200, (short)200);
386 rateOfGrowthMap.set(x, y, z);
387 continue;
388 }
389
390 if (z < 0) {
391 z++;
392 z = clamp(z, (short)-200, (short)200);
393 rateOfGrowthMap.set(x, y, z);
394 }
395 }
396 }
397}
398
399
400/* comefrom: doSimInit */
401void Micropolis::initSimMemory()
402{
403 //printf("initSimMemory\n");
404
405 setCommonInits();
406
407 for (short x = 0; x < 240; x++) {
408 resHist[x] = 0;
409 comHist[x] = 0;
410 indHist[x] = 0;
411 moneyHist[x] = 128;
412 crimeHist[x] = 0;
413 pollutionHist[x] = 0;
414 }
415
416 crimeRamp = 0;
417 pollutionRamp = 0;
418 totalPop = 0;
419 resValve = 0;
420 comValve = 0;
421 indValve = 0;
422 resCap = false; // Do not block residential growth
423 comCap = false; // Do not block commercial growth
424 indCap = false; // Do not block industrial growth
425
426 externalMarket = 6.0;
429
430 /* This clears powermem */
432 doPowerScan();
433 newPower = true; /* post rel */
434
435 initSimLoad = 0;
436}
437
438
439/* comefrom: doSimInit */
441{
442 // Disaster delay table for each scenario
443 static const short disasterWaitTable[SC_COUNT] = {
444 0, // No scenario (free playing)
445 2, // Dullsville (boredom)
446 10, // San francisco (earth quake)
447 4 * 10, // Hamburg (fire bombs)
448 20, // Bern (traffic)
449 3, // Tokyo (scary monster)
450 5, // Detroit (crime)
451 5, // Boston (nuclear meltdown)
452 2 * 48, // Rio (flooding)
453 };
454
455 // Time to wait before score calculation for each scenario
456 static const short scoreWaitTable[SC_COUNT] = {
457 0, // No scenario (free playing)
458 30 * 48, // Dullsville (boredom)
459 5 * 48, // San francisco (earth quake)
460 5 * 48, // Hamburg (fire bombs)
461 10 * 48, // Bern (traffic)
462 5 * 48, // Tokyo (scary monster)
463 10 * 48, // Detroit (crime)
464 5 * 48, // Boston (nuclear meltdown)
465 10 * 48, // Rio (flooding)
466 };
467
468 externalMarket = (float)miscHist[1];
469 resPop = miscHist[2];
470 comPop = miscHist[3];
471 indPop = miscHist[4];
472 resValve = miscHist[5];
473 comValve = miscHist[6];
474 indValve = miscHist[7];
475 crimeRamp = miscHist[10];
476 pollutionRamp = miscHist[11];
481
482 if (cityTime < 0) {
483 cityTime = 0;
484 }
485
486 if (!externalMarket) {
487 externalMarket = 4.0;
488 }
489
490 // Set game level
493 }
495
496 setCommonInits();
497
498 // Load cityClass
502 }
503
504 cityScore = miscHist[17];
505 if (cityScore > 999 || cityScore < 1) {
506 cityScore = 500;
507 }
508
509 resCap = false;
510 comCap = false;
511 indCap = false;
512
513 cityTaxAverage = (cityTime % 48) * 7; /* post */
514
515 // Set power map.
518
519 doNilPower();
520
524 initSimLoad = 0;
525
526 if (scenario >= SC_COUNT) {
528 }
529
530 if (scenario != SC_NONE) {
531 assert(LENGTH_OF(disasterWaitTable) == SC_COUNT);
532 assert(LENGTH_OF(scoreWaitTable) == SC_COUNT);
533
535 disasterWait = disasterWaitTable[disasterEvent];
537 scoreWait = scoreWaitTable[disasterEvent];
538
540 } else {
542 disasterWait = 0;
544 scoreWait = 0;
545 }
546
547 doStartGame();
548}
549
550
551/* comefrom: initSimMemory simLoadInit */
552void Micropolis::setCommonInits()
553{
554 evalInit();
558 taxFlag = false;
559 taxFund = 0;
560}
561
562
563/* comefrom: simulate doSimInit */
565{
567 static const short taxTable[21] = {
568 200, 150, 120, 100, 80, 50, 30, 0, -10, -40, -100,
569 -150, -200, -250, -300, -350, -400, -450, -500, -550, -600,
570 };
571 static const float extMarketParamTable[3] = {
572 1.2f, 1.1f, 0.98f,
573 };
574 assert(LEVEL_COUNT == LENGTH_OF(extMarketParamTable));
575
577 short resPopDenom = 8;
578 float birthRate = 0.02;
579 float laborBaseMax = 1.3;
580 float internalMarketDenom = 3.7;
581 float projectedIndPopMin = 5.0;
582 float resRatioDefault = 1.3;
583 float resRatioMax = 2;
584 float comRatioMax = 2;
585 float indRatioMax = 2;
586 short taxMax = 20;
587 float taxTableScale = 600;
588
591 float employment, migration, births, laborBase, internalMarket;
592 float resRatio, comRatio, indRatio;
593 float normalizedResPop, projectedResPop, projectedComPop, projectedIndPop;
594
595 miscHist[1] = (short)externalMarket;
596 miscHist[2] = resPop;
597 miscHist[3] = comPop;
598 miscHist[4] = indPop;
599 miscHist[5] = resValve;
600 miscHist[6] = comValve;
601 miscHist[7] = indValve;
602 miscHist[10] = crimeRamp;
603 miscHist[11] = pollutionRamp;
607 miscHist[15] = gameLevel;
608 miscHist[16] = (short)cityClass;
609 miscHist[17] = cityScore;
610
611 normalizedResPop = (float)resPop / (float)resPopDenom;
613 totalPop = (short)(normalizedResPop + comPop + indPop);
614
615 if (resPop > 0) {
616 employment = (comHist[1] + indHist[1]) / normalizedResPop;
617 } else {
618 employment = 1;
619 }
620
621 migration = normalizedResPop * (employment - 1);
622 births = normalizedResPop * birthRate;
623 projectedResPop = normalizedResPop + migration + births; // Projected res pop.
624
625 // Compute laborBase
626 float temp = comHist[1] + indHist[1];
627 if (temp > 0.0) {
628 laborBase = (resHist[1] / temp);
629 } else {
630 laborBase = 1;
631 }
632 laborBase = clamp(laborBase, 0.0f, laborBaseMax);
633
634 internalMarket = (float)(normalizedResPop + comPop + indPop) / internalMarketDenom;
635
636 projectedComPop = internalMarket * laborBase;
637
638 assert(gameLevel >= LEVEL_FIRST && gameLevel <= LEVEL_LAST);
639 projectedIndPop = indPop * laborBase * extMarketParamTable[gameLevel];
640 projectedIndPop = max(projectedIndPop, projectedIndPopMin);
641
642 if (normalizedResPop > 0) {
643 resRatio = (float)projectedResPop / (float)normalizedResPop; // projected -vs- actual.
644 } else {
645 resRatio = resRatioDefault;
646 }
647
648 if (comPop > 0) {
649 comRatio = (float)projectedComPop / (float)comPop;
650 } else {
651 comRatio = (float)projectedComPop;
652 }
653
654 if (indPop > 0) {
655 indRatio = (float)projectedIndPop / (float)indPop;
656 } else {
657 indRatio = (float)projectedIndPop;
658 }
659
660 resRatio = min(resRatio, resRatioMax);
661 comRatio = min(comRatio, comRatioMax);
662 resRatio = min(indRatio, indRatioMax);
663
664 // Global tax and game level effects.
665 short z = min((short)(cityTax + gameLevel), taxMax);
666 resRatio = (resRatio - 1) * taxTableScale + taxTable[z];
667 comRatio = (comRatio - 1) * taxTableScale + taxTable[z];
668 indRatio = (indRatio - 1) * taxTableScale + taxTable[z];
669
670 // Ratios are velocity changes to valves.
671 resValve = clamp(resValve + (short)resRatio, -RES_VALVE_RANGE, RES_VALVE_RANGE);
672 comValve = clamp(comValve + (short)comRatio, -COM_VALVE_RANGE, COM_VALVE_RANGE);
673 indValve = clamp(indValve + (short)indRatio, -IND_VALVE_RANGE, IND_VALVE_RANGE);
674
675 if (resCap && resValve > 0) {
676 resValve = 0; // Need a stadium, so cap resValve.
677 }
678
679 if (comCap && comValve > 0) {
680 comValve = 0; // Need a airport, so cap comValve.
681 }
682
683 if (indCap && indValve > 0) {
684 indValve = 0; // Need an seaport, so cap indValve.
685 }
686
687 valveFlag = true;
688}
689
690
691/* comefrom: simulate doSimInit */
692void Micropolis::clearCensus()
693{
696 firePop = 0;
697 roadTotal = 0;
698 railTotal = 0;
699 resPop = 0;
700 comPop = 0;
701 indPop = 0;
702 resZonePop = 0;
703 comZonePop = 0;
704 indZonePop = 0;
705 hospitalPop = 0;
706 churchPop = 0;
708 fireStationPop = 0;
709 stadiumPop = 0;
710 coalPowerPop = 0;
711 nuclearPowerPop = 0;
712 seaportPop = 0;
713 airportPop = 0;
714 powerStackPointer = 0; /* Reset before Mapscan */
715
717 //fireStationEffectMap.clear(); // Added in rev293
719 //policeStationEffectMap.clear(); // Added in rev293
720
721}
722
723
731{
732 // TODO: Make configurable parameters.
733 int resPopDenom = 8;
734
735 short x;
736
737 /* put census#s in Historical Graphs and scroll data */
738 resHist10Max = 0;
739 comHist10Max = 0;
740 indHist10Max = 0;
741
742 for (x = 118; x >= 0; x--) {
743
747
748 resHist[x + 1] = resHist[x];
749 comHist[x + 1] = comHist[x];
750 indHist[x + 1] = indHist[x];
751 crimeHist[x + 1] = crimeHist[x];
752 pollutionHist[x + 1] = pollutionHist[x];
753 moneyHist[x + 1] = moneyHist[x];
754
755 }
756
760
761 resHist[0] = resPop / resPopDenom;
762 comHist[0] = comPop;
763 indHist[0] = indPop;
764
765 crimeRamp += (crimeAverage - crimeRamp) / 4;
766 crimeHist[0] = min(crimeRamp, (short)255);
767
768 pollutionRamp += (pollutionAverage - pollutionRamp) / 4;
769 pollutionHist[0] = min(pollutionRamp, (short)255);
770
771 x = (cashFlow / 20) + 128; /* scale to 0..255 */
772 moneyHist[0] = clamp(x, (short)0, (short)255);
773
774 changeCensus();
775
776 short resPopScaled = resPop >> 8;
777
778 if (hospitalPop < resPopScaled) {
779 needHospital = 1;
780 }
781
782 if (hospitalPop > resPopScaled) {
783 needHospital = -1;
784 }
785
786 if (hospitalPop == resPopScaled) {
787 needHospital = 0;
788 }
789
790 int faithfulPop = resPopScaled + faith;
791
792 if (churchPop < faithfulPop) {
793 needChurch = 1;
794 }
795
796 if (churchPop > faithfulPop) {
797 needChurch = -1;
798 }
799
800 if (churchPop == faithfulPop) {
801 needChurch = 0;
802 }
803}
804
805
806/* comefrom: simulate */
807void Micropolis::take120Census()
808{
809 // TODO: Make configurable parameters.
810 int resPopDenom = 8;
811
812 /* Long Term Graphs */
813 short x;
814
815 resHist120Max = 0;
816 comHist120Max = 0;
817 indHist120Max = 0;
818
819 for (x = 238; x >= 120; x--) {
820
824
825 resHist[x + 1] = resHist[x];
826 comHist[x + 1] = comHist[x];
827 indHist[x + 1] = indHist[x];
828 crimeHist[x + 1] = crimeHist[x];
829 pollutionHist[x + 1] = pollutionHist[x];
830 moneyHist[x + 1] = moneyHist[x];
831
832 }
833
837
838 resHist[120] = resPop / resPopDenom;
839 comHist[120] = comPop;
840 indHist[120] = indPop;
841 crimeHist[120] = crimeHist[0] ;
843 moneyHist[120] = moneyHist[0];
844 changeCensus();
845}
846
847
857{
858 short z;
859
863 static const float RLevels[3] = { 0.7, 0.9, 1.2 };
864 static const float FLevels[3] = { 1.4, 1.2, 0.8 };
865
866 assert(LEVEL_COUNT == LENGTH_OF(RLevels));
867 assert(LEVEL_COUNT == LENGTH_OF(FLevels));
868
869 cashFlow = 0;
870
877 if (!taxFlag) { // If the Tax Port is clear
878
880 z = cityTaxAverage / 48; // post release
881
882 cityTaxAverage = 0;
883
884 policeFund = (long)policeStationPop * 100;
885 fireFund = (long)fireStationPop * 100;
886 roadFund = (long)((roadTotal + (railTotal * 2)) * RLevels[gameLevel]);
887 taxFund = (long)((((Quad)totalPop * landValueAverage) / 120) * cityTax * FLevels[gameLevel]);
888
889 if (totalPop > 0) {
890 /* There are people to tax. */
891 cashFlow = (short)(taxFund - (policeFund + fireFund + roadFund));
892 doBudget();
893 } else {
894 /* Nobody lives here. */
898 }
899 }
900}
901
902
913{
914 // Compute road effects of funding
916 if (roadFund > 0) {
917 // Multiply with funding fraction
918 roadEffect = (short)((float)roadEffect * (float)roadSpend / (float)roadFund);
919 }
920
921 // Compute police station effects of funding
923 if (policeFund > 0) {
924 // Multiply with funding fraction
925 policeEffect = (short)((float)policeEffect * (float)policeSpend / (float)policeFund);
926 }
927
928 // Compute fire station effects of funding
930 if (fireFund > 0) {
931 // Multiply with funding fraction
932 fireEffect = (short)((float)fireEffect * (float)fireSpend / (float)fireFund);
933 }
934
935#if 0
936 printf("========== updateFundEffects road %d %d %d fire %d %d %d police %d %d %d\n",
937 (int)roadEffect, (int)roadSpend, (int)roadFund,
938 (int)fireEffect, (int)fireSpend, (int)fireFund,
939 (int)policeEffect, (int)policeSpend, (int)policeFund);
940#endif
941
942 mustDrawBudget = 1;
943}
944
945
946/* comefrom: simulate doSimInit */
947void Micropolis::mapScan(int x1, int x2)
948{
949 short x, y;
950
951 //printf("mapScan %d %d\n", x1, x2);
952
953 for (x = x1; x < x2; x++) {
954 for (y = 0; y < WORLD_H; y++) {
955
956 MapValue mapVal = map[x][y];
957 MapTile tile = mapVal & LOMASK; /* Mask off status bits */
958
959 if (tile == DIRT) {
960 continue;
961 }
962
963 if (tile < FLOOD) {
964 continue;
965 }
966
967 // tile >= FLOOD
968
969 Position pos(x, y);
970
971
972 if (tile < ROADBASE) {
973
974 if (tile >= FIREBASE) {
975 firePop++;
976 if (!(getRandom16() & 3)) {
977 doFire(pos); /* 1 in 4 times */
978 }
979 continue;
980 }
981
982 if (tile < RADTILE) {
983 doFlood(pos);
984 } else {
985 doRadTile(pos);
986 }
987
988 continue;
989 }
990
991 if (newPower && (mapVal & CONDBIT)) {
992 // Copy PWRBIT from powerGridMap
993 setZonePower(pos);
994 }
995
996 if (tile >= ROADBASE && tile < POWERBASE) {
997 doRoad(pos);
998 continue;
999 }
1000
1001 if (mapVal & ZONEBIT) { /* process Zones */
1002 doZone(pos);
1003 continue;
1004 }
1005
1006 if (tile >= RAILBASE && tile < RESBASE) {
1007 doRail(pos);
1008 continue;
1009 }
1010
1011 if (tile >= SOMETINYEXP && tile <= LASTTINYEXP) {
1012 /* clear AniRubble */
1013 map[x][y] = randomRubble();
1014 }
1015 }
1016 }
1017}
1018
1019
1026{
1027 railTotal++;
1028
1029 generateTrain(pos.posX, pos.posY);
1030
1031 if (roadEffect < (15 * MAX_ROAD_EFFECT / 16)) {
1032
1033 // roadEffect < 15/16 of max road, enable deteriorating rail
1034 if (!(getRandom16() & 511)) {
1035
1036 MapValue curValue = map[pos.posX][pos.posY];
1037 if (!(curValue & CONDBIT)) {
1038
1039 // Otherwise the '(getRandom16() & 31)' makes no sense
1040 assert(MAX_ROAD_EFFECT == 32);
1041 if (roadEffect < (getRandom16() & 31)) {
1042 MapTile tile = curValue & LOMASK;
1043 if (tile < RAILBASE + 2) {
1044 map[pos.posX][pos.posY] = RIVER;
1045 } else {
1046 map[pos.posX][pos.posY] = randomRubble();
1047 }
1048 return;
1049 }
1050 }
1051 }
1052 }
1053}
1054
1055
1061{
1062 if ((getRandom16() & 4095) == 0) {
1063 map[pos.posX][pos.posY] = DIRT; /* Radioactive decay */
1064 }
1065}
1066
1067
1073{
1074 short tden, z;
1075 static const short densityTable[3] = { ROADBASE, LTRFBASE, HTRFBASE };
1076
1077 roadTotal++;
1078
1079 MapValue mapValue = map[pos.posX][pos.posY];
1080 MapTile tile = mapValue & LOMASK;
1081
1082 /* generateBus(pos.posX, pos.posY); */
1083
1084 if (roadEffect < (15 * MAX_ROAD_EFFECT / 16)) {
1085 // roadEffect < 15/16 of max road, enable deteriorating road
1086 if ((getRandom16() & 511) == 0) {
1087 if (!(mapValue & CONDBIT)) {
1088 assert(MAX_ROAD_EFFECT == 32); // Otherwise the '(getRandom16() & 31)' makes no sense
1089 if (roadEffect < (getRandom16() & 31)) {
1090 if ((tile & 15) < 2 || (tile & 15) == 15) {
1091 map[pos.posX][pos.posY] = RIVER;
1092 } else {
1093 map[pos.posX][pos.posY] = randomRubble();
1094 }
1095 return;
1096 }
1097 }
1098 }
1099 }
1100
1101 if ((mapValue & BURNBIT) == 0) { /* If Bridge */
1102 roadTotal += 4; // Bridge counts as 4 road tiles
1103 if (doBridge(Position(pos.posX, pos.posY), tile)) {
1104 return;
1105 }
1106 }
1107
1108 if (tile < LTRFBASE) {
1109 tden = 0;
1110 } else if (tile < HTRFBASE) {
1111 tden = 1;
1112 } else {
1113 roadTotal++; // Heavy traffic counts as 2 roads.
1114 tden = 2;
1115 }
1116
1117 short trafficDensity = trafficDensityMap.worldGet(pos.posX, pos.posY) >>6;
1118
1119 if (trafficDensity > 1) {
1120 trafficDensity--;
1121 }
1122
1123 if (tden != trafficDensity) { /* tden 0..2 */
1124 z = ((tile - ROADBASE) & 15) + densityTable[trafficDensity];
1125 z |= mapValue & (ALLBITS - ANIMBIT);
1126
1127 if (trafficDensity > 0) {
1128 z |= ANIMBIT;
1129 }
1130
1131 map[pos.posX][pos.posY] = z;
1132 }
1133}
1134
1135
1146{
1147 static short HDx[7] = { -2, 2, -2, -1, 0, 1, 2 };
1148 static short HDy[7] = { -1, -1, 0, 0, 0, 0, 0 };
1149 static short HBRTAB[7] = {
1150 HBRDG1 | BULLBIT, HBRDG3 | BULLBIT, HBRDG0 | BULLBIT,
1151 RIVER, BRWH | BULLBIT, RIVER, HBRDG2 | BULLBIT,
1152 };
1153 static short HBRTAB2[7] = {
1154 RIVER, RIVER, HBRIDGE | BULLBIT, HBRIDGE | BULLBIT, HBRIDGE | BULLBIT,
1156 };
1157 static short VDx[7] = { 0, 1, 0, 0, 0, 0, 1 };
1158 static short VDy[7] = { -2, -2, -1, 0, 1, 2, 2 };
1159 static short VBRTAB[7] = {
1160 VBRDG0 | BULLBIT, VBRDG1 | BULLBIT, RIVER, BRWV | BULLBIT,
1161 RIVER, VBRDG2 | BULLBIT, VBRDG3 | BULLBIT,
1162 };
1163 static short VBRTAB2[7] = {
1165 VBRIDGE | BULLBIT, VBRIDGE | BULLBIT, RIVER,
1166 };
1167 int z, x, y, MPtem;
1168
1169 if (tile == BRWV) { /* Vertical bridge close */
1170
1171 if ((!(getRandom16() & 3)) && getBoatDistance(pos) > 340) {
1172
1173 for (z = 0; z < 7; z++) { /* Close */
1174
1175 x = pos.posX + VDx[z];
1176 y = pos.posY + VDy[z];
1177
1178 if (testBounds(x, y)) {
1179
1180 if ((map[x][y] & LOMASK) == (VBRTAB[z] & LOMASK)) {
1181 map[x][y] = VBRTAB2[z];
1182 }
1183
1184 }
1185 }
1186 }
1187 return true;
1188 }
1189
1190 if (tile == BRWH) { /* Horizontal bridge close */
1191
1192 if ((!(getRandom16() & 3)) && getBoatDistance(pos) > 340) {
1193
1194 for (z = 0; z < 7; z++) { /* Close */
1195
1196 x = pos.posX + HDx[z];
1197 y = pos.posY + HDy[z];
1198
1199 if (testBounds(x, y)) {
1200
1201 if ((map[x][y] & LOMASK) == (HBRTAB[z] & LOMASK)) {
1202
1203 map[x][y] = HBRTAB2[z];
1204
1205 }
1206 }
1207 }
1208 }
1209 return true;
1210 }
1211
1212 if (getBoatDistance(pos) < 300 || (!(getRandom16() & 7))) {
1213 if (tile & 1) {
1214 if (pos.posX < WORLD_W - 1) {
1215 if (map[pos.posX + 1][pos.posY] == CHANNEL) { /* Vertical open */
1216
1217 for (z = 0; z < 7; z++) {
1218
1219 x = pos.posX + VDx[z];
1220 y = pos.posY + VDy[z];
1221
1222 if (testBounds(x, y)) {
1223
1224 MPtem = map[x][y];
1225 if (MPtem == CHANNEL || ((MPtem & 15) == (VBRTAB2[z] & 15))) {
1226 map[x][y] = VBRTAB[z];
1227 }
1228 }
1229 }
1230 return true;
1231 }
1232 }
1233 return false;
1234
1235 } else {
1236
1237 if (pos.posY > 0) {
1238 if (map[pos.posX][pos.posY - 1] == CHANNEL) {
1239
1240 /* Horizontal open */
1241 for (z = 0; z < 7; z++) {
1242
1243 x = pos.posX + HDx[z];
1244 y = pos.posY + HDy[z];
1245
1246 if (testBounds(x, y)) {
1247
1248 MPtem = map[x][y];
1249 if (((MPtem & 15) == (HBRTAB2[z] & 15)) || MPtem == CHANNEL) {
1250 map[x][y] = HBRTAB[z];
1251 }
1252 }
1253 }
1254 return true;
1255 }
1256 }
1257 return false;
1258 }
1259
1260 }
1261 return false;
1262}
1263
1264
1271{
1272 int sprDist;
1273 SimSprite *sprite;
1274
1275 int dist = 99999;
1276 int mx = pos.posX * 16 + 8;
1277 int my = pos.posY * 16 + 8;
1278
1279 for (sprite = spriteList; sprite != NULL; sprite = sprite->next) {
1280 if (sprite->type == SPRITE_SHIP && sprite->frame != 0) {
1281
1282 sprDist = absoluteValue(sprite->x + sprite->xHot - mx)
1283 + absoluteValue(sprite->y + sprite->yHot - my);
1284
1285 dist = min(dist, sprDist);
1286 }
1287 }
1288 return dist;
1289}
1290
1291
1301{
1302 static const short DX[4] = { -1, 0, 1, 0 };
1303 static const short DY[4] = { 0, -1, 0, 1 };
1304
1305 // Try to set neighbouring tiles on fire as well
1306 for (short z = 0; z < 4; z++) {
1307
1308 if ((getRandom16() & 7) == 0) {
1309
1310 short xTem = pos.posX + DX[z];
1311 short yTem = pos.posY + DY[z];
1312
1313 if (testBounds(xTem, yTem)) {
1314
1315 MapValue c = map[xTem][yTem];
1316 if (!(c & BURNBIT)) {
1317 continue;
1318 }
1319
1320 if (c & ZONEBIT) {
1321 // Neighbour is a zone and burnable
1322 fireZone(Position(xTem, yTem), c);
1323
1324 if ((c & LOMASK) > IZB) { /* Explode */
1325 makeExplosionAt(xTem *16 + 8, yTem * 16 + 8);
1326 }
1327 }
1328
1329 map[xTem][yTem] = randomFire();
1330 }
1331 }
1332 }
1333
1334 // Compute likelyhood of fire running out of fuel
1335 short rate = 10; // Likelyhood of extinguishing (bigger means less chance)
1336 short z = fireStationEffectMap.worldGet(pos.posX, pos.posY);
1337
1338 if (z > 0) {
1339 rate = 3;
1340 if (z > 20) {
1341 rate = 2;
1342 }
1343 if (z > 100) {
1344 rate = 1;
1345 }
1346 }
1347
1348 // Decide whether to put out the fire.
1349 if (getRandom(rate) == 0) {
1350 map[pos.posX][pos.posY] = randomRubble();
1351 }
1352}
1353
1354
1364{
1365 short XYmax;
1366
1367 int value = rateOfGrowthMap.worldGet(pos.posX, pos.posY);
1368 value = clamp(value - 20, -200, 200);
1369 rateOfGrowthMap.worldSet(pos.posX, pos.posY, value);
1370
1371 ch = ch & LOMASK;
1372
1373 if (ch < PORTBASE) {
1374 XYmax = 2;
1375 } else {
1376 if (ch == AIRPORT) {
1377 XYmax = 5;
1378 } else {
1379 XYmax = 4;
1380 }
1381 }
1382
1383 // Make remaining tiles of the zone bulldozable
1384 for (short x = -1; x < XYmax; x++) {
1385 for (short y = -1; y < XYmax; y++) {
1386
1387 short xTem = pos.posX + x;
1388 short yTem = pos.posY + y;
1389
1390 if (!testBounds(xTem, yTem)) {
1391 continue;
1392 }
1393
1394 if ((MapTile)(map[xTem][yTem] & LOMASK) >= ROADBASE) {
1395 /* post release */
1396 map[xTem][yTem] |= BULLBIT;
1397 }
1398
1399 }
1400 }
1401}
1402
1403
1410void Micropolis::repairZone(const Position &pos, MapTile zCent, short zSize)
1411{
1412 MapTile tile = zCent - 2 - zSize;
1413
1414 // y and x loops one position shifted to compensate for the center-tile position.
1415 for (short y = -1; y < zSize - 1; y++) {
1416 for (short x = -1; x < zSize - 1; x++) {
1417
1418 int xx = pos.posX + x;
1419 int yy = pos.posY + y;
1420
1421 tile++;
1422
1423 if (testBounds(xx, yy)) {
1424
1425 MapValue mapValue = map[xx][yy];
1426
1427 if (mapValue & ZONEBIT) {
1428 continue;
1429 }
1430
1431 if (mapValue & ANIMBIT) {
1432 continue;
1433 }
1434
1435 MapTile mapTile = mapValue & LOMASK;
1436
1437 if (mapTile < RUBBLE || mapTile >= ROADBASE) {
1438 map[xx][yy] = tile | CONDBIT | BURNBIT;
1439 }
1440 }
1441 }
1442 }
1443}
1444
1445
1451void Micropolis::doSpecialZone(const Position &pos, bool powerOn)
1452{
1453 // Bigger numbers reduce chance of nuclear melt down
1454 static const short meltdownTable[3] = { 30000, 20000, 10000 };
1455
1456 MapTile tile = map[pos.posX][pos.posY] & LOMASK;
1457
1458 switch (tile) {
1459
1460 case POWERPLANT:
1461
1462 coalPowerPop++;
1463
1464 if ((cityTime & 7) == 0) {
1465 repairZone(pos, POWERPLANT, 4); /* post */
1466 }
1467
1468 pushPowerStack(pos);
1469 coalSmoke(pos);
1470
1471 return;
1472
1473 case NUCLEAR:
1474
1475 assert(LEVEL_COUNT == LENGTH_OF(meltdownTable));
1476
1477 if (enableDisasters && !getRandom(meltdownTable[gameLevel])) {
1478 doMeltdown(pos);
1479 return;
1480 }
1481
1483
1484 if ((cityTime & 7) == 0) {
1485 repairZone(pos, NUCLEAR, 4); /* post */
1486 }
1487
1488 pushPowerStack(pos);
1489
1490 return;
1491
1492 case FIRESTATION: {
1493
1494 int z;
1495
1497
1498 if (!(cityTime & 7)) {
1499 repairZone(pos, FIRESTATION, 3); /* post */
1500 }
1501
1502 if (powerOn) {
1503 z = fireEffect; /* if powered get effect */
1504 } else {
1505 z = fireEffect / 2; /* from the funding ratio */
1506 }
1507
1508 Position pos2(pos);
1509 bool foundRoad = findPerimeterRoad(&pos2);
1510
1511 if (!foundRoad) {
1512 z = z / 2; /* post FD's need roads */
1513 }
1514
1515 int value = fireStationMap.worldGet(pos2.posX, pos2.posY);
1516 value += z;
1517 fireStationMap.worldSet(pos2.posX, pos2.posY, value);
1518
1519 return;
1520 }
1521
1522 case POLICESTATION: {
1523
1524 int z;
1525
1527
1528 if (!(cityTime & 7)) {
1529 repairZone(pos, POLICESTATION, 3); /* post */
1530 }
1531
1532 if (powerOn) {
1533 z = policeEffect;
1534 } else {
1535 z = policeEffect / 2;
1536 }
1537
1538 Position pos2(pos);
1539 bool foundRoad = findPerimeterRoad(&pos2);
1540
1541 if (!foundRoad) {
1542 z = z / 2; /* post PD's need roads */
1543 }
1544
1545 int value = policeStationMap.worldGet(pos2.posX, pos2.posY);
1546 value += z;
1547 policeStationMap.worldSet(pos2.posX, pos2.posY, value);
1548
1549 return;
1550 }
1551
1552 case STADIUM: // Empty stadium
1553
1554 stadiumPop++;
1555
1556 if (!(cityTime & 15)) {
1557 repairZone(pos, STADIUM, 4);
1558 }
1559
1560 if (powerOn) {
1561 // Every now and then, display a match
1562 if (((cityTime + pos.posX + pos.posY) & 31) == 0) {
1563 drawStadium(pos, FULLSTADIUM);
1564 map[pos.posX + 1][pos.posY] = FOOTBALLGAME1 + ANIMBIT;
1565 map[pos.posX + 1][pos.posY + 1] = FOOTBALLGAME2 + ANIMBIT;
1566 }
1567 }
1568
1569 return;
1570
1571 case FULLSTADIUM: // Full stadium
1572
1573 stadiumPop++;
1574
1575 if (((cityTime + pos.posX + pos.posY) & 7) == 0) {
1576 // Stop the match
1577 drawStadium(pos, STADIUM);
1578 }
1579
1580 return;
1581
1582 case AIRPORT:
1583
1584 airportPop++;
1585
1586 if ((cityTime & 7) == 0) {
1587 repairZone(pos, AIRPORT, 6);
1588 }
1589
1590 // If powered, display a rotating radar
1591 if (powerOn) {
1592 if ((map[pos.posX + 1][pos.posY - 1] & LOMASK) == RADAR) {
1593 map[pos.posX + 1][pos.posY - 1] = RADAR0 + ANIMBIT + CONDBIT + BURNBIT;
1594 }
1595 } else {
1596 map[pos.posX + 1][pos.posY - 1] = RADAR + CONDBIT + BURNBIT;
1597 }
1598
1599 if (powerOn) { // Handle the airport only if there is power
1600 doAirport(pos);
1601 }
1602
1603 return;
1604
1605 case PORT:
1606
1607 seaportPop++;
1608
1609 if ((cityTime & 15) == 0) {
1610 repairZone(pos, PORT, 4);
1611 }
1612
1613 // If port has power and there is no ship, generate one
1614 if (powerOn && getSprite(SPRITE_SHIP) == NULL) {
1615 generateShip();
1616 }
1617
1618 return;
1619 }
1620}
1621
1622
1631{
1632 int x, y;
1633
1634 z = z - 5;
1635
1636 for (y = center.posY - 1; y < center.posY + 3; y++) {
1637 for (x = center.posX - 1; x < center.posX + 3; x++) {
1638 map[x][y] = z | BNCNBIT;
1639 z++;
1640 }
1641 }
1642
1643 map[center.posX][center.posY] |= ZONEBIT | PWRBIT;
1644}
1645
1646
1652{
1653 if (getRandom(5) == 0) {
1654 generatePlane(pos);
1655 return;
1656 }
1657
1658 if (getRandom(12) == 0) {
1659 generateCopter(pos);
1660 }
1661}
1662
1663
1669{
1670 static const short SmTb[4] = {
1673 };
1674 static const short dx[4] = { 1, 2, 1, 2 };
1675 static const short dy[4] = { -1, -1, 0, 0 };
1676
1677 for (short x = 0; x < 4; x++) {
1678 map[pos.posX + dx[x]][pos.posY + dy[x]] =
1679 SmTb[x] | ANIMBIT | CONDBIT | PWRBIT | BURNBIT;
1680 }
1681}
1682
1683
1689{
1690 makeExplosion(pos.posX - 1, pos.posY - 1);
1691 makeExplosion(pos.posX - 1, pos.posY + 2);
1692 makeExplosion(pos.posX + 2, pos.posY - 1);
1693 makeExplosion(pos.posX + 2, pos.posY + 2);
1694
1695 // Whole power plant is at fire
1696 for (int x = pos.posX - 1; x < pos.posX + 3; x++) {
1697 for (int y = pos.posY - 1; y < pos.posY + 3; y++) {
1698 map[x][y] = randomFire();
1699 }
1700 }
1701
1702 // Add lots of radiation tiles around the plant
1703 for (int z = 0; z < 200; z++) {
1704
1705 int x = pos.posX - 20 + getRandom(40);
1706 int y = pos.posY - 15 + getRandom(30);
1707
1708 if (!testBounds(x, y)) { // Ignore off-map positions
1709 continue;
1710 }
1711
1712 MapValue t = map[x][y];
1713
1714 if (t & ZONEBIT) {
1715 continue; // Ignore zones
1716 }
1717
1718 if ((t & BURNBIT) || t == DIRT) {
1719 map[x][y] = RADTILE; // Make tile radio-active
1720 }
1721
1722 }
1723
1724 // Report disaster to the user
1725 sendMessage(MESSAGE_NUCLEAR_MELTDOWN, pos.posX, pos.posY, true, true);
1726}
1727
1728
DATA worldGet(int x, int y) const
Definition map_type.h:316
const int MAP_BLOCKSIZE
Definition map_type.h:121
void set(int x, int y, DATA val)
Definition map_type.h:248
const int MAP_W
Number of clusters in horizontal direction.
Definition map_type.h:122
void clear()
Definition map_type.h:222
const int MAP_H
Number of clusters in vertical direction.
Definition map_type.h:123
DATA get(int x, int y) const
Definition map_type.h:265
void fill(DATA val)
Definition map_type.h:208
void worldSet(int x, int y, DATA val)
Definition map_type.h:297
Quad roadEffect
SimSprite * spriteList
List of active sprites.
void generateCopter(const Position &pos)
Definition sprite.cpp:1969
bool doInitialEval
Need to perform initial city evaluation.
int mustDrawBudget
void doMeltdown(const Position &pos)
short indPop
Definition micropolis.h:997
short stadiumPop
Number of stadiums.
short indZonePop
Number of industrial zones.
void evalInit()
Definition evaluate.cpp:136
Scenario scoreType
The type of score table to use.
void coalSmoke(const Position &pos)
void doRadTile(const Position &pos)
short indHist10Max
short crimeAverage
void doZone(const Position &pos)
Definition zone.cpp:91
GameLevel gameLevel
Difficulty level of the game (0..2)
Scenario scenario
Scenario being played.
void simLoadInit()
Definition simulate.cpp:440
short poweredZoneCount
Number of powered tiles in all zone.
Quad policeEffect
void take10Census()
Definition simulate.cpp:730
void doSpecialZone(const Position &pos, bool PwrOn)
short * resHist
void makeExplosion(int x, int y)
Definition sprite.cpp:2020
void changeCensus()
Definition graph.cpp:122
int powerStackPointer
Stack counter, points to top-most item.
short graph10Max
MapByte1 powerGridMap
short unpoweredZoneCount
Number of unpowered tiles in all zones.
bool setZonePower(const Position &pos)
Definition zone.cpp:433
void doRoad(const Position &pos)
short newMapFlags[MAP_TYPE_COUNT]
short churchPop
Number of churches.
short firePop
Definition micropolis.h:976
short * moneyHist
short faith
Faith bias.
MapShort8 fireStationEffectMap
short resPop
Definition micropolis.h:983
short getRandom(short range)
Definition random.cpp:110
void sendMessages()
Definition message.cpp:87
void fireAnalysis()
Definition scan.cpp:120
int getBoatDistance(const Position &pos)
int getRandom16()
Definition random.cpp:130
void decRateOfGrowthMap()
Definition simulate.cpp:371
bool enableDisasters
Enable disasters.
void generatePlane(const Position &pos)
Definition sprite.cpp:1985
void setValves()
Definition simulate.cpp:564
short graph120Max
short scoreWait
Time to wait before computing the score.
void fireZone(const Position &pos, MapValue ch)
void doDisasters()
Definition disasters.cpp:92
short resZonePop
Number of residential zones.
short pollutionAverage
void collectTax()
Definition simulate.cpp:856
void drawStadium(const Position &center, MapTile z)
void pushPowerStack(const Position &pos)
Definition power.cpp:173
short resHist120Max
bool indCap
Block industrial growth.
Quad fireEffect
short totalPopLast
bool resCap
Block residential growth.
short * crimeHist
short * pollutionHist
short airportPop
void generateShip()
Definition sprite.cpp:1858
short policeStationPop
MapValue randomFire()
void repairZone(const Position &pos, MapTile zCent, short zSize)
short disasterWait
Count-down timer for the disaster.
SimSprite * getSprite(int type)
Definition sprite.cpp:338
MapShort8 fireStationMap
short totalPop
short landValueAverage
unsigned short * map[WORLD_W]
short coalPowerPop
void doStartGame()
short hospitalPop
Number of hospitals.
void crimeScan()
Definition scan.cpp:413
bool censusChanged
short * indHist
void generateTrain(int x, int y)
Definition sprite.cpp:1836
short comHist10Max
short * comHist
void sendMessage(short Mnum, short x=NOWHERE, short y=NOWHERE, bool picture=false, bool important=false)
Definition message.cpp:390
void doAirport(const Position &pos)
Scenario disasterEvent
The disaster for which a count-down is running.
MapShort8 policeStationMap
void setGameLevel(GameLevel level)
MapByte2 trafficDensityMap
Traffic density map.
short cityScore
bool comCap
Block commercial growth.
void decTrafficMap()
Definition simulate.cpp:339
void doFire(const Position &pos)
Quad policeSpend
CityClass cityClass
City class, affected by city population.
short nuclearPowerPop
static bool testBounds(int wx, int wy)
void makeExplosionAt(int x, int y)
Definition sprite.cpp:2033
short fireStationPop
void doStartScenario(int scenario)
short comPop
Definition micropolis.h:990
void doNilPower()
Definition simulate.cpp:323
short needHospital
Quad policeFund
short needChurch
MapShort8 rateOfGrowthMap
bool doBridge(const Position &pos, MapTile tile)
short cityTax
short railTotal
Definition micropolis.h:971
MapValue randomRubble()
void doPowerScan()
Definition power.cpp:125
short * miscHist
void updateFundEffects()
Definition simulate.cpp:912
short comZonePop
Number of commercial zones.
void populationDensityScan()
Definition scan.cpp:136
void doFlood(const Position &pos)
short seaportPop
short roadTotal
Definition micropolis.h:964
void doRail(const Position &pos)
short comHist120Max
void cityEvaluation()
Definition evaluate.cpp:110
void doBudget()
Definition budget.cpp:97
bool findPerimeterRoad(Position *pos)
Definition traffic.cpp:239
void doSimInit()
Definition simulate.cpp:288
short resHist10Max
short indHist120Max
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 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
SimSprite * next
Pointer to next SimSprite object in the list.
Definition micropolis.h:888
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_NONE
No scenario (free playing)
Definition micropolis.h:699
@ SC_COUNT
Number of scenarios.
Definition micropolis.h:710
@ MAP_TYPE_DYNAMIC
Dynamic filter.
Definition micropolis.h:321
@ MAP_TYPE_ALL
All zones.
Definition micropolis.h:307
@ MAP_TYPE_IND
Industrial zones.
Definition micropolis.h:310
@ MAP_TYPE_COM
Commercial zones.
Definition micropolis.h:309
@ MAP_TYPE_RES
Residential zones.
Definition micropolis.h:308
@ MAP_TYPE_ROAD
Roads.
Definition micropolis.h:312
@ MAP_TYPE_POWER
Power connectivity.
Definition micropolis.h:311
@ MAP_TYPE_TRAFFIC_DENSITY
Traffic.
Definition micropolis.h:315
@ HTRFBASE
First tile with high traffic.
Definition micropolis.h:452
@ HBRIDGE
Horizontal bridge.
Definition micropolis.h:426
@ VBRIDGE
Vertical bridge.
Definition micropolis.h:428
@ STADIUM
'Center tile' stadium.
Definition micropolis.h:595
@ NUCLEAR
'Center' tile nuclear power plant.
Definition micropolis.h:604
@ PORTBASE
Top-left tile of the seaport.
Definition micropolis.h:567
@ IZB
Center tile of first non-empty industry zone.
Definition micropolis.h:542
@ PORT
Center tile of the seaport.
Definition micropolis.h:568
@ COALSMOKE3
927 last animation tile for chimney at coal power plant (2, 1).
Definition micropolis.h:644
@ POWERPLANT
'Center' tile of coal power plant.
Definition micropolis.h:580
@ COALSMOKE4
931 last animation tile for chimney at coal power plant (3, 1).
Definition micropolis.h:647
@ RADTILE
Radio-active contaminated tile.
Definition micropolis.h:415
@ FIRESTATION
'Center tile' of fire station.
Definition micropolis.h:585
@ LTRFBASE
First tile with low traffic.
Definition micropolis.h:443
@ DIRT
Clear tile.
Definition micropolis.h:382
@ COALSMOKE1
919 last animation tile for chimney at coal power plant (2, 0).
Definition micropolis.h:638
@ COALSMOKE2
923 last animation tile for chimney at coal power plant (3, 0).
Definition micropolis.h:641
CityClass
Definition micropolis.h:751
@ CC_MEGALOPOLIS
Megalopolis, > 500000 citizens.
Definition micropolis.h:757
@ CC_VILLAGE
Village.
Definition micropolis.h:752
static const int MAX_FIRE_STATION_EFFECT
Definition micropolis.h:263
GameLevel
Definition micropolis.h:763
@ LEVEL_FIRST
First game level value.
Definition micropolis.h:770
@ LEVEL_LAST
Last game level value.
Definition micropolis.h:771
@ LEVEL_COUNT
Number of game levels.
Definition micropolis.h:768
static T min(const T a, const T b)
Definition micropolis.h:784
static const int MAX_ROAD_EFFECT
Definition micropolis.h:253
@ SPRITE_SHIP
Ship.
Definition micropolis.h:334
#define LENGTH_OF(array)
Definition micropolis.h:843
static const int MAX_POLICE_STATION_EFFECT
Definition micropolis.h:258
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
static T max(const T a, const T b)
Definition micropolis.h:796
static const int CENSUS_FREQUENCY_10
Definition simulate.cpp:90
static const int CENSUS_FREQUENCY_120
Definition simulate.cpp:96
static const int TAX_FREQUENCY
Definition simulate.cpp:101
Defines string identification numbers for texts used in the Micropolis game engine.
@ MESSAGE_NUCLEAR_MELTDOWN
A Nuclear Meltdown has occurred !!!
Definition text.h:155
unsigned short MapTile
Definition tool.h:108
@ 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
@ CONDBIT
bit 14. tile can conduct electricity.
Definition tool.h:121
@ PWRBIT
bit 15, tile has power.
Definition tool.h:120
@ BULLBIT
bit 12, tile is bulldozable.
Definition tool.h:123
@ ANIMBIT
bit 11, tile is animated.
Definition tool.h:124
@ ALLBITS
Mask for the bits-part of the tile.
Definition tool.h:128
unsigned short MapValue
Definition tool.h:101