behaviors: move terrain-related behaviors from MapScanner
git-svn-id: https://micropolis.googlecode.com/svn/trunk/micropolis-java@871 d9718cc8-9f43-0410-858b-315f434eb58c
This commit is contained in:
parent
4717c93039
commit
81c05604df
4 changed files with 381 additions and 348 deletions
|
@ -30,12 +30,6 @@ class MapScanner extends TileBehavior
|
|||
|
||||
public static enum B
|
||||
{
|
||||
FIRE,
|
||||
FLOOD,
|
||||
RADIOACTIVE,
|
||||
ROAD,
|
||||
RAIL,
|
||||
EXPLOSION,
|
||||
RESIDENTIAL,
|
||||
HOSPITAL_CHURCH,
|
||||
COMMERCIAL,
|
||||
|
@ -50,31 +44,10 @@ class MapScanner extends TileBehavior
|
|||
SEAPORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the tile identified by xpos and ypos properties.
|
||||
*/
|
||||
@Override
|
||||
public void apply()
|
||||
{
|
||||
switch (behavior) {
|
||||
case FIRE:
|
||||
doFire();
|
||||
return;
|
||||
case FLOOD:
|
||||
doFlood();
|
||||
return;
|
||||
case RADIOACTIVE:
|
||||
doRadioactiveTile();
|
||||
return;
|
||||
case ROAD:
|
||||
doRoad();
|
||||
return;
|
||||
case RAIL:
|
||||
doRail();
|
||||
return;
|
||||
case EXPLOSION:
|
||||
// clear AniRubble
|
||||
city.setTile(xpos, ypos, (char)(RUBBLE + PRNG.nextInt(4) + BULLBIT));
|
||||
return;
|
||||
case RESIDENTIAL:
|
||||
doResidential();
|
||||
return;
|
||||
|
@ -116,320 +89,6 @@ class MapScanner extends TileBehavior
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is a radioactive tile.
|
||||
*/
|
||||
void doRadioactiveTile()
|
||||
{
|
||||
if (PRNG.nextInt(4096) == 0)
|
||||
{
|
||||
// radioactive decay
|
||||
city.setTile(xpos, ypos, DIRT);
|
||||
}
|
||||
}
|
||||
|
||||
static int [] TRAFFIC_DENSITY_TAB = { ROADBASE, LTRFBASE, HTRFBASE };
|
||||
|
||||
/**
|
||||
* Called when the current tile is a road tile.
|
||||
*/
|
||||
void doRoad()
|
||||
{
|
||||
city.roadTotal++;
|
||||
|
||||
if (city.roadEffect < 30)
|
||||
{
|
||||
// deteriorating roads
|
||||
if (PRNG.nextInt(512) == 0)
|
||||
{
|
||||
if (!isConductive(rawTile))
|
||||
{
|
||||
if (city.roadEffect < PRNG.nextInt(32))
|
||||
{
|
||||
if (isOverWater(rawTile))
|
||||
city.setTile(xpos, ypos, RIVER);
|
||||
else
|
||||
city.setTile(xpos, ypos, (char)(RUBBLE + PRNG.nextInt(4) + BULLBIT));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isCombustible(rawTile)) //bridge
|
||||
{
|
||||
city.roadTotal += 4;
|
||||
if (doBridge())
|
||||
return;
|
||||
}
|
||||
|
||||
int tden;
|
||||
if ((rawTile & LOMASK) < LTRFBASE)
|
||||
tden = 0;
|
||||
else if ((rawTile & LOMASK) < HTRFBASE)
|
||||
tden = 1;
|
||||
else {
|
||||
city.roadTotal++;
|
||||
tden = 2;
|
||||
}
|
||||
|
||||
int trafficDensity = city.getTrafficDensity(xpos, ypos);
|
||||
int newLevel = trafficDensity < 64 ? 0 :
|
||||
trafficDensity < 192 ? 1 : 2;
|
||||
|
||||
assert newLevel >= 0 && newLevel < TRAFFIC_DENSITY_TAB.length;
|
||||
|
||||
if (tden != newLevel)
|
||||
{
|
||||
int z = (((rawTile & LOMASK) - ROADBASE) & 15) + TRAFFIC_DENSITY_TAB[newLevel];
|
||||
z += rawTile & ALLBITS;
|
||||
|
||||
city.setTile(xpos, ypos, (char) z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is an active fire.
|
||||
*/
|
||||
void doFire()
|
||||
{
|
||||
city.firePop++;
|
||||
|
||||
// one in four times
|
||||
if (PRNG.nextInt(4) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int [] DX = { 0, 1, 0, -1 };
|
||||
final int [] DY = { -1, 0, 1, 0 };
|
||||
|
||||
for (int dir = 0; dir < 4; dir++)
|
||||
{
|
||||
if (PRNG.nextInt(8) == 0)
|
||||
{
|
||||
int xtem = xpos + DX[dir];
|
||||
int ytem = ypos + DY[dir];
|
||||
if (!city.testBounds(xtem, ytem))
|
||||
continue;
|
||||
|
||||
int c = city.map[ytem][xtem];
|
||||
if (isCombustible(c)) {
|
||||
if (isZoneCenter(c)) {
|
||||
city.killZone(xtem, ytem, c);
|
||||
if ((c & LOMASK) > IZB) { //explode
|
||||
city.makeExplosion(xtem, ytem);
|
||||
}
|
||||
}
|
||||
city.setTile(xtem, ytem, (char)(FIRE + PRNG.nextInt(4)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cov = city.fireRate[ypos/8][xpos/8]; //fire station coverage
|
||||
int rate = cov > 100 ? 1 :
|
||||
cov > 20 ? 2 :
|
||||
cov != 0 ? 3 : 10;
|
||||
|
||||
if (PRNG.nextInt(rate+1) == 0) {
|
||||
city.setTile(xpos, ypos, (char)(RUBBLE + PRNG.nextInt(4) + BULLBIT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is a flooding tile.
|
||||
*/
|
||||
void doFlood()
|
||||
{
|
||||
final int [] DX = { 0, 1, 0, -1 };
|
||||
final int [] DY = { -1, 0, 1, 0 };
|
||||
|
||||
if (city.floodCnt != 0)
|
||||
{
|
||||
for (int z = 0; z < 4; z++)
|
||||
{
|
||||
if (PRNG.nextInt(8) == 0) {
|
||||
int xx = xpos + DX[z];
|
||||
int yy = ypos + DY[z];
|
||||
if (city.testBounds(xx, yy)) {
|
||||
int c = city.getTile(xx, yy);
|
||||
int t = c & LOMASK;
|
||||
if (isCombustible(c) || c == DIRT ||
|
||||
(t >= WOODS5 && t < FLOOD))
|
||||
{
|
||||
if (isZoneCenter(c)) {
|
||||
city.killZone(xx, yy, c);
|
||||
}
|
||||
city.setTile(xx, yy, (char)(FLOOD + PRNG.nextInt(3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (PRNG.nextInt(16) == 0) {
|
||||
city.setTile(xpos, ypos, DIRT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is railroad.
|
||||
*/
|
||||
void doRail()
|
||||
{
|
||||
city.railTotal++;
|
||||
city.generateTrain(xpos, ypos);
|
||||
|
||||
if (city.roadEffect < 30) { // deteriorating rail
|
||||
if (PRNG.nextInt(512) == 0) {
|
||||
if (!isConductive(rawTile)) {
|
||||
if (city.roadEffect < PRNG.nextInt(32)) {
|
||||
if (isOverWater(rawTile)) {
|
||||
city.setTile(xpos,ypos,RIVER);
|
||||
} else {
|
||||
city.setTile(xpos,ypos,(char)(RUBBLE + PRNG.nextInt(4)+BULLBIT));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is a road bridge over water.
|
||||
* Handles the draw bridge. For the draw bridge to appear,
|
||||
* there must be a boat on the water, the boat must be
|
||||
* within a certain distance of the bridge, it must be where
|
||||
* the map generator placed 'channel' tiles (these are tiles
|
||||
* that look just like regular river tiles but have a different
|
||||
* numeric value), and you must be a little lucky.
|
||||
*
|
||||
* @return true if the draw bridge is open; false otherwise
|
||||
*/
|
||||
boolean doBridge()
|
||||
{
|
||||
final int HDx[] = { -2, 2, -2, -1, 0, 1, 2 };
|
||||
final int HDy[] = { -1, -1, 0, 0, 0, 0, 0 };
|
||||
final char HBRTAB[] = {
|
||||
HBRDG1 | BULLBIT, HBRDG3 | BULLBIT,
|
||||
HBRDG0 | BULLBIT, RIVER,
|
||||
BRWH | BULLBIT, RIVER,
|
||||
HBRDG2 | BULLBIT };
|
||||
final char HBRTAB2[] = {
|
||||
RIVER, RIVER,
|
||||
HBRIDGE | BULLBIT, HBRIDGE | BULLBIT,
|
||||
HBRIDGE | BULLBIT, HBRIDGE | BULLBIT,
|
||||
HBRIDGE | BULLBIT };
|
||||
|
||||
final int VDx[] = { 0, 1, 0, 0, 0, 0, 1 };
|
||||
final int VDy[] = { -2, -2, -1, 0, 1, 2, 2 };
|
||||
final char VBRTAB[] = {
|
||||
VBRDG0 | BULLBIT, VBRDG1 | BULLBIT,
|
||||
RIVER, BRWV | BULLBIT,
|
||||
RIVER, VBRDG2 | BULLBIT,
|
||||
VBRDG3 | BULLBIT };
|
||||
final char VBRTAB2[] = {
|
||||
VBRIDGE | BULLBIT, RIVER,
|
||||
VBRIDGE | BULLBIT, VBRIDGE | BULLBIT,
|
||||
VBRIDGE | BULLBIT, VBRIDGE | BULLBIT,
|
||||
RIVER };
|
||||
|
||||
if (tile == BRWV) {
|
||||
// vertical bridge, open
|
||||
if (PRNG.nextInt(4) == 0 && getBoatDis() > 340/16) {
|
||||
//close the bridge
|
||||
applyBridgeChange(VDx, VDy, VBRTAB, VBRTAB2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (tile == BRWH) {
|
||||
// horizontal bridge, open
|
||||
if (PRNG.nextInt(4) == 0 && getBoatDis() > 340/16) {
|
||||
// close the bridge
|
||||
applyBridgeChange(HDx, HDy, HBRTAB, HBRTAB2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getBoatDis() < 300/16 && PRNG.nextInt(8) == 0) {
|
||||
if ((rawTile & 1) != 0) {
|
||||
// vertical bridge
|
||||
if (xpos < city.getWidth()-1) {
|
||||
// look for CHANNEL tile to right of
|
||||
// bridge. the CHANNEL tiles are only
|
||||
// found in the very center of the
|
||||
// river
|
||||
if (city.getTile(xpos+1,ypos) == CHANNEL) {
|
||||
// vertical bridge, open it up
|
||||
applyBridgeChange(VDx, VDy, VBRTAB2, VBRTAB);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// horizontal bridge
|
||||
if (ypos > 0) {
|
||||
// look for CHANNEL tile just above
|
||||
// bridge. the CHANNEL tiles are only
|
||||
// found in the very center of the
|
||||
// river
|
||||
if (city.getTile(xpos, ypos-1) == CHANNEL) {
|
||||
// open it up
|
||||
applyBridgeChange(HDx, HDy, HBRTAB2, HBRTAB);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for doBridge- it toggles the draw-bridge.
|
||||
*/
|
||||
private void applyBridgeChange(int [] Dx, int [] Dy, char [] fromTab, char [] toTab)
|
||||
{
|
||||
//FIXME- a closed bridge with traffic on it is not
|
||||
// correctly handled by this subroutine, because the
|
||||
// the tiles representing traffic on a bridge do not match
|
||||
// the expected tile values of fromTab
|
||||
|
||||
for (int z = 0; z < 7; z++) {
|
||||
int x = xpos + Dx[z];
|
||||
int y = ypos + Dy[z];
|
||||
if (city.testBounds(x,y)) {
|
||||
if ((city.map[y][x] & LOMASK) == (fromTab[z] & LOMASK) ||
|
||||
(city.map[y][x] == CHANNEL)
|
||||
) {
|
||||
city.setTile(x, y, toTab[z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate how far away the boat currently is from the
|
||||
* current tile.
|
||||
*/
|
||||
int getBoatDis()
|
||||
{
|
||||
int dist = 99999;
|
||||
for (Sprite s : city.sprites)
|
||||
{
|
||||
if (s.isVisible() && s.kind == SpriteKind.SHI)
|
||||
{
|
||||
int x = s.x / 16;
|
||||
int y = s.y / 16;
|
||||
int d = Math.abs(xpos-x) + Math.abs(ypos-y);
|
||||
dist = Math.min(d, dist);
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
boolean checkZonePower()
|
||||
{
|
||||
boolean zonePwrFlag = setZonePower();
|
||||
|
|
|
@ -1395,12 +1395,12 @@ public class Micropolis
|
|||
HashMap<String,TileBehavior> bb;
|
||||
bb = new HashMap<String,TileBehavior>();
|
||||
|
||||
bb.put("FIRE", new MapScanner(this, MapScanner.B.FIRE));
|
||||
bb.put("FLOOD", new MapScanner(this, MapScanner.B.FLOOD));
|
||||
bb.put("RADIOACTIVE", new MapScanner(this, MapScanner.B.RADIOACTIVE));
|
||||
bb.put("ROAD", new MapScanner(this, MapScanner.B.ROAD));
|
||||
bb.put("RAIL", new MapScanner(this, MapScanner.B.RAIL));
|
||||
bb.put("EXPLOSION", new MapScanner(this, MapScanner.B.EXPLOSION));
|
||||
bb.put("FIRE", new TerrainBehavior(this, TerrainBehavior.B.FIRE));
|
||||
bb.put("FLOOD", new TerrainBehavior(this, TerrainBehavior.B.FLOOD));
|
||||
bb.put("RADIOACTIVE", new TerrainBehavior(this, TerrainBehavior.B.RADIOACTIVE));
|
||||
bb.put("ROAD", new TerrainBehavior(this, TerrainBehavior.B.ROAD));
|
||||
bb.put("RAIL", new TerrainBehavior(this, TerrainBehavior.B.RAIL));
|
||||
bb.put("EXPLOSION", new TerrainBehavior(this, TerrainBehavior.B.EXPLOSION));
|
||||
bb.put("RESIDENTIAL", new MapScanner(this, MapScanner.B.RESIDENTIAL));
|
||||
bb.put("HOSPITAL_CHURCH", new MapScanner(this, MapScanner.B.HOSPITAL_CHURCH));
|
||||
bb.put("COMMERCIAL", new MapScanner(this, MapScanner.B.COMMERCIAL));
|
||||
|
|
371
src/micropolisj/engine/TerrainBehavior.java
Normal file
371
src/micropolisj/engine/TerrainBehavior.java
Normal file
|
@ -0,0 +1,371 @@
|
|||
// This file is part of MicropolisJ.
|
||||
// Copyright (C) 2013 Jason Long
|
||||
// Portions Copyright (C) 1989-2007 Electronic Arts Inc.
|
||||
//
|
||||
// MicropolisJ is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU GPLv3, with additional terms.
|
||||
// See the README file, included in this distribution, for details.
|
||||
|
||||
package micropolisj.engine;
|
||||
|
||||
import static micropolisj.engine.TileConstants.*;
|
||||
|
||||
class TerrainBehavior extends TileBehavior
|
||||
{
|
||||
final B behavior;
|
||||
|
||||
TerrainBehavior(Micropolis city, B behavior)
|
||||
{
|
||||
super(city);
|
||||
this.behavior = behavior;
|
||||
}
|
||||
|
||||
static enum B
|
||||
{
|
||||
FIRE,
|
||||
FLOOD,
|
||||
RADIOACTIVE,
|
||||
ROAD,
|
||||
RAIL,
|
||||
EXPLOSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply()
|
||||
{
|
||||
switch (behavior) {
|
||||
case FIRE:
|
||||
doFire();
|
||||
return;
|
||||
case FLOOD:
|
||||
doFlood();
|
||||
return;
|
||||
case RADIOACTIVE:
|
||||
doRadioactiveTile();
|
||||
return;
|
||||
case ROAD:
|
||||
doRoad();
|
||||
return;
|
||||
case RAIL:
|
||||
doRail();
|
||||
return;
|
||||
case EXPLOSION:
|
||||
// clear AniRubble
|
||||
city.setTile(xpos, ypos, (char)(RUBBLE + PRNG.nextInt(4) + BULLBIT));
|
||||
return;
|
||||
default:
|
||||
assert false;
|
||||
}
|
||||
}
|
||||
|
||||
void doFire()
|
||||
{
|
||||
city.firePop++;
|
||||
|
||||
// one in four times
|
||||
if (PRNG.nextInt(4) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int [] DX = { 0, 1, 0, -1 };
|
||||
final int [] DY = { -1, 0, 1, 0 };
|
||||
|
||||
for (int dir = 0; dir < 4; dir++)
|
||||
{
|
||||
if (PRNG.nextInt(8) == 0)
|
||||
{
|
||||
int xtem = xpos + DX[dir];
|
||||
int ytem = ypos + DY[dir];
|
||||
if (!city.testBounds(xtem, ytem))
|
||||
continue;
|
||||
|
||||
int c = city.map[ytem][xtem];
|
||||
if (isCombustible(c)) {
|
||||
if (isZoneCenter(c)) {
|
||||
city.killZone(xtem, ytem, c);
|
||||
if ((c & LOMASK) > IZB) { //explode
|
||||
city.makeExplosion(xtem, ytem);
|
||||
}
|
||||
}
|
||||
city.setTile(xtem, ytem, (char)(FIRE + PRNG.nextInt(4)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cov = city.fireRate[ypos/8][xpos/8]; //fire station coverage
|
||||
int rate = cov > 100 ? 1 :
|
||||
cov > 20 ? 2 :
|
||||
cov != 0 ? 3 : 10;
|
||||
|
||||
if (PRNG.nextInt(rate+1) == 0) {
|
||||
city.setTile(xpos, ypos, (char)(RUBBLE + PRNG.nextInt(4) + BULLBIT));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is a flooding tile.
|
||||
*/
|
||||
void doFlood()
|
||||
{
|
||||
final int [] DX = { 0, 1, 0, -1 };
|
||||
final int [] DY = { -1, 0, 1, 0 };
|
||||
|
||||
if (city.floodCnt != 0)
|
||||
{
|
||||
for (int z = 0; z < 4; z++)
|
||||
{
|
||||
if (PRNG.nextInt(8) == 0) {
|
||||
int xx = xpos + DX[z];
|
||||
int yy = ypos + DY[z];
|
||||
if (city.testBounds(xx, yy)) {
|
||||
int c = city.getTile(xx, yy);
|
||||
int t = c & LOMASK;
|
||||
if (isCombustible(c) || c == DIRT ||
|
||||
(t >= WOODS5 && t < FLOOD))
|
||||
{
|
||||
if (isZoneCenter(c)) {
|
||||
city.killZone(xx, yy, c);
|
||||
}
|
||||
city.setTile(xx, yy, (char)(FLOOD + PRNG.nextInt(3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (PRNG.nextInt(16) == 0) {
|
||||
city.setTile(xpos, ypos, DIRT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is a radioactive tile.
|
||||
*/
|
||||
void doRadioactiveTile()
|
||||
{
|
||||
if (PRNG.nextInt(4096) == 0)
|
||||
{
|
||||
// radioactive decay
|
||||
city.setTile(xpos, ypos, DIRT);
|
||||
}
|
||||
}
|
||||
|
||||
static int [] TRAFFIC_DENSITY_TAB = { ROADBASE, LTRFBASE, HTRFBASE };
|
||||
|
||||
/**
|
||||
* Called when the current tile is a road tile.
|
||||
*/
|
||||
void doRoad()
|
||||
{
|
||||
city.roadTotal++;
|
||||
|
||||
if (city.roadEffect < 30)
|
||||
{
|
||||
// deteriorating roads
|
||||
if (PRNG.nextInt(512) == 0)
|
||||
{
|
||||
if (!isConductive(rawTile))
|
||||
{
|
||||
if (city.roadEffect < PRNG.nextInt(32))
|
||||
{
|
||||
if (isOverWater(rawTile))
|
||||
city.setTile(xpos, ypos, RIVER);
|
||||
else
|
||||
city.setTile(xpos, ypos, (char)(RUBBLE + PRNG.nextInt(4) + BULLBIT));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isCombustible(rawTile)) //bridge
|
||||
{
|
||||
city.roadTotal += 4;
|
||||
if (doBridge())
|
||||
return;
|
||||
}
|
||||
|
||||
int tden;
|
||||
if ((rawTile & LOMASK) < LTRFBASE)
|
||||
tden = 0;
|
||||
else if ((rawTile & LOMASK) < HTRFBASE)
|
||||
tden = 1;
|
||||
else {
|
||||
city.roadTotal++;
|
||||
tden = 2;
|
||||
}
|
||||
|
||||
int trafficDensity = city.getTrafficDensity(xpos, ypos);
|
||||
int newLevel = trafficDensity < 64 ? 0 :
|
||||
trafficDensity < 192 ? 1 : 2;
|
||||
|
||||
assert newLevel >= 0 && newLevel < TRAFFIC_DENSITY_TAB.length;
|
||||
|
||||
if (tden != newLevel)
|
||||
{
|
||||
int z = (((rawTile & LOMASK) - ROADBASE) & 15) + TRAFFIC_DENSITY_TAB[newLevel];
|
||||
z += rawTile & ALLBITS;
|
||||
|
||||
city.setTile(xpos, ypos, (char) z);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is railroad.
|
||||
*/
|
||||
void doRail()
|
||||
{
|
||||
city.railTotal++;
|
||||
city.generateTrain(xpos, ypos);
|
||||
|
||||
if (city.roadEffect < 30) { // deteriorating rail
|
||||
if (PRNG.nextInt(512) == 0) {
|
||||
if (!isConductive(rawTile)) {
|
||||
if (city.roadEffect < PRNG.nextInt(32)) {
|
||||
if (isOverWater(rawTile)) {
|
||||
city.setTile(xpos,ypos,RIVER);
|
||||
} else {
|
||||
city.setTile(xpos,ypos,(char)(RUBBLE + PRNG.nextInt(4)+BULLBIT));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current tile is a road bridge over water.
|
||||
* Handles the draw bridge. For the draw bridge to appear,
|
||||
* there must be a boat on the water, the boat must be
|
||||
* within a certain distance of the bridge, it must be where
|
||||
* the map generator placed 'channel' tiles (these are tiles
|
||||
* that look just like regular river tiles but have a different
|
||||
* numeric value), and you must be a little lucky.
|
||||
*
|
||||
* @return true if the draw bridge is open; false otherwise
|
||||
*/
|
||||
boolean doBridge()
|
||||
{
|
||||
final int HDx[] = { -2, 2, -2, -1, 0, 1, 2 };
|
||||
final int HDy[] = { -1, -1, 0, 0, 0, 0, 0 };
|
||||
final char HBRTAB[] = {
|
||||
HBRDG1 | BULLBIT, HBRDG3 | BULLBIT,
|
||||
HBRDG0 | BULLBIT, RIVER,
|
||||
BRWH | BULLBIT, RIVER,
|
||||
HBRDG2 | BULLBIT };
|
||||
final char HBRTAB2[] = {
|
||||
RIVER, RIVER,
|
||||
HBRIDGE | BULLBIT, HBRIDGE | BULLBIT,
|
||||
HBRIDGE | BULLBIT, HBRIDGE | BULLBIT,
|
||||
HBRIDGE | BULLBIT };
|
||||
|
||||
final int VDx[] = { 0, 1, 0, 0, 0, 0, 1 };
|
||||
final int VDy[] = { -2, -2, -1, 0, 1, 2, 2 };
|
||||
final char VBRTAB[] = {
|
||||
VBRDG0 | BULLBIT, VBRDG1 | BULLBIT,
|
||||
RIVER, BRWV | BULLBIT,
|
||||
RIVER, VBRDG2 | BULLBIT,
|
||||
VBRDG3 | BULLBIT };
|
||||
final char VBRTAB2[] = {
|
||||
VBRIDGE | BULLBIT, RIVER,
|
||||
VBRIDGE | BULLBIT, VBRIDGE | BULLBIT,
|
||||
VBRIDGE | BULLBIT, VBRIDGE | BULLBIT,
|
||||
RIVER };
|
||||
|
||||
if (tile == BRWV) {
|
||||
// vertical bridge, open
|
||||
if (PRNG.nextInt(4) == 0 && getBoatDis() > 340/16) {
|
||||
//close the bridge
|
||||
applyBridgeChange(VDx, VDy, VBRTAB, VBRTAB2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (tile == BRWH) {
|
||||
// horizontal bridge, open
|
||||
if (PRNG.nextInt(4) == 0 && getBoatDis() > 340/16) {
|
||||
// close the bridge
|
||||
applyBridgeChange(HDx, HDy, HBRTAB, HBRTAB2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getBoatDis() < 300/16 && PRNG.nextInt(8) == 0) {
|
||||
if ((rawTile & 1) != 0) {
|
||||
// vertical bridge
|
||||
if (xpos < city.getWidth()-1) {
|
||||
// look for CHANNEL tile to right of
|
||||
// bridge. the CHANNEL tiles are only
|
||||
// found in the very center of the
|
||||
// river
|
||||
if (city.getTile(xpos+1,ypos) == CHANNEL) {
|
||||
// vertical bridge, open it up
|
||||
applyBridgeChange(VDx, VDy, VBRTAB2, VBRTAB);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// horizontal bridge
|
||||
if (ypos > 0) {
|
||||
// look for CHANNEL tile just above
|
||||
// bridge. the CHANNEL tiles are only
|
||||
// found in the very center of the
|
||||
// river
|
||||
if (city.getTile(xpos, ypos-1) == CHANNEL) {
|
||||
// open it up
|
||||
applyBridgeChange(HDx, HDy, HBRTAB2, HBRTAB);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for doBridge- it toggles the draw-bridge.
|
||||
*/
|
||||
private void applyBridgeChange(int [] Dx, int [] Dy, char [] fromTab, char [] toTab)
|
||||
{
|
||||
//FIXME- a closed bridge with traffic on it is not
|
||||
// correctly handled by this subroutine, because the
|
||||
// the tiles representing traffic on a bridge do not match
|
||||
// the expected tile values of fromTab
|
||||
|
||||
for (int z = 0; z < 7; z++) {
|
||||
int x = xpos + Dx[z];
|
||||
int y = ypos + Dy[z];
|
||||
if (city.testBounds(x,y)) {
|
||||
if ((city.map[y][x] & LOMASK) == (fromTab[z] & LOMASK) ||
|
||||
(city.map[y][x] == CHANNEL)
|
||||
) {
|
||||
city.setTile(x, y, toTab[z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate how far away the boat currently is from the
|
||||
* current tile.
|
||||
*/
|
||||
int getBoatDis()
|
||||
{
|
||||
int dist = 99999;
|
||||
for (Sprite s : city.sprites)
|
||||
{
|
||||
if (s.isVisible() && s.kind == SpriteKind.SHI)
|
||||
{
|
||||
int x = s.x / 16;
|
||||
int y = s.y / 16;
|
||||
int d = Math.abs(xpos-x) + Math.abs(ypos-y);
|
||||
dist = Math.min(d, dist);
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
}
|
|
@ -35,5 +35,8 @@ public abstract class TileBehavior
|
|||
apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the tile identified by xpos and ypos properties.
|
||||
*/
|
||||
public abstract void apply();
|
||||
}
|
||||
|
|
Reference in a new issue