Micropolis
scan.cpp
Go to the documentation of this file.
1/* scan.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
81
83
90static void smoothStationMap(MapShort8 *map)
91{
92 short x, y, edge;
93 MapShort8 tempMap(*map);
94
95 for (x = 0; x < tempMap.MAP_W; x++) {
96 for (y = 0; y < tempMap.MAP_H; y++) {
97 edge = 0;
98 if (x > 0) {
99 edge += tempMap.get(x - 1, y);
100 }
101 if (x < tempMap.MAP_W - 1) {
102 edge += tempMap.get(x + 1, y);
103 }
104 if (y > 0) {
105 edge += tempMap.get(x, y - 1);
106 }
107 if (y < tempMap.MAP_H - 1) {
108 edge += tempMap.get(x, y + 1);
109 }
110 edge = tempMap.get(x, y) + edge / 4;
111 map->set(x, y, edge / 2);
112 }
113 }
114}
115
131
132
137{
138 /* sets: populationDensityMap, , , comRateMap */
139 tempMap1.clear();
140 Quad Xtot = 0;
141 Quad Ytot = 0;
142 Quad Ztot = 0;
143 for (int x = 0; x < WORLD_W; x++) {
144 for (int y = 0; y < WORLD_H; y++) {
145 MapValue mapValue = map[x][y];
146 if (mapValue & ZONEBIT) {
147 MapTile mapTile = mapValue & LOMASK;
148 int pop = getPopulationDensity(Position(x, y), mapTile) * 8;
149 pop = min(pop, 254);
150
151 tempMap1.worldSet(x, y, (Byte)pop);
152 Xtot += x;
153 Ytot += y;
154 Ztot++;
155 }
156 }
157 }
158
159 doSmooth1(); // tempMap1 -> tempMap2
160 doSmooth2(); // tempMap2 -> tempMap1
161 doSmooth1(); // tempMap1 -> tempMap2
162
165
166 // Copy tempMap2 to populationDensityMap, multiplying by 2
167 Byte *srcMap = tempMap2.getBase();
168 Byte *destMap = populationDensityMap.getBase();
169 for (int i = 0; i < tempMap2.MAP_W * tempMap2.MAP_H; i++) {
170 destMap[i] = srcMap[i] * 2;
171 }
172
173 computeComRateMap(); /* Compute the comRateMap */
174
175
176 // Compute new city center
177 if (Ztot > 0) { /* Find Center of Mass for City */
178 cityCenterX = (short)(Xtot / Ztot);
179 cityCenterY = (short)(Ytot / Ztot);
180 } else {
181 cityCenterX = WORLD_W / 2; /* if pop==0 center of map is city center */
182 cityCenterY = WORLD_H / 2;
183 }
184
185 // Set flags for updated maps
189}
190
191
199{
200 int pop;
201
202 if (tile == FREEZ) {
203 pop = doFreePop(pos);
204 return pop;
205 }
206
207 if (tile < COMBASE) {
208 pop = getResZonePop(tile);
209 return pop;
210 }
211
212 if (tile < INDBASE) {
213 pop = getComZonePop(tile) * 8;
214 return pop;
215 }
216
217 if (tile < PORTBASE) {
218 pop = getIndZonePop(tile) * 8;
219 return pop;
220 }
221
222 return 0;
223}
224
225
226/* comefrom: simulate SpecialInit */
227void Micropolis::pollutionTerrainLandValueScan()
228{
229 /* Does pollution, terrain, land value */
230 Quad ptot, LVtot;
231 int x, y, z, dis;
232 int pollutionLevel, loc, worldX, worldY, Mx, My, pnum, LVnum, pmax;
233
234 // tempMap3 is a map of development density, smoothed into terrainMap.
235 tempMap3.clear();
236
237 LVtot = 0;
238 LVnum = 0;
239
240 for (x = 0; x < landValueMap.MAP_W; x++) {
241 for (y = 0; y < landValueMap.MAP_H; y++) {
242 pollutionLevel = 0;
243 bool landValueFlag = false;
244 worldX = x * 2;
245 worldY = y * 2;
246
247 for (Mx = worldX; Mx <= worldX + 1; Mx++) {
248 for (My = worldY; My <= worldY + 1; My++) {
249 loc = (map[Mx][My] & LOMASK);
250 if (loc) {
251 if (loc < RUBBLE) {
252 // Increment terrain memory.
253 Byte value = tempMap3.get(x >>1, y >>1);
254 tempMap3.set(x >>1, y >>1, value + 15);
255 continue;
256 }
257 pollutionLevel += getPollutionValue(loc);
258 if (loc >= ROADBASE) {
259 landValueFlag = true;
260 }
261 }
262 }
263 }
264
265/* XXX ??? This might have to do with the radiation tile returning -40.
266 if (pollutionLevel < 0) {
267 pollutionLevel = 250;
268 }
269*/
270
271 pollutionLevel = min(pollutionLevel, 255);
272 tempMap1.set(x, y, pollutionLevel);
273
274 if (landValueFlag) { /* LandValue Equation */
275 dis = 34 - getCityCenterDistance(worldX, worldY) / 2;
276 dis = dis <<2;
277 dis += terrainDensityMap.get(x >>1, y >>1);
278 dis -= pollutionDensityMap.get(x, y);
279 if (crimeRateMap.get(x, y) > 190) {
280 dis -= 20;
281 }
282 dis = clamp(dis, 1, 250);
283 landValueMap.set(x, y, dis);
284 LVtot += dis;
285 LVnum++;
286 } else {
287 landValueMap.set(x, y, 0);
288 }
289 }
290 }
291
292 if (LVnum > 0) {
293 landValueAverage = (short)(LVtot / LVnum);
294 } else {
296 }
297
298 doSmooth1(); // tempMap1 -> tempMap2
299 doSmooth2(); // tempMap2 -> tempMap1
300
301 pmax = 0;
302 pnum = 0;
303 ptot = 0;
304
305 for (x = 0; x < WORLD_W; x += pollutionDensityMap.MAP_BLOCKSIZE) {
306 for (y = 0; y < WORLD_H; y += pollutionDensityMap.MAP_BLOCKSIZE) {
307 z = tempMap1.worldGet(x, y);
309
310 if (z) { /* get pollute average */
311 pnum++;
312 ptot += z;
313 /* find max pol for monster */
314 if (z > pmax || (z == pmax && (getRandom16() & 3) == 0)) {
315 pmax = z;
316 pollutionMaxX = x;
317 pollutionMaxY = y;
318 }
319 }
320 }
321 }
322 if (pnum) {
323 pollutionAverage = (short)(ptot / pnum);
324 } else {
326 }
327
328 smoothTerrain();
329
333}
334
335
342{
343 if (loc < POWERBASE) {
344
345 if (loc >= HTRFBASE) {
346 return /* 25 */ 75; /* heavy traf */
347 }
348
349 if (loc >= LTRFBASE) {
350 return /* 10 */ 50; /* light traf */
351 }
352
353 if (loc < ROADBASE) {
354
355 if (loc > FIREBASE) {
356 return /* 60 */ 90;
357 }
358
359 /* XXX: Why negative pollution from radiation? */
360 if (loc >= RADTILE) {
361 return /* -40 */ 255; /* radioactivity */
362 }
363
364 }
365 return 0;
366 }
367
368 if (loc <= LASTIND) {
369 return 0;
370 }
371
372 if (loc < PORTBASE) {
373 return 50; /* Ind */
374 }
375
376 if (loc <= LASTPOWERPLANT) {
377 return /* 60 */ 100; /* prt, aprt, cpp */
378 }
379
380 return 0;
381}
382
383
393{
394 int xDis, yDis;
395
396 if (x > cityCenterX) {
397 xDis = x - cityCenterX;
398 } else {
399 xDis = cityCenterX - x;
400 }
401
402 if (y > cityCenterY) {
403 yDis = y - cityCenterY;
404 } else {
405 yDis = cityCenterY - y;
406 }
407
408 return min(xDis + yDis, 64);
409}
410
411
414{
418
419 Quad totz = 0;
420 int numz = 0;
421 int cmax = 0;
422
423 for (int x = 0; x < WORLD_W; x += crimeRateMap.MAP_BLOCKSIZE) {
424 for (int y = 0; y < WORLD_H; y += crimeRateMap.MAP_BLOCKSIZE) {
425 int z = landValueMap.worldGet(x, y);
426 if (z > 0) {
427 ++numz;
428 z = 128 - z;
430 z = min(z, 300);
431 z -= policeStationMap.worldGet(x, y);
432 z = clamp(z, 0, 250);
433 crimeRateMap.worldSet(x, y, (Byte)z);
434 totz += z;
435
436 // Update new crime hot-spot
437 if (z > cmax || (z == cmax && (getRandom16() & 3) == 0)) {
438 cmax = z;
439 crimeMaxX = x;
440 crimeMaxY = y;
441 }
442
443 } else {
444 crimeRateMap.worldSet(x, y, 0);
445 }
446 }
447 }
448
449 if (numz > 0) {
450 crimeAverage = (short)(totz / numz);
451 } else {
452 crimeAverage = 0;
453 }
454
456
460}
461
462
463/* comefrom: pollutionTerrainLandValueScan */
464void Micropolis::smoothTerrain()
465{
466 if (donDither & 1) {
467 int x, y = 0, dir = 1;
468 unsigned z = 0;
469
470 for (x = 0; x < terrainDensityMap.MAP_W; x++) {
471 for (; y != terrainDensityMap.MAP_H && y != -1; y += dir) {
472 z +=
473 tempMap3.get((x == 0) ? x : (x - 1), y) +
474 tempMap3.get((x == (terrainDensityMap.MAP_W - 1)) ? x : (x + 1), y) +
475 tempMap3.get(x, (y == 0) ? (0) : (y - 1)) +
476 tempMap3.get(x, (y == (terrainDensityMap.MAP_H - 1)) ? y : (y + 1)) +
477 (tempMap3.get(x, y) <<2);
478 Byte val = (Byte)(z / 8);
479 terrainDensityMap.set(x, y, val);
480 z &= 0x7;
481 }
482 dir = -dir;
483 y += dir;
484 }
485 } else {
486 short x, y;
487
488 for (x = 0; x < terrainDensityMap.MAP_W; x++) {
489 for (y = 0; y < terrainDensityMap.MAP_H; y++) {
490 unsigned z = 0;
491 if (x > 0) {
492 z += tempMap3.get(x - 1, y);
493 }
494 if (x < (terrainDensityMap.MAP_W - 1)) {
495 z += tempMap3.get(x + 1, y);
496 }
497 if (y > 0) {
498 z += tempMap3.get(x, y - 1);
499 }
500 if (y < (terrainDensityMap.MAP_H - 1)) {
501 z += tempMap3.get(x, y + 1);
502 }
503 Byte val = (Byte)(z / 4 + tempMap3.get(x, y)) / 2;
504 terrainDensityMap.set(x, y, val);
505 }
506 }
507 }
508}
509
516static void smoothDitherMap(const MapByte2 &srcMap,
517 MapByte2 *destMap,
518 bool ditherFlag)
519{
520 if (ditherFlag) {
521 int x, y = 0, z = 0, dir = 1;
522
523 for (x = 0; x < srcMap.MAP_W; x++) {
524 for (; y != srcMap.MAP_H && y != -1; y += dir) {
525 z +=
526 srcMap.get((x == 0) ? x : (x - 1), y) +
527 srcMap.get((x == srcMap.MAP_W - 1) ? x : (x + 1), y) +
528 srcMap.get(x, (y == 0) ? (0) : (y - 1)) +
529 srcMap.get(x, (y == (srcMap.MAP_H - 1)) ? y : (y + 1)) +
530 srcMap.get(x, y);
531 Byte val = (Byte)(z / 4);
532 destMap->set(x, y, val);
533 z &= 3;
534 }
535 dir = -dir;
536 y += dir;
537 }
538 } else {
539 short x, y, z;
540
541 for (x = 0; x < srcMap.MAP_W; x++) {
542 for (y = 0; y < srcMap.MAP_H; y++) {
543 z = 0;
544 if (x > 0) {
545 z += srcMap.get(x - 1, y);
546 }
547 if (x < srcMap.MAP_W - 1) {
548 z += srcMap.get(x + 1, y);
549 }
550 if (y > 0) {
551 z += srcMap.get(x, y - 1);
552 }
553 if (y < (srcMap.MAP_H - 1)) {
554 z += srcMap.get(x, y + 1);
555 }
556 z = (z + srcMap.get(x, y)) >>2;
557 if (z > 255) {
558 z = 255;
559 }
560 destMap->set(x, y, (Byte)z);
561 }
562 }
563 }
564}
565
566
567/* Smooth Micropolis::tempMap1 to Micropolis::tempMap2 */
568void Micropolis::doSmooth1()
569{
571}
572
573
574/* Smooth Micropolis::tempMap2 to Micropolis::tempMap1 */
575void Micropolis::doSmooth2()
576{
578}
579
580
586{
587 short x, y, z;
588
589 for (x = 0; x < comRateMap.MAP_W; x++) {
590 for (y = 0; y < comRateMap.MAP_H; y++) {
591 z = (short)(getCityCenterDistance(x * 8,y * 8) / 2); // 0..32
592 z = z * 4; // 0..128
593 z = 64 - z; // 64..-64
594 comRateMap.set(x, y, z);
595 }
596 }
597}
598
599
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 * getBase()
Definition map_type.h:233
DATA get(int x, int y) const
Definition map_type.h:265
void worldSet(int x, int y, DATA val)
Definition map_type.h:297
short crimeMaxX
X coordinate of most criminal area. Not used.
MapShort8 policeStationEffectMap
short getResZonePop(MapTile mapTile)
Definition zone.cpp:711
short doFreePop(const Position &pos)
Definition zone.cpp:409
short crimeAverage
short getIndZonePop(MapTile tile)
Definition zone.cpp:1001
MapByte2 crimeRateMap
Crime rate map.
MapByte4 terrainDensityMap
short newMapFlags[MAP_TYPE_COUNT]
MapShort8 comRateMap
short cityCenterY
Y coordinate of city center.
MapShort8 fireStationEffectMap
short pollutionMaxY
Y coordinate of most polluted area.
void fireAnalysis()
Definition scan.cpp:120
int getRandom16()
Definition random.cpp:130
MapByte4 tempMap3
short pollutionMaxX
X coordinate of most polluted area.
short pollutionAverage
int getPollutionValue(int loc)
Definition scan.cpp:341
void computeComRateMap()
Definition scan.cpp:585
short getComZonePop(MapTile tile)
Definition zone.cpp:866
MapShort8 fireStationMap
short cityCenterX
X coordinate of city center.
short landValueAverage
unsigned short * map[WORLD_W]
void crimeScan()
Definition scan.cpp:413
MapShort8 policeStationMap
MapByte2 pollutionDensityMap
Pollution density map.
MapByte2 tempMap1
int getCityCenterDistance(int x, int y)
Definition scan.cpp:392
int getPopulationDensity(const Position &pos, MapTile tile)
Definition scan.cpp:198
MapByte2 populationDensityMap
Population density map.
MapByte2 landValueMap
Land value map.
MapByte2 tempMap2
short crimeMaxY
Y coordinate of most criminal area. Not used.
void populationDensityScan()
Definition scan.cpp:136
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.
@ MAP_TYPE_POLLUTION
Pollution.
Definition micropolis.h:316
@ MAP_TYPE_POPULATION_DENSITY
Population density.
Definition micropolis.h:313
@ MAP_TYPE_DYNAMIC
Dynamic filter.
Definition micropolis.h:321
@ MAP_TYPE_LAND_VALUE
Land value.
Definition micropolis.h:318
@ MAP_TYPE_FIRE_RADIUS
Fire station coverage radius.
Definition micropolis.h:319
@ MAP_TYPE_CRIME
Crime rate.
Definition micropolis.h:317
@ MAP_TYPE_RATE_OF_GROWTH
Rate of growth.
Definition micropolis.h:314
@ MAP_TYPE_POLICE_RADIUS
Police station coverage radius.
Definition micropolis.h:320
@ LASTPOWERPLANT
Last tile of coal power plant.
Definition micropolis.h:581
@ HTRFBASE
First tile with high traffic.
Definition micropolis.h:452
@ PORTBASE
Top-left tile of the seaport.
Definition micropolis.h:567
@ RADTILE
Radio-active contaminated tile.
Definition micropolis.h:415
@ LTRFBASE
First tile with low traffic.
Definition micropolis.h:443
@ INDBASE
Top-left tile of empty industrial zone.
Definition micropolis.h:536
@ LASTIND
Last tile of empty industrial zone.
Definition micropolis.h:538
static T min(const T a, const T b)
Definition micropolis.h:784
static T clamp(const T val, const T lower, const T upper)
Definition micropolis.h:809
static void smoothStationMap(MapShort8 *map)
Definition scan.cpp:90
static void smoothDitherMap(const MapByte2 &srcMap, MapByte2 *destMap, bool ditherFlag)
Definition scan.cpp:516
unsigned short MapTile
Definition tool.h:108
@ 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
unsigned short MapValue
Definition tool.h:101