Methapolis  0.27
 All Classes Namespaces Files Functions Variables Enumerator
MapScanner.java
Go to the documentation of this file.
1 // This file is part of MicropolisJ.
2 // Copyright (C) 2013 Jason Long
3 // Portions Copyright (C) 1989-2007 Electronic Arts Inc.
4 //
5 // MicropolisJ is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU GPLv3, with additional terms.
7 // See the README file, included in this distribution, for details.
8 
9 package micropolisj.engine;
10 
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;
50 
55 class MapScanner extends TileBehavior {
56  final B behavior;
57  TrafficGen traffic;
58 
59  MapScanner(Micropolis city, B behavior) {
60  super(city);
61  this.behavior = behavior;
62  this.traffic = new TrafficGen(city);
63  tile = 5;
64  }
65 
66  public static enum B {
67  RESIDENTIAL, HOSPITAL_CHURCH, COMMERCIAL, INDUSTRIAL, COAL, NUCLEAR, FIRESTATION, POLICESTATION, STADIUM_EMPTY, STADIUM_FULL, AIRPORT, SEAPORT, UNIVERSITY, TEMPEL;
68  }
69 
70  @Override
71  public void apply() {
72  // TODO custom: wait for the playerInfo to be generated
73  PlayerInfo playerInfo = city.getPlayerInfo(Utilities.getPlayerID(rawTile));
74 
75  if(playerInfo == null) {
76  return;
77  }
78 
79  switch(behavior) {
80  case RESIDENTIAL:
81  doResidential(playerInfo);
82  return;
83  case HOSPITAL_CHURCH:
84  doHospitalChurch(playerInfo);
85  return;
86  case COMMERCIAL:
87  doCommercial(playerInfo);
88  return;
89  case INDUSTRIAL:
90  doIndustrial(playerInfo);
91  return;
92  case COAL:
93  doCoalPower(playerInfo);
94  return;
95  case NUCLEAR:
96  doNuclearPower(playerInfo);
97  return;
98  case FIRESTATION:
99  doFireStation(playerInfo);
100  return;
101  case POLICESTATION:
102  doPoliceStation(playerInfo);
103  return;
104  case STADIUM_EMPTY:
105  doStadiumEmpty(playerInfo);
106  return;
107  case STADIUM_FULL:
108  doStadiumFull(playerInfo);
109  return;
110  case AIRPORT:
111  doAirport(playerInfo);
112  return;
113  case SEAPORT:
114  doSeaport(playerInfo);
115  return;
116  case UNIVERSITY:
117  doUniversity(playerInfo);
118  return;
119  case TEMPEL:
120  doTempel(playerInfo);
121  return;
122  default:
123  assert false;
124  }
125  }
126 
127  boolean checkZonePower() {
128  boolean zonePwrFlag = setZonePower();
129 
130 
131  PlayerInfo playerInfo = city.getPlayerInfo(Utilities.getPlayerID(rawTile));
132 
133  if(zonePwrFlag) {
134  playerInfo.poweredZoneCount++;
135  }
136  else {
137  playerInfo.unpoweredZoneCount++;
138  }
139 
140  return zonePwrFlag;
141  }
142 
143  boolean setZonePower() {
144  boolean oldPower = (rawTile & PWRBIT) == PWRBIT;
145  boolean newPower = (tile == NUCLEAR || tile == POWERPLANT || city.hasPower(xpos, ypos));
146 
147  if(newPower && !oldPower) {
148  city.setTile(xpos, ypos, (char) (rawTile | PWRBIT));
149  city.powerZone(xpos, ypos, getZoneSizeFor(tile));
150  }
151  else if(!newPower && oldPower) {
152  city.setTile(xpos, ypos, (char) (rawTile & (~PWRBIT)), Utilities.getPlayerID(rawTile));
153  city.shutdownZone(xpos, ypos, getZoneSizeFor(tile));
154  }
155 
156  return newPower;
157  }
158 
168  boolean zonePlop(int base) {
169  assert isZoneCenter(base);
170 
171  TileSpec.BuildingInfo bi = Tiles.get(base).getBuildingInfo();
172  assert bi != null;
173  if(bi == null)
174  return false;
175 
176  for(int y = ypos - 1; y < ypos - 1 + bi.height; y++) {
177  for(int x = xpos - 1; x < xpos - 1 + bi.width; x++) {
178  if(!city.testBounds(x, y)) {
179  return false;
180  }
181  if(isIndestructible2(city.getTile(x, y))) {
182  // radioactive, on fire, or flooded
183  return false;
184  }
185  }
186  }
187 
188  assert bi.members.length == bi.width * bi.height;
189  int i = 0;
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));
193  i++;
194  }
195  }
196 
197  // refresh rawTile, tile
198  this.rawTile = city.map[ypos][xpos];
199  this.tile = (char) (rawTile & LOMASK);
200 
201  setZonePower();
202  return true;
203  }
204 
205 
206  void doCoalPower(PlayerInfo playerInfo) {
207  checkZonePower();
208 
209  playerInfo.coalCount++;
210 
211  if((city.cityTime % 8) == 0) {
212  repairZone(POWERPLANT, 4);
213  }
214 
215  city.powerPlants.add(new CityLocation(xpos, ypos));
216  }
217 
218  void doNuclearPower(PlayerInfo playerInfo) {
219  checkZonePower();
220 
221  if(!city.noDisasters && PRNG.nextInt(Micropolis.MltdwnTab[city.gameLevel] + 1) == 0) {
222  city.doMeltdown(xpos, ypos);
223  return;
224  }
225 
226  playerInfo.nuclearCount++;
227  if((city.cityTime % 8) == 0) {
228  repairZone(NUCLEAR, 4);
229  }
230 
231  city.powerPlants.add(new CityLocation(xpos, ypos));
232  }
233 
234  void doFireStation(PlayerInfo playerInfo) {
235  playerInfo.fireStationCount++;
236 
237  if((city.cityTime % 8) == 0) {
238  repairZone(FIRESTATION, 3);
239  }
240 
241  int z;
242  if(checkZonePower()) {
243  z = playerInfo.fireEffect; // if powered, get effect
244  }
245  else {
246  z = playerInfo.fireEffect / 2; // from the funding ratio
247  }
248 
249  traffic.mapX = xpos;
250  traffic.mapY = ypos;
251  if(!traffic.findPerimeterRoad()) {
252  z /= 2;
253  }
254 
255  city.fireStMap[ypos / 8][xpos / 8] += z;
256  }
257 
258  void doPoliceStation(PlayerInfo playerInfo) {
259  playerInfo.policeCount++;
260 
261  if((city.cityTime % 8) == 0) {
262  repairZone(POLICESTATION, 3);
263  }
264 
265  int z;
266  if(checkZonePower()) {
267  z = playerInfo.policeEffect;
268  }
269  else {
270  z = playerInfo.policeEffect / 2;
271  }
272 
273  traffic.mapX = xpos;
274  traffic.mapY = ypos;
275  if(!traffic.findPerimeterRoad()) {
276  z /= 2;
277  }
278 
279  city.policeMap[ypos / 8][xpos / 8] += z;
280  }
281 
282  void doUniversity(PlayerInfo playerInfo) {
283  int tilePlayerID = Utilities.getPlayerID(rawTile);
284  city.getPlayerInfo(tilePlayerID).researchCount++;
285 
286  if((city.cityTime % 8) == 0) {
287  repairZone(UNIVERSITY, 3);
288  }
289  if(checkZonePower()) {
290  city.addResearchPoints(tilePlayerID);
291  }
292  }
293 
294  void doStadiumEmpty(PlayerInfo playerInfo) {
295  int tilePlayerID = Utilities.getPlayerID(rawTile);
296 
297  playerInfo.stadiumCount++;
298 
299  if((city.cityTime % 16) == 0) {
300  repairZone(STADIUM, 4);
301  }
302 
303  if(checkZonePower()) {
304  if(((city.cityTime + xpos + ypos) % 32) == 0) {
305  drawStadium(FULLSTADIUM, tilePlayerID);
306  city.setTile(xpos + 1, ypos, (char) (FOOTBALLGAME1), tilePlayerID);
307  city.setTile(xpos + 1, ypos + 1, (char) (FOOTBALLGAME2), tilePlayerID);
308  }
309  }
310  }
311 
312  void doStadiumFull(PlayerInfo playerInfo) {
313  checkZonePower();
314 
315  int tilePlayerID = Utilities.getPlayerID(rawTile);
316  playerInfo.stadiumCount++;
317 
318  if(((city.cityTime + xpos + ypos) % 8) == 0) {
319  drawStadium(STADIUM, tilePlayerID);
320  }
321  }
322 
323  void doAirport(PlayerInfo playerInfo) {
324  playerInfo.airportCount++;
325 
326  if((city.cityTime % 8) == 0) {
327  repairZone(AIRPORT, 6);
328  }
329 
330  if(checkZonePower()) {
331 
332  if(PRNG.nextInt(6) == 0) {
333  city.generatePlane(xpos, ypos);
334  }
335 
336  if(PRNG.nextInt(13) == 0) {
337  city.generateCopter(xpos, ypos);
338  }
339  }
340  }
341 
342  //Tempel Methode
343  void doTempel(PlayerInfo playerInfo) {
344  checkZonePower();
345 
346  playerInfo.tempelCount++;
347  if(playerInfo.countdown == 0){
348  city.notifyEnd();
349  playerInfo.countdown = -1;
350  }else if(playerInfo.countdown > 0){
351  city.notifyCountdown(playerInfo.countdown);
352  playerInfo.countdown--;
353  }
354  if((city.cityTime % 8) == 0) {
355  repairZone(TEMPEL, 6);
356  }
357  }
358 
359  void doSeaport(PlayerInfo playerInfo) {
360  playerInfo.seaportCount++;
361 
362  if((city.cityTime % 16) == 0) {
363  repairZone(PORT, 4);
364  }
365 
366  if(checkZonePower() && !city.hasSprite(SpriteKind.SHI)) {
367  city.generateShip();
368  }
369  }
370 
374  void makeHospital(PlayerInfo playerInfo) {
375  if(playerInfo.needHospital > 0) {
376  zonePlop(HOSPITAL);
377  playerInfo.needHospital = 0;
378  }
379 
380  // FIXME- should be 'else if'
381  if(playerInfo.needChurch > 0) {
382  zonePlop(CHURCH);
383  playerInfo.needChurch = 0;
384  }
385  }
386 
391  void doHospitalChurch(PlayerInfo playerInfo) {
392  checkZonePower();
393 
394  if(tile == HOSPITAL) {
395  playerInfo.hospitalCount++;
396 
397  if(city.cityTime % 16 == 0) {
398  repairZone(HOSPITAL, 3);
399  }
400  if(playerInfo.needHospital == -1) // too many hospitals
401  {
402  if(PRNG.nextInt(21) == 0) {
403  zonePlop(RESCLR);
404  }
405  }
406  }
407  else if(tile == CHURCH) {
408  playerInfo.churchCount++;
409 
410  if(city.cityTime % 16 == 0) {
411  repairZone(CHURCH, 3);
412  }
413  if(playerInfo.needChurch == -1) // too many churches
414  {
415  if(PRNG.nextInt(21) == 0) {
416  zonePlop(RESCLR);
417  }
418  }
419  }
420  }
421 
432  void repairZone(char zoneCenter, int zoneSize) {
433  // from the given center tile, figure out what the
434  // northwest tile should be
435  int zoneBase = zoneCenter - 1 - zoneSize;
436 // System.out.println("repairing");
437 // System.out.println((int)zoneCenter);
438 // int tilePlayerId = Utilities.getPlayerID(zoneBase);
439 
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;
444 
445  if(city.testBounds(xx, yy)) {
446  int thCh = city.getTile(xx, yy);
447  if(isZoneCenter(thCh)) {
448  continue;
449  }
450 
451  if(isAnimated(thCh))
452  continue;
453 
454  if(!isIndestructible(thCh)) { // not rubble, radiactive, on
455  // fire or flooded
456 // System.out.println(zoneBase);
457  city.setTile(xx, yy, (char) zoneBase);
458  }
459  }
460  }
461  }
462  }
463 
468  void doCommercial(PlayerInfo playerInfo) {
469  boolean powerOn = checkZonePower();
470 
471  playerInfo.comZoneCount++;
472 
473  int tpop = commercialZonePop(tile);
474  playerInfo.comPop += tpop;
475 
476  int trafficGood;
477  if(tpop > PRNG.nextInt(6)) {
478  trafficGood = makeTraffic(ZoneType.COMMERCIAL);
479  }
480  else {
481  trafficGood = 1;
482  }
483 
484  if(trafficGood == -1) {
485  int value = getCRValue();
486  doCommercialOut(tpop, value);
487  return;
488  }
489 
490  if(PRNG.nextInt(8) == 0) {
491  int locValve = evalCommercial(trafficGood);
492  int zscore = playerInfo.comValve + locValve;
493 
494  if(!powerOn)
495  zscore = -500;
496 
497  if(trafficGood != 0 && zscore > -350 && zscore - 26380 > (PRNG.nextInt(0x10000) - 0x8000)) {
498  int value = getCRValue();
499  doCommercialIn(tpop, value);
500  return;
501  }
502 
503  if(zscore < 350 && zscore + 26380 < (PRNG.nextInt(0x10000) - 0x8000)) {
504  int value = getCRValue();
505  doCommercialOut(tpop, value);
506  }
507  }
508  }
509 
514  void doIndustrial(PlayerInfo playerInfo) {
515  boolean powerOn = checkZonePower();
516 
517  playerInfo.indZoneCount++;
518 
519  int tpop = industrialZonePop(tile);
520  playerInfo.indPop += tpop;
521 
522  int trafficGood;
523  if(tpop > PRNG.nextInt(6)) {
524  trafficGood = makeTraffic(ZoneType.INDUSTRIAL);
525  }
526  else {
527  trafficGood = 1;
528  }
529 
530  if(trafficGood == -1) {
531  doIndustrialOut(tpop, PRNG.nextInt(2));
532  return;
533  }
534 
535  if(PRNG.nextInt(8) == 0) {
536  int locValve = evalIndustrial(trafficGood);
537  int zscore = playerInfo.indValve + locValve;
538 
539  if(!powerOn)
540  zscore = -500;
541 
542  if(zscore > -350 && zscore - 26380 > (PRNG.nextInt(0x10000) - 0x8000)) {
543  int value = PRNG.nextInt(2);
544  doIndustrialIn(tpop, value);
545  return;
546  }
547 
548  if(zscore < 350 && zscore + 26380 < (PRNG.nextInt(0x10000) - 0x8000)) {
549  int value = PRNG.nextInt(2);
550  doIndustrialOut(tpop, value);
551  }
552  }
553  }
554 
559  void doResidential(PlayerInfo playerInfo) {
560  boolean powerOn = checkZonePower();
561 
562  playerInfo.resZoneCount++;
563 
564  int tpop; // population of this zone
565  if(tile == RESCLR) {
566  tpop = city.doFreePop(xpos, ypos);
567  }
568  else {
569  tpop = residentialZonePop(tile);
570  }
571 
572  playerInfo.resPop += tpop;
573 
574  int trafficGood;
575  if(tpop > PRNG.nextInt(36)) {
576  trafficGood = makeTraffic(ZoneType.RESIDENTIAL);
577  }
578  else {
579  trafficGood = 1;
580  }
581 
582  if(trafficGood == -1) {
583  int value = getCRValue();
584  doResidentialOut(tpop, value);
585  return;
586  }
587 
588  if(tile == RESCLR || PRNG.nextInt(8) == 0) {
589  int locValve = evalResidential(trafficGood);
590  int zscore = playerInfo.resValve + locValve;
591 
592  if(!powerOn)
593  zscore = -500;
594 
595  if(zscore > -350 && zscore - 26380 > (PRNG.nextInt(0x10000) - 0x8000)) {
596  if(tpop == 0 && PRNG.nextInt(4) == 0) {
597  makeHospital(playerInfo);
598  return;
599  }
600 
601  int value = getCRValue();
602  doResidentialIn(tpop, value);
603  return;
604  }
605 
606  if(zscore < 350 && zscore + 26380 < (PRNG.nextInt(0x10000) - 0x8000)) {
607  int value = getCRValue();
608  doResidentialOut(tpop, value);
609  }
610  }
611  }
612 
619  int evalLot(int x, int y) {
620  // test for clear lot
621  int aTile = city.getTile(x, y);
622  if(aTile != DIRT && !isResidentialClear(aTile)) {
623  return -1;
624  }
625 
626  int score = 1;
627 
628  final int[] DX = {
629  0, 1, 0, -1
630  };
631  final int[] DY = {
632  -1, 0, 1, 0
633  };
634  for(int z = 0; z < 4; z++) {
635  int xx = x + DX[z];
636  int yy = y + DY[z];
637 
638  // look for road
639  if(city.testBounds(xx, yy)) {
640  int tmp = city.getTile(xx, yy);
641  if(isRoadAny(tmp) || isRail(tmp)) {
642  score++;
643  }
644  }
645  }
646 
647  return score;
648  }
649 
653  private void buildHouse(int value) {
654  assert value >= 0 && value <= 3;
655 
656  final int[] ZeX = {
657  0, -1, 0, 1, -1, 1, -1, 0, 1
658  };
659  final int[] ZeY = {
660  0, -1, -1, -1, 0, 0, 1, 1, 1
661  };
662 
663  int bestLoc = 0;
664  int hscore = 0;
665 
666  for(int z = 1; z < 9; z++) {
667  int xx = xpos + ZeX[z];
668  int yy = ypos + ZeY[z];
669 
670  if(city.testBounds(xx, yy)) {
671  int score = evalLot(xx, yy);
672 
673  if(score != 0) {
674  if(score > hscore) {
675  hscore = score;
676  bestLoc = z;
677  }
678 
679  if((score == hscore) && PRNG.nextInt(8) == 0) {
680  bestLoc = z;
681  }
682  }
683  }
684  }
685 
686  if(bestLoc != 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;
691 
692  assert city.testBounds(xx, yy);
693  city.setTile(xx, yy, (char) (HOUSE + houseNumber), Utilities.getPlayerID(rawTile));
694  }
695  }
696 
697  private void doCommercialIn(int pop, int value) {
698  int z = city.getLandValue(xpos, ypos) / 32;
699  if(pop > z)
700  return;
701 
702  if(pop < 5) {
703  comPlop(pop, value);
704  adjustROG(8);
705  }
706  }
707 
708  private void doIndustrialIn(int pop, int value) {
709  if(pop < 4) {
710  indPlop(pop, value);
711  adjustROG(8);
712  }
713  }
714 
715  private void doResidentialIn(int pop, int value) {
716  assert value >= 0 && value <= 3;
717 
718  int z = city.pollutionMem[ypos / 2][xpos / 2];
719  if(z > 128)
720  return;
721 
722  this.tile = rawTile & LOMASK;
723  if(tile == RESCLR) {
724  if(pop < 8) {
725  buildHouse(value);
726  adjustROG(1);
727  return;
728  }
729 
730  if(city.getPopulationDensity(xpos, ypos) > 64) {
731  residentialPlop(0, value);
732  adjustROG(8);
733  return;
734  }
735  return;
736  }
737 
738  if(pop < 40) {
739  residentialPlop(pop / 8 - 1, value);
740  adjustROG(8);
741  }
742  }
743 
744  void comPlop(int density, int value) {
745  int base = (value * 5 + density) * 9 + CZB;
746  zonePlop(base);
747  }
748 
749  void indPlop(int density, int value) {
750  int base = (value * 4 + density) * 9 + IZB;
751  zonePlop(base);
752  }
753 
754  void residentialPlop(int density, int value) {
755  int base = (value * 4 + density) * 9 + RZB;
756  zonePlop(base);
757  }
758 
759  private void doCommercialOut(int pop, int value) {
760  if(pop > 1) {
761  comPlop(pop - 2, value);
762  adjustROG(-8);
763  }
764  else if(pop == 1) {
765  zonePlop(COMCLR);
766  adjustROG(-8);
767  }
768  }
769 
770  private void doIndustrialOut(int pop, int value) {
771  if(pop > 1) {
772  indPlop(pop - 2, value);
773  adjustROG(-8);
774  }
775  else if(pop == 1) {
776  zonePlop(INDCLR);
777  adjustROG(-8);
778  }
779  }
780 
781  private void doResidentialOut(int pop, int value) {
782  assert value >= 0 && value < 4;
783 
784  int tilePlayerID = Utilities.getPlayerID(rawTile);
785 
786  final char[] Brdr = {
787  0, 3, 6, 1, 4, 7, 2, 5, 8
788  };
789 
790  if(pop == 0)
791  return;
792 
793  if(pop > 16) {
794  // downgrade to a lower-density full-size residential zone
795  residentialPlop((pop - 24) / 8, value);
796  adjustROG(-8);
797  return;
798  }
799 
800  if(pop == 16) {
801  // downgrade from full-size zone to 8 little houses
802 
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++) {
807  if(city.testBounds(x, y)) {
808  if(!(x == xpos && y == ypos)) {
809  // pick a random small house
810  int houseNumber = value * 3 + PRNG.nextInt(3);
811  city.setTile(x, y, (char) (HOUSE + houseNumber), tilePlayerID);
812  }
813  }
814  }
815  }
816 
817  adjustROG(-8);
818  return;
819  }
820 
821  if(pop < 16) {
822  // remove one little house
823  adjustROG(-1);
824  int z = 0;
825 
826  for(int x = xpos - 1; x <= xpos + 1; x++) {
827  for(int y = ypos - 1; y <= ypos + 1; y++) {
828  if(city.testBounds(x, y)) {
829  int loc = city.map[y][x] & LOMASK;
830  if(loc >= LHTHR && loc <= HHTHR) { // little house
831  city.setTile(x, y, (char) (Brdr[z] + RESCLR - 4), tilePlayerID);
832  return;
833  }
834  }
835  z++;
836  }
837  }
838  }
839  }
840 
847  int evalCommercial(int traf) {
848  if(traf < 0)
849  return -3000;
850 
851  return city.comRate[ypos / 8][xpos / 8];
852  }
853 
860  int evalIndustrial(int traf) {
861  if(traf < 0)
862  return -1000;
863  else
864  return 0;
865  }
866 
874  int evalResidential(int traf) {
875  if(traf < 0)
876  return -3000;
877 
878  int value = city.getLandValue(xpos, ypos);
879  value -= city.pollutionMem[ypos / 2][xpos / 2];
880 
881  if(value < 0)
882  value = 0; // cap at 0
883  else
884  value *= 32;
885 
886  if(value > 6000)
887  value = 6000; // cap at 6000
888 
889  return value - 3000;
890  }
891 
899  int getCRValue() {
900  int lval = city.getLandValue(xpos, ypos);
901  lval -= city.pollutionMem[ypos / 2][xpos / 2];
902 
903  if(lval < 30)
904  return 0;
905 
906  if(lval < 80)
907  return 1;
908 
909  if(lval < 150)
910  return 2;
911 
912  return 3;
913  }
914 
923  void adjustROG(int amount) {
924  city.rateOGMem[ypos / 8][xpos / 8] += 4 * amount;
925  }
926 
933  void drawStadium(int zoneCenter, int playerID) {
934  int zoneBase = zoneCenter - 1 - 4;
935 
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);
939  }
940  }
941  }
942 
947  int makeTraffic(ZoneType zoneType) {
948  traffic.mapX = xpos;
949  traffic.mapY = ypos;
950  traffic.sourceZone = zoneType;
951  return traffic.makeTraffic();
952  }
953 }