rewritten tile system, added intial flood fill system

v5stable
Ondřej Hruška 11 years ago
parent 307d8d2b10
commit 7b862cb5c8
  1. 2
      src/mightypork/rogue/App.java
  2. 2
      src/mightypork/rogue/screens/gamescreen/world/Minimap.java
  3. 2
      src/mightypork/rogue/world/entity/models/PlayerModel.java
  4. 32
      src/mightypork/rogue/world/gen/ScratchMap.java
  5. 12
      src/mightypork/rogue/world/level/Level.java
  6. 4
      src/mightypork/rogue/world/level/render/TileRenderContext.java
  7. 21
      src/mightypork/rogue/world/pathfinding/FillContext.java
  8. 41
      src/mightypork/rogue/world/pathfinding/FloodFill.java
  9. 167
      src/mightypork/rogue/world/tile/Tile.java
  10. 54
      src/mightypork/rogue/world/tile/TileData.java
  11. 76
      src/mightypork/rogue/world/tile/TileModel.java
  12. 56
      src/mightypork/rogue/world/tile/TileRenderer.java
  13. 12
      src/mightypork/rogue/world/tile/TileType.java
  14. 63
      src/mightypork/rogue/world/tile/Tiles.java
  15. 53
      src/mightypork/rogue/world/tile/models/AbstractNullTile.java
  16. 62
      src/mightypork/rogue/world/tile/models/AbstractTile.java
  17. 50
      src/mightypork/rogue/world/tile/models/Floor.java
  18. 29
      src/mightypork/rogue/world/tile/models/NullTile.java
  19. 65
      src/mightypork/rogue/world/tile/models/SimpleDoor.java
  20. 55
      src/mightypork/rogue/world/tile/models/Wall.java
  21. 4
      src/mightypork/rogue/world/tile/renderers/DoorTileRenderer.java
  22. 2
      src/mightypork/rogue/world/tile/renderers/NullTileRenderer.java
  23. 58
      src/mightypork/rogue/world/tile/tiles/BasicTile.java
  24. 46
      src/mightypork/rogue/world/tile/tiles/DoorTile.java
  25. 45
      src/mightypork/rogue/world/tile/tiles/FloorTile.java
  26. 36
      src/mightypork/rogue/world/tile/tiles/LockedDoorTile.java
  27. 86
      src/mightypork/rogue/world/tile/tiles/NullTile.java
  28. 64
      src/mightypork/rogue/world/tile/tiles/TileWithItems.java
  29. 46
      src/mightypork/rogue/world/tile/tiles/WallTile.java
  30. 23
      src/mightypork/util/files/ion/IonBinary.java
  31. 31
      src/mightypork/util/files/ion/IonBinaryHeadless.java

@ -25,7 +25,6 @@ import mightypork.rogue.screens.test_render.ScreenTestRender;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.control.eventbus.BusEvent; import mightypork.util.control.eventbus.BusEvent;
import mightypork.util.control.eventbus.EventBus; import mightypork.util.control.eventbus.EventBus;
import mightypork.util.files.ion.Ion; import mightypork.util.files.ion.Ion;
@ -107,7 +106,6 @@ public final class App extends BaseApp {
@Override @Override
protected void preInit() protected void preInit()
{ {
Ion.registerBinary(Tile.ION_MARK, Tile.class);
Ion.registerBinary(Item.ION_MARK, Item.class); Ion.registerBinary(Item.ION_MARK, Item.class);
Ion.registerBinary(Level.ION_MARK, Level.class); Ion.registerBinary(Level.ION_MARK, Level.class);
Ion.registerBinary(Entity.ION_MARK, Entity.class); Ion.registerBinary(Entity.ION_MARK, Entity.class);

@ -64,7 +64,7 @@ public class Minimap extends InputComponent implements MouseButtonListener {
for (pos.x = 0, point.x = tl.xi(); pos.x < lw; pos.x++, point.x += unit) { for (pos.x = 0, point.x = tl.xi(); pos.x < lw; pos.x++, point.x += unit) {
final Tile t = lvl.getTile(pos); final Tile t = lvl.getTile(pos);
if (t.isNull() || !t.data.explored) continue; if (t.isNull() || !t.isExplored()) continue;
final Color clr = t.getMapColor(); final Color clr = t.getMapColor();

@ -86,7 +86,7 @@ public class PlayerModel extends EntityModel {
@Override @Override
public int getPathCost(Entity entity, Coord from, Coord to) public int getPathCost(Entity entity, Coord from, Coord to)
{ {
if (!entity.getLevel().getTile(entity.getCoord()).data.explored) { if (!entity.getLevel().getTile(entity.getCoord()).isExplored()) {
return 1000; return 1000;
} }

@ -15,6 +15,7 @@ import mightypork.rogue.world.pathfinding.PathFinder;
import mightypork.rogue.world.pathfinding.PathFindingContext; import mightypork.rogue.world.pathfinding.PathFindingContext;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.Tiles; import mightypork.rogue.world.tile.Tiles;
import mightypork.util.logging.Log; import mightypork.util.logging.Log;
import mightypork.util.math.Calc; import mightypork.util.math.Calc;
@ -43,14 +44,24 @@ public class ScratchMap {
{ {
final Tile t = get(pos); final Tile t = get(pos);
if (t.isNull()) return 60; switch (t.getType()) {
case NULL:
return 60;
if (t.isDoor()) return 10; // door case DOOR:
if (t.isFloor()) return 20; // floor return 10;
if (t.isWall() && t.genData.isProtected) return 1000; case FLOOR:
return 20;
return 100; // wall case WALL:
if (t.genData.isProtected) return 1000;
return 100;
default:
throw new RuntimeException("Unknown tile type: " + t.getType());
}
} }
@ -79,7 +90,8 @@ public class ScratchMap {
private static final boolean FIX_GLITCHES = true; private static final boolean FIX_GLITCHES = true;
public ScratchMap(int max_size, Theme theme, Random rand) { public ScratchMap(int max_size, Theme theme, Random rand)
{
map = new Tile[max_size][max_size]; map = new Tile[max_size][max_size];
genMin = Coord.make((max_size / 2) - 1, (max_size / 2) - 1); genMin = Coord.make((max_size / 2) - 1, (max_size / 2) - 1);
@ -161,9 +173,7 @@ public class ScratchMap {
public Tile get(Coord pos) public Tile get(Coord pos)
{ {
if (!isIn(pos)) { if (!isIn(pos)) { throw new IndexOutOfBoundsException("Tile not in map: " + pos); }
throw new IndexOutOfBoundsException("Tile not in map: " + pos);
}
return map[pos.y][pos.x]; return map[pos.y][pos.x];
} }
@ -177,9 +187,7 @@ public class ScratchMap {
public boolean set(Coord pos, Tile tile) public boolean set(Coord pos, Tile tile)
{ {
if (!isIn(pos)) { if (!isIn(pos)) { throw new IndexOutOfBoundsException("Tile not in map: " + pos); }
throw new IndexOutOfBoundsException("Tile not in map: " + pos);
}
map[pos.y][pos.x] = tile; map[pos.y][pos.x] = tile;
return true; return true;

@ -100,7 +100,7 @@ public class Level implements MapAccess, IonBinary {
public final void setTile(Coord pos, int tileId) public final void setTile(Coord pos, int tileId)
{ {
setTile(pos, new Tile(tileId)); setTile(pos, Tiles.create(tileId));
} }
@ -163,10 +163,7 @@ public class Level implements MapAccess, IonBinary {
// load tiles // load tiles
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) { for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
for (c.y = 0; c.y < size.y; c.y++) { for (c.y = 0; c.y < size.y; c.y++) {
// no mark setTile(c, Tiles.loadTile(in));
final Tile tile = new Tile();
tile.load(in);
setTile(c, tile);
} }
} }
@ -192,8 +189,7 @@ public class Level implements MapAccess, IonBinary {
for (final Coord c = Coord.zero(); c.x < size.x; c.x++) { for (final Coord c = Coord.zero(); c.x < size.x; c.x++) {
for (c.y = 0; c.y < size.y; c.y++) { for (c.y = 0; c.y < size.y; c.y++) {
// no mark to save space Tiles.saveTile(out, getTile(c));
getTile(c).save(out);
} }
} }
} }
@ -333,7 +329,7 @@ public class Level implements MapAccess, IonBinary {
if (Calc.dist(coord.x, coord.y, c.x, c.y) > radius) continue; if (Calc.dist(coord.x, coord.y, c.x, c.y) > radius) continue;
final Tile t = getTile(c); final Tile t = getTile(c);
if (!t.isNull()) { if (!t.isNull()) {
t.data.explored = true; t.setExplored();
} }
} }
} }

@ -24,7 +24,7 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
{ {
super(map, drawArea); super(map, drawArea);
this.tiler.setOverlap(0.01); // avoid gaps (rounding error?) //this.tiler.setOverlap(0.02); // avoid gaps (rounding error?)
this.noise = map.getNoiseGen(); this.noise = map.getNoiseGen();
} }
@ -69,7 +69,7 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
public void renderItems() public void renderItems()
{ {
map.getTile(pos).renderItems(this); map.getTile(pos).renderExtra(this);
} }

@ -0,0 +1,21 @@
package mightypork.rogue.world.pathfinding;
import mightypork.rogue.world.Coord;
public interface FillContext {
boolean canEnter(Coord pos);
boolean canSpread(Coord pos);
/**
* Get the max distance filled form start point. Use -1 for unlimited range.
*
* @return max distance
*/
int getMaxDistance();
}

@ -0,0 +1,41 @@
package mightypork.rogue.world.pathfinding;
import java.util.*;
import mightypork.rogue.world.Coord;
public class FloodFill {
private static final Coord[] spread = { Coord.make(0, -1), Coord.make(0, 1), Coord.make(1, 0), Coord.make(-1, 0) };
public static final Collection<Coord> fill(Coord start, FillContext context)
{
Set<Coord> filled = new HashSet<>();
Stack<Coord> active = new Stack<>();
int maxDist = context.getMaxDistance();
active.push(start);
while (!active.isEmpty()) {
Coord current = active.pop();
filled.add(current);
for (Coord spr : spread) {
Coord next = current.add(spr);
if (next.dist(start) > maxDist) continue;
if (context.canSpread(next)) {
active.push(next);
}
}
}
return filled;
}
}

@ -8,6 +8,7 @@ import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.level.Level; import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.level.render.TileRenderContext; import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.util.files.ion.IonBinary; import mightypork.util.files.ion.IonBinary;
import mightypork.util.files.ion.IonBinaryHeadless;
import mightypork.util.files.ion.IonInput; import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput; import mightypork.util.files.ion.IonOutput;
import mightypork.util.math.color.Color; import mightypork.util.math.color.Color;
@ -18,211 +19,129 @@ import mightypork.util.math.color.Color;
* *
* @author MightyPork * @author MightyPork
*/ */
public final class Tile implements IonBinary { public abstract class Tile implements IonBinaryHeadless {
public static final short ION_MARK = 50;
private TileModel model;
private TileRenderer renderer;
private int id;
private final Stack<Item> items = new Stack<>();
/** persistent field for model, reflected by renderer */
public final TileData data = new TileData();
// tmp extras
public final TileRenderData renderData = new TileRenderData(); public final TileRenderData renderData = new TileRenderData();
public final TileGenData genData = new TileGenData(); public final TileGenData genData = new TileGenData();
// temporary flag for map. protected final TileRenderer renderer;
private boolean occupied;
public final int id;
public Tile(int id) { protected final Stack<Item> items = new Stack<>();
this(Tiles.get(id));
}
public Tile(TileModel model) { // temporary flag for map.
setModel(model); protected boolean occupied;
} protected boolean explored;
public Tile() {
}
private void setModel(TileModel model) public Tile(int id, TileRenderer renderer)
{ {
this.model = model; this.id = id;
this.id = model.id; this.renderer = renderer;
this.renderer = model.renderer;
} }
/** /**
* Render the tile alone (must not use other than the main map texture) * Render the tile, using the main texture sheet.
*/ */
public void renderTile(TileRenderContext context) public abstract void renderTile(TileRenderContext context);
{
renderer.render(context);
if (hasItems()) {
renderer.renderItemOnTile(items.peek(), context);
}
}
/** /**
* Render items * Render extra stuff (ie. dropped items).<br>
* Called after the whole map is rendered using renderTile.
* *
* @param context * @param context
*/ */
public void renderItems(TileRenderContext context) public abstract void renderExtra(TileRenderContext context);
{
if (hasItems()) {
renderer.renderItemOnTile(items.peek(), context);
}
}
@Override @Override
public void save(IonOutput out) throws IOException public void save(IonOutput out) throws IOException
{ {
out.writeIntByte(id); out.writeBoolean(explored);
if (model.hasDroppedItems()) {
out.writeSequence(items);
}
data.save(out);
} }
@Override @Override
public void load(IonInput in) throws IOException public void load(IonInput in) throws IOException
{ {
id = in.readIntByte(); explored = in.readBoolean();
// if model changed
if (model == null || id != model.id) {
setModel(Tiles.get(id));
}
if (model.hasDroppedItems()) {
in.readSequence(items);
}
data.load(in);
} }
/** public final boolean isOccupied()
* Update tile logic state (on server)
*
* @param level the level
* @param delta delta time
*/
public void update(Level level, double delta)
{ {
model.update(this, level, delta); return occupied;
} }
public boolean isWalkable() public final void setOccupied(boolean occupied)
{ {
return model.isWalkable(this); this.occupied = occupied;
} }
public boolean isDoor() public final boolean isExplored()
{ {
return model.isDoor(); return explored;
} }
public boolean isNull() public void setExplored()
{ {
return model.isNullTile(); explored = true;
} }
public TileModel getModel() public final boolean isNull()
{ {
return model; return getType() == TileType.NULL;
} }
public boolean hasItems() public final boolean isWall()
{ {
return model.hasDroppedItems() && !items.isEmpty(); return getType() == TileType.WALL;
} }
public boolean doesCastShadow() public final boolean isFloor()
{ {
return model.doesCastShadow(); return getType() == TileType.FLOOR;
} }
@Override public final boolean isDoor()
public short getIonMark()
{ {
return ION_MARK; return getType() == TileType.DOOR;
} }
public boolean isOccupied() public abstract void update(Level level, double delta);
{
return occupied;
}
public void setOccupied(boolean occupied)
{
this.occupied = occupied;
}
public abstract boolean isWalkable();
public boolean isWall()
{
return model.isWall();
}
public abstract boolean isPotentiallyWalkable();
public boolean isFloor()
{
return model.isFloor();
}
public abstract TileType getType();
public boolean isPotentiallyWalkable()
{
return model.isPotentiallyWalkable();
}
public abstract boolean canHaveItems();
public Color getMapColor()
{
return model.getMapColor(this);
}
public abstract boolean doesCastShadow();
public boolean isExplored()
{
return data.explored;
}
public abstract boolean doesReceiveShadow();
public void explore()
{
data.explored = true;
}
public abstract Color getMapColor();
public boolean doesReceiveShadow()
{
return model.doesReceiveShadow();
}
} }

@ -1,54 +0,0 @@
package mightypork.rogue.world.tile;
import java.io.IOException;
import mightypork.util.error.YouFuckedUpException;
import mightypork.util.files.ion.IonBinary;
import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
public class TileData implements IonBinary {
private static final byte BIT_EXPLORED = 1 << 0;
private static final byte BIT_LOCKED = 1 << 1;
public boolean explored = false;
public boolean locked = false;
public final IonBundle extra = new IonBundle();
@Override
public void load(IonInput in) throws IOException
{
final byte flags = in.readByte();
in.readBundle(extra);
explored = (flags & BIT_EXPLORED) != 0;
locked = (flags & BIT_LOCKED) != 0;
}
@Override
public void save(IonOutput out) throws IOException
{
byte flags = 0;
if (explored) flags |= BIT_EXPLORED;
if (locked) flags |= BIT_LOCKED;
out.writeByte(flags);
out.writeBundle(extra);
}
@Override
public short getIonMark()
{
throw new YouFuckedUpException("TileData is not to be read from ION using mark.");
}
}

@ -1,8 +1,9 @@
package mightypork.rogue.world.tile; package mightypork.rogue.world.tile;
import mightypork.rogue.world.level.Level; import java.io.IOException;
import mightypork.util.math.color.Color; import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
/** /**
@ -10,79 +11,46 @@ import mightypork.util.math.color.Color;
* *
* @author MightyPork * @author MightyPork
*/ */
public abstract class TileModel { public final class TileModel {
/** Model ID */ /** Model ID */
public final int id; public final int id;
public TileRenderer renderer = TileRenderer.NONE; public final TileRenderer renderer;
public final Class<? extends Tile> tileClass;
public TileModel(int id) public TileModel(int id, Class<? extends Tile> tile, TileRenderer renderer)
{ {
Tiles.register(id, this); Tiles.register(id, this);
this.id = id; this.id = id;
}
public TileModel setRenderer(TileRenderer renderer)
{
this.renderer = renderer; this.renderer = renderer;
return this; this.tileClass = tile;
} }
/** /**
* @return new tile of this type; if 100% invariant, can return cached one. * @return new tile of this type
*/ */
public Tile createTile() public Tile createTile()
{ {
return new Tile(this); try {
return tileClass.getConstructor(int.class, TileRenderer.class).newInstance(id, renderer);
} catch (Exception e) {
throw new RuntimeException("Could not instantiate a tile.", e);
}
} }
public abstract boolean isWalkable(Tile tile); public Tile loadTile(IonInput in) throws IOException
public abstract boolean isDoor();
public abstract boolean isWall();
public abstract boolean isFloor();
public abstract boolean doesCastShadow();
public abstract boolean doesReceiveShadow();
public boolean isNullTile()
{ {
return false; Tile t = createTile();
t.load(in);
return t;
} }
/** public void saveTile(IonOutput out, Tile tile) throws IOException
* Update tile in world {
*/ tile.save(out);
public abstract void update(Tile tile, Level level, double delta); }
/**
* @return true if this item can have dropped items
*/
public abstract boolean hasDroppedItems();
/**
* @return true if walkable at some conditions (ie. floor, hidden door,
* locked door etc)
*/
public abstract boolean isPotentiallyWalkable();
public abstract Color getMapColor(Tile tile);
} }

@ -4,9 +4,7 @@ import mightypork.gamecore.render.Render;
import mightypork.gamecore.render.textures.TxQuad; import mightypork.gamecore.render.textures.TxQuad;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.rogue.world.Sides; import mightypork.rogue.world.Sides;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.level.render.TileRenderContext; import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.renderers.NullTileRenderer;
import mightypork.util.math.constraints.rect.Rect; import mightypork.util.math.constraints.rect.Rect;
@ -17,16 +15,12 @@ import mightypork.util.math.constraints.rect.Rect;
*/ */
public abstract class TileRenderer { public abstract class TileRenderer {
public static final TileRenderer NONE = new NullTileRenderer();
private static TxQuad SH_N, SH_S, SH_E, SH_W, SH_NW, SH_NE, SH_SW, SH_SE; private static TxQuad SH_N, SH_S, SH_E, SH_W, SH_NW, SH_NE, SH_SW, SH_SE;
private static TxQuad UFOG_N, UFOG_S, UFOG_E, UFOG_W, UFOG_NW, UFOG_NE, UFOG_SW, UFOG_SE; private static TxQuad UFOG_N, UFOG_S, UFOG_E, UFOG_W, UFOG_NW, UFOG_NE, UFOG_SW, UFOG_SE;
private static boolean inited; private static boolean inited;
private DroppedItemRenderer itemRenderer;
public TileRenderer() { public TileRenderer() {
if (!inited) { if (!inited) {
@ -51,41 +45,10 @@ public abstract class TileRenderer {
} }
/** public abstract void renderTile(TileRenderContext context);
* Update tile renderer
*
* @param delta delta time
*/
public void update(double delta)
{
if (itemRenderer != null) {
itemRenderer.update(delta);
}
}
/** public void renderShadows(TileRenderContext context)
* Render the tile.
*
* @param context
*/
public final void render(TileRenderContext context)
{
Tile t = context.getTile();
if (t.isNull() || !t.isExplored()) return;
renderTile(context);
if (t.doesReceiveShadow()) renderShadows(context);
renderUFog(context);
}
protected abstract void renderTile(TileRenderContext context);
protected void renderShadows(TileRenderContext context)
{ {
final TileRenderData trd = context.getTile().renderData; final TileRenderData trd = context.getTile().renderData;
@ -96,7 +59,7 @@ public abstract class TileRenderer {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
final Tile t2 = context.getAdjacentTile(Sides.get(i)); final Tile t2 = context.getAdjacentTile(Sides.get(i));
if (t2.doesCastShadow()) { if (!t2.isNull() && t2.doesCastShadow()) {
trd.shadows |= Sides.bit(i); trd.shadows |= Sides.bit(i);
} }
} }
@ -120,9 +83,8 @@ public abstract class TileRenderer {
} }
protected void renderUFog(TileRenderContext context) public void renderUnexploredFog(TileRenderContext context)
{ {
// TODO cache in tile, update neighbouring tiles upon "explored" flag changed. // TODO cache in tile, update neighbouring tiles upon "explored" flag changed.
byte ufog = 0; byte ufog = 0;
@ -150,14 +112,4 @@ public abstract class TileRenderer {
if ((ufog & Sides.S) != 0) Render.quadTextured(rect, UFOG_S); if ((ufog & Sides.S) != 0) Render.quadTextured(rect, UFOG_S);
if ((ufog & Sides.SE_CORNER) == Sides.SE) Render.quadTextured(rect, UFOG_SE); if ((ufog & Sides.SE_CORNER) == Sides.SE) Render.quadTextured(rect, UFOG_SE);
} }
public void renderItemOnTile(Item item, TileRenderContext context)
{
if (itemRenderer == null) {
itemRenderer = new DroppedItemRenderer();
}
itemRenderer.render(item, context);
}
} }

@ -0,0 +1,12 @@
package mightypork.rogue.world.tile;
/**
* Kinds of tiles
*
* @author MightyPork
*/
public enum TileType
{
NULL, FLOOR, WALL, DOOR;
}

@ -1,11 +1,18 @@
package mightypork.rogue.world.tile; package mightypork.rogue.world.tile;
import mightypork.rogue.world.tile.models.Floor; import java.io.IOException;
import mightypork.rogue.world.tile.models.NullTile;
import mightypork.rogue.world.tile.models.SimpleDoor;
import mightypork.rogue.world.tile.models.Wall;
import mightypork.rogue.world.tile.renderers.BasicTileRenderer; import mightypork.rogue.world.tile.renderers.BasicTileRenderer;
import mightypork.rogue.world.tile.renderers.DoorTileRenderer;
import mightypork.rogue.world.tile.renderers.NullTileRenderer;
import mightypork.rogue.world.tile.tiles.DoorTile;
import mightypork.rogue.world.tile.tiles.FloorTile;
import mightypork.rogue.world.tile.tiles.NullTile;
import mightypork.rogue.world.tile.tiles.WallTile;
import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
/** /**
* Tile registry * Tile registry
@ -16,29 +23,13 @@ public final class Tiles {
private static final TileModel[] tiles = new TileModel[256]; private static final TileModel[] tiles = new TileModel[256];
public static final TileModel NULL = new NullTile(0); public static final TileModel NULL = new TileModel(0, NullTile.class, new NullTileRenderer());
public static final TileModel FLOOR_DARK = new Floor(10).setRenderer(new BasicTileRenderer("tile.floor.dark"));
public static final TileModel WALL_BRICK = new Wall(11).setRenderer(new BasicTileRenderer("tile.wall.brick"));
public static final TileModel DOOR = new SimpleDoor(12); public static final TileModel FLOOR_DARK = new TileModel(10, FloorTile.class, new BasicTileRenderer("tile.floor.dark"));
public static final TileModel WALL_BRICK = new TileModel(11, WallTile.class, new BasicTileRenderer("tile.wall.brick"));
public static final TileModel DOOR = new TileModel(12, DoorTile.class, new DoorTileRenderer("tile.door.closed", "tile.door.open"));
// public static final TileModel BRICK_FLOOR_VINES = new Floor(2).setTexture("tile.floor.mossy_bricks");
// public static final TileModel BRICK_WALL_VINES = new Wall(3).setTexture("tile.wall.mossy_bricks");
//
// public static final TileModel BRICK_FLOOR_RECT = new Floor(4).setTexture("tile.floor.rect_bricks");
// public static final TileModel BRICK_WALL_SMALL = new Wall(5).setTexture("tile.wall.small_bricks");
//
// public static final TileModel SANDSTONE_FLOOR = new Floor(6).setTexture("tile.floor.sandstone");
// public static final TileModel SANDSTONE_WALL = new Wall(7).setTexture("tile.wall.sandstone");
//
// public static final TileModel BRCOBBLE_FLOOR = new Floor(8).setTexture("tile.floor.brown_cobble");
// public static final TileModel BRCOBBLE_WALL = new Wall(9).setTexture("tile.wall.brown_cobble");
//
// public static final TileModel CRYSTAL_FLOOR = new Floor(10).setTexture("tile.floor.crystal");
// public static final TileModel CRYSTAL_WALL = new Wall(11).setTexture("tile.wall.crystal");
public static void register(int id, TileModel model) public static void register(int id, TileModel model)
{ {
if (id < 0 || id >= tiles.length) { throw new IllegalArgumentException("Tile ID " + id + " is out of range."); } if (id < 0 || id >= tiles.length) { throw new IllegalArgumentException("Tile ID " + id + " is out of range."); }
@ -57,4 +48,28 @@ public final class Tiles {
return m; return m;
} }
public static Tile loadTile(IonInput in) throws IOException
{
int id = in.readIntByte();
TileModel model = get(id);
return model.loadTile(in);
}
public static void saveTile(IonOutput out, Tile tile) throws IOException
{
out.writeIntByte(tile.id);
TileModel model = get(tile.id);
model.saveTile(out, tile);
}
public static Tile create(int tileId)
{
return get(tileId).createTile();
}
} }

@ -1,53 +0,0 @@
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.tile.Tile;
/**
* Null tile
*
* @author MightyPork
*/
public abstract class AbstractNullTile extends AbstractTile {
private Tile inst;
public AbstractNullTile(int id)
{
super(id);
}
@Override
public boolean isNullTile()
{
return true;
}
@Override
public Tile createTile()
{
if (inst == null) {
inst = new Tile(this);
}
return inst;
}
@Override
public boolean hasDroppedItems()
{
return false;
}
@Override
public boolean doesCastShadow()
{
return false;
}
}

@ -1,62 +0,0 @@
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel;
import mightypork.util.annotations.DefaultImpl;
/**
* Basic implementation of a tile.
*
* @author MightyPork
*/
public abstract class AbstractTile extends TileModel {
public AbstractTile(int id)
{
super(id);
}
@Override
public boolean isWalkable(Tile tile)
{
return isPotentiallyWalkable();
}
@Override
public boolean isDoor()
{
return false;
}
@Override
public boolean isWall()
{
return false;
}
@Override
public boolean isFloor()
{
return false;
}
@Override
public boolean doesReceiveShadow()
{
return isFloor();
}
@Override
@DefaultImpl
public void update(Tile tile, Level level, double delta)
{
}
}

@ -1,50 +0,0 @@
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.RGB;
public class Floor extends AbstractTile {
public Floor(int id)
{
super(id);
}
@Override
public boolean isPotentiallyWalkable()
{
return true;
}
@Override
public boolean hasDroppedItems()
{
return true;
}
@Override
public boolean doesCastShadow()
{
return false;
}
@Override
public boolean isFloor()
{
return true;
}
@Override
public Color getMapColor(Tile tile)
{
return RGB.GRAY_DARK;
}
}

@ -1,29 +0,0 @@
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.RGB;
public class NullTile extends AbstractNullTile {
public NullTile(int id)
{
super(id);
}
@Override
public boolean isPotentiallyWalkable()
{
return false;
}
@Override
public Color getMapColor(Tile tile)
{
return RGB.NONE;
}
}

@ -1,65 +0,0 @@
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.renderers.DoorRenderer;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.PAL16;
public class SimpleDoor extends AbstractTile {
public SimpleDoor(int id)
{
super(id);
setRenderer(new DoorRenderer("tile.door.closed", "tile.door.open"));
}
@Override
public boolean isPotentiallyWalkable()
{
return true;
}
@Override
public boolean isWalkable(Tile tile)
{
return !isLocked(tile);
}
protected boolean isLocked(Tile tile)
{
return false;
}
@Override
public boolean isDoor()
{
return true;
}
@Override
public boolean doesCastShadow()
{
return true;
}
@Override
public boolean hasDroppedItems()
{
return false;
}
@Override
public Color getMapColor(Tile tile)
{
return PAL16.NEWPOOP;
}
}

@ -1,55 +0,0 @@
package mightypork.rogue.world.tile.models;
import mightypork.rogue.world.tile.Tile;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.RGB;
/**
* Template for wall tiles with no metadata
*
* @author MightyPork
*/
public class Wall extends AbstractTile {
public Wall(int id)
{
super(id);
}
@Override
public final boolean hasDroppedItems()
{
return false;
}
@Override
public final boolean doesCastShadow()
{
return true;
}
@Override
public final boolean isWall()
{
return true;
}
@Override
public final boolean isPotentiallyWalkable()
{
return false;
}
@Override
public Color getMapColor(Tile tile)
{
return RGB.GRAY_LIGHT;
}
}

@ -10,13 +10,13 @@ import mightypork.rogue.world.tile.TileRenderer;
import mightypork.util.math.constraints.rect.Rect; import mightypork.util.math.constraints.rect.Rect;
public class DoorRenderer extends TileRenderer { public class DoorTileRenderer extends TileRenderer {
private final TxQuad closed; private final TxQuad closed;
private final TxQuad open; private final TxQuad open;
public DoorRenderer(String quadClosed, String quadOpen) public DoorTileRenderer(String quadClosed, String quadOpen)
{ {
this.closed = Res.getTxQuad(quadClosed); this.closed = Res.getTxQuad(quadClosed);
this.open = Res.getTxQuad(quadOpen); this.open = Res.getTxQuad(quadOpen);

@ -8,7 +8,7 @@ import mightypork.rogue.world.tile.TileRenderer;
public class NullTileRenderer extends TileRenderer { public class NullTileRenderer extends TileRenderer {
@Override @Override
protected void renderTile(TileRenderContext context) public void renderTile(TileRenderContext context)
{ {
} }

@ -0,0 +1,58 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.util.annotations.DefaultImpl;
public abstract class BasicTile extends Tile {
public BasicTile(int id, TileRenderer renderer)
{
super(id, renderer);
}
@Override
public boolean isWalkable()
{
return isPotentiallyWalkable();
}
@Override
public void renderTile(TileRenderContext context)
{
if (!isExplored()) return;
renderer.renderTile(context);
if (doesReceiveShadow()) renderer.renderShadows(context);
renderer.renderUnexploredFog(context);
}
@Override
@DefaultImpl
public void renderExtra(TileRenderContext context)
{
}
@Override
@DefaultImpl
public void update(Level level, double delta)
{
}
@Override
public boolean doesReceiveShadow()
{
return !doesCastShadow();
}
}

@ -0,0 +1,46 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.PAL16;
public class DoorTile extends BasicTile {
public DoorTile(int id, TileRenderer renderer)
{
super(id, renderer);
}
@Override
public boolean isPotentiallyWalkable()
{
return true;
}
@Override
public TileType getType()
{
return TileType.DOOR;
}
@Override
public boolean canHaveItems()
{
return false;
}
@Override
public boolean doesCastShadow()
{
return true;
}
@Override
public Color getMapColor()
{
return PAL16.NEWPOOP;
}
}

@ -0,0 +1,45 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.RGB;
public class FloorTile extends TileWithItems {
public FloorTile(int id, TileRenderer renderer)
{
super(id, renderer);
}
@Override
public boolean isPotentiallyWalkable()
{
return true;
}
@Override
public TileType getType()
{
return TileType.FLOOR;
}
@Override
public boolean doesCastShadow()
{
return false;
}
@Override
public Color getMapColor()
{
return RGB.GRAY_DARK;
}
}

@ -0,0 +1,36 @@
package mightypork.rogue.world.tile.tiles;
import java.io.IOException;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
public class LockedDoorTile extends DoorTile {
public boolean locked = true;
public LockedDoorTile(int id, TileRenderer renderer)
{
super(id, renderer);
}
@Override
public void load(IonInput in) throws IOException
{
super.load(in);
locked = in.readBoolean();
}
@Override
public void save(IonOutput out) throws IOException
{
super.save(out);
out.writeBoolean(locked);
}
}

@ -0,0 +1,86 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.RGB;
public class NullTile extends Tile {
public NullTile(int id, TileRenderer renderer)
{
super(id, renderer);
}
@Override
public void update(Level level, double delta)
{
}
@Override
public void renderTile(TileRenderContext context)
{
}
@Override
public void renderExtra(TileRenderContext context)
{
}
@Override
public boolean isWalkable()
{
return false;
}
@Override
public boolean isPotentiallyWalkable()
{
return false;
}
@Override
public TileType getType()
{
return TileType.NULL;
}
@Override
public boolean canHaveItems()
{
return false;
}
@Override
public boolean doesCastShadow()
{
return false;
}
@Override
public boolean doesReceiveShadow()
{
return false;
}
@Override
public Color getMapColor()
{
return RGB.NONE;
}
}

@ -0,0 +1,64 @@
package mightypork.rogue.world.tile.tiles;
import java.io.IOException;
import mightypork.rogue.world.level.Level;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.DroppedItemRenderer;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput;
public abstract class TileWithItems extends BasicTile {
private DroppedItemRenderer itemRenderer = new DroppedItemRenderer();
public TileWithItems(int id, TileRenderer renderer)
{
super(id, renderer);
}
@Override
public void renderExtra(TileRenderContext context)
{
if (!items.isEmpty()) {
itemRenderer.render(items.peek(), context);
}
}
@Override
public void update(Level level, double delta)
{
itemRenderer.update(delta);
}
@Override
public boolean canHaveItems()
{
return true;
}
@Override
public void save(IonOutput out) throws IOException
{
super.save(out);
out.writeSequence(items);
}
@Override
public void load(IonInput in) throws IOException
{
super.load(in);
in.readSequence(items);
}
}

@ -0,0 +1,46 @@
package mightypork.rogue.world.tile.tiles;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.TileType;
import mightypork.util.math.color.Color;
import mightypork.util.math.color.RGB;
public class WallTile extends BasicTile {
public WallTile(int id, TileRenderer renderer)
{
super(id, renderer);
}
@Override
public boolean isPotentiallyWalkable()
{
return false;
}
@Override
public TileType getType()
{
return TileType.WALL;
}
@Override
public boolean canHaveItems()
{
return false;
}
@Override
public boolean doesCastShadow()
{
return true;
}
@Override
public Color getMapColor()
{
return RGB.GRAY_LIGHT;
}
}

@ -5,30 +5,11 @@ import java.io.IOException;
/** /**
* Binary ion object * Binary ion object, with a mark = saveable / loadable on it's own
* *
* @author MightyPork * @author MightyPork
*/ */
public interface IonBinary { public interface IonBinary extends IonBinaryHeadless {
/**
* Load data from the input stream.
*
* @param in input stream
* @throws IOException
*/
void load(IonInput in) throws IOException;
/**
* Store data to output stream (in such way that the load method will later
* be able to read it).
*
* @param out Output stream
* @throws IOException
*/
void save(IonOutput out) throws IOException;
/** /**
* Get Ion mark byte. * Get Ion mark byte.

@ -0,0 +1,31 @@
package mightypork.util.files.ion;
import java.io.IOException;
/**
* Binary ion object, with no mark = cannot be loaded on it's own
*
* @author MightyPork
*/
public interface IonBinaryHeadless {
/**
* Load data from the input stream.
*
* @param in input stream
* @throws IOException
*/
void load(IonInput in) throws IOException;
/**
* Store data to output stream (in such way that the load method will later
* be able to read it).
*
* @param out Output stream
* @throws IOException
*/
void save(IonOutput out) throws IOException;
}
Loading…
Cancel
Save