diff --git a/SPD-classes/src/main/java/com/watabou/utils/Rect.java b/SPD-classes/src/main/java/com/watabou/utils/Rect.java index 808d7631b..7a6b9aace 100644 --- a/SPD-classes/src/main/java/com/watabou/utils/Rect.java +++ b/SPD-classes/src/main/java/com/watabou/utils/Rect.java @@ -99,6 +99,15 @@ public class Rect { return result; } + public Rect union( Rect other ){ + Rect result = new Rect(); + result.left = Math.min( left, other.left ); + result.right = Math.max( right, other.right ); + result.top = Math.min( top, other.top ); + result.bottom = Math.max( bottom, other.bottom ); + return result; + } + public Rect union( int x, int y ) { if (isEmpty()) { return set( x, y, x + 1, y + 1 ); diff --git a/core/src/main/assets/wall_blocking.png b/core/src/main/assets/wall_blocking.png index 3f9253583..be1a4f012 100644 Binary files a/core/src/main/assets/wall_blocking.png and b/core/src/main/assets/wall_blocking.png differ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java index 7d671a9bf..5aca2a517 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java @@ -29,12 +29,14 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MindVision; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Wandmaker; import com.shatteredpixel.shatteredpixeldungeon.items.Ankh; import com.shatteredpixel.shatteredpixeldungeon.items.Generator; +import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose; import com.shatteredpixel.shatteredpixeldungeon.items.potions.Potion; @@ -744,30 +746,45 @@ public class Dungeon { level.updateFieldOfView(hero, level.heroFOV); - if (hero.buff(MindVision.class) != null || hero.buff(Awareness.class) != null) { - BArray.or( level.visited, level.heroFOV, 0, level.heroFOV.length, level.visited ); - - GameScene.updateFog(); - } else { - - int cx = hero.pos % level.width(); - int cy = hero.pos / level.width(); - - int ax = Math.max( 0, cx - dist ); - int bx = Math.min( cx + dist, level.width() - 1 ); - int ay = Math.max( 0, cy - dist ); - int by = Math.min( cy + dist, level.height() - 1 ); - - int len = bx - ax + 1; - int pos = ax + ay * level.width(); - - for (int y = ay; y <= by; y++, pos+=level.width()) { - BArray.or( level.visited, level.heroFOV, pos, len, level.visited ); - } - - GameScene.updateFog(ax, ay, len, by-ay); + int x = hero.pos % level.width(); + int y = hero.pos / level.width(); + + //left, right, top, bottom + int l = Math.max( 0, x - dist ); + int r = Math.min( x + dist, level.width() - 1 ); + int t = Math.max( 0, y - dist ); + int b = Math.min( y + dist, level.height() - 1 ); + + int length = r - l + 1; + int width = t - b + 1; + + int pos = l + t * level.width(); + + for (int i = t; i <= b; i++) { + BArray.or( level.visited, level.heroFOV, pos, length, level.visited ); + pos+=level.width(); + } + + GameScene.updateFog(l, t, length, width); + + if (hero.buff(MindVision.class) != null){ + for (Mob m : level.mobs.toArray(new Mob[0])){ + BArray.or( level.visited, level.heroFOV, m.pos - 1 - level.width(), 3, level.visited ); + BArray.or( level.visited, level.heroFOV, m.pos, 3, level.visited ); + BArray.or( level.visited, level.heroFOV, m.pos - 1 + level.width(), 3, level.visited ); + //updates adjacent cells too + GameScene.updateFog(m.pos, 2); + } + } + + if (hero.buff(Awareness.class) != null){ + for (Heap h : level.heaps.values()){ + BArray.or( level.visited, level.heroFOV, h.pos - 1 - level.width(), 3, level.visited ); + BArray.or( level.visited, level.heroFOV, h.pos - 1, 3, level.visited ); + BArray.or( level.visited, level.heroFOV, h.pos - 1 + level.width(), 3, level.visited ); + GameScene.updateFog(h.pos, 2); + } } - GameScene.afterObserve(); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index 0d581d86c..bbf547ef0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -105,7 +105,6 @@ import com.watabou.noosa.audio.Music; import com.watabou.noosa.audio.Sample; import com.watabou.noosa.particles.Emitter; import com.watabou.utils.GameMath; -import com.watabou.utils.PathFinder; import com.watabou.utils.Random; import java.io.IOException; @@ -777,7 +776,8 @@ public class GameScene extends PixelScene { scene.visualGrid.updateMapCell( cell ); scene.terrainFeatures.updateMapCell( cell ); scene.walls.updateMapCell( cell ); - updateFog( cell ); + //update adjacent cells too + updateFog( cell, 1 ); } } @@ -813,21 +813,11 @@ public class GameScene extends PixelScene { scene.wallBlocking.updateArea(x, y, w, h); } } - - public static void updateFog( int cell ){ + + public static void updateFog( int cell, int radius ){ if (scene != null) { - //update in a 3x3 grid to account for neighbours which might also be affected - if (Dungeon.level.insideMap(cell)) { - for (int i : PathFinder.NEIGHBOURS9) { - scene.fog.updateFogCell( cell + i ); - scene.wallBlocking.updateMapCell( cell + i ); - } - - //unless we're at the level's edge, then just do the one tile. - } else { - scene.fog.updateFogCell( cell ); - scene.wallBlocking.updateMapCell( cell ); - } + scene.fog.updateFog( cell, radius ); + scene.wallBlocking.updateArea( cell, radius ); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/FogOfWar.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/FogOfWar.java index beec35886..63112318b 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/FogOfWar.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/FogOfWar.java @@ -36,6 +36,7 @@ import com.watabou.utils.Rect; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; +import java.util.ArrayList; public class FogOfWar extends Image { @@ -77,11 +78,19 @@ public class FogOfWar extends Image { private int width2; private int height2; - private volatile Rect updated; - private Rect updating; + private volatile ArrayList toUpdate; + private volatile ArrayList updating; + //should be divisible by 2 private static final int PIX_PER_TILE = 2; + /* + TODO currently the center of each fox pixel is aligned with the inside of a cell + might be possible to create a better fog effect by aligning them with edges of a cell, + similar to the existing fog effect in vanilla (although probably with more precision) + the advantage here is that it may be possible to totally eliminate the tile blocking map + */ + public FogOfWar( int mapWidth, int mapHeight ) { super(); @@ -113,26 +122,47 @@ public class FogOfWar extends Image { DungeonTilemap.SIZE / PIX_PER_TILE, DungeonTilemap.SIZE / PIX_PER_TILE); - updated = new Rect(0, 0, mapWidth, mapHeight); + toUpdate = new ArrayList<>(); + toUpdate.add(new Rect(0, 0, mapWidth, mapHeight)); } public synchronized void updateFog(){ - updated.set( 0, 0, mapWidth, mapHeight ); + toUpdate.clear(); + toUpdate.add(new Rect(0, 0, mapWidth, mapHeight)); + } + + public synchronized void updateFog(Rect update){ + for (Rect r : toUpdate.toArray(new Rect[0])){ + if (!r.intersect(update).isEmpty()){ + toUpdate.remove(r); + toUpdate.add(r.union(update)); + return; + } + } + toUpdate.add(update); } - public synchronized void updateFogCell( int cell ){ - updateFogArea( cell % mapWidth , cell / mapWidth, 1, 1 ); + public synchronized void updateFog( int cell, int radius ){ + Rect update = new Rect( + (cell % mapWidth) - radius, + (cell / mapWidth) - radius, + (cell % mapWidth) - radius + 1 + 2*radius, + (cell / mapWidth) - radius + 1 + 2*radius); + update.left = Math.max(0, update.left); + update.top = Math.max(0, update.top); + update.right = Math.min(mapWidth, update.right); + update.bottom = Math.min(mapHeight, update.bottom); + if (update.isEmpty()) return; + updateFog( update ); } public synchronized void updateFogArea(int x, int y, int w, int h){ - updated.union(x, y); - updated.union(x + w, y + h); - updated = updated.intersect( new Rect(0, 0, mapWidth, mapHeight) ); + updateFog(new Rect(x, y, x + w, y + h)); } - public synchronized void moveToUpdating(){ - updating = new Rect(updated); - updated.setEmpty(); + private synchronized void moveToUpdating(){ + updating = toUpdate; + toUpdate = new ArrayList<>(); } private boolean[] visible; @@ -147,101 +177,116 @@ public class FogOfWar extends Image { this.brightness = ShatteredPixelDungeon.brightness() + 2; moveToUpdating(); - - boolean fullUpdate = updating.height() == mapHeight && updating.width() == mapWidth; + + boolean fullUpdate = false; + if (updating.size() == 1){ + Rect update = updating.get(0); + if (update.height() == mapHeight && update.width() == mapWidth){ + fullUpdate = true; + } + } FogTexture fog = (FogTexture)texture; int cell; - int[] colorArray = new int[PIX_PER_TILE*PIX_PER_TILE]; - for (int i=updating.top; i < updating.bottom; i++) { - cell = mapWidth * i + updating.left; - for (int j=updating.left; j < updating.right; j++) { - - if (cell >= Dungeon.level.length()) continue; //do nothing - - if (!Dungeon.level.discoverable[cell] - || (!visible[cell] && !visited[cell] && !mapped[cell])){ - //we skip filling cells here if it isn't a full update - // because they must already be dark - if (fullUpdate) - fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]); - cell++; - continue; - } - - //wall tiles - if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell])){ - - //internal wall tiles - if (cell + mapWidth >= mapLength){ - fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]); - - } else if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + mapWidth])){ - - //these tiles need to check both the left and right side, to account for only one half of them being seen - if (cell % mapWidth != 0){ - - //picks the darkest fog between current tile, left, and below-left(if left is a wall). - if (cell + mapWidth < mapLength && DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell - 1])){ - - //if below-left is also a wall, then we should be dark no matter what. - if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + mapWidth - 1])){ - colorArray[0] = colorArray[2] = FOG_COLORS[INVISIBLE][brightness]; - } else { - colorArray[0] = colorArray[2] = FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth - 1), getCellFog(cell - 1)))][brightness]; - } - - } else { - colorArray[0] = colorArray[2] = FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell - 1))][brightness]; - } - - } else { - colorArray[0] = colorArray [2] = FOG_COLORS[INVISIBLE][brightness]; - } - - if ((cell+1) % mapWidth != 0){ - - //picks the darkest fog between current tile, right, and below-right(if right is a wall). - if (cell + mapWidth < mapLength && DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + 1])){ - - //if below-right is also a wall, then we should be dark no matter what. - if (DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell + mapWidth + 1])){ - colorArray[1] = colorArray[3] = FOG_COLORS[INVISIBLE][brightness]; - } else { - colorArray[1] = colorArray[3] = FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth + 1), getCellFog(cell + 1)))][brightness]; - } - - } else { - colorArray[1] = colorArray[3] = - FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + 1))][brightness]; - } - - } else { - colorArray[1] = colorArray [3] = FOG_COLORS[INVISIBLE][brightness]; - } - - fillCell(j, i, colorArray); - - //camera-facing wall tiles - } else { - fillCell(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + mapWidth))][brightness]); + + for (Rect update : updating) { + for (int i = update.top; i <= update.bottom; i++) { + cell = mapWidth * i + update.left; + for (int j = update.left; j <= update.right; j++) { + + if (cell >= Dungeon.level.length()) continue; //do nothing + + if (!Dungeon.level.discoverable[cell] + || (!visible[cell] && !visited[cell] && !mapped[cell])) { + //we skip filling cells here if it isn't a full update + // because they must already be dark + if (fullUpdate) + fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]); + cell++; + continue; } - - //other tiles - } else { - fillCell(j, i, FOG_COLORS[getCellFog(cell)][brightness]); + + //wall tiles + if (wall(cell)) { + + //always dark if nothing is beneath them + if (cell + mapWidth >= mapLength) { + fillCell(j, i, FOG_COLORS[INVISIBLE][brightness]); + + //internal wall tiles, need to check both the left and right side, + // to account for only one half of them being seen + } else if (wall(cell + mapWidth)) { + + //left side + if (cell % mapWidth != 0) { + + //picks the darkest fog between current tile, left, and below-left(if left is a wall). + if (wall(cell - 1)) { + + //if below-left is also a wall, then we should be dark no matter what. + if (wall(cell + mapWidth - 1)) { + fillLeft(j, i, FOG_COLORS[INVISIBLE][brightness]); + } else { + fillLeft(j, i, FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth - 1), getCellFog(cell - 1)))][brightness]); + } + + } else { + fillLeft(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell - 1))][brightness]); + } + + } else { + fillLeft(j, i, FOG_COLORS[INVISIBLE][brightness]); + } + + //right side + if ((cell + 1) % mapWidth != 0) { + + //picks the darkest fog between current tile, right, and below-right(if right is a wall). + if (wall(cell + 1)) { + + //if below-right is also a wall, then we should be dark no matter what. + if (wall(cell + mapWidth + 1)) { + fillRight(j, i, FOG_COLORS[INVISIBLE][brightness]); + } else { + fillRight(j, i, FOG_COLORS[Math.max(getCellFog(cell), Math.max(getCellFog(cell + mapWidth + 1), getCellFog(cell + 1)))][brightness]); + } + + } else { + fillRight(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + 1))][brightness]); + } + + } else { + fillRight(j, i, FOG_COLORS[INVISIBLE][brightness]); + } + + //camera-facing wall tiles + //darkest between themselves and the tile below them + } else { + fillCell(j, i, FOG_COLORS[Math.max(getCellFog(cell), getCellFog(cell + mapWidth))][brightness]); + } + + //other tiles, just their direct value + } else { + fillCell(j, i, FOG_COLORS[getCellFog(cell)][brightness]); + } + + cell++; } - - cell++; } + + } + + if (updating.size() == 1 && !fullUpdate){ + fog.update(updating.get(0).top * PIX_PER_TILE, updating.get(0).bottom * PIX_PER_TILE); + } else { + fog.update(); } - if (updating.width() == mapWidth && updating.height() == mapHeight) - fog.update(); - else - fog.update(updating.top * PIX_PER_TILE, updating.bottom * PIX_PER_TILE); - + } + + private boolean wall(int cell) { + return DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell]); } private int getCellFog( int cell ){ @@ -256,13 +301,23 @@ public class FogOfWar extends Image { return INVISIBLE; } } - - private void fillCell( int x, int y, int[] colors){ + + private void fillLeft( int x, int y, int color){ FogTexture fog = (FogTexture)texture; for (int i = 0; i < PIX_PER_TILE; i++){ fog.pixels.position(((y * PIX_PER_TILE)+i)*width2 + x * PIX_PER_TILE); - for (int j = 0; j < PIX_PER_TILE; j++) { - fog.pixels.put(colors[i*PIX_PER_TILE + j]); + for (int j = 0; j < PIX_PER_TILE/2; j++) { + fog.pixels.put(color); + } + } + } + + private void fillRight( int x, int y, int color){ + FogTexture fog = (FogTexture)texture; + for (int i = 0; i < PIX_PER_TILE; i++){ + fog.pixels.position(((y * PIX_PER_TILE)+i)*width2 + x * PIX_PER_TILE + PIX_PER_TILE/2); + for (int j = PIX_PER_TILE/2; j < PIX_PER_TILE; j++) { + fog.pixels.put(color); } } } @@ -356,9 +411,8 @@ public class FogOfWar extends Image { @Override public void draw() { - if (!updated.isEmpty()){ + if (!toUpdate.isEmpty()){ updateTexture(Dungeon.level.heroFOV, Dungeon.level.visited, Dungeon.level.mapped); - updating.setEmpty(); } super.draw(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java index ac2e0749d..bf27cef03 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/tiles/WallBlockingTilemap.java @@ -30,11 +30,12 @@ public class WallBlockingTilemap extends Tilemap { public static final int SIZE = 16; - private static final int CLEARED = -1; - private static final int BLOCK_NONE = 0; - private static final int BLOCK_RIGHT = 1; - private static final int BLOCK_LEFT = 2; - private static final int BLOCK_ALL = 3; + private static final int CLEARED = -2; + private static final int BLOCK_NONE = -1; + private static final int BLOCK_RIGHT = 0; + private static final int BLOCK_LEFT = 1; + private static final int BLOCK_ALL = 2; + private static final int BLOCK_BELOW = 3; public WallBlockingTilemap() { super("wall_blocking.png", new TextureFilm( "wall_blocking.png", SIZE, SIZE ) ); @@ -45,109 +46,158 @@ public class WallBlockingTilemap extends Tilemap { public synchronized void updateMap() { super.updateMap(); data = new int[size]; //clears all values, including cleared tiles - for (int i = 0; i < data.length; i++) - updateMapCell(i); + + for (int cell = 0; cell < data.length; cell++) { + //force all none-discoverable and border cells to cleared + if (!Dungeon.level.discoverable[cell] || + !Dungeon.level.insideMap(cell)){ + data[cell] = CLEARED; + } else { + updateMapCell(cell); + } + } } + private int curr; + @Override public synchronized void updateMapCell(int cell) { - int prev = data[cell]; - int curr; + + //TODO should doors be considered? currently the blocking is a bit permissive around doors - if (prev == CLEARED){ - return; + //non-wall tiles + if (!wall(cell)) { - } else if (!Dungeon.level.discoverable[cell]) { - curr = CLEARED; - - //handles blocking wall overhang (which is technically on a none wall tile) - } else if (!wall(cell)) { - - if (!fogHidden(cell)) { + //clear empty floor tiles and cells which are visible + if (!fogHidden(cell) || !wall(cell + mapWidth)) { curr = CLEARED; - } else if ( wall(cell + mapWidth) && !fogHidden(cell + mapWidth) - && fogHidden(cell - 1) && fogHidden(cell + 1)) { - curr = BLOCK_ALL; + //block wall overhang if: + //- The cell below is a wall and visible + //- All of left, below-left, right, below-right is either a wall or hidden + } else if ( !fogHidden(cell + mapWidth) + && (fogHidden(cell - 1) || wall(cell - 1)) + && (fogHidden(cell + 1) || wall(cell + 1)) + && (fogHidden(cell - 1 + mapWidth) || wall(cell - 1 + mapWidth)) + && (fogHidden(cell + 1 + mapWidth) || wall(cell + 1 + mapWidth))) { + curr = BLOCK_BELOW; } else { curr = BLOCK_NONE; } + //wall tiles } else { - if (fogHidden(cell - mapWidth) && fogHidden(cell) && fogHidden(cell + mapWidth)) { - curr = BLOCK_NONE; + //camera-facing wall tiles + if (!wall(cell + mapWidth)) { - //camera-facing wall tiles - } else if (!wall(cell + mapWidth)) { - - if (!fogHidden(cell + mapWidth)){ + //Block a camera-facing wall if: + //- the cell above, above-left, or above-right is not a wall, visible, and has a wall below + //- none of the remaining 5 neighbour cells are both not a wall and visible + + //if all 3 above are wall we can shortcut and just clear the cell + if (wall(cell - 1 - mapWidth) && wall(cell - mapWidth) && wall(cell + 1 - mapWidth)){ curr = CLEARED; - - } else if ((cell + 1) % mapWidth != 0 && !fogHidden(cell + 1) - && !door(cell + 1) && !(wall(cell + 1) && wall(cell + 1 + mapWidth))){ - curr = CLEARED; - - } else if (cell % mapWidth != 0 && !fogHidden(cell - 1) - && !door(cell - 1) && !(wall(cell - 1) && wall(cell - 1 + mapWidth))){ - curr = CLEARED; - + + } else if ((!wall(cell - 1 - mapWidth) && !fogHidden(cell - 1 - mapWidth) && wall(cell - 1)) || + (!wall(cell - mapWidth) && !fogHidden(cell - mapWidth)) || + (!wall(cell + 1 - mapWidth) && !fogHidden(cell + 1 - mapWidth) && wall(cell+1))){ + + if ( !fogHidden( cell + mapWidth) || + (!wall(cell - 1) && !fogHidden(cell - 1)) || + (!wall(cell - 1 + mapWidth) && !fogHidden(cell - 1 + mapWidth)) || + (!wall(cell + 1) && !fogHidden(cell + 1)) || + (!wall(cell + 1 + mapWidth) && !fogHidden(cell + 1 + mapWidth))){ + curr = CLEARED; + } else { + curr = BLOCK_ALL; + } + } else { - curr = BLOCK_ALL; + curr = BLOCK_NONE; } - //internal wall tiles + //internal wall tiles } else { + + //Block the side of an internal wall if: + //- the cell above, below, or the cell itself is visible + //and all of the following are NOT true: + //- the top-side neighbour is visible and the side neighbour isn't a wall. + //- the side neighbour is both not a wall and visible + //- the bottom-side neighbour is both not a wall and visible curr = BLOCK_NONE; - - if ((cell + 1) % mapWidth != 0) { - if ((wall(cell + 1) || fogHidden(cell + 1 - mapWidth)) - && fogHidden(cell + 1) - && (wall(cell + 1 + mapWidth) || fogHidden(cell + 1 + mapWidth))){ + + if (!fogHidden(cell - mapWidth) + || !fogHidden(cell) + || !fogHidden(cell + mapWidth)) { + + //right side + if ((!wall(cell + 1) && !fogHidden(cell + 1 - mapWidth)) || + (!wall(cell + 1) && !fogHidden(cell + 1)) || + (!wall(cell + 1 + mapWidth) && !fogHidden(cell + 1 + mapWidth)) + ){ + //do nothing + } else { curr += 1; } - } - - if (cell % mapWidth != 0) { - if ((wall(cell - 1) || fogHidden(cell - 1 - mapWidth)) - && fogHidden(cell - 1) - && (wall(cell - 1 + mapWidth) || fogHidden(cell - 1 + mapWidth))){ + + //left side + if ((!wall(cell - 1) && !fogHidden(cell - 1 - mapWidth)) || + (!wall(cell - 1) && !fogHidden(cell - 1)) || + (!wall(cell - 1 + mapWidth) && !fogHidden(cell - 1 + mapWidth)) + ){ + //do nothing + } else { curr += 2; } - } - - if (curr == BLOCK_NONE) { - curr = CLEARED; + + if (curr == BLOCK_NONE) { + curr = CLEARED; + } } } } - if (prev != curr){ + if (data[cell] != curr){ data[cell] = curr; super.updateMapCell(cell); } } private boolean fogHidden(int cell){ - if (cell < 0 || cell >= Dungeon.level.length()) return false; - if (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell]) return true; - if (wall(cell) && cell + mapWidth < Dungeon.level.length() && !wall(cell + mapWidth) && - !Dungeon.level.visited[cell + mapWidth] && !Dungeon.level.mapped[cell + mapWidth]) + if (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell]) { return true; + } else if (wall(cell) && !wall(cell + mapWidth) && + !Dungeon.level.visited[cell + mapWidth] && !Dungeon.level.mapped[cell + mapWidth]) { + return true; + } return false; } - //for the purposes of wall stitching, tiles below the map count as walls private boolean wall(int cell) { - return cell >= 0 && (cell >= size || DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell])); + return DungeonTileSheet.wallStitcheable(Dungeon.level.map[cell]); } private boolean door(int cell) { - return cell >= 0 && cell < size && DungeonTileSheet.doorTile(Dungeon.level.map[cell]); + return DungeonTileSheet.doorTile(Dungeon.level.map[cell]); + } + + public synchronized void updateArea(int cell, int radius){ + int l = cell%mapWidth - radius; + int t = cell/mapWidth - radius; + int r = cell%mapWidth + radius; + int b = cell/mapWidth + radius; + updateArea( + Math.max(0, l), + Math.max(0, t), + Math.min(mapWidth-1, r - l), + Math.min(mapHeight-1, b - t) + ); } public synchronized void updateArea(int x, int y, int w, int h) {