9 package micropolisj.engine;
11 import static micropolisj.engine.TileConstants.AIRPORT;
12 import static micropolisj.engine.TileConstants.CHURCH;
13 import static micropolisj.engine.TileConstants.COMCLR;
14 import static micropolisj.engine.TileConstants.CZB;
15 import static micropolisj.engine.TileConstants.DIRT;
16 import static micropolisj.engine.TileConstants.FIRESTATION;
17 import static micropolisj.engine.TileConstants.FOOTBALLGAME1;
18 import static micropolisj.engine.TileConstants.FOOTBALLGAME2;
19 import static micropolisj.engine.TileConstants.FULLSTADIUM;
20 import static micropolisj.engine.TileConstants.HHTHR;
21 import static micropolisj.engine.TileConstants.HOSPITAL;
22 import static micropolisj.engine.TileConstants.HOUSE;
23 import static micropolisj.engine.TileConstants.INDCLR;
24 import static micropolisj.engine.TileConstants.IZB;
25 import static micropolisj.engine.TileConstants.LHTHR;
26 import static micropolisj.engine.TileConstants.LOMASK;
27 import static micropolisj.engine.TileConstants.NUCLEAR;
28 import static micropolisj.engine.TileConstants.POLICESTATION;
29 import static micropolisj.engine.TileConstants.PORT;
30 import static micropolisj.engine.TileConstants.POWERPLANT;
31 import static micropolisj.engine.TileConstants.PWRBIT;
32 import static micropolisj.engine.TileConstants.RESCLR;
33 import static micropolisj.engine.TileConstants.RZB;
34 import static micropolisj.engine.TileConstants.STADIUM;
35 import static micropolisj.engine.TileConstants.TEMPEL;
36 import static micropolisj.engine.TileConstants.UNIVERSITY;
37 import static micropolisj.engine.TileConstants.commercialZonePop;
38 import static micropolisj.engine.TileConstants.getZoneSizeFor;
39 import static micropolisj.engine.TileConstants.industrialZonePop;
40 import static micropolisj.engine.TileConstants.isAnimated;
41 import static micropolisj.engine.TileConstants.isIndestructible;
42 import static micropolisj.engine.TileConstants.isIndestructible2;
43 import static micropolisj.engine.TileConstants.isRail;
44 import static micropolisj.engine.TileConstants.isResidentialClear;
45 import static micropolisj.engine.TileConstants.isRoadAny;
46 import static micropolisj.engine.TileConstants.isZoneCenter;
47 import static micropolisj.engine.TileConstants.residentialZonePop;
48 import micropolisj.engine.TrafficGen.ZoneType;
49 import micropolisj.util.Utilities;
55 class MapScanner
extends TileBehavior {
59 MapScanner(Micropolis city, B behavior) {
61 this.behavior = behavior;
62 this.traffic =
new TrafficGen(city);
66 public static enum B {
67 RESIDENTIAL, HOSPITAL_CHURCH, COMMERCIAL, INDUSTRIAL, COAL, NUCLEAR, FIRESTATION, POLICESTATION, STADIUM_EMPTY, STADIUM_FULL, AIRPORT, SEAPORT, UNIVERSITY, TEMPEL;
75 if(playerInfo == null) {
81 doResidential(playerInfo);
84 doHospitalChurch(playerInfo);
87 doCommercial(playerInfo);
90 doIndustrial(playerInfo);
93 doCoalPower(playerInfo);
96 doNuclearPower(playerInfo);
99 doFireStation(playerInfo);
102 doPoliceStation(playerInfo);
105 doStadiumEmpty(playerInfo);
108 doStadiumFull(playerInfo);
111 doAirport(playerInfo);
114 doSeaport(playerInfo);
117 doUniversity(playerInfo);
120 doTempel(playerInfo);
127 boolean checkZonePower() {
128 boolean zonePwrFlag = setZonePower();
137 playerInfo.unpoweredZoneCount++;
143 boolean setZonePower() {
144 boolean oldPower = (rawTile & PWRBIT) == PWRBIT;
145 boolean newPower = (tile == NUCLEAR || tile == POWERPLANT ||
city.hasPower(xpos, ypos));
147 if(newPower && !oldPower) {
148 city.
setTile(xpos, ypos, (
char) (rawTile | PWRBIT));
149 city.powerZone(xpos, ypos, getZoneSizeFor(tile));
151 else if(!newPower && oldPower) {
152 city.
setTile(xpos, ypos, (
char) (rawTile & (~PWRBIT)), Utilities.getPlayerID(rawTile));
153 city.shutdownZone(xpos, ypos, getZoneSizeFor(tile));
168 boolean zonePlop(
int base) {
169 assert isZoneCenter(base);
171 TileSpec.BuildingInfo bi = Tiles.get(base).getBuildingInfo();
176 for(
int y = ypos - 1; y < ypos - 1 + bi.height; y++) {
177 for(
int x = xpos - 1; x < xpos - 1 + bi.width; x++) {
188 assert bi.members.length == bi.width * bi.height;
190 for(
int y = ypos - 1; y < ypos - 1 + bi.height; y++) {
191 for(
int x = xpos - 1; x < xpos - 1 + bi.width; x++) {
192 city.
setTile(x, y, (
char) bi.members[i], Utilities.getPlayerID(rawTile));
198 this.rawTile =
city.
map[ypos][xpos];
199 this.tile = (char) (rawTile & LOMASK);
206 void doCoalPower(PlayerInfo playerInfo) {
209 playerInfo.coalCount++;
212 repairZone(POWERPLANT, 4);
218 void doNuclearPower(PlayerInfo playerInfo) {
222 city.doMeltdown(xpos, ypos);
226 playerInfo.nuclearCount++;
228 repairZone(NUCLEAR, 4);
234 void doFireStation(PlayerInfo playerInfo) {
235 playerInfo.fireStationCount++;
238 repairZone(FIRESTATION, 3);
242 if(checkZonePower()) {
243 z = playerInfo.fireEffect;
246 z = playerInfo.fireEffect / 2;
251 if(!traffic.findPerimeterRoad()) {
255 city.fireStMap[ypos / 8][xpos / 8] += z;
258 void doPoliceStation(PlayerInfo playerInfo) {
259 playerInfo.policeCount++;
262 repairZone(POLICESTATION, 3);
266 if(checkZonePower()) {
267 z = playerInfo.policeEffect;
270 z = playerInfo.policeEffect / 2;
275 if(!traffic.findPerimeterRoad()) {
279 city.policeMap[ypos / 8][xpos / 8] += z;
282 void doUniversity(PlayerInfo playerInfo) {
283 int tilePlayerID = Utilities.getPlayerID(rawTile);
287 repairZone(UNIVERSITY, 3);
289 if(checkZonePower()) {
294 void doStadiumEmpty(PlayerInfo playerInfo) {
295 int tilePlayerID = Utilities.getPlayerID(rawTile);
297 playerInfo.stadiumCount++;
300 repairZone(STADIUM, 4);
303 if(checkZonePower()) {
305 drawStadium(FULLSTADIUM, tilePlayerID);
306 city.
setTile(xpos + 1, ypos, (
char) (FOOTBALLGAME1), tilePlayerID);
307 city.
setTile(xpos + 1, ypos + 1, (
char) (FOOTBALLGAME2), tilePlayerID);
312 void doStadiumFull(PlayerInfo playerInfo) {
315 int tilePlayerID = Utilities.getPlayerID(rawTile);
316 playerInfo.stadiumCount++;
319 drawStadium(STADIUM, tilePlayerID);
323 void doAirport(PlayerInfo playerInfo) {
324 playerInfo.airportCount++;
327 repairZone(AIRPORT, 6);
330 if(checkZonePower()) {
332 if(
PRNG.nextInt(6) == 0) {
333 city.generatePlane(xpos, ypos);
336 if(
PRNG.nextInt(13) == 0) {
337 city.generateCopter(xpos, ypos);
343 void doTempel(PlayerInfo playerInfo) {
346 playerInfo.tempelCount++;
347 if(playerInfo.countdown == 0){
349 playerInfo.countdown = -1;
350 }
else if(playerInfo.countdown > 0){
352 playerInfo.countdown--;
355 repairZone(TEMPEL, 6);
359 void doSeaport(PlayerInfo playerInfo) {
360 playerInfo.seaportCount++;
366 if(checkZonePower() && !
city.hasSprite(SpriteKind.SHI)) {
374 void makeHospital(PlayerInfo playerInfo) {
375 if(playerInfo.needHospital > 0) {
377 playerInfo.needHospital = 0;
381 if(playerInfo.needChurch > 0) {
383 playerInfo.needChurch = 0;
391 void doHospitalChurch(PlayerInfo playerInfo) {
394 if(tile == HOSPITAL) {
395 playerInfo.hospitalCount++;
398 repairZone(HOSPITAL, 3);
400 if(playerInfo.needHospital == -1)
402 if(
PRNG.nextInt(21) == 0) {
407 else if(tile == CHURCH) {
408 playerInfo.churchCount++;
411 repairZone(CHURCH, 3);
413 if(playerInfo.needChurch == -1)
415 if(
PRNG.nextInt(21) == 0) {
432 void repairZone(
char zoneCenter,
int zoneSize) {
435 int zoneBase = zoneCenter - 1 - zoneSize;
440 for(
int y = 0; y < zoneSize; y++) {
441 for(
int x = 0; x < zoneSize; x++, zoneBase++) {
442 int xx = xpos - 1 + x;
443 int yy = ypos - 1 + y;
447 if(isZoneCenter(thCh)) {
454 if(!isIndestructible(thCh)) {
468 void doCommercial(PlayerInfo playerInfo) {
469 boolean powerOn = checkZonePower();
471 playerInfo.comZoneCount++;
473 int tpop = commercialZonePop(tile);
474 playerInfo.comPop += tpop;
477 if(tpop >
PRNG.nextInt(6)) {
478 trafficGood = makeTraffic(ZoneType.COMMERCIAL);
484 if(trafficGood == -1) {
485 int value = getCRValue();
486 doCommercialOut(tpop, value);
490 if(
PRNG.nextInt(8) == 0) {
491 int locValve = evalCommercial(trafficGood);
492 int zscore = playerInfo.comValve + locValve;
497 if(trafficGood != 0 && zscore > -350 && zscore - 26380 > (
PRNG.nextInt(0x10000) - 0x8000)) {
498 int value = getCRValue();
499 doCommercialIn(tpop, value);
503 if(zscore < 350 && zscore + 26380 < (
PRNG.nextInt(0x10000) - 0x8000)) {
504 int value = getCRValue();
505 doCommercialOut(tpop, value);
514 void doIndustrial(PlayerInfo playerInfo) {
515 boolean powerOn = checkZonePower();
517 playerInfo.indZoneCount++;
519 int tpop = industrialZonePop(tile);
520 playerInfo.indPop += tpop;
523 if(tpop >
PRNG.nextInt(6)) {
524 trafficGood = makeTraffic(ZoneType.INDUSTRIAL);
530 if(trafficGood == -1) {
531 doIndustrialOut(tpop,
PRNG.nextInt(2));
535 if(
PRNG.nextInt(8) == 0) {
536 int locValve = evalIndustrial(trafficGood);
537 int zscore = playerInfo.indValve + locValve;
542 if(zscore > -350 && zscore - 26380 > (
PRNG.nextInt(0x10000) - 0x8000)) {
543 int value =
PRNG.nextInt(2);
544 doIndustrialIn(tpop, value);
548 if(zscore < 350 && zscore + 26380 < (
PRNG.nextInt(0x10000) - 0x8000)) {
549 int value =
PRNG.nextInt(2);
550 doIndustrialOut(tpop, value);
559 void doResidential(PlayerInfo playerInfo) {
560 boolean powerOn = checkZonePower();
562 playerInfo.resZoneCount++;
566 tpop =
city.doFreePop(xpos, ypos);
569 tpop = residentialZonePop(tile);
572 playerInfo.resPop += tpop;
575 if(tpop >
PRNG.nextInt(36)) {
576 trafficGood = makeTraffic(ZoneType.RESIDENTIAL);
582 if(trafficGood == -1) {
583 int value = getCRValue();
584 doResidentialOut(tpop, value);
588 if(tile == RESCLR ||
PRNG.nextInt(8) == 0) {
589 int locValve = evalResidential(trafficGood);
590 int zscore = playerInfo.resValve + locValve;
595 if(zscore > -350 && zscore - 26380 > (
PRNG.nextInt(0x10000) - 0x8000)) {
596 if(tpop == 0 &&
PRNG.nextInt(4) == 0) {
597 makeHospital(playerInfo);
601 int value = getCRValue();
602 doResidentialIn(tpop, value);
606 if(zscore < 350 && zscore + 26380 < (
PRNG.nextInt(0x10000) - 0x8000)) {
607 int value = getCRValue();
608 doResidentialOut(tpop, value);
619 int evalLot(
int x,
int y) {
622 if(aTile != DIRT && !isResidentialClear(aTile)) {
634 for(
int z = 0; z < 4; z++) {
641 if(isRoadAny(tmp) || isRail(tmp)) {
653 private void buildHouse(
int value) {
654 assert value >= 0 && value <= 3;
657 0, -1, 0, 1, -1, 1, -1, 0, 1
660 0, -1, -1, -1, 0, 0, 1, 1, 1
666 for(
int z = 1; z < 9; z++) {
667 int xx = xpos + ZeX[z];
668 int yy = ypos + ZeY[z];
671 int score = evalLot(xx, yy);
679 if((score == hscore) &&
PRNG.nextInt(8) == 0) {
687 int xx = xpos + ZeX[bestLoc];
688 int yy = ypos + ZeY[bestLoc];
689 int houseNumber = value * 3 +
PRNG.nextInt(3);
690 assert houseNumber >= 0 && houseNumber < 12;
693 city.
setTile(xx, yy, (
char) (HOUSE + houseNumber), Utilities.getPlayerID(rawTile));
697 private void doCommercialIn(
int pop,
int value) {
708 private void doIndustrialIn(
int pop,
int value) {
715 private void doResidentialIn(
int pop,
int value) {
716 assert value >= 0 && value <= 3;
722 this.tile = rawTile & LOMASK;
730 if(
city.getPopulationDensity(xpos, ypos) > 64) {
731 residentialPlop(0, value);
739 residentialPlop(pop / 8 - 1, value);
744 void comPlop(
int density,
int value) {
745 int base = (value * 5 + density) * 9 + CZB;
749 void indPlop(
int density,
int value) {
750 int base = (value * 4 + density) * 9 + IZB;
754 void residentialPlop(
int density,
int value) {
755 int base = (value * 4 + density) * 9 + RZB;
759 private void doCommercialOut(
int pop,
int value) {
761 comPlop(pop - 2, value);
770 private void doIndustrialOut(
int pop,
int value) {
772 indPlop(pop - 2, value);
781 private void doResidentialOut(
int pop,
int value) {
782 assert value >= 0 && value < 4;
784 int tilePlayerID = Utilities.getPlayerID(rawTile);
786 final char[] Brdr = {
787 0, 3, 6, 1, 4, 7, 2, 5, 8
795 residentialPlop((pop - 24) / 8, value);
803 int pwrBit = (rawTile & PWRBIT);
804 city.
setTile(xpos, ypos, (
char) (RESCLR | pwrBit), tilePlayerID);
805 for(
int x = xpos - 1; x <= xpos + 1; x++) {
806 for(
int y = ypos - 1; y <= ypos + 1; y++) {
808 if(!(x == xpos && y == ypos)) {
810 int houseNumber = value * 3 +
PRNG.nextInt(3);
811 city.
setTile(x, y, (
char) (HOUSE + houseNumber), tilePlayerID);
826 for(
int x = xpos - 1; x <= xpos + 1; x++) {
827 for(
int y = ypos - 1; y <= ypos + 1; y++) {
829 int loc =
city.
map[y][x] & LOMASK;
830 if(loc >= LHTHR && loc <= HHTHR) {
831 city.
setTile(x, y, (
char) (Brdr[z] + RESCLR - 4), tilePlayerID);
847 int evalCommercial(
int traf) {
851 return city.comRate[ypos / 8][xpos / 8];
860 int evalIndustrial(
int traf) {
874 int evalResidential(
int traf) {
923 void adjustROG(
int amount) {
933 void drawStadium(
int zoneCenter,
int playerID) {
934 int zoneBase = zoneCenter - 1 - 4;
936 for(
int y = 0; y < 4; y++) {
937 for(
int x = 0; x < 4; x++, zoneBase++) {
938 city.
setTile(xpos - 1 + x, ypos - 1 + y, (
char) (zoneBase | (x == 1 && y == 1 ? (PWRBIT) : 0)), playerID);
947 int makeTraffic(ZoneType zoneType) {
950 traffic.sourceZone = zoneType;
951 return traffic.makeTraffic();